X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FResultSource.pm;h=1be530e774a989e881004b67094077f67ab554c0;hb=096f421241;hp=3174957c8c4f9fd9646218ad0708722b749ab353;hpb=de60a93dfda2e3384c2f6a00d55b352a4b4188c0;p=dbsrgits%2FDBIx-Class.git diff --git a/lib/DBIx/Class/ResultSource.pm b/lib/DBIx/Class/ResultSource.pm index 3174957..1be530e 100644 --- a/lib/DBIx/Class/ResultSource.pm +++ b/lib/DBIx/Class/ResultSource.pm @@ -12,7 +12,7 @@ __PACKAGE__->load_components(qw/AccessorGroup/); __PACKAGE__->mk_group_accessors('simple' => qw/_ordered_columns _columns _primaries _unique_constraints name resultset_attributes - schema from _relationships/); + schema from _relationships column_info_from_storage source_name/); __PACKAGE__->mk_group_accessors('component_class' => qw/resultset_class result_class/); @@ -30,12 +30,25 @@ retrieved, most usually a table (see L) =head1 METHODS +=pod + +=head2 new + + $class->new(); + + $class->new({attribute_name => value}); + +Creates a new ResultSource object. Not normally called directly by end users. + =cut sub new { my ($class, $attrs) = @_; $class = ref $class if ref $class; - my $new = bless({ %{$attrs || {}}, _resultset => undef }, $class); + + my $new = { %{$attrs || {}}, _resultset => undef }; + bless $new, $class; + $new->{resultset_class} ||= 'DBIx::Class::ResultSet'; $new->{resultset_attributes} = { %{$new->{resultset_attributes} || {}} }; $new->{_ordered_columns} = [ @{$new->{_ordered_columns}||[]}]; @@ -43,6 +56,9 @@ sub new { $new->{_relationships} = { %{$new->{_relationships}||{}} }; $new->{name} ||= "!!NAME NOT SET!!"; $new->{_columns_info_loaded} ||= 0; + if(!defined $new->column_info_from_storage) { + $new->{column_info_from_storage} = 1 + } return $new; } @@ -171,24 +187,38 @@ sub column_info { unless exists $self->_columns->{$column}; #warn $self->{_columns_info_loaded}, "\n"; if ( ! $self->_columns->{$column}{data_type} + and $self->column_info_from_storage and ! $self->{_columns_info_loaded} and $self->schema and $self->storage ) { $self->{_columns_info_loaded}++; my $info; + my $lc_info; # eval for the case of storage without table - eval { $info = $self->storage->columns_info_for($self->from) }; + eval { $info = $self->storage->columns_info_for( $self->from ) }; unless ($@) { + for my $realcol ( keys %{$info} ) { + $lc_info->{lc $realcol} = $info->{$realcol}; + } foreach my $col ( keys %{$self->_columns} ) { - foreach my $i ( keys %{$info->{$col}} ) { - $self->_columns->{$col}{$i} = $info->{$col}{$i}; - } + $self->_columns->{$col} = { %{ $self->_columns->{$col}}, %{$info->{$col} || $lc_info->{lc $col}} }; } } } return $self->_columns->{$column}; } +=head2 column_info_from_storage + +Enables or disables the on-demand automatic loading of the above +column metadata from storage as neccesary. Defaults to true in the +current release, but will default to false in future releases starting +with 0.08000. This is *deprecated*, and should not be used. It will +be removed before 1.0. + + __PACKAGE__->column_info_from_storage(0); + __PACKAGE__->column_info_from_storage(1); + =head2 columns my @column_names = $obj->columns; @@ -232,7 +262,7 @@ sub remove_columns { } foreach (@cols) { - undef $columns->{$_}; + delete $columns->{$_}; }; $self->_ordered_columns(\@remaining); @@ -283,19 +313,31 @@ sub primary_columns { =head2 add_unique_constraint Declare a unique constraint on this source. Call once for each unique -constraint. Unique constraints are used when you call C on a -L. Only columns in the constraint are searched, -for example: +constraint. # For UNIQUE (column1, column2) __PACKAGE__->add_unique_constraint( constraint_name => [ qw/column1 column2/ ], ); +Alternatively, you can specify only the columns: + + __PACKAGE__->add_unique_constraint([ qw/column1 column2/ ]); + +This will result in a unique constraint named C, where +C is replaced with the table name. + +Unique constraints are used, for example, when you call +L. Only columns in the constraint are searched. + =cut sub add_unique_constraint { - my ($self, $name, $cols) = @_; + my $self = shift; + my $cols = pop @_; + my $name = shift; + + $name ||= $self->name_unique_constraint($cols); foreach my $col (@$cols) { $self->throw_exception("No such column $col on table " . $self->name) @@ -307,6 +349,22 @@ sub add_unique_constraint { $self->_unique_constraints(\%unique_constraints); } +=head2 name_unique_constraint + +Return a name for a unique constraint containing the specified columns. These +names consist of the table name and each column name, separated by underscores. + +For example, a constraint on a table named C containing the columns +C and C would result in a constraint name of C<cd_artist_title>. + +=cut + +sub name_unique_constraint { + my ($self, $cols) = @_; + + return join '_', $self->name, @$cols; +} + =head2 unique_constraints Read-only accessor which returns the list of unique constraints on this source. @@ -317,13 +375,48 @@ sub unique_constraints { return %{shift->_unique_constraints||{}}; } +=head2 unique_constraint_names + +Returns the list of unique constraint names defined on this source. + +=cut + +sub unique_constraint_names { + my ($self) = @_; + + my %unique_constraints = $self->unique_constraints; + + return keys %unique_constraints; +} + +=head2 unique_constraint_columns + +Returns the list of columns that make up the specified unique constraint. + +=cut + +sub unique_constraint_columns { + my ($self, $constraint_name) = @_; + + my %unique_constraints = $self->unique_constraints; + + $self->throw_exception( + "Unknown unique constraint $constraint_name on '" . $self->name . "'" + ) unless exists $unique_constraints{$constraint_name}; + + return @{ $unique_constraints{$constraint_name} }; +} + =head2 from Returns an expression of the source to be supplied to storage to specify retrieval from this source. In the case of a database, the required FROM clause contents. -=cut +=head2 schema + +Returns the L<DBIx::Class::Schema> object that this result source +belongs too. =head2 storage @@ -418,10 +511,7 @@ sub add_relationship { my $f_source = $self->schema->source($f_source_name); unless ($f_source) { - eval "require $f_source_name;"; - if ($@) { - die $@ unless $@ =~ /Can't locate/; - } + $self->ensure_class_loaded($f_source_name); $f_source = $f_source_name->result_source; #my $s_class = ref($self->schema); #$f_source_name =~ m/^${s_class}::(.*)$/; @@ -493,7 +583,7 @@ sub has_relationship { =back -Returns an array of hash references of relationship information for +Returns an array of hash references of relationship information for the other side of the specified relationship name. =cut @@ -508,13 +598,13 @@ sub reverse_relationship_info { my @cond = keys(%{$rel_info->{cond}}); my @refkeys = map {/^\w+\.(\w+)$/} @cond; my @keys = map {$rel_info->{cond}->{$_} =~ /^\w+\.(\w+)$/} @cond; - + # Get the related result source for this relationship my $othertable = $self->related_source($rel); # Get all the relationships for that source that related to this source # whose foreign column set are our self columns on $rel and whose self - # columns are our foreign columns on $rel. + # columns are our foreign columns on $rel. my @otherrels = $othertable->relationships(); my $otherrelationship; foreach my $otherrel (@otherrels) { @@ -539,7 +629,7 @@ sub reverse_relationship_info { my @other_cond = keys(%$othercond); my @other_refkeys = map {/^\w+\.(\w+)$/} @other_cond; my @other_keys = map {$othercond->{$_} =~ /^\w+\.(\w+)$/} @other_cond; - next if (!$self->compare_relationship_keys(\@refkeys, \@other_keys) || + next if (!$self->compare_relationship_keys(\@refkeys, \@other_keys) || !$self->compare_relationship_keys(\@other_refkeys, \@keys)); $ret->{$otherrel} = $otherrel_info; } @@ -650,7 +740,8 @@ sub resolve_condition { #warn %$cond; if (ref $cond eq 'HASH') { my %ret; - while (my ($k, $v) = each %{$cond}) { + foreach my $k (keys %{$cond}) { + my $v = $cond->{$k}; # XXX should probably check these are valid columns $k =~ s/^foreign\.// || $self->throw_exception("Invalid rel cond key ${k}"); @@ -660,8 +751,12 @@ sub resolve_condition { #warn "$self $k $for $v"; $ret{$k} = $for->get_column($v); #warn %ret; + } elsif (!defined $for) { # undef, i.e. "no object" + $ret{$k} = undef; } elsif (ref $as) { # reverse object $ret{$v} = $as->get_column($k); + } elsif (!defined $as) { # undef, i.e. "no reverse object" + $ret{$v} = undef; } else { $ret{"${as}.${k}"} = "${for}.${v}"; } @@ -846,13 +941,38 @@ sub resultset { 'resultset does not take any arguments. If you want another resultset, '. 'call it on the schema instead.' ) if scalar @_; - return $self->{_resultset} - if ref $self->{_resultset} eq $self->resultset_class; - return $self->{_resultset} = $self->resultset_class->new( + + # disabled until we can figure out a way to do it without consistency issues + # + #return $self->{_resultset} + # if ref $self->{_resultset} eq $self->resultset_class; + #return $self->{_resultset} = + + return $self->resultset_class->new( $self, $self->{resultset_attributes} ); } +=head2 source_name + +=over 4 + +=item Arguments: $source_name + +=back + +Set the name of the result source when it is loaded into a schema. +This is usefull if you want to refer to a result source by a name other than +its class name. + + package ArchivedBooks; + use base qw/DBIx::Class/; + __PACKAGE__->table('books_archive'); + __PACKAGE__->source_name('Books'); + + # from your schema... + $schema->resultset('Books')->find(1); + =head2 throw_exception See L<DBIx::Class::Schema/"throw_exception">.