File Coverage

blib/lib/Persistent/Base.pm
Criterion Covered Total %
statement 194 359 54.0
branch 62 204 30.3
condition 11 35 31.4
subroutine 24 39 61.5
pod 4 23 17.3
total 295 660 44.7


line stmt bran cond sub pod time code
1             ########################################################################
2             # File: Base.pm
3             # Author: David Winters
4             # RCS: $Id: Base.pm,v 1.16 2000/02/26 03:38:28 winters Exp winters $
5             #
6             # An abstract base class for persistent objects.
7             # This class should be inherited by other persistent classes that
8             # implement object persistence.
9             #
10             # This file contains POD documentation that may be viewed with the
11             # perldoc, pod2man, or pod2html utilities.
12             #
13             # Copyright (c) 1998-2000 David Winters. All rights reserved.
14             # This program is free software; you can redistribute it
15             # and/or modify it under the same terms as Perl itself.
16             ########################################################################
17              
18             package Persistent::Base;
19             require 5.004;
20              
21 6     6   39 use strict;
  6         12  
  6         310  
22 6     6   31 use vars qw($VERSION $REVISION $AUTOLOAD);
  6         11  
  6         371  
23              
24 6     6   31 use Carp;
  6         21  
  6         355  
25 6     6   519 use English;
  6         11  
  6         38  
26              
27             $VERSION = '0.52';
28             $REVISION = (qw$Revision: 1.16 $)[1];
29              
30             =head1 NAME
31              
32             Persistent::Base - An Abstract Persistent Base Class
33              
34             =head1 SYNOPSIS
35              
36             ### we are a subclass of ... ###
37             use Persistent::Base;
38             @ISA = qw(Persistent::Base);
39              
40             =head1 ABSTRACT
41              
42             This is an abstract class used by the Persistent framework of classes
43             to implement persistence with various types of data stores. This
44             class provides the methods and interface for implementing Persistent
45             classes. Refer to the L documentation for a very thorough
46             introduction to using the Persistent framework of classes.
47              
48             This class is part of the Persistent base package which is available
49             from:
50              
51             http://www.bigsnow.org/persistent
52             ftp://ftp.bigsnow.org/pub/persistent
53              
54             =head1 DESCRIPTION
55              
56             Before we get started describing the methods in detail, it should be
57             noted that all error handling in this class is done with exceptions.
58             So you should wrap an eval block around all of your code. Please see
59             the L documentation for more information on exception
60             handling in Perl.
61              
62             =cut
63              
64             ########################################################################
65             #
66             # --------------
67             # PUBLIC METHODS
68             # --------------
69             #
70             # NOTE: These methods do not need to be overridden in the subclasses.
71             # However, you may certainly override these methods if you see
72             # the need to. Perhaps, for performance or reuseability reasons.
73             #
74             ########################################################################
75              
76             ########################################################################
77             # Function: new
78             # Description: Object constructor.
79             # Parameters: @params = initialization parameters
80             # Returns: $this = reference to the newly allocated object
81             ########################################################################
82             sub new {
83 11     11 0 3155 my $proto = shift;
84 11   33     75 my $class = ref($proto) || $proto;
85              
86             ### allocate a hash for the object's data ###
87 11         25 my $this = {};
88 11         26 bless $this, $class;
89 11         318 $this->_trace();
90 11         66 $this->initialize(@_); ### call hook for subclass initialization ###
91              
92 11         34 return $this;
93             }
94              
95             ########################################################################
96             # Function: initialize
97             # Description: Initializes an object.
98             # Parameters: @params = initialization parameters
99             # Returns: None
100             ########################################################################
101             sub initialize {
102 11     11 0 14 my $this = shift;
103 11 50       33 ref($this) or croak "$this is not an object";
104              
105 11         28 $this->_trace();
106 11         53 $this->datastore(@_); ### initialize the data store ###
107              
108 11         15 0;
109             }
110              
111             ########################################################################
112             # Function: DESTROY
113             # Description: Object destructor.
114             # Parameters: None
115             # Returns: None
116             ########################################################################
117             sub DESTROY {
118 11     11   214 my $this = shift;
119 11 50       36 ref($this) or croak "$this is not an object";
120              
121 11         38 $this->_trace();
122              
123 11         88 0;
124             }
125              
126             ########################################################################
127             # Function: AUTOLOAD
128             # Description: Gets/sets the attributes of the object.
129             # Uses autoloading to access any instance field.
130             # Parameters: $value (optional) = value to set the attribute to
131             # Returns: $value = value of the attribute
132             ########################################################################
133             sub AUTOLOAD {
134 76     76   310 my($this, @data) = @_;
135 76 50       155 ref($this) or croak "$this is not an object";
136              
137 76         143 $this->_trace();
138              
139 76         109 my $name = $AUTOLOAD; ### get name of attribute ###
140 76         274 $name =~ s/.*://; ### strip fully-qualified portion ###
141 76         164 $this->value($name, @data);
142             }
143              
144             ########################################################################
145             # Function: datastore_type
146             # Description: Gets/sets the type of the datastore.
147             # The persistent subclass for the type ($type) of datastore
148             # will be loaded at run-time and initialized with the
149             # arguments passed (@args);
150             # Parameters: $type = type of datastore
151             # @args = arguments to pass to the specific datastore
152             # method for the type ($type)
153             # Returns: whatever is returned by the datastore method for the type
154             ########################################################################
155             sub datastore_type {
156 0 0   0 0 0 (@_ > 0) or croak 'Usage: $obj->datastore_type([$type])';
157 0         0 my $this = shift;
158 0         0 my $class = ref $this;
159 0 0       0 $class or croak "$this is not an object";
160              
161 0         0 $this->_trace();
162              
163 0 0       0 if ($class =~ /Persistent::/) { ### direct instantiation ###
164 0         0 $this->object_type(@_);
165             } else { ### inheritance ###
166 0         0 $this->parent_type(@_);
167             }
168             }
169              
170             ########################################################################
171             # Function: object_type
172             # Description: Gets/sets the type of the object.
173             # The persistent subclass for the type ($type) of datastore
174             # will be loaded at run-time and initialized with the
175             # arguments passed (@args);
176             # Parameters: $type = type of datastore
177             # @args = arguments to pass to the specific datastore
178             # method for the type ($type)
179             # Returns: whatever is returned by the datastore method for the type
180             ########################################################################
181             sub object_type {
182 0 0   0 0 0 (@_ > 0) or croak 'Usage: $obj->object_type([$type])';
183 0         0 my $this = shift;
184 0 0       0 ref($this) or croak "$this is not an object";
185              
186 0         0 $this->_trace();
187              
188 0         0 my $type = shift;
189 0 0       0 if (defined $type) { ### set it ###
190             ### free the object's resources ###
191 0         0 $this->DESTROY();
192              
193             ### set the object's class ###
194 0         0 my $class = "Persistent::${type}";
195 0         0 eval "require $class";
196 0 0       0 croak $EVAL_ERROR if $EVAL_ERROR;
197 0         0 bless $this, $class;
198             } else { ### get it ###
199 0         0 $type = ref $this;
200 0         0 $type =~ s/Persistent:://;
201             }
202              
203 0         0 $type;
204             }
205              
206             ########################################################################
207             # Function: parent_type
208             # Description: Gets/sets the type of the object.
209             # The persistent subclass for the type ($type) of datastore
210             # will be loaded at run-time and initialized with the
211             # arguments passed (@args);
212             # Parameters: $type = type of datastore
213             # @args = arguments to pass to the specific datastore
214             # method for the type ($type)
215             # Returns: whatever is returned by the datastore method for the type
216             ########################################################################
217             sub parent_type {
218 0 0   0 0 0 (@_ > 0) or croak 'Usage: $obj->parent_type([$type])';
219 0         0 my $this = shift;
220 0         0 my $class = ref $this;
221 0 0       0 $class or croak "$this is not an object";
222              
223 0         0 $this->_trace();
224              
225 0         0 my $type = shift;
226 0 0       0 if (defined $type) { ### set it ###
227             ### free the object's resources ###
228 0         0 $this->DESTROY();
229              
230             ### set parent class ###
231 0         0 eval("require Persistent::${type}; " .
232             "\@${class}::ISA = qw(Persistent::${type});");
233 0 0       0 croak $EVAL_ERROR if $EVAL_ERROR;
234             } else { ### get it ###
235 0         0 ($type) = eval "\@${class}::ISA"; ### get parent class ###
236 0         0 $type =~ s/Persistent:://;
237             }
238              
239 0         0 $type;
240             }
241              
242             ########################################################################
243             # Function: data_type
244             # Description: Returns the data type of an attribute.
245             # Parameters: $attribute = name of an attribute of the object
246             # Returns: $data_type = data type for the attribute
247             ########################################################################
248             sub data_type {
249 0 0   0 0 0 (@_ == 2) or croak 'Usage: $obj->data_type($attribute)';
250 0         0 my($this, $attribute) = @_;
251 0 0       0 ref($this) or croak "$this is not an object";
252              
253 0         0 $this->_trace();
254              
255 0 0       0 if (defined $this->{MetaData}->{$attribute}) {
256 0         0 $this->{MetaData}->{$attribute}->{DataType};
257             } else {
258 0         0 croak "'$attribute' is not an attribute of this object";
259             }
260             }
261              
262             ########################################################################
263             # Function: data_type_params
264             # Description: Returns the data type parameters of an attribute.
265             # The parameters are dependent on the data type.
266             # Parameters: $attribute = name of an attribute of the object
267             # Returns: \@data_type_params = reference to an array containing the
268             # data type parameters for the attribute
269             ########################################################################
270             sub data_type_params {
271 0 0   0 0 0 (@_ == 2) or croak 'Usage: $obj->data_type_params($attribute)';
272 0         0 my($this, $attribute) = @_;
273 0 0       0 ref($this) or croak "$this is not an object";
274              
275 0         0 $this->_trace();
276              
277 0 0       0 if (defined $this->{MetaData}->{$attribute}) {
278 0         0 [@{$this->{MetaData}->{$attribute}->{DataTypeParams}}];
  0         0  
279             } else {
280 0         0 croak "'$attribute' is not an attribute of this object";
281             }
282             }
283              
284             ########################################################################
285             # Function: data_type_object
286             # Description: Returns the data type object of an attribute.
287             # Parameters: $attribute = name of an attribute of the object
288             # Returns: $data_type_obj = data type object for the attribute
289             ########################################################################
290             sub data_type_object {
291 0 0   0 0 0 (@_ == 2) or croak 'Usage: $obj->data_type_object($attribute)';
292 0         0 my($this, $attribute) = @_;
293 0 0       0 ref($this) or croak "$this is not an object";
294              
295 0         0 $this->_trace();
296              
297 0 0       0 if (defined $this->{Data}->{$attribute}) {
298 0         0 $this->{Data}->{$attribute};
299             } else {
300 0         0 croak "'$attribute' is not an attribute of this object";
301             }
302             }
303              
304             ########################################################################
305             # Function: add_attribute
306             # Description: Adds an attribute to the object.
307             # Parameters: $name = name of the attribute
308             # $type = type of the attribute
309             # valid values are the following:
310             # 'id' or 'i'
311             # 'persistent' or 'p'
312             # 'transient' or 't'
313             # $data_type = data type of the attribute
314             # valid values are the following:
315             # 'varchar'
316             # 'char'
317             # 'string'
318             # 'number'
319             # 'datetime'
320             # @args = arguments to be passed to the data type constructor
321             # Returns: None
322             ########################################################################
323             sub add_attribute {
324 55 50   55 0 331 (@_ > 3) or
325             croak 'Usage: $obj->add_attribute($name, $type, $data_type, @args)';
326 55         124 my($this, $name, $type, $data_type, @args) = @_;
327 55 50       136 ref($this) or croak "$this is not an object";
328              
329             ### validate arguments ###
330 55 50 33     883 croak "name must be defined" if !defined($name) || $name eq '';
331 55 50 33     789 croak "type must be defined" if !defined($type) || $type eq '';
332 55 50 33     1617 croak "data type must be defined"
333             if !defined($data_type) || $data_type eq '';
334              
335             ### store the field metadata and allocate the field ###
336 55         254 $this->{MetaData}->{$name}->{DataType} = $data_type;
337 55         163 $this->{MetaData}->{$name}->{DataTypeParams} = [@args];
338 55         163 my $dt_obj = $this->_allocate_data_type($data_type, @args);
339 55 100       315 if ($type =~ /^i/i) { ### ID fields ###
    50          
    0          
340 11         53 $this->{Data}->{$name}->[0] = $dt_obj;
341 11         20 push(@{$this->{DataOrder}}, $name);
  11         31  
342 11         13 push(@{$this->{IdFields}}, $name);
  11         52  
343             } elsif ($type =~ /^p/i) { ### persistent fields ###
344 44         118 $this->{Data}->{$name}->[0] = $dt_obj;
345 44         66 push(@{$this->{DataOrder}}, $name);
  44         153  
346             } elsif ($type =~ /^t/i) { ### transient fields ###
347 0         0 $this->{TempData}->{$name}->[0] = $dt_obj;
348             } else {
349 0         0 croak "field type ($type) is invalid";
350             }
351             }
352              
353             ########################################################################
354             # Function: value
355             # Description: Gets/sets the value of an attribute.
356             # Parameters: $attribute = name of the attribute
357             # $value (optional) = value to set the attribute to
358             # Returns: $value = value of the attribute
359             ########################################################################
360             sub value {
361 213     213 0 383 my($this, $attribute, @data) = @_;
362 213 50       427 ref($this) or croak "$this is not an object";
363              
364 213         345 $this->_trace();
365              
366 213         286 $attribute = lc($attribute); ### attributes are case insensitive ###
367              
368             ### check for existence of the attribute ###
369 213 50       481 if (exists $this->{Data}->{$attribute}) { ### persistent ###
    0          
370 213         717 $this->{Data}->{$attribute}->[0]->value(@data);
371             } elsif (exists $this->{TempData}->{$attribute}) { ### transient ###
372 0         0 $this->{TempData}->{$attribute}->[0]->value(@data);
373             } else {
374 0         0 croak "'$attribute' is not an attribute of this object";
375             }
376             }
377              
378             ########################################################################
379             # Function: clear
380             # Description: Clears the fields of the object.
381             # Parameters: None
382             # Returns: None
383             ########################################################################
384             sub clear {
385 0 0   0 0 0 (@_ == 1) or croak 'Usage: $obj->clear()';
386 0         0 my $this = shift;
387 0 0       0 ref($this) or croak "$this is not an object";
388              
389 0         0 $this->_trace();
390              
391             ### clear the persistent data ###
392 0         0 foreach my $attr (keys %{$this->{Data}}) {
  0         0  
393 0         0 $this->value($attr, undef);
394             }
395              
396             ### clear the transient data ###
397 0         0 foreach my $attr (keys %{$this->{TempData}}) {
  0         0  
398 0         0 $this->value($attr, undef);
399             }
400              
401             ### clear the previous ID ###
402 0         0 undef(%{$this->{PrevId}});
  0         0  
403             }
404              
405             ########################################################################
406             # Function: update
407             # Description: Updates the object in the data store.
408             # Parameters: None
409             # Returns: true = the object did previously exist in the datastore
410             # false = the object did not previously exist
411             ########################################################################
412             sub update {
413 2 50   2 0 13 (@_ > 0) or croak 'Usage: $obj->update([@id])';
414 2         3 my ($this, @id) = @_;
415 2 50       13 ref($this) or croak "$this is not an object";
416              
417 2         4 $this->_trace();
418              
419             ### set previous ID if passed ###
420 2 50       4 if (@id) {
421 0         0 $this->_check_id(@id);
422 0         0 $this->_prev_id(@id);
423             }
424              
425             ### check that the object exists in the data store ###
426 2 50       6 if (!$this->_is_valid_id($this->_prev_id())) {
427 0         0 croak "Object does not already exist in the data store";
428             }
429              
430 2         12 my $rc = $this->delete();
431 2         11 $this->insert();
432              
433 2         7 $rc;
434             }
435              
436             ########################################################################
437             # Function: save
438             # Description: Saves the object to the data store.
439             # Parameters: None
440             # Returns: true = the object did previously exist in the datastore
441             # false = the object did not previously exist
442             ########################################################################
443             sub save {
444 0 0   0 0 0 (@_ == 1) or croak 'Usage: $obj->save()';
445 0         0 my $this = shift;
446 0 0       0 ref($this) or croak "$this is not an object";
447              
448 0         0 $this->_trace();
449              
450             ### determine if the object is already saved in the database ###
451 0 0       0 if ($this->_is_valid_id($this->_prev_id())) {
452 0         0 $this->update(); ### return what update returned ###
453             } else {
454 0         0 $this->insert();
455 0         0 0; ### object did not previously exist ###
456             }
457             }
458              
459             ########################################################################
460             # Function: restore
461             # Description: Restores the object from the data store.
462             # Parameters: @id = unique identifier assigned to the object
463             # Returns: true = an object was restored
464             # false = an object was not restored
465             ########################################################################
466             sub restore {
467 0 0   0 0 0 (@_ > 1) or croak 'Usage: $obj->restore()';
468 0         0 my ($this, @id) = @_;
469 0 0       0 ref($this) or croak "$this is not an object";
470              
471 0         0 $this->_trace();
472              
473             ### check that the ID is valid ###
474 0         0 $this->_check_id(@id);
475              
476             ### build SQL-like WHERE clause with ID ###
477 0         0 my @exprs;
478 0         0 foreach my $idfield (@{$this->{IdFields}}) {
  0         0  
479 0         0 push(@exprs, sprintf("$idfield = %s", $this->quote(shift @id)));
480             }
481 0         0 my $expr = join(' and ', @exprs);
482              
483             ### restore the object ###
484 0         0 $this->restore_where($expr);
485 0         0 my $rc = $this->restore_next();
486              
487             ### check if more than one object exists with the same ID ###
488 0 0       0 if ($this->restore_next()) {
489 0         0 $expr =~ s/ AND /, /; ### a bit of formatting ###
490 0         0 croak("More than one object exists with this ID ($expr)");
491             }
492              
493 0         0 $rc;
494             }
495              
496             ########################################################################
497             # Function: restore_all
498             # Description: Restores all the objects from the data store and optionally
499             # sorted.
500             # Parameters $order_by (optional) = sort expression for the objects
501             # in the form of an SQL ORDER BY clause
502             # Returns: None
503             ########################################################################
504             sub restore_all {
505 5 50   5 0 40 (@_ < 3) or croak 'Usage: $obj->restore_all([$order_by])';
506 5         95 my ($this, $order_by) = @_;
507 5 50       17 ref($this) or croak "$this is not an object";
508              
509 5         16 $this->_trace();
510              
511 5         40 $this->restore_where(undef, $order_by); ### null query => restore all ###
512             }
513              
514             ########################################################################
515             # Function: restore_next
516             # Description: Restores the next object from the data store that matches the
517             # query expression in the previous restore_where or restore_all
518             # method calls.
519             # Parameters: None
520             # Returns: true = an object was restored
521             # false = an object was not restored; no more objects to restore
522             ########################################################################
523             sub restore_next {
524 11 50   11 0 114 (@_ == 1) or croak 'Usage: $obj->restore_next()';
525 11         13 my ($this) = @_;
526 11 50       26 ref($this) or croak "$this is not an object";
527              
528 11         24 $this->_trace();
529              
530 11         12 my $aref = shift(@{$this->{RestoredData}});
  11         23  
531 11 100       25 if (defined $aref) { ### found an object ###
532              
533             ### clear the transient data ###
534 9         14 foreach my $attr (keys %{$this->{TempData}}) {
  9         33  
535 0         0 $this->value($attr, undef);
536             }
537              
538             ### load the persistent data ###
539 9         16 foreach my $attr (@{$this->{DataOrder}}) {
  9         18  
540 45         108 $this->value($attr, shift @$aref);
541             }
542              
543             ### save the object ID ###
544 9         37 $this->_prev_id($this->_id());
545              
546 9         22 1;
547             } else { ### no more objects left ###
548 2         7 0;
549             }
550             }
551              
552             ########################################################################
553             # Function: data
554             # Description: Gets/Sets all data fields of an object.
555             # Parameters: $href (optional) = a reference to a hash of object data
556             # Returns: $href = a reference to a hash of object data
557             ########################################################################
558             sub data {
559 0 0   0 0 0 (@_ > 0) or croak 'Usage: $obj->data([$href])';
560 0         0 my ($this, $href) = @_;
561 0 0       0 ref($this) or croak "$this is not an object";
562              
563 0         0 $this->_trace();
564              
565             ### set data fields ###
566 0 0 0     0 if (defined $href && ref $href eq 'HASH') {
567 0         0 foreach my $attr (keys %$href) {
568 0         0 $this->value($attr, $href->{$attr});
569             }
570             }
571              
572             ### get data fields ###
573 0         0 $href = {};
574 0         0 foreach my $attr (@{$this->{DataOrder}}) {
  0         0  
575 0         0 my @values = $this->value($attr);
576 0 0       0 if (@values > 1) {
577 0         0 $href->{$attr} = [@values];
578             } else {
579 0         0 $href->{$attr} = pop @values;
580             }
581             }
582              
583             ### return reference to hash of data ###
584 0         0 $href;
585             }
586              
587             ########################################################################
588             # Function: quote
589             # Description: Quote a string literal for use in a query statement by
590             # escaping any special characters (such as quotation marks)
591             # contained within the string and adding the required type
592             # of outer quotation marks.
593             # Parameters: $str = string to quote and escape
594             # Returns: $quoted_str = quoted string
595             ########################################################################
596             sub quote {
597 3 50   3 0 29 (@_ == 2) or croak 'Usage: $obj->quote($str)';
598 3         6 my ($this, $str) = @_;
599 3 50       7 ref($this) or croak "$this is not an object";
600              
601 3 50       5 if (defined $str) {
602 3         8 $str =~ s/\'/\\\'/g; # Perl escaping
603 3         42 "'$str'";
604             } else {
605 0         0 "";
606             }
607             }
608              
609             ########################################################################
610             # Function: debug
611             # Description: Gets/Sets the debugging level.
612             # Parameters: $level = a string representing the debug level/type
613             # Valid levels/types are the following:
614             # 'Trace' -> show a call stack trace
615             # 'SQL' -> show SQL statements generated
616             # 'LDAP' -> show LDAP filters
617             # Returns: None
618             ########################################################################
619             sub debug {
620 0 0   0 0 0 (@_ > 0) or croak 'Usage: $obj->debug([$flag])';
621 0         0 my $this = shift;
622              
623 0         0 $this->_trace();
624              
625 0 0       0 $this->{Debug} = shift if @_;
626 0 0       0 $this->{Debug} or '';
627             }
628              
629             =head1 ABSTRACT METHODS THAT NEED TO BE OVERRIDDEN IN THE SUBCLASS
630              
631             =cut
632              
633             ########################################################################
634             #
635             # -------------------------------------------------------------------------
636             # PUBLIC ABSTRACT METHODS TO BE OVERRIDDEN (REDEFINED) IN THE DERIVED CLASS
637             # -------------------------------------------------------------------------
638             #
639             # NOTE: These methods MUST be overridden in the subclasses.
640             # In order, for even a minimal subclass to work, you must
641             # override these methods in the subclass.
642             #
643             ########################################################################
644              
645             ########################################################################
646             # datastore
647             ########################################################################
648              
649             =head2 datastore -- Sets/Returns the Data Store Parameters
650              
651             eval {
652             ### set the data store ###
653             $person->datastore(@args);
654              
655             ### get the data store ###
656             $href = $person->datastore();
657             };
658             croak "Exception caught: $@" if $@;
659              
660             Returns (and optionally sets) the data store of the object. This
661             method throws Perl execeptions so use it with an eval block.
662              
663             Setting the data store can involve anything from initializing a
664             connection to opening a file. Getting a data store usually means
665             returning information pertaining to the data store in a useful form,
666             such as a connection to a database or a location of a file.
667              
668             This method requires implementing.
669              
670             Parameters:
671              
672             =over 4
673              
674             =item Varies by implementation.
675              
676             =back
677              
678             Returns:
679              
680             =over 4
681              
682             =item Varies by implementation.
683              
684             =back
685              
686             =cut
687              
688             sub datastore {
689 0 0   0 1 0 (@_ > 0) or croak 'Usage: $obj->datastore()';
690 0         0 my $this = shift;
691 0 0       0 ref($this) or croak "$this is not an object";
692              
693 0         0 $this->_trace();
694              
695 0         0 croak "method not implemented";
696             }
697              
698             ########################################################################
699             # insert
700             ########################################################################
701              
702             =head2 insert -- Insert an Object into the Data Store
703              
704             eval {
705             $person->insert();
706             };
707             croak "Exception caught: $@" if $@;
708              
709             Inserts an object into the data store. This method throws Perl
710             execeptions so use it with an eval block.
711              
712             This method requires implementing.
713              
714             Parameters:
715              
716             =over 4
717              
718             =item None.
719              
720             =back
721              
722             Returns:
723              
724             =over 4
725              
726             =item None.
727              
728             =back
729              
730             See the L documentation for more information.
731              
732             =cut
733              
734             sub insert {
735 0 0   0 1 0 (@_ > 0) or croak 'Usage: $obj->insert()';
736 0         0 my $this = shift;
737 0 0       0 ref($this) or croak "$this is not an object";
738              
739 0         0 $this->_trace();
740              
741 0         0 croak "method not implemented";
742             }
743              
744             ########################################################################
745             # delete
746             ########################################################################
747              
748             =head2 delete -- Delete an Object from the Data Store
749              
750             eval {
751             $person->delete();
752             };
753             croak "Exception caught: $@" if $@;
754              
755             Deletes an object from the data store. This method throws Perl
756             execeptions so use it with an eval block.
757              
758             This method requires implementing.
759              
760             Parameters:
761              
762             =over 4
763              
764             =item I<@id>
765              
766             Values of the Identity attributes of the object. This argument is
767             optional and will default to the Identifier values of the object as
768             the default.
769              
770             =back
771              
772             Returns:
773              
774             =over 4
775              
776             =item I<$flag>
777              
778             A true value if the object previously existed in the data store (it
779             was deleted), and a false value if not (nothing to delete).
780              
781             =back
782              
783             See the L documentation for more information.
784              
785             =cut
786              
787             sub delete {
788 0 0   0 1 0 (@_ > 0) or croak 'Usage: $obj->delete([@id])';
789 0         0 my ($this, @id) = @_;
790 0 0       0 ref($this) or croak "$this is not an object";
791              
792 0         0 $this->_trace();
793              
794 0         0 croak "method not implemented";
795             }
796              
797             ########################################################################
798             # restore_where
799             ########################################################################
800              
801             =head2 restore_where -- Conditionally Restoring Objects
802              
803             use Persistent::File;
804              
805             eval {
806             my $person = new Persistent::File('people.txt', '|');
807             $person->restore_where(
808             "lastname = 'Flintstone' and telnum =~ /^[(]?650/",
809             "lastname, firstname, telnum DESC"
810             );
811             while ($person->restore_next()) {
812             print "Restored: "; print_person($person);
813             }
814             };
815             croak "Exception caught: $@" if $@;
816              
817             Restores objects from the data store that meet the specified
818             conditions. The objects are returned one at a time by using the
819             I method and in a sorted order if specified. This
820             method throws Perl execeptions so use it with an eval block.
821              
822             Since this is a Perl implemented Persistent class, the
823             I method expects all patterm matching to use Perl
824             regular expressions.
825              
826             This method requires implementing.
827              
828             Parameters:
829              
830             =over 4
831              
832             =item I<$where>
833              
834             Conditional expression for the requested objects. The format of this
835             expression is similar to a SQL WHERE clause. This argument is
836             optional.
837              
838             =item I<$order_by>
839              
840             Sort expression for the requested objects. The format of this
841             expression is similar to a SQL ORDER BY clause. This argument is
842             optional.
843              
844             =back
845              
846             Returns:
847              
848             =over 4
849              
850             =item I<$num_of_objs>
851              
852             The number of objects that match the conditions.
853              
854             =back
855              
856             See the L documentation for more information.
857              
858             =cut
859              
860             sub restore_where {
861 0 0   0 1 0 (@_ < 4) or croak 'Usage: $obj->restore_where([$where], [$order_by])';
862 0         0 my ($this, $where, $order_by) = @_;
863 0 0       0 ref($this) or croak "$this is not an object";
864              
865 0         0 $this->_trace();
866              
867 0         0 croak "method not implemented";
868             }
869              
870             ########################################################################
871             # PRIVATE METHODS
872             ########################################################################
873              
874             ########################################################################
875             #
876             # ---------------
877             # PRIVATE METHODS
878             # ---------------
879             #
880             # NOTE: These methods do not need to be overridden in the subclasses.
881             # However, you may certainly override these methods if you see
882             # the need to.
883             #
884             ########################################################################
885              
886             ########################################################################
887             # Function: _id
888             # Description: Gets/Sets the ID of the object.
889             # Parameters: @id (optional) = the unique attribute(s) of the object
890             # Returns: @id = the unique attribute(s) of the object
891             ########################################################################
892             sub _id {
893 32     32   50 my($this, @id) = @_;
894 32 50       73 ref($this) or croak "$this is not an object";
895              
896 32         56 $this->_trace();
897              
898 32 50       71 if (@id) { ### set the ID ###
899 0         0 my @new_id = @id;
900 0         0 foreach my $idfield (@{$this->{IdFields}}) {
  0         0  
901 0         0 $this->value($idfield, shift @new_id);
902             }
903             } else { ### get the ID ###
904 32         35 foreach my $idfield (@{$this->{IdFields}}) {
  32         76  
905 32         66 push(@id, $this->value($idfield));
906             }
907             }
908              
909 32         118 @id;
910             }
911              
912             ########################################################################
913             # Function: _prev_id
914             # Description: Gets/Sets the previous ID of the object.
915             # Parameters: @id (optional) = the unique attribute(s) of the object
916             # Returns: @id = the unique attribute(s) of the object
917             ########################################################################
918             sub _prev_id {
919 26     26   55 my($this, @id) = @_;
920 26 50       57 ref($this) or croak "$this is not an object";
921              
922 26         50 $this->_trace();
923              
924 26 100       54 if (@id) { ### set the previous ID ###
925 21         34 my @new_id = @id;
926 21         25 foreach my $idfield (@{$this->{IdFields}}) {
  21         193  
927 21         84 $this->{PrevId}->{$idfield} = shift @new_id;
928             }
929             } else { ### get the previous ID ###
930 5         9 foreach my $idfield (@{$this->{IdFields}}) {
  5         19  
931 5         14 push(@id, $this->{PrevId}->{$idfield});
932             }
933             }
934              
935 26         75 @id;
936             }
937              
938             ########################################################################
939             # Function: _is_valid_id
940             # Description: Returns whether the ID is valid or not.
941             # Parameters: @id (optional) = ID of the object
942             # Returns: 1 = ID is valid
943             # 0 = ID is not valid
944             ########################################################################
945             sub _is_valid_id {
946 17     17   33 my($this, @id) = @_;
947 17 50       39 ref($this) or croak "$this is not an object";
948              
949 17         34 $this->_trace();
950              
951 17 50       49 @id = $this->_id() if !@id;
952 17         28 foreach my $idfield (@{$this->{IdFields}}) {
  17         34  
953 17 50       58 return 0 if !defined(shift @id);
954             }
955 17         74 1;
956             }
957              
958             ########################################################################
959             # Function: _check_id
960             # Description: Checks that the ID is valid.
961             # Parameters: @id (optional) = ID of the object
962             # Returns: None
963             ########################################################################
964             sub _check_id {
965 15     15   36 my($this, @id) = @_;
966 15 50       38 ref($this) or croak "$this is not an object";
967              
968 15         36 $this->_trace();
969              
970 15 100       69 @id = $this->_id() if !@id;
971 15 50       61 if (!$this->_is_valid_id(@id)) {
972 0   0     0 croak(sprintf("The ID (%s) is not valid for this object",
973             join(', ', map($_ || '', @id))));
974             }
975             }
976              
977             ########################################################################
978             # Function: _parse_query
979             # Description: Parses an SQL-like WHERE clause query and converts it
980             # into a Perl boolean expression.
981             # Parameters: $query = SQL-like WHERE clause
982             # Returns: $bool_expr = Perl boolean expression
983             ########################################################################
984              
985             sub _parse_query {
986 7 50   7   29 (@_ > 0) or croak 'Usage: $obj->_parse_query()';
987 7         14 my($this, $query) = @_;
988 7 50       24 ref($this) or croak "$this is not an object";
989              
990 7         20 $this->_trace();
991              
992 7         67 my %string_op = ( ### map operators to string operators ###
993             '==' => 'eq',
994             '<' => 'lt',
995             '<=' => 'le',
996             '>' => 'gt',
997             '>=' => 'ge',
998             '!=' => 'ne',
999             '=~' => '=~',
1000             );
1001 7         10 my $any_op = '<=|>=|<|>|!=|==|=~'; ### any comparison operator ###
1002              
1003             ### convert SQL-like query into a Perl boolean expression ###
1004 7 100 66     41 if (!defined($query) || $query =~ /^\s*$/) {
1005 5         24 1;
1006             } else {
1007              
1008             ### squirrel away all instances of escaped quotes for later ###
1009 2         4 $query =~ s/\\\'/\200/g; ### hopefully, \200 and \201 aren't used ###
1010 2         4 $query =~ s/\\\"/\201/g;
1011              
1012             ### replace all '=' with '==' ###
1013 2         29 $query =~ s/([^!><=])=([^~])/$1==$2/g;
1014              
1015             ### replace var with $var ###
1016 2         57 $query =~ s/(\w+)\s*($any_op)/\$$1 $2/g;
1017              
1018             ### replace comparison operators before quoted strings ###
1019             ### with string comparison operators ###
1020 2         49 $query =~ s{
1021             ($any_op) ### any comparison operator ###
1022             \s* ### followed by zero or more spaces ###
1023             ([\'\"]) ### then by a quoted string ###
1024             }{
1025 3         15 "$string_op{$1} $2"
1026             }goxse; ### global, compile-once, extended, ###
1027             ### treat as single line, eval ###
1028              
1029             ### restore all escaped quote characters ###
1030 2         7 $query =~ s/\200/\\\'/g;
1031 2         2 $query =~ s/\201/\\\"/g;
1032              
1033             ### return modified query and field list ###
1034 2         12 $query;
1035             }
1036             }
1037              
1038             ########################################################################
1039             # Function: _sort_objects
1040             # Description: Sorts the objects returned from a datastore.
1041             # Parameters: $order_by = SQL-like ORDER BY clause
1042             # \@objs_data = reference to an array of objects data
1043             # Returns: None
1044             ########################################################################
1045              
1046             sub _sort_objects {
1047 2 50   2   6 (@_ > 0) or croak 'Usage: $obj->_sort_objects()';
1048 2         3 my($this, $order_by, $objs_data) = @_;
1049 2 50       7 ref($this) or croak "$this is not an object";
1050              
1051 2         5 $this->_trace();
1052              
1053             ### make sure an ORDER BY clause has been passed ###
1054 2 50 33     17 if (defined $order_by && $order_by !~ /^\s*$/) {
1055 2         15 my $sort_expr = $this->_build_sort_expr($order_by);
1056 2         9 local $^W = 0; ### turn off warnings for the eval ###
1057 2         13 @$objs_data = sort {eval($sort_expr)} @$objs_data;
  9         475  
1058             }
1059             }
1060              
1061             ########################################################################
1062             # Function: _build_sort_expr
1063             # Description: Parses an SQL-like ORDER BY clause and converts it
1064             # into a Perl sort expression.
1065             # Parameters: $order_by = SQL-like ORDER BY clause
1066             # Returns: $sort_expr = Perl sort expression
1067             ########################################################################
1068              
1069             sub _build_sort_expr {
1070 2 50   2   6 (@_ > 0) or croak 'Usage: $obj->_build_sort_expr()';
1071 2         4 my($this, $order_by) = @_;
1072 2 50       6 ref($this) or croak "$this is not an object";
1073              
1074 2         5 $this->_trace();
1075              
1076             ### make sure an ORDER BY clause has been passed ###
1077 2         2 my $sort_expr;
1078 2 50 33     16 if (!defined $order_by || $order_by =~ /^\s*$/) {
1079 0         0 $sort_expr = 0;
1080             } else {
1081              
1082             ### build a map from column name to column number ###
1083 2         4 my $i = 0;
1084 2         4 my %field_num = map {$_ => $i++} @{$this->{DataOrder}};
  10         24  
  2         4  
1085              
1086             ### build the sort expression ###
1087 2         4 my @exprs;
1088 2         6 foreach my $stmt (split(/\s*,\s*/, $order_by)) {
1089              
1090             ### parse ORDER BY clause ###
1091 2         8 my($field, $order) = split(/\s/, $stmt);
1092 2         4 my $field_num = $field_num{$field};
1093 2 50       6 if (!defined($field_num)) {
1094 0         0 croak "'$field' is not a persistent attribute of the object";
1095             }
1096              
1097             ### determine sort order ###
1098 2         3 my($var1, $var2);
1099 2 50 33     7 if (defined $order && $order =~ /DESC/i) {
1100 0         0 $var1 = '$b'; $var2 = '$a';
  0         0  
1101             } else {
1102 2         3 $var1 = '$a'; $var2 = '$b';
  2         2  
1103             }
1104              
1105             ### get the comparison operator for the data type ###
1106 2         14 my $cmp_op = $this->{Data}->{$field}->[0]->get_compare_op();
1107              
1108             ### build and store the sort expression ###
1109 2         12 my $data_access_str = $this->_get_data_access_str();
1110 2         14 push(@exprs, sprintf("$data_access_str %s $data_access_str",
1111             $var1, $field_num, $cmp_op, $var2, $field_num));
1112             }
1113              
1114             ### join sort the expressions together ###
1115 2         8 $sort_expr = join(' || ', @exprs);
1116             }
1117              
1118 2         4 $sort_expr; ### return the sort expression ###
1119             }
1120              
1121             ########################################################################
1122             # Function: _get_data_access_str
1123             # Description: Returns a string that contains the format for how to
1124             # access the data of the restored objects.
1125             # Parameters: None
1126             # Returns: $str = data access string
1127             ########################################################################
1128              
1129             sub _get_data_access_str {
1130 2 50   2   7 (@_ > 0) or croak 'Usage: $obj->_data_access_str()';
1131 2         2 my $this = shift;
1132 2 50       4 ref($this) or croak "$this is not an object";
1133              
1134 2         3 '%s->[%s]';
1135             }
1136              
1137             ########################################################################
1138             # Function: _allocate_data_type
1139             # Description: Allocatea a data type.
1140             # Parameters: $data_type = data type to allocate
1141             # valid values are the following:
1142             # 'varchar'
1143             # 'char'
1144             # 'string'
1145             # 'number'
1146             # 'datetime'
1147             # @args = arguments to be passed to the data type constructor
1148             # Returns: $ref = reference to the allocated data type
1149             ########################################################################
1150              
1151             sub _allocate_data_type {
1152 55 50   55   116 (@_ > 1) or croak 'Usage: $obj->_allocate_data_type($data_type, @args)';
1153 55         100 my($this, $data_type, @args) = @_;
1154 55 50       112 ref($this) or croak "$this is not an object";
1155              
1156             ### validate arguments ###
1157 55 50 33     318 croak "data type must be defined"
1158             if !defined($data_type) || $data_type eq '';
1159              
1160 55         59 my $ref;
1161 55 100       257 if ($data_type =~ /^varchar$/i) {
    50          
    50          
    50          
    0          
1162 44         3837 require Persistent::DataType::VarChar;
1163 44         199 $ref = new Persistent::DataType::VarChar(@args);
1164             } elsif ($data_type =~ /^char$/i) {
1165 0         0 require Persistent::DataType::Char;
1166 0         0 $ref = new Persistent::DataType::Char(@args);
1167             } elsif ($data_type =~ /^string$/i) {
1168 0         0 require Persistent::DataType::String;
1169 0         0 $ref = new Persistent::DataType::String(@args);
1170             } elsif ($data_type =~ /^number$/i) {
1171 11         3961 require Persistent::DataType::Number;
1172 11         91 $ref = new Persistent::DataType::Number(@args);
1173             } elsif ($data_type =~ /^datetime$/i) {
1174 0         0 require Persistent::DataType::DateTime;
1175 0         0 $ref = new Persistent::DataType::DateTime(@args);
1176             } else {
1177 0         0 croak "data type ($data_type) is invalid";
1178             }
1179              
1180 55         122 $ref;
1181             }
1182              
1183             ########################################################################
1184             # Function: _trace
1185             # Description: Print a trace message for the subroutine caller if
1186             # debugging is turned on.
1187             # Parameters: None
1188             # Returns: None
1189             ########################################################################
1190             sub _trace {
1191 619     619   723 my $this = shift;
1192 619 50       1204 ref($this) or croak "$this is not an object";
1193              
1194 619 50 33     1928 if (defined $this->{Debug} && $this->{Debug} eq 'Trace') {
1195 0           my $i = 1;
1196              
1197 0           my ($package, $filename, $line, $subroutine) = caller($i);
1198 0           my $msg = "$subroutine() ... ";
1199              
1200 0           for ($i = 1; my $f = caller($i); $i++) {}
1201              
1202 0           ($package, $filename, $line, $subroutine) = caller($i - 1);
1203 0           $msg .= "$subroutine() called from $filename $line\n";
1204              
1205 0           warn $msg;
1206             }
1207             }
1208              
1209             ### end of library ###
1210             1;
1211             __END__