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   130818 use strict;
  7         19  
  7         190  
9 7     7   37 use warnings;
  7         15  
  7         184  
10 7     7   40 use base qw(Class::Accessor);
  7         16  
  7         1054  
11 7     7   4190 use ClearPress::util;
  7         16  
  7         63  
12 7     7   235 use English qw(-no_match_vars);
  7         17  
  7         47  
13 7     7   2241 use Carp;
  7         16  
  7         364  
14 7     7   3349 use Lingua::EN::Inflect qw(PL);
  7         157898  
  7         888  
15 7     7   2430 use Lingua::EN::PluralToSingular qw(to_singular);
  7         11496  
  7         511  
16 7     7   55 use POSIX qw(strftime);
  7         15  
  7         92  
17 7     7   559 use Readonly;
  7         16  
  7         13060  
18              
19             our $VERSION = q[476.4.2];
20              
21             Readonly::Scalar our $DBI_CACHE_OVERWRITE => 3;
22              
23             our $EXPERIMENTAL_PL = 0;
24              
25 9     9 1 654 sub fields { return (); }
26              
27             sub _plfunc {
28 31     31   75 my $thing = shift;
29 31 50       159 return $EXPERIMENTAL_PL ? PL(to_singular($thing)) : PL($thing);
30             }
31              
32             sub primary_key {
33 201     201 1 1217 my $self = shift;
34 201         823 return ($self->fields())[0];
35             }
36              
37       83 1   sub secondary_key {
38             }
39              
40             sub table {
41 46     46 1 898 my $self = shift;
42 46   100     225 my $tbl = (ref $self) || $self;
43 46 100       157 if(!$tbl) {
44 1         7 return;
45             }
46 45         497 ($tbl) = $tbl =~ /.*::([^:]+)/smx;
47 45         254 return $tbl;
48             }
49              
50       77 1   sub init { }
51              
52             sub new {
53 77     77 1 26277 my ($class, $ref) = @_;
54 77   100     383 $ref ||= {};
55              
56 77         342 my $pk = $class->primary_key();
57              
58 77 100       667 if(!ref $ref) {
59 1 50       4 if($pk) {
60 1         3 $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         192 bless $ref, $class;
69              
70 77         299 my $sk = $ref->secondary_key();
71 77 0 33     241 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         348 $ref->init($ref);
89              
90 77         403 return $ref;
91             }
92              
93             sub util {
94 59     59 1 5174 my ($self, $util) = @_;
95              
96 59 100       220 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         12 return ClearPress::util->new();
105             }
106              
107 58 100       185 if($util) {
108 1         4 $self->{util} = $util;
109 1         3 return $util;
110             }
111              
112 57 100       263 if($self->{util}) {
113 54         269 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         20 my $ns = "${ref}::util";
123 3         33 $nsutil = $ns->new();
124              
125 3 100       10 } or do {
126 1         239 carp qq[Failed to construct a util from the current namespace ($ref).];
127             };
128              
129 3 100       172 if($nsutil) {
130 2         19 $self->{util} = $nsutil;
131 2         15 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         10 my $cputil = ClearPress::util->new();
140 1         9 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 35435 my ($self, $field) = @_;
150              
151 98 100       354 if(!exists $self->{$field}) {
152 18         112 $self->read();
153             }
154              
155 98         397 return $self->SUPER::get($field);
156             }
157              
158             sub gen_getarray {
159 9     9 1 83 my ($self, $class, $query, @args) = @_;
160 9         56 my $util = $self->util();
161              
162 9 50       45 if(!ref $self) {
163 0         0 $self = $self->new({
164             util => $util,
165             });
166             }
167              
168 9         32 my $res = [];
169 9         24 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         132 $sth = $dbh->prepare($query);
177 9         3839 $sth->execute(@args);
178 9         69 1; # sth->execute() does not return true!
179              
180 9 50       25 } 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         405 while(my $ref = $sth->fetchrow_hashref()) {
188 7         79 $ref->{util} = $util;
189 7         17 push @{$res}, $class->new($ref);
  7         43  
190             }
191 9         83 $sth->finish();
192              
193 9         192 return $res;
194             }
195              
196             sub gen_getall {
197 6     6 1 26 my ($self, $class, $cachekey) = @_;
198 6   33     53 $class ||= ref $self;
199              
200 6 50       26 if(!$cachekey) {
201 6         60 ($cachekey) = $class =~ /([^:]+)$/smx;
202 6         34 $cachekey = _plfunc($cachekey);
203             }
204              
205 6 50       3507 if(!$self->{$cachekey}) {
206 6         33 my $sortk = $self->secondary_key;
207 6 50       27 if(!$sortk) {
208 6         25 $sortk = $self->primary_key;
209             }
210 6         81 my $query = <<"EOT";
211             /* model::gen_getall */
212 6         44 SELECT @{[join q(, ), $class->fields()]}
213 6         98 FROM @{[$class->table()]}
214             ORDER BY $sortk
215             EOT
216 6         44 $self->{$cachekey} = $self->gen_getarray($class, $query);
217             }
218              
219 6         45 return $self->{$cachekey};
220             }
221              
222             sub gen_getfriends {
223 1     1 1 6 my ($self, $class, $cachekey) = @_;
224 1   33     7 $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       16 if(!$self->{$cachekey}) {
232 1         9 my $link = $self->primary_key();
233 1         12 my $query = <<"EOT";
234             /* model::gen_getfriends */
235 1         13 SELECT @{[join q(, ), $class->fields()]}
236 1         20 FROM @{[$class->table()]}
237             WHERE $link=?
238             ORDER BY $link
239             EOT
240 1         11 $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 17 my ($self, $class, $through, $cachekey) = @_;
248 4   33     118 $class ||= ref $self;
249              
250 4 50       18 if(!$cachekey) {
251 0         0 ($cachekey) = $class =~ /([^:]+)$/smx;
252 0         0 $cachekey = _plfunc($cachekey);
253             }
254              
255 4 100       19 if(!$self->{$cachekey}) {
256 1         13 my ($through_pkg) = (ref $self) =~ /^(.*::)[^:]+$/smx;
257 1         7 $through_pkg .= $through;
258 1         9 my $through_key = $self->primary_key();
259 1         17 my $friend_key = $class->primary_key();
260 1         9 my $query = <<"EOT";
261             /* model::gen_getfriends_through */
262             SELECT @{[join q(, ),
263 2         88 (map { "f.$_" } $class->fields()),
264 1         6 (map { "t.$_" } $through_pkg->fields())]}
  3         26  
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         24 $self->{$cachekey} = $self->gen_getarray($class, $query, $self->$through_key());
271             }
272              
273 4         104 return $self->{$cachekey};
274             }
275              
276             sub gen_getobj {
277 1     1 1 17 my ($self, $class) = @_;
278 1   33     7 $class ||= ref $self;
279 1         8 my $pk = $class->primary_key();
280 1         20 my ($cachekey) = $class =~ /([^:]+)$/smx;
281 1   33     16 $self->{$cachekey} ||= $class->new({
282             util => $self->util(),
283             $pk => $self->$pk(),
284             });
285 1         5 return $self->{$cachekey};
286             }
287              
288             sub gen_getobj_through {
289 2     2 1 9 my ($self, $class, $through, $cachekey) = @_;
290 2   33     8 $class ||= ref $self;
291              
292 2 50       9 if(!$cachekey) {
293 2         20 ($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         11 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         11 $self->{$cachekey} = $self->gen_getarray($class, $query, $self->$through_key())->[0];
311             }
312              
313 2         19 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 5827 my ($class, @args) = @_;
323 1         187 carp q[hasa is deprecated. Use has_a];
324 1         119 return $class->has_a(@args);
325             }
326              
327             sub has_a {
328 9     9 1 79 my ($class, $attr) = @_;
329              
330 9 100       45 if(ref $attr ne 'ARRAY') {
331 5         18 $attr = [$attr];
332             }
333              
334 9         22 for my $single (@{$attr}) {
  9         31  
335 9         23 my $pkg = $single;
336              
337 9 50       48 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         36 my $namespace = "${class}::$pkg";
343 9         23 my $yield = $class;
344 9 50       47 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         101 $yield =~ s/^(.*model::).*$/$1$pkg/smx;
349              
350 9 50       33 if (defined &{$namespace}) {
  9         65  
351 0         0 next;
352             }
353              
354 7     7   55 no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict)
  7         18  
  7         2176  
355 9         60 *{$namespace} = sub {
356 0     0   0 my $self = shift;
357 0         0 return $self->gen_getobj($yield);
358 9         52 };
359             }
360              
361 9         233 return;
362             }
363              
364             sub hasmany {
365 1     1 1 2781 my ($class, @args) = @_;
366 1         156 carp q[hasmany is deprecated. Use has_many];
367 1         122 return $class->has_many(@args);
368             }
369              
370             sub has_many {
371 5     5 1 51 my ($class, $attr) = @_;
372              
373 5 50       30 if(ref $attr ne 'ARRAY') {
374 5         20 $attr = [$attr];
375             }
376              
377 5         16 for my $single (@{$attr}) {
  5         19  
378 5         15 my $pkg = $single;
379              
380 5 100       26 if(ref $single eq 'HASH') {
381 4         10 ($pkg) = values %{$single};
  4         20  
382 4         12 ($single) = keys %{$single};
  4         17  
383             }
384              
385 5         32 my $plural = _plfunc($single);
386 5         1385 my $namespace = "${class}::$plural";
387 5         17 my $yield = $class;
388 5         55 $yield =~ s/^(.*model::).*$/$1$pkg/smx;
389              
390 5 50       31 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       15 if (defined &{$namespace}) {
  5         44  
395 0         0 next;
396             }
397              
398 7     7   55 no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict)
  7         13  
  7         2454  
399 5         38 *{$namespace} = sub {
400 1     1   4 my $self = shift;
401 1         16 return $self->gen_getfriends($yield, $plural);
402 5         36 };
403             }
404              
405 5         22 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 43 my ($class, $attr) = @_;
415              
416 4 50       22 if(ref $attr ne 'ARRAY') {
417 4         16 $attr = [$attr];
418             }
419              
420 4         10 for my $single (@{$attr}) {
  4         14  
421 4         10 my $pkg = $single;
422              
423 4 50       22 if(ref $single eq 'HASH') {
424 0         0 ($pkg) = values %{$single};
  0         0  
425 0         0 ($single) = keys %{$single};
  0         0  
426             }
427 4         24 $pkg =~ s/[|].*//smx;
428              
429 4         79 my $through;
430 4         26 ($single, $through) = split /[|]/smx, $single;
431              
432 4 50       17 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         11 my $yield = $class;
438 4         35 $yield =~ s/^(.*model::).*$/$1$pkg/smx;
439              
440 4 50       21 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       12 if (defined &{$namespace}) {
  4         29  
445 0         0 next;
446             }
447              
448 7     7   61 no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict)
  7         17  
  7         2191  
449 4         33 *{$namespace} = sub {
450 2     2   7 my $self = shift;
451 2         16 return $self->gen_getobj_through($yield, $through);
452 4         22 };
453             }
454              
455 4         16 return;
456             }
457              
458             sub has_many_through {
459 4     4 1 59 my ($class, $attr) = @_;
460              
461 4 50       19 if(ref $attr ne 'ARRAY') {
462 4         14 $attr = [$attr];
463             }
464              
465 4         11 for my $single (@{$attr}) {
  4         12  
466 4         10 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         22 $pkg =~ s/[|].*//smx;
473              
474 4         10 my $through;
475 4         17 ($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         25 my $plural = _plfunc($single);
482 4         1267 my $namespace = "${class}::$plural";
483 4         13 my $yield = $class;
484 4         43 $yield =~ s/^(.*model::).*$/$1$pkg/smx;
485              
486 4 50       25 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       12 if (defined &{$namespace}) {
  4         56  
491 0         0 next;
492             }
493              
494 7     7   50 no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict)
  7         18  
  7         1225  
495 4         33 *{$namespace} = sub {
496 4     4   14 my $self = shift;
497              
498 4         32 return $self->gen_getfriends_through($yield, $through, $plural);
499 4         31 };
500             }
501              
502 4         19 return;
503             }
504              
505             sub has_all {
506 16     16 1 16976 my ($class) = @_;
507              
508 16         129 my ($single) = $class =~ /([^:]+)$/smx;
509 16         55 my $plural = _plfunc($single);
510 16         18262 my $namespace = "${class}::$plural";
511              
512 16 50       34 if (defined &{$namespace}) {
  16         137  
513 0         0 return;
514             }
515              
516 7     7   49 no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict)
  7         16  
  7         8605  
517 16         77 *{$namespace} = sub {
518 6     6   38515 my $self = shift;
519 6         51 return $self->gen_getall();
520 16         77 };
521              
522 16         51 return 1;
523             }
524              
525             sub create {
526 16     16 1 228 my $self = shift;
527 16         91 my $util = $self->util();
528 16         127 my $dbh = $util->dbh();
529 16         75 my $pk = $self->primary_key();
530 16         180 my $tr_state = $util->transactions();
531 16         365 my $table = $self->table();
532              
533 16 50       95 if(!$table) {
534 0         0 croak q(No table defined);
535             }
536              
537             #########
538             # disallow saving against zero
539             #
540 16 50       109 if(!$self->$pk()) {
541 16         185 delete $self->{$pk};
542             }
543              
544 16         102 my $query = <<"EOT";
545 16         72 INSERT INTO $table (@{[join q(, ), $self->fields()]})
546 16         198 VALUES (@{[join q(, ), map { q(?) } $self->fields()]})
  72         290  
547             EOT
548              
549 16         85 my @args = map { $self->{$_} } $self->fields();
  72         236  
550             eval {
551 16         71 my $drv = $util->driver();
552 16         95 my $id = $drv->create($query, @args);
553 16         110 $self->$pk($id);
554              
555 16 50       52 } 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       259701 $tr_state and $dbh->commit();
563 16         229 1;
564              
565 16 50       476 } or do {
566 0 0       0 $tr_state and $dbh->rollback();
567 0         0 croak $EVAL_ERROR;
568             };
569              
570 16         461 return 1;
571             }
572              
573             sub read { ## no critic (homonym)
574 25     25 1 97 my ($self, $query, @args) = @_;
575 25         89 my $pk = $self->primary_key();
576 25         215 my $util = $self->util;
577              
578 25 100 66     205 if(!$query && !$self->{$pk}) {
579             # carp q(No primary key);
580 16         60 return;
581             }
582              
583 9         47 my $table = $self->table();
584 9 50       46 if(!$table) {
585 0         0 croak q(No table defined);
586             }
587              
588 9 50       44 if(!$self->{_loaded}) {
589 9 50       36 if(!$query) {
590 9         23 $query = <<"EOT";
591             /* model::read */
592 9         42 SELECT @{[join q(, ), $self->fields()]}
593             FROM $table
594             WHERE $pk=?
595             EOT
596 9         136 @args = ($self->{$pk});
597             }
598              
599             eval {
600 9         94 my $sth = $util->dbh->prepare($query);
601 9         2212 $sth->execute(@args);
602              
603 9         466 my $ref = $sth->fetchrow_hashref();
604              
605 9 100       97 if(!$sth->rows()) {
606             #########
607             # entity not in database
608             #
609 1         9 $sth->finish();
610 1         247 croak q[missing entity];
611             }
612              
613 8         59 $sth->finish();
614              
615 8         44 my $warnings = $util->driver->sth_has_warnings($sth);
616 8 50       33 if(!$warnings) {
617 8         108 for my $f ($self->fields()) {
618 52         179 $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         227 1;
628              
629 9 100       32 } or do {
630 1 50       71 if($EVAL_ERROR =~ /missing\sentity/smx) {
631 1         9 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 64 my $self = shift;
642 4         24 my $pk = $self->primary_key();
643              
644 4 50 33     55 if(!$pk || !$self->$pk()) {
645 0         0 croak q(No primary key);
646             }
647              
648 4         68 my $table = $self->table();
649 4 50       17 if(!$table) {
650 0         0 croak q(No table defined);
651             }
652              
653 4         18 my $util = $self->util();
654 4         24 my $tr_state = $util->transactions();
655 4         73 my $dbh = $util->dbh();
656 20         63 my @fields = grep { exists $self->{$_} }
657 4         24 grep { $_ ne $pk }
  24         91  
658             $self->fields();
659 4         16 my $query = <<"EOT";
660 4         20 UPDATE @{[$self->table()]}
661             SET @{[join q(, ),
662 4         18 map { qq[$_ = ?] }
  15         59  
663             @fields]}
664             WHERE $pk=?
665             EOT
666              
667             eval {
668 4         17 $dbh->do($query, {}, (map { $self->$_() } @fields), $self->$pk);
  15         99  
669              
670 4 50       16 } 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       46665 $tr_state and $dbh->commit();
677 4         50 1;
678              
679 4 50       1280 } or do {
680 0         0 croak $EVAL_ERROR;
681             };
682              
683 4         58 return 1;
684             }
685              
686             sub delete { ## no critic (homonym)
687 1     1 1 16 my $self = shift;
688 1         5 my $util = $self->util();
689 1         9 my $tr_state = $util->transactions();
690 1         21 my $dbh = $util->dbh();
691 1         6 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         14 my $query = <<"EOT";
698 1         6 DELETE FROM @{[$self->table()]}
699             WHERE $pk=?
700             EOT
701              
702             eval {
703 1         6 $dbh->do($query, {}, $self->$pk());
704              
705 1 50       5 } 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       23247 $tr_state and $dbh->commit();
712 1         14 1;
713              
714 1 50       517 } 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 15 my $self = shift;
734 1         4 my $date = q[];
735              
736 1 50       4 if(scalar grep { $_ eq 'date' } $self->fields()) {
  7         26  
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       5 if(!$date) {
743 1         86 $date = strftime q(%Y-%m-%dT%H:%M:%SZ), gmtime;
744             }
745              
746 1         11 return $date;
747             }
748              
749             sub isodate {
750 3     3 1 150 return strftime q(%Y-%m-%d %H:%M:%S), gmtime;
751             }
752              
753             1;
754             __END__