File Coverage

blib/lib/DBIx/SQLite/Simple/Table.pm
Criterion Covered Total %
statement 199 220 90.4
branch 37 56 66.0
condition n/a
subroutine 31 35 88.5
pod 13 13 100.0
total 280 324 86.4


line stmt bran cond sub pod time code
1             #
2             # $Id: Table.pm,v 1.25 2007-01-27 13:35:02 gomor Exp $
3             #
4              
5             package DBIx::SQLite::Simple::Table;
6 3     3   1384 use strict;
  3         5  
  3         99  
7 3     3   12 use warnings;
  3         4  
  3         69  
8 3     3   10 use Carp;
  3         3  
  3         4835  
9              
10             require Class::Gomor::Array;
11             our @ISA = qw(Class::Gomor::Array);
12              
13             our @AS = qw(
14             dbo
15             );
16             __PACKAGE__->cgBuildIndices;
17             __PACKAGE__->cgBuildAccessorsScalar(\@AS);
18              
19             require DBIx::SQLite::Simple;
20              
21             # XXX: do all SQL request with prepare/execute
22              
23             =head1 NAME
24              
25             DBIx::SQLite::Simple::Table - superclass only used to handle SQL tables
26              
27             =head1 SYNOPSIS
28              
29             # Example of a table with a primary key
30              
31             package TPub;
32              
33             require DBIx::SQLite::Simple::Table;
34             our @ISA = qw(DBIx::SQLite::Simple::Table);
35              
36             our @AS = qw(
37             idPub
38             pub
39             );
40             __PACKAGE__->cgBuildIndices;
41             __PACKAGE__->cgBuildAccessorsScalar(\@AS);
42              
43             # 'our $Id' and 'our @Fields' are named Id and Fields for a good
44             # reason, so do not name these variables by another name.
45             our $Id = $AS[0];
46             our @Fields = @AS[1..$#AS];
47              
48             1;
49              
50             # Example of a table with no key at all
51              
52             package TBeer;
53              
54             require DBIx::SQLite::Simple::Table;
55             our @ISA = qw(DBIx::SQLite::Simple::Table);
56              
57             our @AS = qw(
58             beer
59             country
60             );
61             __PACKAGE__->cgBuildIndices;
62             __PACKAGE__->cgBuildAccessorsScalar(\@AS);
63              
64             our @Fields = @AS;
65              
66             1;
67              
68             # Now, we have two tables, we can play with the database
69              
70             package main;
71              
72             require DBIx::SQLite::Simple;
73             my $db = DBIx::SQLite::Simple->new(db => 'sqlite.db');
74              
75             # Create to object to play with the two tables
76             my $tPub = TPub->new;
77             my $tBeer = TBeer->new;
78              
79             # Create tables
80             $tPub->create unless $tPub->exists;
81             $tBeer->create unless $tBeer->exists;
82              
83             # Create some entries
84             my @pubEntries;
85             push @pubEntries, TPub->new(pub => $_) for (qw(corner friends));
86              
87             my @beerEntries;
88             push @beerEntries, TBeer->new(beer => $_, country => 'BE')
89             for (qw(grim leffe bud));
90              
91             # Now insert those entries;
92             $tPub->insert(\@pubEntries);
93             $tBeer->insert(\@beerEntries);
94              
95             # Get friends pub
96             my $friends = $tPub->select(pub => 'friends');
97              
98             # Lookup id
99             my $id = $tPub->lookupId(pub => 'friends');
100              
101             # Lookup string
102             my $str = $tPub->lookupString('pub', idPub => $id);
103              
104             # Add a beer from 'chez moi'
105             my $dremmwel = TBeer->new(beer => 'Dremmwel', country => '?');
106             $tBeer->insert([ $dremmwel ]);
107              
108             $tPub->commit;
109             $tBeer->commit;
110              
111             # Update Dremmwel
112             my $dremmwelOld = $dremmwel->cgClone;
113             $dremmwel->country('BZH');
114             $tBeer->update([ $dremmwel ], $dremmwelOld);
115             $tBeer->commit;
116              
117             # Delete all pubs
118             $tPub->delete(\@pubEntries);
119              
120             =head1 ATTRIBUTES
121              
122             =over 4
123              
124             =item B
125              
126             Stores a DBIx::SQLite::Simple object.
127              
128             =back
129              
130             =head1 METHODS
131              
132             =over 4
133              
134             =item B
135              
136             Object creator. Will return an object used to access corresponding SQL table. You can pass an optional parameter: dbo. By default, it uses the global variable $DBIx::SQLite::Simple::Dbo.
137              
138             =cut
139              
140             sub new {
141 16     16 1 88 my $self = shift->SUPER::new(@_);
142              
143 16 50       2052 $self->dbo($DBIx::SQLite::Simple::Dbo)
144             unless $self->dbo;
145              
146 16         239 $self;
147             }
148              
149             sub __toObj {
150 4     4   7 my $self = shift;
151 4         8 my ($fields, $aref) = @_;
152              
153 4         5 my $class = ref($self);
154              
155 4         6 my @obj = ();
156 4         9 for my $h (@$aref) {
157 9         13 my %values = map { $_ => $h->{$_} } @$fields;
  18         47  
158 9         25 push @obj, $class->new(%values);
159             }
160 4         64 \@obj;
161             }
162              
163 0     0   0 sub _carp { shift; carp("@{[(caller(0))[3]]}: ".shift()."\n"); undef }
  0         0  
  0         0  
  0         0  
164              
165             sub _create {
166 2     2   3 my $self = shift;
167 2         4 my ($fields, $noKey) = @_;
168              
169 2         12 my ($table) = ref($self) =~ /^(?:.*::)?(.*)/;
170              
171 2         11 my $query = 'CREATE TABLE '. $table. '(';
172 2 100       7 if ($noKey) {
173 1         2 $query .= $fields->[0]. ', ';
174             }
175             else {
176 1         4 $query .= $fields->[0]. ' INTEGER PRIMARY KEY, ';
177             }
178 2         3 shift(@$fields);
179 2         7 $query .= $_. ', ' for @$fields;
180 2         8 $query =~ s/, $/)/;
181              
182 2         7 $self->dbo->_dbh->do($query);
183              
184 2 50       818 return $self->_carp('_create: do: query['.$query.']: '.
185             $self->dbo->_dbh->errstr)
186             if $self->dbo->_dbh->err;
187              
188 2         39 1;
189             }
190              
191             =item B
192              
193             Just a convenient method to commit pending changes to the whole database.
194              
195             =cut
196              
197 8     8 1 52 sub commit { shift->dbo->commit }
198              
199             sub _exists {
200 2     2   3 my $self = shift;
201              
202 2         13 my ($table) = ref($self) =~ /^(?:.*::)?(.*)/;
203              
204 2         5 $self->dbo->_dbh->do('SELECT * FROM '. $table);
205 2 50       534 $self->dbo->_dbh->err ? undef : 1;
206             }
207              
208             sub _delete {
209 2     2   4 my $self = shift;
210 2         4 my ($fields, $values) = @_;
211              
212 2         21 my ($table) = ref($self) =~ /^(?:.*::)?(.*)/;
213            
214 2         9 my $query = 'DELETE FROM '. $table. ' WHERE ';
215 2         13 $query .= $_. '=? AND ' for @$fields;
216 2         13 $query =~ s/ AND $//;
217 2         16 my $sth = $self->dbo->_dbh->prepare($query);
218              
219 2 50       362 return $self->_carp('_delete: prepare: query['.$query.']: '.
220             $self->dbo->_dbh->errstr)
221             if $self->dbo->_dbh->err;
222              
223 2         48 for my $obj (@$values) {
224 5         71 my @fields;
225 5         22 push @fields, $obj->$_ for @$fields;
226 5         618 $sth->execute(@fields);
227              
228 5 50       34 return $self->_carp('_delete: execute: '.$self->dbo->_dbh->errstr)
229             if $self->dbo->_dbh->err;
230             }
231 2         51 $sth->finish;
232              
233 2         39 1;
234             }
235              
236             sub _update {
237 2     2   4 my $self = shift;
238 2         3 my ($fields, $id, $values, $where) = @_;
239              
240 2         13 my ($table) = ref($self) =~ /^(?:.*::)?(.*)/;
241              
242 2         6 my $query = 'UPDATE '. $table. ' SET ';
243 2         11 $query .= $_. '=?, ' for @$fields;
244 2         9 $query =~ s/, $/ WHERE /;
245 2 100       7 if ($id) {
246 1         1 $query .= $id. '=?';
247             }
248             else {
249 1         4 $query .= $_. '=? AND ' for @$fields;
250 1         3 $query =~ s/ AND $//;
251             }
252 2         12 my $sth = $self->dbo->_dbh->prepare($query);
253              
254 2 50       156 return $self->_carp('_update: prepare: query['.$query.']: '.
255             $self->dbo->_dbh->errstr)
256             if $self->dbo->_dbh->err;
257              
258 2         45 for my $obj (@$values) {
259 2         2 my @fields;
260 2         12 push @fields, $obj->$_ for @$fields;
261 1         4 $id ? do { push @fields, $obj->$id }
262 2 100       39 : do { push @fields, $where->$_ for @$fields };
  1         2  
263 2         365 $sth->execute(@fields);
264              
265 2 50       13 return $self->_carp('_update: execute: '.$self->dbo->_dbh->errstr)
266             if $self->dbo->_dbh->err;
267             }
268 2         47 $sth->finish;
269              
270 2         22 1;
271             }
272              
273             sub _insert {
274 4     4   8 my $self = shift;
275 4         9 my ($fields, $values) = @_;
276              
277 4         36 my ($table) = ref($self) =~ /^(?:.*::)?(.*)/;
278            
279 4         11 my $query = 'INSERT INTO '. $table. '(';
280 4         19 $query .= $_. ', ' for @$fields;
281 4         22 $query =~ s/, $/) VALUES (/;
282 4         13 $query .= ('?, ' x scalar @$fields);
283 4         12 $query =~ s/, $/)/;
284 4         18 my $sth = $self->dbo->_dbh->prepare($query);
285              
286 4 50       400 return $self->_carp('_insert: prepare: query['.$query.']: '.
287             $self->dbo->_dbh->errstr)
288             if $self->dbo->_dbh->err;
289              
290 4         71 for my $obj (@$values) {
291 10         109 my @fields;
292 10         37 push @fields, $obj->$_ for @$fields;
293 10         660 $sth->execute(@fields);
294              
295 10 50       30 return $self->_carp('_insert: execute: '.$self->dbo->_dbh->errstr)
296             if $self->dbo->_dbh->err;
297             }
298 4         80 $sth->finish;
299              
300 4         49 1;
301             }
302              
303             sub _select {
304 4     4   10 my $self = shift;
305 4         9 my (%fields) = @_;
306              
307 4         33 my ($table) = ref($self) =~ /^(?:.*::)?(.*)/;
308              
309 4         14 my $query = 'SELECT * FROM '. $table. ' WHERE ';
310 4 100       16 if (%fields) {
311 1         3 do { $query .= $_. '=? AND ' } for keys %fields;
  1         3  
312 1         6 $query =~ s/ AND $//;
313             }
314             else {
315 3         57 $query =~ s/ WHERE $//;
316             }
317              
318 4         24 my $sth = $self->dbo->_dbh->prepare($query);
319              
320 4 50       470 return $self->_carp('_select: prepare: query['.$query.']: '.
321             $self->dbo->_dbh->errstr)
322             if $self->dbo->_dbh->err;
323              
324 4 100       256 %fields
325             ? $sth->execute(values %fields)
326             : $sth->execute;
327              
328 4 50       18 return $self->_carp('_select: execute: '.$self->dbo->_dbh->errstr)
329             if $self->dbo->_dbh->err;
330              
331 4         114 my $res = $sth->fetchall_arrayref({});
332              
333 4 50       295 return $self->_carp('_select: fetchall_arrayref: '.$self->dbo->_dbh->errstr)
334             if $self->dbo->_dbh->err;
335              
336 4         71 $sth->finish;
337              
338 4 50       56 $self->can('_toObj')
339             ? return $self->_toObj($res)
340             : return $res->[0];
341             }
342              
343             sub _lookupId {
344 2     2   2 my $self = shift;
345 2         6 my ($id, %fields) = @_;
346              
347 2         14 my ($table) = ref($self) =~ /^(?:.*::)?(.*)/;
348              
349 2         6 my $query = 'SELECT '. $id. ' FROM '. $table. ' WHERE ';
350 2         6 do { $query .= $_. '=? AND ' } for keys %fields;
  2         6  
351 2         10 $query =~ s/ AND $//;
352              
353 2         10 my $sth = $self->dbo->_dbh->prepare($query);
354              
355 2 50       227 return $self->_carp('_lookupId: prepare: query['.$query.']: '.
356             $self->dbo->_dbh->errstr)
357             if $self->dbo->_dbh->err;
358              
359 2         158 $sth->execute(values %fields);
360              
361 2 50       10 return $self->_carp('_lookupId: execute: '.$self->dbo->_dbh->errstr)
362             if $self->dbo->_dbh->err;
363              
364 2         63 my @res = $sth->fetchrow_array;
365              
366 2 50       7 return $self->_carp('_lookupId: fetchrow_array: '.$self->dbo->_dbh->errstr)
367             if $self->dbo->_dbh->err;
368              
369 2         38 $sth->finish;
370              
371 2         89 $res[0];
372             }
373              
374             sub _lookupString {
375 2     2   4 my $self = shift;
376 2         4 my ($string, %fields) = @_;
377              
378 2         15 my ($table) = ref($self) =~ /^(?:.*::)?(.*)/;
379              
380 2         7 my $query = 'SELECT '. $string. ' FROM '. $table. ' WHERE ';
381 2         6 do { $query .= $_. '=? AND ' } for keys %fields;
  2         6  
382 2         8 $query =~ s/ AND $//;
383              
384 2         6 my $sth = $self->dbo->_dbh->prepare($query);
385              
386 2 50       162 return $self->_carp('_lookupString: prepare: query['.$query.']: '.
387             $self->dbo->_dbh->errstr)
388             if $self->dbo->_dbh->err;
389              
390 2         141 $sth->execute(values %fields);
391              
392 2 50       9 return $self->_carp('_lookupString: execute: '.$self->dbo->_dbh->errstr)
393             if $self->dbo->_dbh->err;
394              
395 2         63 my @res = $sth->fetchrow_array;
396              
397 2 50       7 return $self->_carp('_lookupString: fetchrow_array: '.
398             $self->dbo->_dbh->errstr)
399             if $self->dbo->_dbh->err;
400              
401 2         31 $sth->finish;
402              
403 2         55 $res[0];
404             }
405              
406             # XXX: _lookupObject to return a list of objects
407              
408             sub _toObj {
409 4     4   15 my $self = shift;
410              
411 3     3   14 no strict 'refs';
  3         7  
  3         276  
412 4         6 my $id = ${ref($self). '::Id'};
  4         13  
413 4         5 my @fields = @{ref($self). '::Fields'};
  4         18  
414              
415 4 100       24 $id ? return $self->__toObj([ $id, @fields ], @_)
416             : return $self->__toObj(\@fields, @_);
417             }
418              
419             =item B
420              
421             Method to create the table.
422              
423             =cut
424              
425             sub create {
426 2     2 1 62 my $self = shift;
427              
428 3     3   13 no strict 'refs';
  3         2  
  3         383  
429 2         4 my $id = ${ref($self). '::Id'};
  2         8  
430 2         2 my @fields = @{ref($self). '::Fields'};
  2         9  
431              
432 2 100       15 $id ? return $self->_create([ $id, @fields ], @_)
433             : return $self->_create(\@fields, 1, @_);
434             }
435              
436             =item B
437              
438             Method to verify existence of a table.
439              
440             =cut
441              
442 2     2 1 18 sub exists { shift->_exists(@_) }
443              
444             =item B
445              
446             If called without parameters, returns the whole content as an arrayref. If called with a hash as argument containing some table fields with values, it plays as multiple where clauses (return result as an arrayref also). See SYNOPSIS.
447              
448             =cut
449              
450 4     4 1 59977 sub select { shift->_select(@_) }
451              
452             =item B
453              
454             This method returns a reference to an array with each array indice set to the corresponding table object id.
455              
456             =cut
457              
458             sub selectById {
459 0     0 1 0 my $self = shift;
460              
461 3     3   13 no strict 'refs';
  3         4  
  3         250  
462 0         0 my $id = ${ref($self). '::Id'};
  0         0  
463              
464 0         0 my $sorted;
465 0         0 $sorted->[$_->$id] = $_ for @{$self->select(@_)};
  0         0  
466 0         0 $sorted;
467             }
468              
469             =item B
470              
471             Method used to generate a unique key, using to store and retrieve a database element quickly. By default, the key is the first field in the table schema (excluding the id field). It is user responsibility to override this method to use an appropriate key.
472              
473             =cut
474              
475             sub getKey {
476 0     0 1 0 my $self = shift;
477              
478 3     3   13 no strict 'refs';
  3         3  
  3         328  
479 0         0 my @fields = @{ref($self). '::Fields'};
  0         0  
480 0         0 my $key = $fields[0];
481              
482 0         0 $self->$key;
483             }
484              
485             =item B
486              
487             Method used to cache a table content. It uses B to store the object into a reference to a hash. You access a cached element by calling B on an object.
488              
489             =cut
490              
491             sub selectByKey {
492 0     0 1 0 my $self = shift;
493 0         0 my %cache = map { $_->getKey => $_ } @{$self->select(@_)};
  0         0  
  0         0  
494 0         0 \%cache;
495             }
496              
497             =item B($arrayref)
498              
499             Deletes all entries specified in the arrayref (they are all objects of type DBIx::SQLite::Simple::Table).
500              
501             =cut
502              
503             sub delete {
504 2     2 1 121969 my $self = shift;
505              
506 3     3   16 no strict 'refs';
  3         5  
  3         180  
507 2         6 my @fields = @{ref($self). '::Fields'};
  2         22  
508              
509 2         19 $self->_delete(\@fields, @_);
510             }
511              
512             =item B($arrayref)
513              
514             Insert all entries specified in the arrayref (they are all objects of type DBIx
515             ::SQLite::Simple::Table).
516              
517             =cut
518              
519             sub insert {
520 4     4 1 25911 my $self = shift;
521              
522 3     3   11 no strict 'refs';
  3         4  
  3         235  
523 4         8 my $id = ${ref($self). '::Id'};
  4         20  
524 4         4 my @fields = @{ref($self). '::Fields'};
  4         21  
525              
526 4 100       34 $id ? return $self->_insert([ $id, @fields ], @_)
527             : return $self->_insert(\@fields, @_);
528             }
529              
530             =item B($arrayref)
531              
532             Will update elements specified within the arrayref (they are all objects of type DBIx::SQLite::Simple::Table). If an additionnal argument is passed, it will act as a where clause. See SYNOPSIS.
533              
534             =cut
535              
536             sub update {
537 2     2 1 45 my $self = shift;
538              
539 3     3   12 no strict 'refs';
  3         3  
  3         253  
540 2         2 my $id = ${ref($self). '::Id'};
  2         7  
541 2         4 my @fields = @{ref($self). '::Fields'};
  2         41  
542              
543 2 100       16 $id ? return $self->_update([ $id, @fields ], $id, @_)
544             : return $self->_update(\@fields, undef, @_);
545             }
546              
547             =item B(%hash)
548              
549             Returns the the id if the specified field/value hash.
550              
551             =cut
552              
553             sub lookupId {
554 2     2 1 5898 my $self = shift;
555              
556 3     3   11 no strict 'refs';
  3         3  
  3         219  
557 2         3 my $id = ${ref($self). '::Id'};
  2         8  
558              
559 2         9 $self->_lookupId($id, @_);
560             }
561              
562             =item B($field, field2 => value)
563              
564             Returns the content of the specified field. See SYNOPSIS.
565              
566             =cut
567              
568 2     2 1 5909 sub lookupString { shift->_lookupString(@_) }
569              
570             =back
571              
572             =head1 AUTHOR
573              
574             Patrice EGomoRE Auffret
575              
576             =head1 COPYRIGHT AND LICENSE
577              
578             Copyright (c) 2005-2015, Patrice EGomoRE Auffret
579              
580             You may distribute this module under the terms of the Artistic license.
581             See LICENSE.Artistic file in the source distribution archive.
582              
583             =cut
584              
585             1;