File Coverage

blib/lib/Fey/Object/Table.pm
Criterion Covered Total %
statement 57 297 19.1
branch 2 44 4.5
condition 0 18 0.0
subroutine 19 47 40.4
pod 13 14 92.8
total 91 420 21.6


line stmt bran cond sub pod time code
1             package Fey::Object::Table;
2              
3 9     9   50 use strict;
  9         16  
  9         311  
4 9     9   47 use warnings;
  9         18  
  9         338  
5 9     9   49 use namespace::autoclean;
  9         14  
  9         81  
6              
7             our $VERSION = '0.47';
8              
9 9     9   798 use Fey::Literal::Function;
  9         16  
  9         243  
10 9     9   41 use Fey::Placeholder;
  9         15  
  9         196  
11 9     9   39 use Fey::SQL;
  9         17  
  9         234  
12 9     9   44 use Fey::Table;
  9         16  
  9         220  
13 9     9   41 use List::AllUtils qw( all );
  9         18  
  9         609  
14 9     9   5354 use Object::ID qw( object_id );
  9         42385  
  9         75  
15 9     9   657 use Scalar::Util qw( blessed );
  9         18  
  9         568  
16 9     9   57 use Try::Tiny;
  9         22  
  9         607  
17              
18 9     9   55 use Fey::Exceptions qw( param_error );
  9         20  
  9         583  
19 9     9   4952 use Fey::ORM::Exceptions qw( no_such_row );
  9         28  
  9         59  
20              
21 9     9   1878 use Moose;
  9         16  
  9         90  
22              
23             override new => sub {
24             my $class = shift;
25              
26             if ( $class->meta()->_object_cache_is_enabled() ) {
27             my $instance
28             = $class->meta()->_search_cache( ref $_[0] ? $_[0] : {@_} );
29              
30             return $instance if $instance;
31             }
32              
33             my $instance;
34             my @args = @_;
35              
36             $class->_ClearConstructorError();
37              
38             try {
39             $instance = super();
40             }
41             catch {
42             die $_ unless blessed $_ && $_->isa('Fey::Exception::NoSuchRow');
43             $class->_SetConstructorError($_);
44             };
45              
46             return unless $instance;
47              
48             $class->meta()->_write_to_cache($instance)
49             if $class->meta()->_object_cache_is_enabled();
50              
51             return $instance;
52             };
53              
54             # I'd like to use MX::ClassAttribute but trying to apply this to each
55             # Fey::ORM::Table-using class causes all sorts of weird errors.
56             {
57             my %E;
58              
59             sub ConstructorError {
60 0     0 1 0 my $class = shift;
61              
62 0         0 return $E{$class};
63             }
64              
65             sub _SetConstructorError {
66 0     0   0 my $class = shift;
67              
68 0         0 $E{$class} = shift;
69             }
70              
71             sub _ClearConstructorError {
72 4     4   6 my $class = shift;
73              
74 4         6 delete $E{$class};
75             }
76             }
77              
78             sub BUILD {
79 4     4 0 4113 my $self = shift;
80 4         5 my $p = shift;
81              
82 4 50       13 if ( delete $p->{_from_query} ) {
83 4         12 $self->_require_pk($p);
84              
85 4         18 return;
86             }
87              
88 0         0 $self->_load_from_dbms($p);
89              
90 0         0 return;
91             }
92              
93             sub _require_pk {
94 4     4   5 my $self = shift;
95 4         4 my $p = shift;
96              
97             return
98 4     4   35 if all { defined $p->{$_} }
99 4 50       20 map { $_->name() } @{ $self->Table()->primary_key() };
  4         101  
  4         9  
100              
101 0         0 my $package = ref $self;
102 0         0 param_error
103             "$package->new() requires that you pass the primary key if you set _from_query to true.";
104             }
105              
106             sub EnableObjectCache {
107 0     0 1 0 my $class = shift;
108              
109 0         0 $class->meta()->_set_object_cache_is_enabled(1);
110             }
111              
112             sub DisableObjectCache {
113 0     0 1 0 my $class = shift;
114              
115 0         0 $class->meta()->_set_object_cache_is_enabled(0);
116             }
117              
118             sub ClearObjectCache {
119 0     0 1 0 my $class = shift;
120              
121 0         0 $class->meta()->_clear_object_cache();
122             }
123              
124             sub _load_from_dbms {
125 0     0   0 my $self = shift;
126 0         0 my $p = shift;
127              
128 0         0 for my $key ( @{ $self->Table()->candidate_keys() } ) {
  0         0  
129 0         0 my @names = map { $_->name() } @{$key};
  0         0  
  0         0  
130 0 0   0   0 next unless all { defined $p->{$_} } @names;
  0         0  
131              
132 0 0       0 return if $self->_load_from_key( $key, [ @{$p}{@names} ] );
  0         0  
133             }
134              
135 0         0 my $error = 'Could not find a row in ' . $self->Table()->name();
136 0         0 $error .= ' matching the values you provided to the constructor.';
137              
138 0         0 no_such_row $error;
139             }
140              
141             sub _load_from_key {
142 0     0   0 my $self = shift;
143 0         0 my $key = shift;
144 0         0 my $bind = shift;
145              
146 0         0 my $select = $self->_SelectSQLForKey($key);
147              
148 0 0       0 return 1 if $self->_get_column_values( $select, $bind );
149              
150 0         0 my $error = 'Could not find a row in ' . $self->Table()->name();
151 0         0 $error .= ' where ';
152              
153 0         0 my @where;
154              
155             ## no critic (ControlStructures::ProhibitCStyleForLoops)
156 0         0 for ( my $i = 0; $i < @{$key}; $i++ ) {
  0         0  
157 0         0 push @where, $key->[$i]->name() . q{ = } . $bind->[$i];
158             }
159             ## use critic
160              
161 0         0 $error .= join ', ', @where;
162              
163 0         0 no_such_row $error;
164             }
165              
166             # Based on discussions on #moose, this could be done more elegantly
167             # with a custom instance metaclass that lazily initializes a batch of
168             # attributes at once.
169             sub _get_column_values {
170 0     0   0 my $self = shift;
171 0         0 my $select = shift;
172 0         0 my $bind = shift;
173              
174 0         0 my $dbh = $self->_dbh($select);
175              
176 0         0 my $sth = $dbh->prepare( $self->_sql_string( $select, $dbh ) );
177              
178 0         0 $sth->execute( @{$bind} );
  0         0  
179              
180 0         0 my %col_values;
181 0         0 $sth->bind_columns( \( @col_values{ @{ $sth->{NAME} } } ) );
  0         0  
182              
183 0         0 my $fetched = $sth->fetch();
184              
185 0         0 $sth->finish();
186              
187 0 0       0 return unless $fetched;
188              
189 0         0 $self->_set_column_values_from_hashref( \%col_values );
190              
191 0         0 return \%col_values;
192             }
193              
194             sub _set_column_values_from_hashref {
195 0     0   0 my $self = shift;
196 0         0 my $values = shift;
197              
198 0         0 for my $col ( keys %{$values} ) {
  0         0  
199 0         0 my $set_meth = q{_set_} . $col;
200              
201 0         0 $self->$set_meth( $values->{$col} );
202             }
203             }
204              
205             ## no critic (Subroutines::ProhibitUnusedPrivateSubroutines)
206             sub _get_column_value {
207 0     0   0 my $self = shift;
208              
209 0         0 my $col_values = $self->_get_column_values(
210             $self->meta()->_select_by_pk_sql(),
211             [ $self->pk_values_list() ],
212             );
213              
214 0         0 my $name = shift;
215              
216 0         0 return $col_values->{$name};
217             }
218             ## use critic
219              
220             sub pk_values_list {
221 0     0 1 0 my $self = shift;
222              
223 0         0 my @cols = ( map { $_->name() } @{ $self->Table()->primary_key() } );
  0         0  
  0         0  
224              
225 0         0 return map { $self->_deflated_value($_) } @cols;
  0         0  
226             }
227              
228             ## no critic (Subroutines::ProhibitUnusedPrivateSubroutines)
229             sub _MakeSelectByPKSQL {
230 0     0   0 my $class = shift;
231              
232 0         0 return $class->_SelectSQLForKey( $class->Table->primary_key() );
233             }
234             ## use critic
235              
236             sub _SelectSQLForKey {
237 0     0   0 my $class = shift;
238 0         0 my $key = shift;
239              
240 0         0 my $cache = $class->meta()->_select_sql_cache();
241              
242 0         0 my $select = $cache->get($key);
243              
244 0 0       0 return $select if $select;
245              
246 0         0 my $table = $class->Table();
247              
248 0         0 my @select = $table->columns();
249              
250 0         0 $select = $class->SchemaClass()->SQLFactoryClass()->new_select();
251 0         0 $select->select( sort { $a->name() cmp $b->name() } @select );
  0         0  
252 0         0 $select->from($table);
253 0         0 $select->where( $_, '=', Fey::Placeholder->new() ) for @{$key};
  0         0  
254              
255 0         0 $cache->store( $key => $select );
256              
257 0         0 return $select;
258             }
259              
260             sub insert {
261 0     0 1 0 my $class = shift;
262 0         0 my %p = @_;
263              
264 0         0 return $class->insert_many( \%p );
265             }
266              
267             sub insert_many {
268 0     0 1 0 my $class = shift;
269 0         0 my @rows = @_;
270              
271 0         0 my $insert = $class->_insert_for_data( $rows[0] );
272              
273 0         0 my $dbh = $class->_dbh($insert);
274              
275 0         0 my $sth = $dbh->prepare( $class->_sql_string( $insert, $dbh ) );
276              
277             my @auto_inc_columns = (
278 0         0 grep { !exists $rows[0]->{$_} }
279 0         0 map { $_->name() }
280 0         0 grep { $_->is_auto_increment() } $class->Table->columns()
  0         0  
281             );
282              
283 0         0 my $table_name = $class->Table()->name();
284              
285 0         0 my @non_literal_row_keys;
286             my @literal_row_keys;
287 0         0 my @ref_row_keys;
288              
289 0         0 for my $key ( sort keys %{ $rows[0] } ) {
  0         0  
290 0         0 my $val = $rows[0]{$key};
291              
292 0 0 0     0 if (
      0        
      0        
      0        
293             defined $val
294             && blessed $val
295             && $val->can('does')
296             && ( $val->does('Fey::Role::IsLiteral')
297             || $val->does('Fey::Role::SQL::ReturnsData') )
298             ) {
299 0         0 push @literal_row_keys, $key;
300 0         0 push @ref_row_keys, $key;
301             }
302             else {
303 0         0 push @non_literal_row_keys, $key;
304 0 0       0 push @ref_row_keys, $key
305             if ref $val;
306             }
307             }
308              
309             my @bind_attributes
310 0         0 = $class->_bind_attributes_for( $dbh, @non_literal_row_keys );
311              
312 0         0 my $wantarray = wantarray;
313              
314 0         0 my @objects;
315 0         0 for my $row (@rows) {
316 0         0 push @objects,
317             $class->_insert_one_row(
318             $row,
319             $dbh,
320             $sth,
321             \@non_literal_row_keys,
322             \@ref_row_keys,
323             \@bind_attributes,
324             \@auto_inc_columns,
325             $table_name,
326             $wantarray,
327             );
328             }
329              
330 0 0       0 return $wantarray ? @objects : $objects[0];
331             }
332              
333             sub _bind_attributes_for {
334 0     0   0 my $self = shift;
335 0         0 my $dbh = shift;
336 0         0 my @keys = @_;
337              
338 0 0       0 return unless $dbh->{Driver}{Name} eq 'Pg';
339              
340             my @attr = map {
341 0 0       0 lc $self->Table()->column($_)->type() eq 'bytea'
  0         0  
342             ? { pg_type => DBD::Pg::PG_BYTEA() }
343             : {}
344             } @keys;
345              
346 0 0       0 return unless grep { keys %{$_} } @attr;
  0         0  
  0         0  
347              
348 0         0 return @attr;
349             }
350              
351             ## no critic (Subroutines::ProhibitManyArgs)
352             sub _insert_one_row {
353 0     0   0 my $class = shift;
354              
355             # This is really grotesque
356 0         0 my $row = shift;
357 0         0 my $dbh = shift;
358 0         0 my $sth = shift;
359 0         0 my $non_literal_row_keys = shift;
360 0         0 my $ref_row_keys = shift;
361 0         0 my $bind_attributes = shift;
362 0         0 my $auto_inc_columns = shift;
363 0         0 my $table_name = shift;
364 0         0 my $wantarray = shift;
365              
366             $class->_sth_execute(
367             $sth,
368             [
369 0         0 map { $class->_deflated_value( $_, $row->{$_} ) }
370 0         0 @{$non_literal_row_keys}
  0         0  
371             ],
372             $bind_attributes,
373             );
374              
375 0 0       0 return unless defined $wantarray;
376              
377 0         0 my %auto_inc;
378 0         0 for my $col ( @{$auto_inc_columns} ) {
  0         0  
379 0         0 $auto_inc{$col}
380             = $dbh->last_insert_id( undef, undef, $table_name, $col );
381             }
382              
383 0         0 delete @{$row}{ @{$ref_row_keys} }
  0         0  
384 0 0       0 if @{$ref_row_keys};
  0         0  
385              
386 0         0 return $class->new( %{$row}, %auto_inc, _from_query => 1 );
  0         0  
387             }
388              
389             sub _sth_execute {
390 0     0   0 my $self = shift;
391 0         0 my $sth = shift;
392 0         0 my $vals = shift;
393 0         0 my $attr = shift;
394              
395 0 0       0 if ( @{$attr} ) {
  0         0  
396             ## no critic (ControlStructures::ProhibitCStyleForLoops)
397 0         0 for ( my $i = 0; $i < @{$vals}; $i++ ) {
  0         0  
398 0         0 $sth->bind_param( $i + 1, $vals->[$i], $attr->[$i] );
399             }
400             ## use critic
401              
402 0         0 return $sth->execute();
403             }
404             else {
405 0         0 return $sth->execute( @{$vals} );
  0         0  
406             }
407             }
408              
409             sub _deflated_value {
410 0     0   0 my $self = shift;
411 0         0 my $name = shift;
412 0 0       0 my $val = @_ ? shift : $self->$name();
413              
414 0         0 my $meth = $self->meta()->deflator_for($name);
415              
416 0 0       0 return $meth ? $self->$meth($val) : $val;
417             }
418              
419             sub _insert_for_data {
420 0     0   0 my $class = shift;
421 0         0 my $data = shift;
422              
423 0         0 my $insert = $class->SchemaClass()->SQLFactoryClass()->new_insert();
424              
425 0         0 my $table = $class->Table();
426              
427 0         0 $insert->into( $table->columns( sort keys %{$data} ) );
  0         0  
428              
429 0         0 my $ph = Fey::Placeholder->new();
430              
431             my @vals = (
432             map {
433             $_ => (
434             defined $data->{$_}
435             && blessed $data->{$_}
436             && $data->{$_}->can('does')
437             && ( $data->{$_}->does('Fey::Role::IsLiteral')
438             || $data->{$_}->does('Fey::Role::SQL::ReturnsData') )
439 0 0 0     0 ? $data->{$_}
440             : $ph
441             )
442             }
443 0         0 sort keys %{$data}
  0         0  
444             );
445              
446 0         0 $insert->values(@vals);
447              
448 0         0 return $insert;
449             }
450              
451             sub update {
452 0     0 1 0 my $self = shift;
453 0         0 my %p = @_;
454              
455 0         0 my $update = $self->SchemaClass()->SQLFactoryClass()->new_update();
456              
457 0         0 my $table = $self->Table();
458              
459 0         0 $update->update($table);
460              
461             $update->set(
462 0         0 map { $table->column($_) => $self->_deflated_value( $_, $p{$_} ) }
  0         0  
463             sort keys %p
464             );
465              
466 0         0 for my $col ( @{ $table->primary_key() } ) {
  0         0  
467 0         0 my $name = $col->name();
468              
469 0         0 $update->where( $col, '=', $self->_deflated_value($name) );
470             }
471              
472 0         0 my $dbh = $self->_dbh($update);
473              
474 0         0 my $sth = $dbh->prepare( $self->_sql_string( $update, $dbh ) );
475              
476             my @attr = $self->_bind_attributes_for(
477             $dbh,
478             (
479             sort keys %p,
480 0         0 map { $_->name() } @{ $table->primary_key() }
  0         0  
  0         0  
481             ),
482             );
483              
484 0         0 $self->_sth_execute( $sth, [ $update->bind_params() ], \@attr );
485              
486 0         0 for my $k ( sort keys %p ) {
487 0 0       0 if ( ref $p{$k} ) {
488 0         0 my $clear = q{_clear_} . $k;
489 0         0 $self->$clear();
490             }
491             else {
492 0         0 my $set_meth = q{_set_} . $k;
493 0         0 $self->$set_meth( $p{$k} );
494             }
495             }
496              
497 0         0 return;
498             }
499              
500             ## no critic (Subroutines::ProhibitBuiltinHomonyms)
501             sub delete {
502 0     0 1 0 my $self = shift;
503              
504 0         0 my $delete = $self->SchemaClass()->SQLFactoryClass()->new_delete();
505              
506 0         0 my $table = $self->Table();
507              
508 0         0 $delete->from($table);
509              
510 0         0 for my $col ( @{ $table->primary_key() } ) {
  0         0  
511 0         0 my $name = $col->name();
512              
513 0         0 $delete->where( $col, '=', $self->_deflated_value($name) );
514             }
515              
516 0         0 my $dbh = $self->_dbh($delete);
517              
518 0         0 $dbh->do(
519             $self->_sql_string( $delete, $dbh ),
520             {},
521             $delete->bind_params()
522             );
523              
524 0         0 return;
525             }
526             ## use critic
527              
528             sub _dbh {
529 0     0   0 my $self = shift;
530 0         0 my $sql = shift;
531              
532 0         0 my $source = $self->SchemaClass()->DBIManager()->source_for_sql($sql);
533              
534 0 0       0 die "Could not get a source for this sql ($sql)"
535             unless $source;
536              
537 0         0 return $source->dbh();
538             }
539              
540             sub pk_values_hash {
541 0     0 1 0 my $self = shift;
542              
543 0 0       0 my @vals = $self->pk_values_list()
544             or return;
545              
546 0         0 my @cols = ( map { $_->name() } @{ $self->Table()->primary_key() } );
  0         0  
  0         0  
547              
548 0         0 return map { $cols[$_] => $vals[$_] } 0 .. $#vals;
  0         0  
549             }
550              
551             sub Count {
552 0     0 1 0 my $class = shift;
553              
554 0         0 my $select = $class->meta()->_count_sql();
555              
556 0         0 my $dbh = $class->_dbh($select);
557              
558 0         0 my $row
559             = $dbh->selectcol_arrayref( $class->_sql_string( $select, $dbh ) );
560              
561 0         0 return $row->[0];
562             }
563              
564             sub Table {
565 7     7 1 1598 my $class = shift;
566              
567 7         22 return $class->meta()->table();
568             }
569              
570             sub SchemaClass {
571 0     0 1   my $class = shift;
572              
573 0           return $class->meta()->schema_class();
574             }
575              
576             sub _sql_string {
577 0     0     my $self = shift;
578 0           my $sql = shift;
579 0           my $dbh = shift;
580              
581 0           my $cache = $self->meta()->_sql_string_cache();
582              
583 0   0       return $cache->{ object_id($sql) . object_id($dbh) } ||= $sql->sql($dbh);
584             }
585              
586             __PACKAGE__->meta()->make_immutable( inline_constructor => 0 );
587              
588             1;
589              
590             # ABSTRACT: Base class for table-based objects
591              
592             __END__
593              
594             =pod
595              
596             =head1 NAME
597              
598             Fey::Object::Table - Base class for table-based objects
599              
600             =head1 VERSION
601              
602             version 0.47
603              
604             =head1 SYNOPSIS
605              
606             package MyApp::User;
607              
608             use Fey::ORM::Table;
609              
610             has_table(...);
611              
612             =head1 DESCRIPTION
613              
614             This class is a the base class for all table-based objects. It
615             implements a large amount of the core L<Fey::ORM> functionality,
616             including CRUD (create, update, delete) and loading of data from the
617             DBMS.
618              
619             =head1 METHODS
620              
621             This class provides the following methods:
622              
623             =head2 $class->new(...)
624              
625             This method overrides the default C<Moose::Object> constructor in
626             order to implement cache management.
627              
628             By default, object caching is disabled. In that case, this method lets
629             its parent class do most of the work. However, unlike the standard
630             Moose constructor, this method may sometimes not return an object. If
631             it attempts to load object data from the DBMS and cannot find anything
632             matching the parameters given to the constructor, it will return
633             false.
634              
635             If the constructor fails, you can check the value of C<<
636             $class->ConstructorError >> for the error message. This is done so that
637             calling the constructor does not overwrite any value already in C<$@>.
638              
639             If caching is enabled, then this method will attempt to find a
640             matching object in the cache. A match is determined by looking for an
641             object which has a candidate key with the same values as are passed to
642             the constructor.
643              
644             If no match is found, it attempts to create a new object. If this
645             succeeds, it stores it in the cache before returning it.
646              
647             =head3 Constructor Parameters
648              
649             The constructor accepts any attribute of the class as a
650             parameter. This includes any column-based attributes, as well as any
651             additional attributes defined by C<has_one()> or C<has_many()>. Of
652             course, if you disabled caching for C<has_one()> or C<has_many()>
653             relationships, then they are implemented as simple methods, not
654             attributes.
655              
656             If you define additional methods via Moose's C<has()> function, and
657             these will be accepted by the constructor as well.
658              
659             Finally, the constructor accepts a parameter C<_from_query>. This
660             tells the constructor that the parameters passed to the constructor
661             are the result of a C<SELECT>. This stops the C<BUILD()> method from
662             attempting to load the object from the DBMS. However, you still must
663             pass values for the primary key, so that the object is identifiable in
664             the DBMS.
665              
666             =head2 $class->ConstructorError()
667              
668             If the constructor does not return an object, this will always contain the
669             error message from the constructor. This should always be something like
670             "Could not a find a row in SomeTable matching the values you provided to the
671             constructor" or "Could not find a row in SomeTable where table_id = 42".
672              
673             This error is cleared each time the class's constructor is called.
674              
675             =head2 $class->EnableObjectCache()
676              
677             =head2 $class->DisableObjectCache()
678              
679             These methods enable or disable the object cache for the calling
680             class.
681              
682             =head2 $class->Count()
683              
684             Returns the number of rows in the class's associated table.
685              
686             =head2 $class->ClearObjectCache()
687              
688             Clears the object cache for the calling class.
689              
690             =head2 $class->Table()
691              
692             Returns the L<Fey::Table> object passed to C<has_table()>.
693              
694             =head2 $class->SchemaClass()
695              
696             Returns the name of the class associated with the class's table's
697             schema.
698              
699             =head2 $class->insert(%values)
700              
701             Given a hash of column names and values, this method inserts a new row
702             for the class's table, and returns a new object for that row.
703              
704             The values for the columns can be plain scalars or object. Values will
705             be passed through the appropriate deflators. You can also pass
706             L<Fey::Literal> objects of any type.
707              
708             As an optimization, no object will be created in void context.
709              
710             =head2 $class->insert_many( \%values, \%values, ... )
711              
712             This method allows you to insert multiple rows efficiently. It expects
713             an array of hash references. Each hash reference should contain the
714             same set of column names as its keys. The advantage of using this
715             method is that under the hood it uses the same C<DBI> statement handle
716             repeatedly. If you were to call C<< $class->insert() >> repeatedly it
717             would have to recreate the same SQL and DBI statement handle
718             repeatedly.
719              
720             In scalar context, it returns the first object created. In list
721             context, it returns all the objects created.
722              
723             As an optimization, no objects will be created in void context.
724              
725             =head2 $object->update(%values)
726              
727             This method accepts a hash of column keys and values, just like C<<
728             $class->insert() >>. However, it instead updates the values for an
729             existing object's row. It will also make sure that the object's
730             attributes are updated properly. In some cases, it will just clear the
731             attribute, forcing it to be reloaded the next time it is
732             accessed. This is necessary when the update value was a
733             L<Fey::Literal>, since that could be a function that gets interpreted
734             by the DBMS, such as C<NOW()>.
735              
736             =head2 $object->delete()
737              
738             This method deletes the object's associated row from the DBMS.
739              
740             The object is still usable after this method is called, but if you
741             attempt to call any method that tries to access the DBMS it will
742             probably blow up.
743              
744             =head2 $object->pk_values_hash()
745              
746             Returns a hash representing the names and values for the object's
747             primary key. The values are returned in their raw form, regardless of
748             any transforms specific for a primary key column.
749              
750             This may return an empty hash if the primary key for the object has
751             not yet been determined. This can happen if you try to call this
752             method on an object before its attributes have been fetched from the
753             dbms.
754              
755             =head2 $object->pk_values_list()
756              
757             Returns a list of values for the object's primary key. The values are
758             returned in the same order as C<< $self->primary_key() >> returns the
759             columns. The values are returned in their raw form, regardless of any
760             transforms specific for a primary key column.
761              
762             This may return an empty list if the primary key for the object
763             has not yet been determined.
764              
765             =head1 METHODS FOR SUBCLASSES
766              
767             Since your table-based class will be a subclass of this object, there
768             are several methods you may want to use that are not intended for use
769             outside of your subclasses. You may also want to subclass some of
770             these methods in this class.
771              
772             =head2 $class->_dbh($sql)
773              
774             Given a L<Fey::SQL> object, this method returns an appropriate C<DBI>
775             object for that SQL. Internally, it calls C<source_for_sql()> on the
776             schema class's L<Fey::DBIManager> object and then calls C<<
777             $source->dbh() >> on the source.
778              
779             If there is no source for the given SQL, it will die.
780              
781             =head2 $object->_load_from_dbms($params)
782              
783             This method will be called as part of object construction (unless
784             C<_from_query> was true).
785              
786             By default, this method attempts to find a row in the associated table
787             by looking at each of the table's candidate keys in turn. If the
788             parameters passed to the constructor include values for all parts of a
789             key, it does a select to find a matching row.
790              
791             You can override this method in order to attempt to load an object
792             based on some other method. For example, if your user table stores a
793             username and a hashed password, you could accept an I<unhashed>
794             password, and then do a lookup based on the hashed value.
795              
796             This method is expected to create a C<SELECT> statement and then pass
797             the statement and bind parameters to C<< $object->_get_column_values()
798             >>.
799              
800             On success, this method should simply return. If it fails, it should throw a
801             Fey::Exception::NoSuchRow exception. See L<Fey::ORM::Exceptions> for details.
802              
803             =head2 $object->_get_column_values( $select, $bind_params )
804              
805             This method takes a C<SELECT> statement and an array reference of bind
806             parameters. The C<SELECT> is expected to find a single row, which
807             should correspond to the current object. If it finds a row, it sets
808             the corresponding attributes in the object based on the values returns
809             by the C<SELECT>.
810              
811             =head1 AUTHOR
812              
813             Dave Rolsky <autarch@urth.org>
814              
815             =head1 COPYRIGHT AND LICENSE
816              
817             This software is copyright (c) 2011 - 2015 by Dave Rolsky.
818              
819             This is free software; you can redistribute it and/or modify it under
820             the same terms as the Perl 5 programming language system itself.
821              
822             =cut