root/trunk/lib/Data/ObjectDriver/BaseObject.pm @ 553

Revision 553, 36.6 kB (checked in by ykerherve, 11 months ago)

Added Oracle support by integrating
https://rt.cpan.org/Ticket/Display.html?id=41929 patch

Added documentation
Cleaned formatting

  • Property svn:keywords set to Id Revision
Line 
1# $Id$
2
3package Data::ObjectDriver::BaseObject;
4use strict;
5use warnings;
6
7our $HasWeaken;
8eval q{ use Scalar::Util qw(weaken) }; ## no critic
9$HasWeaken = !$@;
10
11use Carp ();
12
13use Class::Trigger qw( pre_save post_save post_load pre_search
14                       pre_insert post_insert pre_update post_update
15                       pre_remove post_remove post_inflate );
16
17use Data::ObjectDriver::ResultSet;
18
19## Global Transaction variables
20our @WorkingDrivers;
21our $TransactionLevel = 0;
22
23sub install_properties {
24    my $class = shift;
25    my($props) = @_;
26    my $columns = delete $props->{columns};
27    $props->{columns} = [];
28    {
29        no strict 'refs'; ## no critic
30        *{"${class}::__properties"} = sub { $props };
31    }
32
33    foreach my $col (@$columns) {
34        $class->install_column($col);
35    }
36    return $props;
37}
38
39sub install_column {
40    my($class, $col, $type) = @_;
41    my $props = $class->properties;
42
43    push @{ $props->{columns} }, $col;
44    $props->{column_names}{$col} = ();
45    # predefine getter/setter methods here
46    # Skip adding this method if the class overloads it.
47    # this lets the SUPER::columnname magic do it's thing
48    if (! $class->can($col)) {
49        no strict 'refs'; ## no critic
50        *{"${class}::$col"} = $class->column_func($col);
51    }
52    if ($type) {
53        $props->{column_defs}{$col} = $type;
54    }
55}
56
57sub properties {
58    my $this = shift;
59    my $class = ref($this) || $this;
60    $class->__properties;
61}
62
63# see docs below
64
65sub has_a {
66    my $class = shift;
67    my @args = @_;
68
69    # Iterate over each remote object
70    foreach my $config (@args) {
71        my $parentclass = $config->{class};
72
73        # Parameters
74        my $column = $config->{column};
75        my $method = $config->{method};
76        my $cached = $config->{cached} || 0;
77        my $parent_method = $config->{parent_method};
78
79        # column is required
80        if (!defined($column)) {
81            die "Please specify a valid column for $parentclass"
82        }
83
84        # create a method name based on the column
85        if (! defined $method) {
86            if (!ref($column)) {
87                $method = $column;
88                $method =~ s/_id$//;
89                $method .= "_obj";
90            } elsif (ref($column) eq 'ARRAY') {
91                foreach my $col (@{$column}) {
92                    my $part = $col;
93                    $part =~ s/_id$//;
94                    $method .= $part . '_';
95                }
96                $method .= "obj";
97            }
98        }
99
100        # die if we have clashing methods method
101        if (! defined $method || defined(*{"${class}::$method"})) {
102            die "Please define a valid method for $class->$column";
103        }
104
105        if ($cached) {
106            # Store cached item inside this object's namespace
107            my $cachekey = "__cache_$method";
108
109            no strict 'refs'; ## no critic
110            *{"${class}::$method"} = sub {
111                my $obj = shift;
112
113                return $obj->{$cachekey}
114                    if defined $obj->{$cachekey};
115
116                my $id = (ref($column) eq 'ARRAY')
117                    ? [ map { $obj->{column_values}->{$_} } @{$column}]
118                    : $obj->{column_values}->{$column}
119                    ;
120                ## Hold in a variable here too, so we don't lose it immediately
121                ## by having only the weak reference.
122                my $ret = $parentclass->lookup($id);
123                if ($HasWeaken) {
124                    $obj->{$cachekey} = $ret;
125                    weaken($obj->{$cachekey});
126                }
127                return $ret;
128            };
129        } else {
130            if (ref($column)) {
131                no strict 'refs'; ## no critic
132                *{"${class}::$method"} = sub {
133                    my $obj = shift;
134                    return $parentclass->lookup([ map{ $obj->{column_values}->{$_} } @{$column}]);
135                };
136            } else {
137                no strict 'refs'; ## no critic
138                *{"${class}::$method"} = sub {
139                    return $parentclass->lookup(shift()->{column_values}->{$column});
140                };
141            }
142        }
143
144        # now add to the parent
145        if (!defined $parent_method) {
146            $parent_method = lc($class);
147            $parent_method =~ s/^.*:://;
148
149            $parent_method .= '_objs';
150        }
151        if (ref($column)) {
152            no strict 'refs'; ## no critic
153            *{"${parentclass}::$parent_method"} = sub {
154                my $obj = shift;
155                my $terms = shift || {};
156                my $args = shift;
157
158                my $primary_key = $obj->primary_key;
159
160                # inject pk search into given terms.
161                # composite key, ugh
162                foreach my $key (@$column) {
163                    $terms->{$key} = shift(@{$primary_key});
164                }
165
166                return $class->search($terms, $args);
167            };
168        } else {
169            no strict 'refs'; ## no critic
170            *{"${parentclass}::$parent_method"} = sub {
171                my $obj = shift;
172                my $terms = shift || {};
173                my $args = shift;
174                # TBD - use primary_key_to_terms
175                $terms->{$column} = $obj->primary_key;
176                return $class->search($terms, $args);
177            };
178        };
179    } # end of loop over class names
180    return;
181}
182
183sub driver {
184    my $class = shift;
185    $class->properties->{driver} ||= $class->properties->{get_driver}->();
186}
187
188sub get_driver {
189    my $class = shift;
190    $class->properties->{get_driver} = shift if @_;
191}
192
193sub new {
194    my $obj = bless {}, shift;
195
196    return $obj->init(@_);
197}
198
199sub init {
200    my $self = shift;
201
202    while (@_) {
203        my $field = shift;
204        my $val   = shift;
205        $self->$field($val);
206    }
207    return $self;
208}
209
210sub is_pkless {
211    my $obj = shift;
212    my $prop_pk = $obj->properties->{primary_key};
213    return 1 if ! $prop_pk;
214    return 1 if ref $prop_pk eq 'ARRAY' && ! @$prop_pk;
215}
216
217sub is_primary_key {
218    my $obj = shift;
219    my($col) = @_;
220
221    my $prop_pk = $obj->properties->{primary_key};
222    if (ref($prop_pk)) {
223        for my $pk (@$prop_pk) {
224            return 1 if $pk eq $col;
225        }
226    } else {
227        return 1 if $prop_pk eq $col;
228    }
229
230    return;
231}
232
233sub primary_key_tuple {
234    my $obj = shift;
235    my $pk = $obj->properties->{primary_key} || return;
236    $pk = [ $pk ] unless ref($pk) eq 'ARRAY';
237    $pk;
238}
239
240sub primary_key {
241    my $obj = shift;
242    my $pk = $obj->primary_key_tuple;
243    my @val = map { $obj->$_() }  @$pk;
244    @val == 1 ? $val[0] : \@val;
245}
246
247sub is_same_array {
248    my($a1, $a2) = @_;
249    return if ($#$a1 != $#$a2);
250    for (my $i = 0; $i <= $#$a1; $i++) {
251        return if $a1->[$i] ne $a2->[$i];
252    }
253    return 1;
254}
255
256sub primary_key_to_terms {
257    my($obj, $id) = @_;
258    my $pk = $obj->primary_key_tuple;
259    if (! defined $id) {
260        $id = $obj->primary_key;
261    } else {
262        if (ref($id) eq 'HASH') {
263            my @keys = sort keys %$id;
264            unless (is_same_array(\@keys, [ sort @$pk ])) {
265                Carp::confess("keys don't match with primary keys: @keys|@$pk");
266            }
267            return $id;
268        }
269    }
270    $id = [ $id ] unless ref($id) eq 'ARRAY';
271    my %terms;
272    @terms{@$pk} = @$id;
273    \%terms;
274}
275
276sub is_same {
277    my($obj, $other) = @_;
278
279    my @a;
280    for my $o ($obj, $other) {
281        push @a, [ map { $o->$_() } @{ $o->primary_key_tuple }];
282    }
283    return is_same_array( @a );
284}
285
286sub object_is_stored {
287    my $obj = shift;
288    return $obj->{__is_stored} ? 1 : 0;
289}
290sub pk_str {
291    my ($obj) = @_;
292    my $pk = $obj->primary_key;
293    return $pk unless ref ($pk) eq 'ARRAY';
294    return join (":", @$pk);
295}
296
297sub has_primary_key {
298    my $obj = shift;
299    return unless @{$obj->primary_key_tuple};
300    my $val = $obj->primary_key;
301    $val = [ $val ] unless ref($val) eq 'ARRAY';
302    for my $v (@$val) {
303        return unless defined $v;
304    }
305    1;
306}
307
308sub datasource { $_[0]->properties->{datasource} }
309
310sub columns_of_type {
311    my $obj = shift;
312    my($type) = @_;
313    my $props = $obj->properties;
314    my $cols = $props->{columns};
315    my $col_defs = $props->{column_defs};
316    my @cols;
317    for my $col (@$cols) {
318        push @cols, $col if $col_defs->{$col} && $col_defs->{$col} eq $type;
319    }
320    \@cols;
321}
322
323sub set_values {
324    my $obj = shift;
325    my $values = shift;
326    for my $col (keys %$values) {
327        unless ( $obj->has_column($col) ) {
328            Carp::croak("You tried to set non-existent column $col to value $values->{$col} on " . ref($obj));
329        }
330        $obj->$col($values->{$col});
331    }
332}
333
334sub set_values_internal {
335    my $obj = shift;
336    my $values = shift;
337    for my $col (keys %$values) {
338        # Not needed for the internal version of this method
339        #unless ( $obj->has_column($col) ) {
340        #    Carp::croak("You tried to set inexistent column $col to value $values->{$col} on " . ref($obj));
341        #}
342
343        $obj->column_values->{$col} = $values->{$col};
344    }
345}
346
347sub clone {
348    my $obj = shift;
349    my $clone = $obj->clone_all;
350    for my $pk (@{ $obj->primary_key_tuple }) {
351        $clone->$pk(undef);
352    }
353    $clone;
354}
355
356sub clone_all {
357    my $obj = shift;
358    my $clone = ref($obj)->new();
359    $clone->set_values_internal($obj->column_values);
360    $clone->{changed_cols} = defined $obj->{changed_cols} ? { %{$obj->{changed_cols}} } : undef;
361    $clone;
362}
363
364sub has_column {
365    return exists $_[0]->properties->{column_names}{$_[1]};
366}
367
368sub column_names {
369    ## Reference to a copy.
370    [ @{ shift->properties->{columns} } ]
371}
372
373sub column_values { $_[0]->{'column_values'} ||= {} }
374
375## In 0.1 version we didn't die on inexistent column
376## which might lead to silent bugs
377## You should override column if you want to find the old
378## behaviour
379sub column {
380    my $obj = shift;
381    my $col = shift or return;
382    unless ($obj->has_column($col)) {
383        Carp::croak("Cannot find column '$col' for class '" . ref($obj) . "'");
384    }
385
386    # set some values
387    if (@_) {
388        $obj->{column_values}->{$col} = shift;
389        unless ($_[0] && ref($_[0]) eq 'HASH' && $_[0]->{no_changed_flag}) {
390            $obj->{changed_cols}->{$col}++;
391        }
392    }
393
394    $obj->{column_values}->{$col};
395}
396
397sub column_func {
398    my $obj = shift;
399    my $col = shift or die "Must specify column";
400
401    return sub {
402        my $obj = shift;
403        # getter
404        return $obj->{column_values}->{$col} unless (@_);
405
406        # setter
407        my ($val, $flags) = @_;
408        $obj->{column_values}->{$col} = $val;
409        unless ($flags && ref($flags) eq 'HASH' && $flags->{no_changed_flag}) {
410            $obj->{changed_cols}->{$col}++;
411        }
412
413        return $obj->{column_values}->{$col};
414    };
415}
416
417
418sub changed_cols_and_pk {
419    my $obj = shift;
420    keys %{$obj->{changed_cols}};
421}
422
423sub changed_cols {
424    my $obj = shift;
425    my $pk = $obj->primary_key_tuple;
426    my %pk = map { $_ => 1 } @$pk;
427    grep !$pk{$_}, $obj->changed_cols_and_pk;
428}
429
430sub is_changed {
431    my $obj = shift;
432    if (@_) {
433        return exists $obj->{changed_cols}->{$_[0]};
434    } else {
435        return $obj->changed_cols > 0;
436    }
437}
438
439sub exists {
440    my $obj = shift;
441    return 0 unless $obj->has_primary_key;
442    $obj->_proxy('exists', @_);
443}
444
445sub save {
446    my $obj = shift;
447    if ($obj->exists(@_)) {
448        return $obj->update(@_);
449    } else {
450        return $obj->insert(@_);
451    }
452}
453
454sub bulk_insert {
455    my $class = shift;
456    my $driver = $class->driver;
457
458    return $driver->bulk_insert($class, @_);
459}
460
461sub lookup {
462    my $class = shift;
463    my $driver = $class->driver;
464    my $obj = $driver->lookup($class, @_) or return;
465    $driver->cache_object($obj);
466    $obj;
467}
468
469sub lookup_multi {
470    my $class = shift;
471    my $driver = $class->driver;
472    my $objs = $driver->lookup_multi($class, @_) or return;
473    for my $obj (@$objs) {
474        $driver->cache_object($obj) if $obj;
475    }
476    $objs;
477}
478
479sub result {
480    my $class = shift;
481    my ($terms, $args) = @_;
482
483    return Data::ObjectDriver::ResultSet->new({
484                          class     => (ref $class || $class),
485                          page_size => delete $args->{page_size},
486                          paging    => delete $args->{no_paging},
487                          terms     => $terms,
488                          args      => $args,
489                          });
490}
491
492sub search {
493    my $class = shift;
494    my($terms, $args) = @_;
495    my $driver = $class->driver;
496    if (wantarray) {
497        my @objs = $driver->search($class, $terms, $args);
498
499        ## Don't attempt to cache objects where the caller specified fetchonly,
500        ## because they won't be complete.
501        ## Also skip this step if we don't get any objects back from the search
502        if (!$args->{fetchonly} || !@objs) {
503            for my $obj (@objs) {
504                $driver->cache_object($obj) if $obj;
505            }
506        }
507        return @objs;
508    } else {
509        my $iter = $driver->search($class, $terms, $args);
510        return $iter if $args->{fetchonly};
511
512        my $caching_iter = sub {
513            my $d = $driver;
514
515            my $o = $iter->();
516            unless ($o) {
517                $iter->end;
518                return;
519            }
520            $driver->cache_object($o);
521            return $o;
522        };
523        return Data::ObjectDriver::Iterator->new($caching_iter, sub { $iter->end });
524    }
525}
526
527sub remove         { shift->_proxy( 'remove',         @_ ) }
528sub update         { shift->_proxy( 'update',         @_ ) }
529sub insert         { shift->_proxy( 'insert',         @_ ) }
530sub replace        { shift->_proxy( 'replace',        @_ ) }
531sub fetch_data     { shift->_proxy( 'fetch_data',     @_ ) }
532sub uncache_object { shift->_proxy( 'uncache_object', @_ ) }
533
534sub refresh {
535    my $obj = shift;
536    return unless $obj->has_primary_key;
537    my $fields = $obj->fetch_data;
538    $obj->set_values_internal($fields);
539    $obj->call_trigger('post_load');
540    return 1;
541}
542
543## NOTE: I wonder if it could be useful to BaseObject superclass
544## to override the global transaction flag. If so, I'd add methods
545## to manipulate this flag and the working drivers. -- Yann
546sub _proxy {
547    my $obj = shift;
548    my($meth, @args) = @_;
549    my $driver = $obj->driver;
550    ## faster than $obj->txn_active && ! $driver->txn_active but see note.
551    if ($TransactionLevel && ! $driver->txn_active) {
552        $driver->begin_work;
553        push @WorkingDrivers, $driver;
554    }
555    $driver->$meth($obj, @args);
556}
557
558sub txn_active { $TransactionLevel }
559
560sub begin_work {
561    my $class = shift;
562    if ( $TransactionLevel > 0 ) {
563        Carp::carp(
564            $TransactionLevel > 1
565            ? "$TransactionLevel transactions already active"
566            : "Transaction already active"
567        );
568    }
569    $TransactionLevel++;
570}
571
572sub commit {
573    my $class = shift;
574    $class->_end_txn('commit');
575}
576
577sub rollback {
578    my $class = shift;
579    $class->_end_txn('rollback');
580}
581
582sub _end_txn {
583    my $class = shift;
584    my $meth  =  shift;
585   
586    ## Ignore nested transactions
587    if ($TransactionLevel > 1) {
588        $TransactionLevel--;
589        return;
590    }
591   
592    if (! $TransactionLevel) {
593        Carp::carp("No active transaction to end; ignoring $meth");
594        return;
595    }
596    my @wd = @WorkingDrivers;
597    $TransactionLevel--;
598    @WorkingDrivers = ();
599   
600    for my $driver (@wd) {
601        $driver->$meth;
602    }
603}
604
605sub txn_debug {
606    my $class = shift;
607    return {
608        txn     => $TransactionLevel,
609        drivers => \@WorkingDrivers,
610    };
611}
612
613sub deflate { { columns => shift->column_values } }
614
615sub inflate {
616    my $class = shift;
617    my($deflated) = @_;
618    my $obj = $class->new;
619    $obj->set_values($deflated->{columns});
620    $obj->{changed_cols} = {};
621    $obj->call_trigger('post_inflate');
622    return $obj;
623}
624
625sub DESTROY { }
626
627sub AUTOLOAD {
628    my $obj = $_[0];
629    (my $col = our $AUTOLOAD) =~ s!.+::!!;
630    Carp::croak("Cannot find method '$col' for class '$obj'") unless ref $obj;
631    unless ($obj->has_column($col)) {
632        Carp::croak("Cannot find column '$col' for class '" . ref($obj) . "'");
633    }
634
635    {
636        no strict 'refs'; ## no critic
637        *$AUTOLOAD = $obj->column_func($col);
638    }
639
640    goto &$AUTOLOAD;
641}
642
643sub has_partitions {
644    my $class = shift;
645    my(%param) = @_;
646    my $how_many = delete $param{number}
647        or Carp::croak("number (of partitions) is required");
648
649    ## save the number of partitions in the class
650    $class->properties->{number_of_partitions} = $how_many;
651
652    ## Save the get_driver subref that we were passed, so that the
653    ## SimplePartition driver can access it.
654    $class->properties->{partition_get_driver} = delete $param{get_driver}
655        or Carp::croak("get_driver is required");
656
657    ## When creating a new $class object, we should automatically fill in
658    ## the partition ID by selecting one at random, unless a partition_id
659    ## is already defined. This allows us to keep it simple but for the
660    ## caller to do something more complex, if it wants to.
661    $class->add_trigger(pre_insert => sub {
662        my($obj, $orig_obj) = @_;
663        unless (defined $obj->partition_id) {
664            my $partition_id = int(rand $how_many) + 1;
665            $obj->partition_id($partition_id);
666            $orig_obj->partition_id($partition_id);
667        }
668    });
669}
670
6711;
672
673__END__
674
675=head1 NAME
676
677Data::ObjectDriver::BaseObject - base class for modeled objects
678
679=head1 SYNOPSIS
680
681    package Ingredient;
682    use base qw( Data::ObjectDriver::BaseObject );
683
684    __PACKAGE__->install_properties({
685        columns     => [ 'ingredient_id', 'recipe_id', 'name', 'quantity' ],
686        datasource  => 'ingredient',
687        primary_key => [ 'recipe_id', 'ingredient_id' ],
688        driver      => FoodDriver->driver,
689    });
690
691    __PACKAGE__->has_a(
692        { class => 'Recipe', column => 'recipe_id', }
693    );
694
695    package main;
696
697    my ($ingredient) = Ingredient->search({ recipe_id => 4, name => 'rutabaga' });
698    $ingredient->quantity(7);
699    $ingredient->save();
700
701
702=head1 DESCRIPTION
703
704I<Data::ObjectDriver::BaseObject> provides services to data objects modeled
705with the I<Data::ObjectDriver> object relational mapper.
706
707=head1 CLASS DEFINITION
708
709=head2 C<Class-E<gt>install_properties(\%params)>
710
711Defines all the properties of the specified object class. Generally you should
712call C<install_properties()> in the body of your class definition, so the
713properties can be set when the class is C<use>d or C<require>d.
714
715Required members of C<%params> are:
716
717=over 4
718
719=item * C<columns>
720
721All the columns in the object class. This property is an arrayref.
722
723=item * C<datasource>
724
725The identifier of the table in which the object class's data are stored.
726Usually the datasource is simply the table name, but the datasource can be
727decorated into the table name by the C<Data::ObjectDriver::DBD> module if the
728database requires special formatting of table names.
729
730=item * C<driver> or C<get_driver>
731
732The driver used to perform database operations (lookup, update, etc) for the
733object class.
734
735C<driver> is the instance of C<Data::ObjectDriver> to use. If your driver
736requires configuration options not available when the properties are initially
737set, specify a coderef as C<get_driver> instead. It will be called the first
738time the driver is needed, storing the driver in the class's C<driver> property
739for subsequent calls.
740
741=back
742
743The optional members of C<%params> are:
744
745=over 4
746
747=item * C<primary_key>
748
749The column or columns used to uniquely identify an instance of the object
750class. If one column (such as a simple numeric ID) identifies the class,
751C<primary_key> should be a scalar. Otherwise, C<primary_key> is an arrayref.
752
753=item * C<column_defs>
754
755Specifies types for specially typed columns, if any, as a hashref. For example,
756if a column holds a timestamp, name it in C<column_defs> as a C<date> for
757proper handling with some C<Data::ObjectDriver::Driver::DBD> database drivers.
758Columns for which types aren't specified are handled as C<char> columns.
759
760Known C<column_defs> types are:
761
762=over 4
763
764=item * C<blob>
765
766A blob of binary data. C<Data::ObjectDriver::Driver::DBD::Pg> maps this to
767C<DBI::Pg::PG_BYTEA>, C<DBD::SQLite> to C<DBI::SQL_BLOB> and C<DBD::Oracle>
768to C<ORA_BLOB>.
769
770=item * C<bin_char>
771
772A non-blob string of binary data. C<Data::ObjectDriver::Driver::DBD::SQLite>
773maps this to C<DBI::SQL_BINARY>.
774
775=back
776
777Other types may be defined by custom database drivers as needed, so consult
778their documentation.
779
780=item * C<db>
781
782The name of the database. When used with C<Data::ObjectDriver::Driver::DBI>
783type object drivers, this name is passed to the C<init_db> method when the
784actual database handle is being created.
785
786=back
787
788Custom object drivers may define other properties for your object classes.
789Consult the documentation of those object drivers for more information.
790
791=head2 C<Class-E<gt>install_column($col, $def)>
792
793Modify the Class definition to declare a new column C<$col> of definition <$def>
794(see L<column_defs>).
795
796=head2 C<Class-E<gt>has_a(@definitions)>
797
798B<NOTE:> C<has_a> is an experimental system, likely to both be buggy and change
799in future versions.
800
801Defines a foreign key reference between two classes, creating accessor methods
802to retrieve objects both ways across the reference. For each defined reference,
803two methods are created: one for objects of class C<Class> to load the objects
804they reference, and one for objects of the referenced class to load the set of
805C<Class> objects that reference I<them>.
806
807For example, this definition:
808
809    package Ingredient;
810    __PACKAGE__->has_a(
811        { class => 'Recipe', column => 'recipe_id' },
812    );
813
814would create C<Ingredient-E<gt>recipe_obj> and C<Recipe-E<gt>ingredient_objs>
815instance methods.
816
817Each member of C<@definitions> is a hashref containing the parameters for
818creating one accessor method. The required members of these hashes are:
819
820=over 4
821
822=item * C<class>
823
824The class to associate.
825
826=item * C<column>
827
828The column or columns in this class that identify the primary key of the
829associated object. As with primary keys, use a single scalar string for a
830single column or an arrayref for a composite key.
831
832=back
833
834The optional members of C<has_a()> definitions are:
835
836=over 4
837
838=item * C<method>
839
840The name of the accessor method to create.
841
842By default, the method name is the concatenated set of column names with each
843C<_id> suffix removed, and the suffix C<_obj> appended at the end of the method
844name. For example, if C<column> were C<['recipe_id', 'ingredient_id']>, the
845resulting method would be called C<recipe_ingredient_obj> by default.
846
847=item * C<cached>
848
849Whether to keep a reference to the foreign object once it's loaded. Subsequent
850calls to the accessor method would return that reference immediately.
851
852=item * C<parent_method>
853
854The name of the reciprocal method created in the referenced class named in
855C<class>.
856
857By default, that method is named with the lowercased name of the current class
858with the suffix C<_objs>. For example, if in your C<Ingredient> class you
859defined a relationship with C<Recipe> on the column C<recipe_id>, this would
860create a C<$recipe-E<gt>ingredient_objs> method.
861
862Note that if you reference one class with multiple sets of fields, you can omit
863only one parent_method; otherwise the methods would be named the same thing.
864For instance, if you had a C<Friend> class with two references to C<User>
865objects in its C<user_id> and C<friend_id> columns, one of them would need a
866C<parent_method>.
867
868=back
869
870=head2 C<Class-E<gt>has_partitions(%param)>
871
872Defines that the given class is partitioned, configuring it for use with the
873C<Data::ObjectDriver::Driver::SimplePartition> object driver. Required members
874of C<%param> are:
875
876=over 4
877
878=item * C<number>
879
880The number of partitions in which objects of this class may be stored.
881
882=item * C<get_driver>
883
884A function that returns an object driver, given a partition ID and any extra
885parameters specified when the class's
886C<Data::ObjectDriver::Driver::SimplePartition> was instantiated.
887
888=back
889
890Note that only the parent object for use with the C<SimplePartition> driver
891should use C<has_partitions()>. See
892C<Data::ObjectDriver::Driver::SimplePartition> for more about partitioning.
893
894=head1 BASIC USAGE
895
896=head2 C<Class-E<gt>lookup($id)>
897
898Returns the instance of C<Class> with the given value for its primary key. If
899C<Class> has a complex primary key (more than one column), C<$id> should be an
900arrayref specifying the column values in the same order as specified in the
901C<primary_key> property.
902
903=head2 C<Class-E<gt>search(\%terms, [\%args])>
904
905Returns all instances of C<Class> that match the values specified in
906C<\%terms>, keyed on column names. In list context, C<search> returns the
907objects containing those values. In scalar context, C<search> returns an
908iterator function containing the same set of objects.
909
910Your search can be customized with parameters specified in C<\%args>. Commonly
911recognized parameters (those implemented by the standard C<Data::ObjectDriver>
912object drivers) are:
913
914=over 4
915
916=item * C<sort>
917
918A column by which to order the object results.
919
920=item * C<direction>
921
922If set to C<descend>, the results (ordered by the C<sort> column) are returned
923in descending order. Otherwise, results will be in ascending order.
924
925=item * C<limit>
926
927The number of results to return, at most. You can use this with C<offset> to
928paginate your C<search()> results.
929
930=item * C<offset>
931
932The number of results to skip before the first returned result. Use this with
933C<limit> to paginate your C<search()> results.
934
935=item * C<fetchonly>
936
937A list (arrayref) of columns that should be requested. If specified, only the
938specified columns of the resulting objects are guaranteed to be set to the
939correct values.
940
941Note that any caching object drivers you use may opt to ignore C<fetchonly>
942instructions, or decline to cache objects queried with C<fetchonly>.
943
944=item * C<for_update>
945
946If true, instructs the object driver to indicate the query is a search, but the
947application may want to update the data after. That is, the generated SQL
948C<SELECT> query will include a C<FOR UPDATE> clause.
949
950=back
951
952All options are passed to the object driver, so your driver may support
953additional options.
954
955=head2 C<Class-E<gt>result(\%terms, [\%args])>
956
957Takes the same I<%terms> and I<%args> arguments that I<search> takes, but
958instead of executing the query immediately, returns a
959I<Data::ObjectDriver::ResultSet> object representing the set of results.
960
961=head2 C<$obj-E<gt>exists()>
962
963Returns true if C<$obj> already exists in the database.
964
965=head2 C<$obj-E<gt>save()>
966
967Saves C<$obj> to the database, whether it is already there or not. That is,
968C<save()> is functionally:
969
970    $obj->exists() ? $obj->update() : $obj->insert()
971
972=head2 C<$obj-E<gt>update()>
973
974Saves changes to C<$obj>, an object that already exists in its database.
975
976=head2 C<$obj-E<gt>insert()>
977
978Adds C<$obj> to the database in which it should exist, according to its object
979driver and configuration.
980
981=head2 C<$obj-E<gt>remove()>
982
983Deletes C<$obj> from its database.
984
985=head2 C<$obj-E<gt>replace()>
986
987Replaces C<$obj> in the database. Does the right thing if the driver
988knows how to REPLACE object, ala MySQL.
989
990=head1 USAGE
991
992=head2 C<Class-E<gt>new(%columns)>
993
994Returns a new object of the given class, initializing its columns with the values
995in C<%columns>.
996
997=head2 C<$obj-E<gt>init(%columns)>
998
999Initializes C<$obj>i by initializing its columns with the values in
1000C<%columns>.
1001
1002Override this method if you must do initial configuration to new instances of
1003C<$obj>'s class that are not more appropriate as a C<post_load> callback.
1004
1005=head2 C<Class-E<gt>properties()>
1006
1007Returns the named object class's properties as a hashref. Note that some of the
1008standard object class properties, such as C<primary_key>, have more convenient
1009accessors than reading the properties directly.
1010
1011=head2 C<Class-E<gt>driver()>
1012
1013Returns the object driver for this class, invoking the class's I<get_driver>
1014function (and caching the result for future calls) if necessary.
1015
1016=head2 C<Class-E<gt>get_driver($get_driver_fn)>
1017
1018Sets the function used to find the object driver for I<Class> objects (that is,
1019the C<get_driver> property).
1020
1021Note that once C<driver()> has been called, the C<get_driver> function is not
1022used. Usually you would specify your function as the C<get_driver> parameter to
1023C<install_properties()>.
1024
1025=head2 C<Class-E<gt>is_pkless()>
1026
1027Returns whether the given object class has a primary key defined.
1028
1029=head2 C<Class-E<gt>is_primary_key($column)>
1030
1031Returns whether the given column is or is part of the primary key for C<Class>
1032objects.
1033
1034=head2 C<$obj-E<gt>primary_key()>
1035
1036Returns the I<values> of the primary key fields of C<$obj>.
1037
1038=head2 C<Class-E<gt>primary_key_tuple()>
1039
1040Returns the I<names> of the primary key fields of C<Class> objects.
1041
1042=head2 C<$obj-E<gt>is_same($other_obj)>
1043
1044Do a primary key check on C<$obj> and $<other_obj> and returns true only if they
1045are identical.
1046
1047=head2 C<$obj-E<gt>object_is_stored()>
1048
1049Returns true if the object hasn't been stored in the database yet.
1050This is particularily useful in triggers where you can then determine
1051if the object is being INSERTED or just UPDATED.
1052
1053=head2 C<$obj-E<gt>pk_str()>
1054
1055returns the primay key has a printable string.
1056
1057=head2 C<$obj-E<gt>has_primary_key()>
1058
1059Returns whether the given object has values for all of its primary key fields.
1060
1061=head2 C<$obj-E<gt>uncache_object()>
1062
1063If you use a Cache driver, returned object will be automatically cached as a result
1064of common retrieve operations. In some rare cases you may want the cache to be cleared
1065explicitely, and this method provides you with a way to do it.
1066
1067=head2 C<$obj-E<gt>primary_key_to_terms([$id])>
1068
1069Returns C<$obj>'s primary key as a hashref of values keyed on column names,
1070suitable for passing as C<search()> terms. If C<$id> is specified, convert that
1071primary key instead of C<$obj>'s.
1072
1073=head2 C<Class-E<gt>datasource()>
1074
1075Returns the datasource for objects of class C<Class>. That is, returns the
1076C<datasource> property of C<Class>.
1077
1078=head2 C<Class-E<gt>columns_of_type($type)>
1079
1080Returns the list of columns in C<Class> objects that hold data of type
1081C<$type>, as an arrayref. Columns are of a certain type when they are set that
1082way in C<Class>'s C<column_defs> property.
1083
1084=head2 C<$obj-E<gt>set_values(\%values)>
1085
1086Sets all the columns of C<$obj> that are members of C<\%values> to the values
1087specified there.
1088
1089=head2 C<$obj-E<gt>set_values_internal(\%values)>
1090
1091Sets new specified values of C<$obj>, without using any overridden mutator
1092methods of C<$obj> and without marking the changed columns changed.
1093
1094=head2 C<$obj-E<gt>clone()>
1095
1096Returns a new object of the same class as I<$obj> containing the same data,
1097except for primary keys, which are set to C<undef>.
1098
1099=head2 C<$obj-E<gt>clone_all()>
1100
1101Returns a new object of the same class as I<$obj> containing the same data,
1102including all key fields.
1103
1104=head2 C<Class-E<gt>has_column($column)>
1105
1106Returns whether a column named C<$column> exists in objects of class <Class>.
1107
1108=head2 C<Class-E<gt>column_names()>
1109
1110Returns the list of columns in C<Class> objects as an arrayref.
1111
1112=head2 C<$obj-E<gt>column_values()>
1113
1114Returns the columns and values in the given object as a hashref.
1115
1116=head2 C<$obj-E<gt>column($column, [$value])>
1117
1118Returns the value of C<$obj>'s column C<$column>. If C<$value> is specified,
1119C<column()> sets the first.
1120
1121Note the usual way of accessing and mutating column values is through the named
1122accessors:
1123
1124    $obj->column('fred', 'barney');  # possible
1125    $obj->fred('barney');            # preferred
1126
1127=head2 C<$obj-E<gt>is_changed([$column])>
1128
1129Returns whether any values in C<$obj> have changed. If C<$column> is given,
1130returns specifically whether that column has changed.
1131
1132=head2 C<$obj-E<gt>changed_cols_and_pk()>
1133
1134Returns the list of all columns that have changed in C<$obj> since it was last
1135loaded from or saved to the database, as a list.
1136
1137=head2 C<$obj-E<gt>changed_cols()>
1138
1139Returns the list of changed columns in C<$obj> as a list, except for any
1140columns in C<$obj>'s primary key (even if they have changed).
1141
1142=head2 C<Class-E<gt>lookup_multi(\@ids)>
1143
1144Returns a list (arrayref) of objects as specified by their primary keys.
1145
1146=head2 C<Class-E<gt>bulk_insert(\@columns, \@data)>
1147
1148Adds the given data, an arrayref of arrayrefs containing column values in the
1149order of column names given in C<\@columns>, as directly to the database as
1150C<Class> records.
1151
1152Note that only some database drivers (for example,
1153C<Data::ObjectDriver::Driver::DBD::Pg>) implement the bulk insert operation.
1154
1155=head2 C<$obj-E<gt>fetch_data()>
1156
1157Returns the current values from C<$obj> as saved in the database, as a hashref.
1158
1159=head2 C<$obj-E<gt>refresh()>
1160
1161Resets the values of C<$obj> from the database. Any unsaved modifications to
1162C<$obj> will be lost, and any made meanwhile will be reflected in C<$obj>
1163afterward.
1164
1165=head2 C<$obj-E<gt>column_func($column)>
1166
1167Creates an accessor/mutator method for column C<$column>, returning it as a
1168coderef.
1169
1170Override this if you need special behavior in all accessor/mutator methods.
1171
1172=head2 C<$obj-E<gt>deflate()>
1173
1174Returns a minimal representation of the object, for use in caches where
1175you might want to preserve space (like memcached). Can also be overridden
1176by subclasses to store the optimal representation of an object in the
1177cache. For example, if you have metadata attached to an object, you might
1178want to store that in the cache, as well.
1179
1180=head2 C<Class-E<gt>inflate($deflated)>
1181
1182Inflates the deflated representation of the object I<$deflated> into a proper
1183object in the class I<Class>. That is, undoes the operation C<$deflated =
1184$obj-E<gt>deflate()> by returning a new object equivalent to C<$obj>.
1185
1186=head1 TRANSACTION SUPPORT AND METHODS
1187
1188=head2 Introduction
1189
1190When dealing with the methods on this class, the transactions are global,
1191i.e: applied to all drivers. You can still enable transactions per driver
1192if you directly use the driver API.
1193
1194=head2 C<Class-E<gt>begin_work>
1195
1196This enable transactions globally for all drivers until the next L<rollback>
1197or L<commit> call on the class.
1198
1199If begin_work is called while a transaction is still active (nested transaction)
1200then the two transactions are merged. So inner transactions are ignored and
1201a warning will be emitted.
1202
1203=head2 C<Class-E<gt>rollback>
1204
1205This rollbacks all the transactions since the last begin work, and exits
1206from the active transaction state.
1207
1208=head2 C<Class-E<gt>commit>
1209
1210Commits the transactions, and exits from the active transaction state.
1211
1212=head2 C<Class-E<gt>txn_debug>
1213
1214Just return the value of the global flag and the current working drivers
1215in a hashref.
1216
1217=head2 C<Class-E<gt>txn_active>
1218
1219Returns true if a transaction is already active.
1220
1221=head1 DIAGNOSTICS
1222
1223=over 4
1224
1225=item * C<Please specify a valid column for I<class>>
1226
1227One of the class relationships you defined with C<has_a()> was missing a
1228C<column> member.
1229
1230=item * C<Please define a valid method for I<column>>
1231
1232One of the class relationships you defined with C<has_a()> was missing its
1233C<method> member and a method name could not be generated, or the class for
1234which you specified the relationship already has a method by that name. Perhaps
1235you specified an additional accessor by the same name for that class.
1236
1237=item * C<keys don't match with primary keys: I<list>>
1238
1239The hashref of values you passed as the ID to C<primary_key_to_terms()> was
1240missing or had extra members. Perhaps you used a full C<column_values()> hash
1241instead of only including that class's key fields.
1242
1243=item * C<You tried to set inexistent column I<column name> to value I<data> on I<class name>>
1244
1245The hashref you specified to C<set_values()> contained keys that are not
1246defined columns for that class of object. Perhaps you invoked it on the wrong
1247class, or did not fully filter members of the hash out before using it.
1248
1249=item * C<Cannot find column 'I<column>' for class 'I<class>'>
1250
1251The column you specified to C<column()> does not exist for that class, you
1252attempted to use an automatically generated accessor/mutator for a column that
1253doesn't exist, or attempted to use a column accessor as a class method instead
1254of an instance method. Perhaps you performed your call on the wrong class or
1255variable, or misspelled a method or column name.
1256
1257=item * C<Must specify column>
1258
1259You invoked the C<column_func()> method without specifying a column name.
1260Column names are required to create the accessor/mutator function, so it knows
1261what data member of the object to use.
1262
1263=item * C<number (of partitions) is required>
1264
1265You attempted to define partitioning for a class without specifying the number
1266of partitions for that class in the C<number> member. Perhaps your logic for
1267determining the number of partitions resulted in C<undef> or 0.
1268
1269=item * C<get_driver is required>
1270
1271You attempted to define partitioning for a class without specifying the
1272function to find the object driver for a partition ID as the C<get_driver>
1273member.
1274
1275=back
1276
1277=head1 BUGS AND LIMITATIONS
1278
1279There are no known bugs in this module.
1280
1281=head1 SEE ALSO
1282
1283L<Data::ObjectDriver>, L<Data::ObjectDriver::Driver::DBI>,
1284L<Data::ObjectDriver::Driver::SimplePartition>
1285
1286=head1 LICENSE
1287
1288I<Data::ObjectDriver> is free software; you may redistribute it and/or modify
1289it under the same terms as Perl itself.
1290
1291=head1 AUTHOR & COPYRIGHT
1292
1293Except where otherwise noted, I<Data::ObjectDriver> is Copyright 2005-2006
1294Six Apart, cpan@sixapart.com. All rights reserved.
1295
1296=cut
1297
Note: See TracBrowser for help on using the browser.