File Coverage

blib/lib/ClearPress/model.pm
Criterion Covered Total %
statement 361 449 80.4
branch 79 148 53.3
condition 16 46 34.7
subroutine 47 51 92.1
pod 30 30 100.0
total 533 724 73.6


line stmt bran cond sub pod time code
1             # -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*-
2             # vim:ts=8:sw=2:et:sta:sts=2
3             #########
4             # Author: rmp
5             # Created: 2006-10-31
6             #
7             package ClearPress::model;
8 7     7   216800 use strict;
  7         34  
  7         200  
9 7     7   40 use warnings;
  7         16  
  7         183  
10 7     7   35 use base qw(Class::Accessor);
  7         16  
  7         1045  
11 7     7   5133 use ClearPress::util;
  7         22  
  7         66  
12 7     7   266 use English qw(-no_match_vars);
  7         16  
  7         85  
13 7     7   2674 use Carp;
  7         20  
  7         393  
14 7     7   3245 use Lingua::EN::Inflect qw(PL);
  7         152204  
  7         835  
15 7     7   2633 use Lingua::EN::PluralToSingular qw(to_singular);
  7         11542  
  7         504  
16 7     7   53 use POSIX qw(strftime);
  7         16  
  7         59  
17 7     7   524 use Readonly;
  7         51  
  7         13089  
18              
19             our $VERSION = q[477.1.4];
20              
21             Readonly::Scalar our $DBI_CACHE_OVERWRITE => 3;
22              
23             our $EXPERIMENTAL_PL = 0;
24              
25 9     9 1 866 sub fields { return (); }
26              
27             sub _plfunc {
28 31     31   72 my $thing = shift;
29 31 50       165 return $EXPERIMENTAL_PL ? PL(to_singular($thing)) : PL($thing);
30             }
31              
32             sub primary_key {
33 201     201 1 1370 my $self = shift;
34 201         1034 return ($self->fields())[0];
35             }
36              
37       83 1   sub secondary_key {
38             }
39              
40             sub table {
41 46     46 1 1794 my $self = shift;
42 46   100     267 my $tbl = (ref $self) || $self;
43 46 100       166 if(!$tbl) {
44 1         7 return;
45             }
46 45         432 ($tbl) = $tbl =~ /.*::([^:]+)/smx;
47 45         244 return $tbl;
48             }
49              
50       77 1   sub init { }
51              
52             sub new {
53 77     77 1 29574 my ($class, $ref) = @_;
54 77   100     449 $ref ||= {};
55              
56 77         455 my $pk = $class->primary_key();
57              
58 77 100       595 if(!ref $ref) {
59 1 50       6 if($pk) {
60 1         4 $ref = {
61             $pk => $ref,
62             };
63             } else {
64 0         0 croak q[Could not set primary key in an object with no fields];
65             }
66             }
67              
68 77         198 bless $ref, $class;
69              
70 77         317 my $sk = $ref->secondary_key();
71 77 0 33     431 if($sk && $ref->{$sk} &&
      0        
72             !$ref->{$pk}) {
73              
74 0         0 my $table = $ref->table;
75 0         0 my $util = $ref->util;
76 0         0 my $dbh = $util->dbh;
77             eval {
78 0         0 my $id = $dbh->selectall_arrayref(qq[/* model::new */ SELECT $pk FROM $table WHERE $sk=?], {}, $ref->{$sk})->[0]->[0];
79 0         0 $ref->{$pk} = $id;
80 0         0 1;
81              
82 0 0       0 } or do {
83 0         0 carp $EVAL_ERROR;
84 0         0 return;
85             };
86             }
87              
88 77         460 $ref->init($ref);
89              
90 77         388 return $ref;
91             }
92              
93             sub util {
94 59     59 1 5181 my ($self, $util) = @_;
95              
96 59 100       229 if(!ref $self) {
97             #########
98             # If we're being accessed as a class method (e.g. for retrieving
99             # type dictionaries) Then play nicely and return a util.
100             #
101             # Note, this currently needs subclassing if you want class-method
102             # support in your own namespace.
103             #
104 1         10 return ClearPress::util->new();
105             }
106              
107 58 100       195 if($util) {
108 1         19 $self->{util} = $util;
109 1         5 return $util;
110             }
111              
112 57 100       293 if($self->{util}) {
113 54         194 return $self->{util};
114             }
115              
116             #########
117             # attempt to instantiate a util using $self's namespace
118             #
119 3         39 my ($ref) = (ref $self) =~ /^([^:]+)/smx;
120 3         11 my $nsutil;
121             eval {
122 3         14 my $ns = "${ref}::util";
123 3         41 $nsutil = $ns->new();
124              
125 3 100       10 } or do {
126 1         467 carp qq[Failed to construct a util from the current namespace ($ref).];
127             };
128              
129 3 100       213 if($nsutil) {
130 2         14 $self->{util} = $nsutil;
131 2         14 return $self->{util};
132             }
133              
134             #########
135             # ClearPress::driver is now a Class::Singleton so, casually ignoring
136             # the state of any open transactions, we should be able to
137             # instantiate more copies on demand
138             #
139 1         12 my $cputil = ClearPress::util->new();
140 1         6 my $config = $cputil->config();
141 0   0     0 my $namespace = $config->val('application', 'namespace') ||
142             $config->val('application', 'name');
143 0         0 $util = "${namespace}::util"->new();
144 0         0 $self->{util} = $util;
145 0         0 return $util;
146             }
147              
148             sub get {
149 98     98 1 43823 my ($self, $field) = @_;
150              
151 98 100       878 if(!exists $self->{$field}) {
152 18         203 $self->read();
153             }
154              
155 98         436 return $self->SUPER::get($field);
156             }
157              
158             sub gen_getarray {
159 9     9 1 79 my ($self, $class, $query, @args) = @_;
160 9         49 my $util = $self->util();
161              
162 9 50       52 if(!ref $self) {
163 0         0 $self = $self->new({
164             util => $util,
165             });
166             }
167              
168 9         30 my $res = [];
169 9         51 my $sth;
170              
171             eval {
172 9         64 my $dbh = $util->dbh();
173             #########
174             # statement caching removed as cache conflicts are dangerous
175             # and could be easily generated by accident
176 9         137 $sth = $dbh->prepare($query);
177 9         2802 $sth->execute(@args);
178 9         74 1; # sth->execute() does not return true!
179              
180 9 50       26 } or do {
181 0         0 $query =~ s/\s+/ /smxg;
182 0         0 local $LIST_SEPARATOR = q[, ];
183 0 0       0 carp qq[GEN_GETARRAY ERROR\nEVAL_ERROR: $EVAL_ERROR\nCaller: @{[q[].caller]}\nQuery:\n$query\nDBH: @{[$util->dbh]}\nUTIL: $util\nParams: @{[map { (defined $_)?$_:'NULL' } @args]}];
  0         0  
  0         0  
  0         0  
  0         0  
184 0         0 return;
185             };
186              
187 9         341 while(my $ref = $sth->fetchrow_hashref()) {
188 7         31 $ref->{util} = $util;
189 7         17 push @{$res}, $class->new($ref);
  7         35  
190             }
191 9         80 $sth->finish();
192              
193 9         190 return $res;
194             }
195              
196             sub gen_getall {
197 6     6 1 25 my ($self, $class, $cachekey) = @_;
198 6   33     63 $class ||= ref $self;
199              
200 6 50       117 if(!$cachekey) {
201 6         66 ($cachekey) = $class =~ /([^:]+)$/smx;
202 6         38 $cachekey = _plfunc($cachekey);
203             }
204              
205 6 50       3528 if(!$self->{$cachekey}) {
206 6         33 my $sortk = $self->secondary_key;
207 6 50       24 if(!$sortk) {
208 6         28 $sortk = $self->primary_key;
209             }
210 6         57 my $query = <<"EOT";
211             /* model::gen_getall */
212 6         49 SELECT @{[join q(, ), $class->fields()]}
213 6         100 FROM @{[$class->table()]}
214             ORDER BY $sortk
215             EOT
216 6         45 $self->{$cachekey} = $self->gen_getarray($class, $query);
217             }
218              
219 6         159 return $self->{$cachekey};
220             }
221              
222             sub gen_getfriends {
223 1     1 1 6 my ($self, $class, $cachekey) = @_;
224 1   33     8 $class ||= ref $self;
225              
226 1 50       7 if(!$cachekey) {
227 0         0 ($cachekey) = $class =~ /([^:]+)$/smx;
228 0         0 $cachekey = _plfunc($cachekey);
229             }
230              
231 1 50       14 if(!$self->{$cachekey}) {
232 1         6 my $link = $self->primary_key();
233 1         12 my $query = <<"EOT";
234             /* model::gen_getfriends */
235 1         11 SELECT @{[join q(, ), $class->fields()]}
236 1         19 FROM @{[$class->table()]}
237             WHERE $link=?
238             ORDER BY $link
239             EOT
240 1         14 $self->{$cachekey} = $self->gen_getarray($class, $query, $self->$link());
241             }
242              
243 1         7 return $self->{$cachekey};
244             }
245              
246             sub gen_getfriends_through {
247 4     4 1 21 my ($self, $class, $through, $cachekey) = @_;
248 4   33     16 $class ||= ref $self;
249              
250 4 50       16 if(!$cachekey) {
251 0         0 ($cachekey) = $class =~ /([^:]+)$/smx;
252 0         0 $cachekey = _plfunc($cachekey);
253             }
254              
255 4 100       17 if(!$self->{$cachekey}) {
256 1         12 my ($through_pkg) = (ref $self) =~ /^(.*::)[^:]+$/smx;
257 1         5 $through_pkg .= $through;
258 1         7 my $through_key = $self->primary_key();
259 1         13 my $friend_key = $class->primary_key();
260 1         9 my $query = <<"EOT";
261             /* model::gen_getfriends_through */
262             SELECT @{[join q(, ),
263 2         16 (map { "f.$_" } $class->fields()),
264 1         5 (map { "t.$_" } $through_pkg->fields())]}
  3         22  
265 1         8 FROM @{[$class->table()]} f,
266             $through t
267             WHERE t.$through_key = ?
268             AND t.$friend_key = f.$friend_key
269             EOT
270 1         13 $self->{$cachekey} = $self->gen_getarray($class, $query, $self->$through_key());
271             }
272              
273 4         41 return $self->{$cachekey};
274             }
275              
276             sub gen_getobj {
277 1     1 1 15 my ($self, $class) = @_;
278 1   33     8 $class ||= ref $self;
279 1         7 my $pk = $class->primary_key();
280 1         18 my ($cachekey) = $class =~ /([^:]+)$/smx;
281 1   33     15 $self->{$cachekey} ||= $class->new({
282             util => $self->util(),
283             $pk => $self->$pk(),
284             });
285 1         6 return $self->{$cachekey};
286             }
287              
288             sub gen_getobj_through {
289 2     2 1 10 my ($self, $class, $through, $cachekey) = @_;
290 2   33     10 $class ||= ref $self;
291              
292 2 50       9 if(!$cachekey) {
293 2         95 ($cachekey) = $class =~ /([^:]+)$/smx;
294             }
295              
296 2 100       11 if(!$self->{$cachekey}) {
297             # todo: use $through class to determine $through_key
298             # - but $through class may not always be implemented
299 1         5 my $through_key = q(id_).$through;
300 1         8 my $friend_key = $class->primary_key();
301 1         8 my $query = <<"EOT";
302             /* model::gen_getobj_through */
303 1         5 SELECT @{[join q(, ), map { "f.$_" } $class->fields()]}
  2         16  
304 1         7 FROM @{[$class->table()]} f,
305             $through t
306             WHERE t.$through_key = ?
307             AND t.$friend_key = f.$friend_key
308             EOT
309              
310 1         12 $self->{$cachekey} = $self->gen_getarray($class, $query, $self->$through_key())->[0];
311             }
312              
313 2         18 return $self->{$cachekey};
314             }
315              
316             sub belongs_to {
317 0     0 1 0 my ($class, @args) = @_;
318 0         0 return $class->has_a(@args);
319             }
320              
321             sub hasa {
322 1     1 1 3946 my ($class, @args) = @_;
323 1         234 carp q[hasa is deprecated. Use has_a];
324 1         1484 return $class->has_a(@args);
325             }
326              
327             sub has_a {
328 9     9 1 76 my ($class, $attr) = @_;
329              
330 9 100       47 if(ref $attr ne 'ARRAY') {
331 5         116 $attr = [$attr];
332             }
333              
334 9         27 for my $single (@{$attr}) {
  9         150  
335 9         28 my $pkg = $single;
336              
337 9 50       32 if(ref $single eq 'HASH') {
338 0         0 ($pkg) = values %{$single};
  0         0  
339 0         0 ($single) = keys %{$single};
  0         0  
340             }
341              
342 9         40 my $namespace = "${class}::$pkg";
343 9         26 my $yield = $class;
344 9 50       48 if($yield !~ /model/smx) {
345 0         0 croak qq[$pkg is not under a model:: namespace. Friend relationships will not work.];
346             }
347              
348 9         113 $yield =~ s/^(.*model::).*$/$1$pkg/smx;
349              
350 9 50       34 if (defined &{$namespace}) {
  9         61  
351 0         0 next;
352             }
353              
354 7     7   59 no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict)
  7         12  
  7         1835  
355 9         55 *{$namespace} = sub {
356 0     0   0 my $self = shift;
357 0         0 return $self->gen_getobj($yield);
358 9         42 };
359             }
360              
361 9         39 return;
362             }
363              
364             sub hasmany {
365 1     1 1 2022 my ($class, @args) = @_;
366 1         210 carp q[hasmany is deprecated. Use has_many];
367 1         151 return $class->has_many(@args);
368             }
369              
370             sub has_many {
371 5     5 1 43 my ($class, $attr) = @_;
372              
373 5 50       30 if(ref $attr ne 'ARRAY') {
374 5         18 $attr = [$attr];
375             }
376              
377 5         73 for my $single (@{$attr}) {
  5         21  
378 5         13 my $pkg = $single;
379              
380 5 100       29 if(ref $single eq 'HASH') {
381 4         13 ($pkg) = values %{$single};
  4         20  
382 4         12 ($single) = keys %{$single};
  4         14  
383             }
384              
385 5         23 my $plural = _plfunc($single);
386 5         1197 my $namespace = "${class}::$plural";
387 5         17 my $yield = $class;
388 5         52 $yield =~ s/^(.*model::).*$/$1$pkg/smx;
389              
390 5 50       30 if($yield !~ /model/smx) {
391 0         0 croak qq[$pkg is not under a model:: namespace. Friend relationships will not work.];
392             }
393              
394 5 50       13 if (defined &{$namespace}) {
  5         36  
395 0         0 next;
396             }
397              
398 7     7   45 no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict)
  7         12  
  7         2095  
399 5         37 *{$namespace} = sub {
400 1     1   4 my $self = shift;
401 1         15 return $self->gen_getfriends($yield, $plural);
402 5         31 };
403             }
404              
405 5         21 return;
406             }
407              
408             sub belongs_to_through {
409 0     0 1 0 my ($class, @args) = @_;
410 0         0 return $class->has_a_through(@args);
411             }
412              
413             sub has_a_through {
414 4     4 1 41 my ($class, $attr) = @_;
415              
416 4 50       22 if(ref $attr ne 'ARRAY') {
417 4         15 $attr = [$attr];
418             }
419              
420 4         10 for my $single (@{$attr}) {
  4         12  
421 4         11 my $pkg = $single;
422              
423 4 50       18 if(ref $single eq 'HASH') {
424 0         0 ($pkg) = values %{$single};
  0         0  
425 0         0 ($single) = keys %{$single};
  0         0  
426             }
427 4         23 $pkg =~ s/[|].*//smx;
428              
429 4         33 my $through;
430 4         22 ($single, $through) = split /[|]/smx, $single;
431              
432 4 50       16 if(!$through) {
433 0         0 croak qq(Cannot build belongs_to_through for $single);
434             }
435              
436 4         17 my $namespace = "${class}::$pkg";
437 4         61 my $yield = $class;
438 4         41 $yield =~ s/^(.*model::).*$/$1$pkg/smx;
439              
440 4 50       24 if($yield !~ /model/smx) {
441 0         0 croak qq[$pkg is not under a model:: namespace. Friend relationships will not work.];
442             }
443              
444 4 50       10 if (defined &{$namespace}) {
  4         32  
445 0         0 next;
446             }
447              
448 7     7   50 no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict)
  7         17  
  7         1833  
449 4         31 *{$namespace} = sub {
450 2     2   9 my $self = shift;
451 2         17 return $self->gen_getobj_through($yield, $through);
452 4         21 };
453             }
454              
455 4         15 return;
456             }
457              
458             sub has_many_through {
459 4     4 1 37 my ($class, $attr) = @_;
460              
461 4 50       18 if(ref $attr ne 'ARRAY') {
462 4         13 $attr = [$attr];
463             }
464              
465 4         9 for my $single (@{$attr}) {
  4         13  
466 4         9 my $pkg = $single;
467              
468 4 50       17 if(ref $single eq 'HASH') {
469 0         0 ($pkg) = values %{$single};
  0         0  
470 0         0 ($single) = keys %{$single};
  0         0  
471             }
472 4         23 $pkg =~ s/[|].*//smx;
473              
474 4         9 my $through;
475 4         18 ($single, $through) = split /[|]/smx, $single;
476              
477 4 50       18 if(!$through) {
478 0         0 croak qq(Cannot build has_many_through for $single);
479             }
480              
481 4         27 my $plural = _plfunc($single);
482 4         1638 my $namespace = "${class}::$plural";
483 4         11 my $yield = $class;
484 4         34 $yield =~ s/^(.*model::).*$/$1$pkg/smx;
485              
486 4 50       24 if($yield !~ /model/smx) {
487 0         0 croak qq[$pkg is not under a model:: namespace. Friend relationships will not work.];
488             }
489              
490 4 50       10 if (defined &{$namespace}) {
  4         30  
491 0         0 next;
492             }
493              
494 7     7   43 no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict)
  7         28  
  7         1022  
495 4         23 *{$namespace} = sub {
496 4     4   18 my $self = shift;
497              
498 4         58 return $self->gen_getfriends_through($yield, $through, $plural);
499 4         22 };
500             }
501              
502 4         15 return;
503             }
504              
505             sub has_all {
506 16     16 1 15249 my ($class) = @_;
507              
508 16         127 my ($single) = $class =~ /([^:]+)$/smx;
509 16         50 my $plural = _plfunc($single);
510 16         17200 my $namespace = "${class}::$plural";
511              
512 16 50       33 if (defined &{$namespace}) {
  16         138  
513 0         0 return;
514             }
515              
516 7     7   41 no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict)
  7         13  
  7         7391  
517 16         73 *{$namespace} = sub {
518 6     6   39986 my $self = shift;
519 6         53 return $self->gen_getall();
520 16         70 };
521              
522 16         49 return 1;
523             }
524              
525             sub create {
526 16     16 1 131 my $self = shift;
527 16         90 my $util = $self->util();
528 16         125 my $dbh = $util->dbh();
529 16         70 my $pk = $self->primary_key();
530 16         229 my $tr_state = $util->transactions();
531 16         627 my $table = $self->table();
532              
533 16 50       76 if(!$table) {
534 0         0 croak q(No table defined);
535             }
536              
537             #########
538             # disallow saving against zero
539             #
540 16 50       106 if(!$self->$pk()) {
541 16         200 delete $self->{$pk};
542             }
543              
544 16         92 my $query = <<"EOT";
545 16         76 INSERT INTO $table (@{[join q(, ), $self->fields()]})
546 16         229 VALUES (@{[join q(, ), map { q(?) } $self->fields()]})
  72         331  
547             EOT
548              
549 16         88 my @args = map { $self->{$_} } $self->fields();
  72         236  
550             eval {
551 16         82 my $drv = $util->driver();
552 16         131 my $id = $drv->create($query, @args);
553 16         124 $self->$pk($id);
554              
555 16 50       111 } or do {
556 0 0       0 $tr_state and $dbh->rollback();
557 0 0       0 carp qq[CREATE Query was:\n$query\n\nParams: @{[map { (defined $_)?$_:'NULL' } @args]}];
  0         0  
  0         0  
558 0         0 croak $EVAL_ERROR;
559             };
560              
561             eval {
562 16 50       255069 $tr_state and $dbh->commit();
563 16         379 1;
564              
565 16 50       822 } or do {
566 0 0       0 $tr_state and $dbh->rollback();
567 0         0 croak $EVAL_ERROR;
568             };
569              
570 16         825 return 1;
571             }
572              
573             sub read { ## no critic (homonym)
574 25     25 1 271 my ($self, $query, @args) = @_;
575 25         229 my $pk = $self->primary_key();
576 25         228 my $util = $self->util;
577              
578 25 100 66     224 if(!$query && !$self->{$pk}) {
579             # carp q(No primary key);
580 16         53 return;
581             }
582              
583 9         55 my $table = $self->table();
584 9 50       47 if(!$table) {
585 0         0 croak q(No table defined);
586             }
587              
588 9 50       54 if(!$self->{_loaded}) {
589 9 50       47 if(!$query) {
590 9         27 $query = <<"EOT";
591             /* model::read */
592 9         43 SELECT @{[join q(, ), $self->fields()]}
593             FROM $table
594             WHERE $pk=?
595             EOT
596 9         141 @args = ($self->{$pk});
597             }
598              
599             eval {
600 9         65 my $sth = $util->dbh->prepare($query);
601 9         2069 $sth->execute(@args);
602              
603 9         852 my $ref = $sth->fetchrow_hashref();
604              
605 9 100       100 if(!$sth->rows()) {
606             #########
607             # entity not in database
608             #
609 1         10 $sth->finish();
610 1         246 croak q[missing entity];
611             }
612              
613 8         65 $sth->finish();
614              
615 8         45 my $warnings = $util->driver->sth_has_warnings($sth);
616 8 50       46 if(!$warnings) {
617 8         41 for my $f ($self->fields()) {
618 52         869 $self->{$f} = $ref->{$f};
619             }
620              
621             } else {
622 0         0 for my $w (@{$warnings}) {
  0         0  
623 0         0 carp qq[ClearPress::model::read: mysql warning: $w->[2]];
624             }
625             }
626              
627 8         207 1;
628              
629 9 100       31 } or do {
630 1 50       76 if($EVAL_ERROR =~ /missing\sentity/smx) {
631 1         10 return;
632             }
633 0 0       0 carp qq[SELECT ERROR\nEVAL_ERROR: $EVAL_ERROR\nQuery:\n$query\n\nParams: @{[map { (defined $_)?$_:'NULL' } @args]}\n];
  0         0  
  0         0  
634             };
635             }
636 8         38 $self->{_loaded} = 1;
637 8         34 return 1;
638             }
639              
640             sub update {
641 4     4 1 59 my $self = shift;
642 4         18 my $pk = $self->primary_key();
643              
644 4 50 33     52 if(!$pk || !$self->$pk()) {
645 0         0 croak q(No primary key);
646             }
647              
648 4         55 my $table = $self->table();
649 4 50       21 if(!$table) {
650 0         0 croak q(No table defined);
651             }
652              
653 4         18 my $util = $self->util();
654 4         27 my $tr_state = $util->transactions();
655 4         63 my $dbh = $util->dbh();
656 20         74 my @fields = grep { exists $self->{$_} }
657 4         25 grep { $_ ne $pk }
  24         92  
658             $self->fields();
659 4         15 my $query = <<"EOT";
660 4         19 UPDATE @{[$self->table()]}
661             SET @{[join q(, ),
662 4         16 map { qq[$_ = ?] }
  15         80  
663             @fields]}
664             WHERE $pk=?
665             EOT
666              
667             eval {
668 4         19 $dbh->do($query, {}, (map { $self->$_() } @fields), $self->$pk);
  15         152  
669              
670 4 50       17 } or do {
671 0 0       0 $tr_state and $dbh->rollback();
672 0         0 croak $EVAL_ERROR.q[ ].$query;
673             };
674              
675             eval {
676 4 50       61696 $tr_state and $dbh->commit();
677 4         60 1;
678              
679 4 50       1519 } or do {
680 0         0 croak $EVAL_ERROR;
681             };
682              
683 4         227 return 1;
684             }
685              
686             sub delete { ## no critic (homonym)
687 1     1 1 15 my $self = shift;
688 1         6 my $util = $self->util();
689 1         10 my $tr_state = $util->transactions();
690 1         23 my $dbh = $util->dbh();
691 1         5 my $pk = $self->primary_key();
692              
693 1 50 33     15 if(!$pk || !$self->$pk()) {
694 0         0 croak q(No primary key);
695             }
696              
697 1         15 my $query = <<"EOT";
698 1         6 DELETE FROM @{[$self->table()]}
699             WHERE $pk=?
700             EOT
701              
702             eval {
703 1         8 $dbh->do($query, {}, $self->$pk());
704              
705 1 50       4 } or do {
706 0 0       0 $tr_state and $dbh->rollback();
707 0         0 croak $EVAL_ERROR.$query;
708             };
709              
710             eval {
711 1 50       30692 $tr_state and $dbh->commit();
712 1         18 1;
713              
714 1 50       925 } or do {
715 0         0 croak $EVAL_ERROR;
716             };
717              
718 1         19 return 1;
719             }
720              
721             sub save {
722 0     0 1 0 my $self = shift;
723 0         0 my $pk = $self->primary_key();
724              
725 0 0 0     0 if($pk && defined $self->{$pk}) {
726 0         0 return $self->update();
727             }
728              
729 0         0 return $self->create();
730             }
731              
732             sub zdate {
733 1     1 1 13 my $self = shift;
734 1         3 my $date = q[];
735              
736 1 50       5 if(scalar grep { $_ eq 'date' } $self->fields()) {
  7         25  
737 0   0     0 $date = $self->date() || q[];
738 0         0 $date =~ s/[ ]/T/smx;
739 0         0 $date .='Z';
740             }
741              
742 1 50       6 if(!$date) {
743 1         96 $date = strftime q(%Y-%m-%dT%H:%M:%SZ), gmtime;
744             }
745              
746 1         12 return $date;
747             }
748              
749             sub isodate {
750 3     3 1 186 return strftime q(%Y-%m-%d %H:%M:%S), gmtime;
751             }
752              
753             1;
754             __END__