X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FResultSource.pm;h=32fb84e77af78fa14e2be5c54b73cee0d673dcde;hb=c079518f7bbe43998aae31cead6127b3b85be92e;hp=8b27139730723337ee9fb240044a102a9edbbe0b;hpb=5a99915c2e3e56ed5b64662fbfdc0c9cdd493bcb;p=dbsrgits%2FDBIx-Class-Historic.git diff --git a/lib/DBIx/Class/ResultSource.pm b/lib/DBIx/Class/ResultSource.pm index 8b27139..32fb84e 100644 --- a/lib/DBIx/Class/ResultSource.pm +++ b/lib/DBIx/Class/ResultSource.pm @@ -15,7 +15,7 @@ __PACKAGE__->mk_group_accessors('simple' => qw/_ordered_columns schema from _relationships/); __PACKAGE__->mk_group_accessors('component_class' => qw/resultset_class - result_class/); + result_class source_name/); =head1 NAME @@ -54,13 +54,12 @@ sub new { $table->add_columns('col1' => \%col1_info, 'col2' => \%col2_info, ...); -Adds columns to the result source. If supplied key => hashref pairs uses -the hashref as the column_info for that column. +Adds columns to the result source. If supplied key => hashref pairs, uses +the hashref as the column_info for that column. Repeated calls of this +method will add more columns, not replace them. -Repeated calls of this method will add more columns, not replace them. - -The contents of the column_info are not set in stone, the following -keys are currently recognised/used by DBIx::Class. +The contents of the column_info are not set in stone. The following +keys are currently recognised/used by DBIx::Class: =over 4 @@ -71,15 +70,15 @@ the name of the column will be used. =item data_type -This contains the column type, it is automatically filled by the +This contains the column type. It is automatically filled by the L producer, and the -L module. If you do not enter the +L module. If you do not enter a data_type, DBIx::Class will attempt to retrieve it from the -database for you, using Ls column_info method. The values of this +database for you, using L's column_info method. The values of this key are typically upper-cased. -Currently there is no standard set of values for the data_type, use -whatever your database(s) support. +Currently there is no standard set of values for the data_type. Use +whatever your database supports. =item size @@ -88,31 +87,32 @@ restriction. This is currently not used by DBIx::Class. =item is_nullable -If the column is allowed to contain NULL values, set a true value -(typically 1), here. This is currently not used by DBIx::Class. +Set this to a true value for a columns that is allowed to contain +NULL values. This is currently not used by DBIx::Class. =item is_auto_increment -Set this to a true value if this is a column that is somehow -automatically filled. This is used to determine which columns to empty +Set this to a true value for a column whose value is somehow +automatically set. This is used to determine which columns to empty when cloning objects using C. =item is_foreign_key -Set this to a true value if this column represents a key from a +Set this to a true value for a column that contains a key from a foreign table. This is currently not used by DBIx::Class. =item default_value -Set this to the default value which will be inserted into this column -by the database. Can contain either values or functions. This is +Set this to the default value which will be inserted into a column +by the database. Can contain either a value or a function. This is currently not used by DBIx::Class. =item sequence -Sets the name of the sequence to use to generate values. If not -specified, L will attempt to retrieve the -name of the sequence from the database automatically. +Set this on a primary key column to the name of the sequence used to +generate a new key value. If not specified, L +will attempt to retrieve the name of the sequence from the database +automatically. =back @@ -120,14 +120,14 @@ name of the sequence from the database automatically. $table->add_column('col' => \%info?); -Convenience alias to add_columns +Convenience alias to add_columns. =cut sub add_columns { my ($self, @cols) = @_; $self->_ordered_columns(\@cols) unless $self->_ordered_columns; - + my @added; my $columns = $self->_columns; while (my $col = shift @cols) { @@ -147,7 +147,7 @@ sub add_columns { if ($obj->has_column($col)) { ... } -Returns 1 if the source has a column of this name, 0 otherwise. +Returns true if the source has a column of this name, false otherwise. =cut @@ -193,7 +193,7 @@ sub column_info { my @column_names = $obj->columns; -Returns all column names in the order they were declared to add_columns +Returns all column names in the order they were declared to add_columns. =cut @@ -205,11 +205,46 @@ sub columns { return @{$self->{_ordered_columns}||[]}; } +=head2 remove_columns + + $table->remove_columns(qw/col1 col2 col3/); + +Removes columns from the result source. + +=head2 remove_column + + $table->remove_column('col'); + +Convenience alias to remove_columns. + +=cut + +sub remove_columns { + my ($self, @cols) = @_; + + return unless $self->_ordered_columns; + + my $columns = $self->_columns; + my @remaining; + + foreach my $col (@{$self->_ordered_columns}) { + push @remaining, $col unless grep(/$col/, @cols); + } + + foreach (@cols) { + undef $columns->{$_}; + }; + + $self->_ordered_columns(\@remaining); +} + +*remove_column = \&remove_columns; + =head2 set_primary_key =over 4 -=item Arguments: (@cols) +=item Arguments: @cols =back @@ -248,16 +283,16 @@ 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, - -e.g., +constraint. # For UNIQUE (column1, column2) __PACKAGE__->add_unique_constraint( constraint_name => [ qw/column1 column2/ ], ); +Unique constraints are used, for example, when you call +L. Only columns in the constraint are searched. + =cut sub add_unique_constraint { @@ -283,11 +318,43 @@ 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. +retrieval from this source. In the case of a database, the required FROM +clause contents. =cut @@ -314,7 +381,7 @@ the current schema. For example: 'foreign.book_id' => 'self.id', }); -The condition C<$cond> needs to be an SQL::Abstract-style +The condition C<$cond> needs to be an L-style representation of the join between the tables. For example, if you're creating a rel from Author to Book, @@ -340,16 +407,16 @@ the SQL command immediately before C. An arrayref containing a list of accessors in the foreign class to proxy in the main class. If, for example, you do the following: - + CD->might_have(liner_notes => 'LinerNotes', undef, { proxy => [ qw/notes/ ], }); - + Then, assuming LinerNotes has an accessor named notes, you can do: my $cd = CD->find(1); - $cd->notes('Notes go here'); # set notes -- LinerNotes object is - # created if it doesn't exist + # set notes -- LinerNotes object is created if it doesn't exist + $cd->notes('Notes go here'); =item accessor @@ -408,7 +475,7 @@ sub add_relationship { =head2 relationships -Returns all valid relationship names for this source +Returns all relationship names for this source. =cut @@ -420,11 +487,12 @@ sub relationships { =over 4 -=item Arguments: ($relname) +=item Arguments: $relname =back -Returns the relationship information for the specified relationship name +Returns a hash of relationship information for the specified relationship +name. =cut @@ -437,11 +505,11 @@ sub relationship_info { =over 4 -=item Arguments: ($rel) +=item Arguments: $rel =back -Returns 1 if the source has a relationship of this name, 0 otherwise. +Returns true if the source has a relationship of this name, false otherwise. =cut @@ -450,15 +518,122 @@ sub has_relationship { return exists $self->_relationships->{$rel}; } +=head2 reverse_relationship_info + +=over 4 + +=item Arguments: $relname + +=back + +Returns an array of hash references of relationship information for +the other side of the specified relationship name. + +=cut + +sub reverse_relationship_info { + my ($self, $rel) = @_; + my $rel_info = $self->relationship_info($rel); + my $ret = {}; + + return $ret unless ((ref $rel_info->{cond}) eq 'HASH'); + + 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. + my @otherrels = $othertable->relationships(); + my $otherrelationship; + foreach my $otherrel (@otherrels) { + my $otherrel_info = $othertable->relationship_info($otherrel); + + my $back = $othertable->related_source($otherrel); + next unless $back->name eq $self->name; + + my @othertestconds; + + if (ref $otherrel_info->{cond} eq 'HASH') { + @othertestconds = ($otherrel_info->{cond}); + } + elsif (ref $otherrel_info->{cond} eq 'ARRAY') { + @othertestconds = @{$otherrel_info->{cond}}; + } + else { + next; + } + + foreach my $othercond (@othertestconds) { + 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) || + !$self->compare_relationship_keys(\@other_refkeys, \@keys)); + $ret->{$otherrel} = $otherrel_info; + } + } + return $ret; +} + +=head2 compare_relationship_keys + +=over 4 + +=item Arguments: $keys1, $keys2 + +=back + +Returns true if both sets of keynames are the same, false otherwise. + +=cut + +sub compare_relationship_keys { + my ($self, $keys1, $keys2) = @_; + + # Make sure every keys1 is in keys2 + my $found; + foreach my $key (@$keys1) { + $found = 0; + foreach my $prim (@$keys2) { + if ($prim eq $key) { + $found = 1; + last; + } + } + last unless $found; + } + + # Make sure every key2 is in key1 + if ($found) { + foreach my $prim (@$keys2) { + $found = 0; + foreach my $key (@$keys1) { + if ($prim eq $key) { + $found = 1; + last; + } + } + last unless $found; + } + } + + return $found; +} + =head2 resolve_join =over 4 -=item Arguments: ($relation) +=item Arguments: $relation =back -Returns the join structure required for the related result source +Returns the join structure required for the related result source. =cut @@ -493,7 +668,7 @@ sub resolve_join { =over 4 -=item Arguments: ($cond, $as, $alias|$object) +=item Arguments: $cond, $as, $alias|$object =back @@ -536,7 +711,7 @@ sub resolve_condition { =over 4 -=item Arguments: (hashref/arrayref/scalar) +=item Arguments: hashref/arrayref/scalar =back @@ -641,11 +816,11 @@ sub resolve_prefetch { =over 4 -=item Arguments: ($relname) +=item Arguments: $relname =back -Returns the result source object for the given relationship +Returns the result source object for the given relationship. =cut @@ -661,11 +836,11 @@ sub related_source { =over 4 -=item Arguments: ($relname) +=item Arguments: $relname =back -Returns the class object for the given relationship +Returns the class name for objects in the given relationship. =cut @@ -704,16 +879,41 @@ 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 throw_exception in L. +See L. =cut @@ -726,7 +926,6 @@ sub throw_exception { } } - =head1 AUTHORS Matt S. Trout