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   175039 use strict;
  7         26  
  7         215  
9 7     7   40 use warnings;
  7         17  
  7         203  
10 7     7   41 use base qw(Class::Accessor);
  7         15  
  7         1077  
11 7     7   3606 use ClearPress::util;
  7         28  
  7         69  
12 7     7   321 use English qw(-no_match_vars);
  7         20  
  7         95  
13 7     7   3672 use Carp;
  7         25  
  7         494  
14 7     7   5472 use Lingua::EN::Inflect qw(PL);
  7         223627  
  7         1050  
15 7     7   3070 use Lingua::EN::PluralToSingular qw(to_singular);
  7         14304  
  7         601  
16 7     7   66 use POSIX qw(strftime);
  7         20  
  7         69  
17 7     7   573 use Readonly;
  7         48  
  7         37019  
18              
19             our $VERSION = q[477.1.2];
20              
21             Readonly::Scalar our $DBI_CACHE_OVERWRITE => 3;
22              
23             our $EXPERIMENTAL_PL = 0;
24              
25 9     9 1 374 sub fields { return (); }
26              
27             sub _plfunc {
28 31     31   80 my $thing = shift;
29 31 50       174 return $EXPERIMENTAL_PL ? PL(to_singular($thing)) : PL($thing);
30             }
31              
32             sub primary_key {
33 201     201 1 1086 my $self = shift;
34 201         968 return ($self->fields())[0];
35             }
36              
37       83 1   sub secondary_key {
38             }
39              
40             sub table {
41 46     46 1 924 my $self = shift;
42 46   100     245 my $tbl = (ref $self) || $self;
43 46 100       153 if(!$tbl) {
44 1         5 return;
45             }
46 45         373 ($tbl) = $tbl =~ /.*::([^:]+)/smx;
47 45         285 return $tbl;
48             }
49              
50       77 1   sub init { }
51              
52             sub new {
53 77     77 1 36846 my ($class, $ref) = @_;
54 77   100     665 $ref ||= {};
55              
56 77         492 my $pk = $class->primary_key();
57              
58 77 100       751 if(!ref $ref) {
59 1 50       6 if($pk) {
60 1         6 $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         331 bless $ref, $class;
69              
70 77         344 my $sk = $ref->secondary_key();
71 77 0 33     280 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         488 $ref->init($ref);
89              
90 77         432 return $ref;
91             }
92              
93             sub util {
94 59     59 1 3418 my ($self, $util) = @_;
95              
96 59 100       2427 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         11 return ClearPress::util->new();
105             }
106              
107 58 100       198 if($util) {
108 1         4 $self->{util} = $util;
109 1         92 return $util;
110             }
111              
112 57 100       279 if($self->{util}) {
113 54         214 return $self->{util};
114             }
115              
116             #########
117             # attempt to instantiate a util using $self's namespace
118             #
119 3         27 my ($ref) = (ref $self) =~ /^([^:]+)/smx;
120 3         10 my $nsutil;
121             eval {
122 3         13 my $ns = "${ref}::util";
123 3         60 $nsutil = $ns->new();
124              
125 3 100       9 } or do {
126 1         192 carp qq[Failed to construct a util from the current namespace ($ref).];
127             };
128              
129 3 100       209 if($nsutil) {
130 2         15 $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         18 my $cputil = ClearPress::util->new();
140 1         7 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 55291 my ($self, $field) = @_;
150              
151 98 100       481 if(!exists $self->{$field}) {
152 18         135 $self->read();
153             }
154              
155 98         473 return $self->SUPER::get($field);
156             }
157              
158             sub gen_getarray {
159 9     9 1 83 my ($self, $class, $query, @args) = @_;
160 9         49 my $util = $self->util();
161              
162 9 50       41 if(!ref $self) {
163 0         0 $self = $self->new({
164             util => $util,
165             });
166             }
167              
168 9         30 my $res = [];
169 9         20 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         144 $sth = $dbh->prepare($query);
177 9         2809 $sth->execute(@args);
178 9         74 1; # sth->execute() does not return true!
179              
180 9 50       24 } 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         359 while(my $ref = $sth->fetchrow_hashref()) {
188 7         30 $ref->{util} = $util;
189 7         18 push @{$res}, $class->new($ref);
  7         37  
190             }
191 9         73 $sth->finish();
192              
193 9         198 return $res;
194             }
195              
196             sub gen_getall {
197 6     6 1 22 my ($self, $class, $cachekey) = @_;
198 6   33     48 $class ||= ref $self;
199              
200 6 50       20 if(!$cachekey) {
201 6         51 ($cachekey) = $class =~ /([^:]+)$/smx;
202 6         31 $cachekey = _plfunc($cachekey);
203             }
204              
205 6 50       7845 if(!$self->{$cachekey}) {
206 6         28 my $sortk = $self->secondary_key;
207 6 50       23 if(!$sortk) {
208 6         23 $sortk = $self->primary_key;
209             }
210 6         46 my $query = <<"EOT";
211             /* model::gen_getall */
212 6         35 SELECT @{[join q(, ), $class->fields()]}
213 6         83 FROM @{[$class->table()]}
214             ORDER BY $sortk
215             EOT
216 6         38 $self->{$cachekey} = $self->gen_getarray($class, $query);
217             }
218              
219 6         40 return $self->{$cachekey};
220             }
221              
222             sub gen_getfriends {
223 1     1 1 6 my ($self, $class, $cachekey) = @_;
224 1   33     6 $class ||= ref $self;
225              
226 1 50       8 if(!$cachekey) {
227 0         0 ($cachekey) = $class =~ /([^:]+)$/smx;
228 0         0 $cachekey = _plfunc($cachekey);
229             }
230              
231 1 50       22 if(!$self->{$cachekey}) {
232 1         10 my $link = $self->primary_key();
233 1         13 my $query = <<"EOT";
234             /* model::gen_getfriends */
235 1         12 SELECT @{[join q(, ), $class->fields()]}
236 1         20 FROM @{[$class->table()]}
237             WHERE $link=?
238             ORDER BY $link
239             EOT
240 1         12 $self->{$cachekey} = $self->gen_getarray($class, $query, $self->$link());
241             }
242              
243 1         9 return $self->{$cachekey};
244             }
245              
246             sub gen_getfriends_through {
247 4     4 1 20 my ($self, $class, $through, $cachekey) = @_;
248 4   33     13 $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         13 my ($through_pkg) = (ref $self) =~ /^(.*::)[^:]+$/smx;
257 1         5 $through_pkg .= $through;
258 1         9 my $through_key = $self->primary_key();
259 1         15 my $friend_key = $class->primary_key();
260 1         10 my $query = <<"EOT";
261             /* model::gen_getfriends_through */
262             SELECT @{[join q(, ),
263 2         20 (map { "f.$_" } $class->fields()),
264 1         6 (map { "t.$_" } $through_pkg->fields())]}
  3         20  
265 1         9 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 16 my ($self, $class) = @_;
278 1   33     5 $class ||= ref $self;
279 1         7 my $pk = $class->primary_key();
280 1         15 my ($cachekey) = $class =~ /([^:]+)$/smx;
281 1   33     13 $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 11 my ($self, $class, $through, $cachekey) = @_;
290 2   33     9 $class ||= ref $self;
291              
292 2 50       8 if(!$cachekey) {
293 2         24 ($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         6 my $through_key = q(id_).$through;
300 1         7 my $friend_key = $class->primary_key();
301 1         10 my $query = <<"EOT";
302             /* model::gen_getobj_through */
303 1         5 SELECT @{[join q(, ), map { "f.$_" } $class->fields()]}
  2         20  
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         129 $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 2868 my ($class, @args) = @_;
323 1         209 carp q[hasa is deprecated. Use has_a];
324 1         192 return $class->has_a(@args);
325             }
326              
327             sub has_a {
328 9     9 1 95 my ($class, $attr) = @_;
329              
330 9 100       54 if(ref $attr ne 'ARRAY') {
331 5         21 $attr = [$attr];
332             }
333              
334 9         23 for my $single (@{$attr}) {
  9         33  
335 9         28 my $pkg = $single;
336              
337 9 50       37 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         152 my $namespace = "${class}::$pkg";
343 9         25 my $yield = $class;
344 9 50       65 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         235 $yield =~ s/^(.*model::).*$/$1$pkg/smx;
349              
350 9 50       30 if (defined &{$namespace}) {
  9         79  
351 0         0 next;
352             }
353              
354 7     7   88 no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict)
  7         23  
  7         2613  
355 9         67 *{$namespace} = sub {
356 0     0   0 my $self = shift;
357 0         0 return $self->gen_getobj($yield);
358 9         59 };
359             }
360              
361 9         37 return;
362             }
363              
364             sub hasmany {
365 1     1 1 2941 my ($class, @args) = @_;
366 1         156 carp q[hasmany is deprecated. Use has_many];
367 1         116 return $class->has_many(@args);
368             }
369              
370             sub has_many {
371 5     5 1 50 my ($class, $attr) = @_;
372              
373 5 50       29 if(ref $attr ne 'ARRAY') {
374 5         19 $attr = [$attr];
375             }
376              
377 5         92 for my $single (@{$attr}) {
  5         21  
378 5         15 my $pkg = $single;
379              
380 5 100       23 if(ref $single eq 'HASH') {
381 4         11 ($pkg) = values %{$single};
  4         19  
382 4         9 ($single) = keys %{$single};
  4         20  
383             }
384              
385 5         22 my $plural = _plfunc($single);
386 5         1414 my $namespace = "${class}::$plural";
387 5         17 my $yield = $class;
388 5         54 $yield =~ s/^(.*model::).*$/$1$pkg/smx;
389              
390 5 50       36 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       12 if (defined &{$namespace}) {
  5         41  
395 0         0 next;
396             }
397              
398 7     7   63 no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict)
  7         18  
  7         2927  
399 5         39 *{$namespace} = sub {
400 1     1   5 my $self = shift;
401 1         11 return $self->gen_getfriends($yield, $plural);
402 5         36 };
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 47 my ($class, $attr) = @_;
415              
416 4 50       28 if(ref $attr ne 'ARRAY') {
417 4         15 $attr = [$attr];
418             }
419              
420 4         12 for my $single (@{$attr}) {
  4         14  
421 4         11 my $pkg = $single;
422              
423 4 50       17 if(ref $single eq 'HASH') {
424 0         0 ($pkg) = values %{$single};
  0         0  
425 0         0 ($single) = keys %{$single};
  0         0  
426             }
427 4         29 $pkg =~ s/[|].*//smx;
428              
429 4         36 my $through;
430 4         23 ($single, $through) = split /[|]/smx, $single;
431              
432 4 50       18 if(!$through) {
433 0         0 croak qq(Cannot build belongs_to_through for $single);
434             }
435              
436 4         18 my $namespace = "${class}::$pkg";
437 4         11 my $yield = $class;
438 4         35 $yield =~ s/^(.*model::).*$/$1$pkg/smx;
439              
440 4 50       25 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       11 if (defined &{$namespace}) {
  4         32  
445 0         0 next;
446             }
447              
448 7     7   66 no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict)
  7         21  
  7         2787  
449 4         33 *{$namespace} = sub {
450 2     2   6 my $self = shift;
451 2         17 return $self->gen_getobj_through($yield, $through);
452 4         23 };
453             }
454              
455 4         18 return;
456             }
457              
458             sub has_many_through {
459 4     4 1 38 my ($class, $attr) = @_;
460              
461 4 50       78 if(ref $attr ne 'ARRAY') {
462 4         17 $attr = [$attr];
463             }
464              
465 4         11 for my $single (@{$attr}) {
  4         15  
466 4         10 my $pkg = $single;
467              
468 4 50       21 if(ref $single eq 'HASH') {
469 0         0 ($pkg) = values %{$single};
  0         0  
470 0         0 ($single) = keys %{$single};
  0         0  
471             }
472 4         25 $pkg =~ s/[|].*//smx;
473              
474 4         15 my $through;
475 4         19 ($single, $through) = split /[|]/smx, $single;
476              
477 4 50       21 if(!$through) {
478 0         0 croak qq(Cannot build has_many_through for $single);
479             }
480              
481 4         26 my $plural = _plfunc($single);
482 4         1462 my $namespace = "${class}::$plural";
483 4         12 my $yield = $class;
484 4         39 $yield =~ s/^(.*model::).*$/$1$pkg/smx;
485              
486 4 50       28 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       11 if (defined &{$namespace}) {
  4         35  
491 0         0 next;
492             }
493              
494 7     7   61 no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict)
  7         17  
  7         1520  
495 4         29 *{$namespace} = sub {
496 4     4   15 my $self = shift;
497              
498 4         95 return $self->gen_getfriends_through($yield, $through, $plural);
499 4         28 };
500             }
501              
502 4         16 return;
503             }
504              
505             sub has_all {
506 16     16 1 20373 my ($class) = @_;
507              
508 16         151 my ($single) = $class =~ /([^:]+)$/smx;
509 16         67 my $plural = _plfunc($single);
510 16         23304 my $namespace = "${class}::$plural";
511              
512 16 50       39 if (defined &{$namespace}) {
  16         173  
513 0         0 return;
514             }
515              
516 7     7   72 no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict)
  7         20  
  7         11195  
517 16         96 *{$namespace} = sub {
518 6     6   28076 my $self = shift;
519 6         43 return $self->gen_getall();
520 16         95 };
521              
522 16         60 return 1;
523             }
524              
525             sub create {
526 16     16 1 140 my $self = shift;
527 16         91 my $util = $self->util();
528 16         134 my $dbh = $util->dbh();
529 16         82 my $pk = $self->primary_key();
530 16         188 my $tr_state = $util->transactions();
531 16         927 my $table = $self->table();
532              
533 16 50       84 if(!$table) {
534 0         0 croak q(No table defined);
535             }
536              
537             #########
538             # disallow saving against zero
539             #
540 16 50       108 if(!$self->$pk()) {
541 16         186 delete $self->{$pk};
542             }
543              
544 16         92 my $query = <<"EOT";
545 16         74 INSERT INTO $table (@{[join q(, ), $self->fields()]})
546 16         210 VALUES (@{[join q(, ), map { q(?) } $self->fields()]})
  72         287  
547             EOT
548              
549 16         86 my @args = map { $self->{$_} } $self->fields();
  72         394  
550             eval {
551 16         77 my $drv = $util->driver();
552 16         106 my $id = $drv->create($query, @args);
553 16         333 $self->$pk($id);
554              
555 16 50       51 } 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       352739 $tr_state and $dbh->commit();
563 16         213 1;
564              
565 16 50       582 } or do {
566 0 0       0 $tr_state and $dbh->rollback();
567 0         0 croak $EVAL_ERROR;
568             };
569              
570 16         375 return 1;
571             }
572              
573             sub read { ## no critic (homonym)
574 25     25 1 118 my ($self, $query, @args) = @_;
575 25         96 my $pk = $self->primary_key();
576 25         220 my $util = $self->util;
577              
578 25 100 66     354 if(!$query && !$self->{$pk}) {
579             # carp q(No primary key);
580 16         56 return;
581             }
582              
583 9         49 my $table = $self->table();
584 9 50       48 if(!$table) {
585 0         0 croak q(No table defined);
586             }
587              
588 9 50       45 if(!$self->{_loaded}) {
589 9 50       39 if(!$query) {
590 9         40 $query = <<"EOT";
591             /* model::read */
592 9         48 SELECT @{[join q(, ), $self->fields()]}
593             FROM $table
594             WHERE $pk=?
595             EOT
596 9         142 @args = ($self->{$pk});
597             }
598              
599             eval {
600 9         184 my $sth = $util->dbh->prepare($query);
601 9         2581 $sth->execute(@args);
602              
603 9         379 my $ref = $sth->fetchrow_hashref();
604              
605 9 100       98 if(!$sth->rows()) {
606             #########
607             # entity not in database
608             #
609 1         6 $sth->finish();
610 1         216 croak q[missing entity];
611             }
612              
613 8         68 $sth->finish();
614              
615 8         45 my $warnings = $util->driver->sth_has_warnings($sth);
616 8 50       49 if(!$warnings) {
617 8         44 for my $f ($self->fields()) {
618 52         233 $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         300 1;
628              
629 9 100       29 } or do {
630 1 50       71 if($EVAL_ERROR =~ /missing\sentity/smx) {
631 1         8 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         44 $self->{_loaded} = 1;
637 8         37 return 1;
638             }
639              
640             sub update {
641 4     4 1 68 my $self = shift;
642 4         20 my $pk = $self->primary_key();
643              
644 4 50 33     85 if(!$pk || !$self->$pk()) {
645 0         0 croak q(No primary key);
646             }
647              
648 4         116 my $table = $self->table();
649 4 50       23 if(!$table) {
650 0         0 croak q(No table defined);
651             }
652              
653 4         19 my $util = $self->util();
654 4         27 my $tr_state = $util->transactions();
655 4         140 my $dbh = $util->dbh();
656 20         65 my @fields = grep { exists $self->{$_} }
657 4         30 grep { $_ ne $pk }
  24         84  
658             $self->fields();
659 4         14 my $query = <<"EOT";
660 4         20 UPDATE @{[$self->table()]}
661             SET @{[join q(, ),
662 4         14 map { qq[$_ = ?] }
  15         72  
663             @fields]}
664             WHERE $pk=?
665             EOT
666              
667             eval {
668 4         18 $dbh->do($query, {}, (map { $self->$_() } @fields), $self->$pk);
  15         141  
669              
670 4 50       15 } 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       80250 $tr_state and $dbh->commit();
677 4         241 1;
678              
679 4 50       1412 } or do {
680 0         0 croak $EVAL_ERROR;
681             };
682              
683 4         114 return 1;
684             }
685              
686             sub delete { ## no critic (homonym)
687 1     1 1 18 my $self = shift;
688 1         4 my $util = $self->util();
689 1         8 my $tr_state = $util->transactions();
690 1         20 my $dbh = $util->dbh();
691 1         5 my $pk = $self->primary_key();
692              
693 1 50 33     14 if(!$pk || !$self->$pk()) {
694 0         0 croak q(No primary key);
695             }
696              
697 1         15 my $query = <<"EOT";
698 1         7 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       25789 $tr_state and $dbh->commit();
712 1         80 1;
713              
714 1 50       605 } 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 24 my $self = shift;
734 1         5 my $date = q[];
735              
736 1 50       7 if(scalar grep { $_ eq 'date' } $self->fields()) {
  7         54  
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       7 if(!$date) {
743 1         101 $date = strftime q(%Y-%m-%dT%H:%M:%SZ), gmtime;
744             }
745              
746 1         16 return $date;
747             }
748              
749             sub isodate {
750 3     3 1 194 return strftime q(%Y-%m-%d %H:%M:%S), gmtime;
751             }
752              
753             1;
754             __END__