Merge the last bits of indirect callchain optimization
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / PK.pm
1 package DBIx::Class::PK;
2
3 use strict;
4 use warnings;
5
6 use base qw/DBIx::Class::Row/;
7
8 use DBIx::Class::_Util 'fail_on_internal_call';
9 use namespace::clean;
10
11 =head1 NAME
12
13 DBIx::Class::PK - Primary Key class
14
15 =head1 SYNOPSIS
16
17 =head1 DESCRIPTION
18
19 This class contains methods for handling primary keys and methods
20 depending on them.
21
22 =head1 METHODS
23
24 =cut
25
26 =head2 id
27
28 Returns the primary key(s) for a row. Can't be called as
29 a class method.
30
31 =cut
32
33 sub id :DBIC_method_is_indirect_sugar {
34   DBIx::Class::_ENV_::ASSERT_NO_INTERNAL_INDIRECT_CALLS and fail_on_internal_call;
35
36   $_[0]->throw_exception( "Can't call id() as a class method" )
37     unless ref $_[0];
38
39   wantarray
40     ? $_[0]->_ident_values
41     : ($_[0]->_ident_values)[0]   # FIXME - horrible horrible legacy crap
42   ;
43 }
44
45 sub _ident_values {
46   my ($self, $use_storage_state) = @_;
47
48   my (@ids, @missing);
49
50   for ($self->result_source->_pri_cols_or_die) {
51     push @ids, ($use_storage_state and exists $self->{_column_data_in_storage}{$_})
52       ? $self->{_column_data_in_storage}{$_}
53       : $self->get_column($_)
54     ;
55     push @missing, $_ if (! defined $ids[-1] and ! $self->has_column_loaded ($_) );
56   }
57
58   if (@missing && $self->in_storage) {
59     $self->throw_exception (
60       'Unable to uniquely identify result object with missing PK columns: '
61       . join (', ', @missing )
62     );
63   }
64
65   return @ids;
66 }
67
68 =head2 ID
69
70 Returns a unique id string identifying a result object by primary key.
71 Used by L<DBIx::Class::CDBICompat::LiveObjectIndex> and
72 L<DBIx::Class::ObjectCache>.
73
74 =over
75
76 =item WARNING
77
78 The default C<_create_ID> method used by this function orders the returned
79 values by the alphabetical order of the primary column names, B<unlike>
80 the L</id> method, which follows the same order in which columns were fed
81 to L<DBIx::Class::ResultSource/set_primary_key>.
82
83 =back
84
85 =cut
86
87 sub ID {
88   my ($self) = @_;
89   $self->throw_exception( "Can't call ID() as a class method" )
90     unless ref $self;
91   return undef unless $self->in_storage;
92   return $self->_create_ID(%{$self->ident_condition});
93 }
94
95 sub _create_ID {
96   my ($self, %vals) = @_;
97   return undef if grep { !defined } values %vals;
98   return join '|', ref $self || $self, $self->result_source->name,
99     map { $_ . '=' . $vals{$_} } sort keys %vals;
100 }
101
102 =head2 ident_condition
103
104   my $cond = $result_source->ident_condition();
105
106   my $cond = $result_source->ident_condition('alias');
107
108 Produces a condition hash to locate a row based on the primary key(s).
109
110 =cut
111
112 sub ident_condition {
113   shift->_mk_ident_cond(@_);
114 }
115
116 sub _storage_ident_condition {
117   shift->_mk_ident_cond(shift, 1);
118 }
119
120 sub _mk_ident_cond {
121   my ($self, $alias, $use_storage_state) = @_;
122
123   my @pks = $self->result_source->_pri_cols_or_die;
124   my @vals = $self->_ident_values($use_storage_state);
125
126   my (%cond, @undef);
127   my $prefix = defined $alias ? $alias.'.' : '';
128   for my $col (@pks) {
129     if (! defined ($cond{$prefix.$col} = shift @vals) ) {
130       push @undef, $col;
131     }
132   }
133
134   if (@undef && $self->in_storage) {
135     $self->throw_exception (
136       'Unable to construct result object identity condition due to NULL PK columns: '
137       . join (', ', @undef)
138     );
139   }
140
141   return \%cond;
142 }
143
144 =head1 FURTHER QUESTIONS?
145
146 Check the list of L<additional DBIC resources|DBIx::Class/GETTING HELP/SUPPORT>.
147
148 =head1 COPYRIGHT AND LICENSE
149
150 This module is free software L<copyright|DBIx::Class/COPYRIGHT AND LICENSE>
151 by the L<DBIx::Class (DBIC) authors|DBIx::Class/AUTHORS>. You can
152 redistribute it and/or modify it under the same terms as the
153 L<DBIx::Class library|DBIx::Class/COPYRIGHT AND LICENSE>.
154
155 =cut
156
157 1;