From: Matt S Trout Date: Sat, 14 Jan 2006 03:18:27 +0000 (+0000) Subject: add_relationship, relationship_info, relationships moved to ResultSource X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=8452e496;p=dbsrgits%2FDBIx-Class-Historic.git add_relationship, relationship_info, relationships moved to ResultSource --- diff --git a/lib/DBIx/Class/DB.pm b/lib/DBIx/Class/DB.pm index f65375d..3166c98 100644 --- a/lib/DBIx/Class/DB.pm +++ b/lib/DBIx/Class/DB.pm @@ -105,9 +105,13 @@ Rolls back the current transaction. sub txn_rollback { $_[0]->storage->txn_rollback } -sub resolve_class { - warn "resolve_class deprecated as of 0.04999_02"; - return shift->class_resolver->class(@_); +{ + my $warn; + + sub resolve_class { + warn "resolve_class deprecated as of 0.04999_02" unless $warn++; + return shift->class_resolver->class(@_); + } } 1; diff --git a/lib/DBIx/Class/Relationship.pm b/lib/DBIx/Class/Relationship.pm index 71c0004..cdb3581 100644 --- a/lib/DBIx/Class/Relationship.pm +++ b/lib/DBIx/Class/Relationship.pm @@ -13,23 +13,6 @@ __PACKAGE__->load_own_components(qw/ Base /); -__PACKAGE__->mk_classdata('_relationships', { } ); - -sub relationships -{ - my $self = shift; - - return keys %{$self->_relationships}; -} - -sub relationship_info -{ - my $self = shift; - my ($rel) = @_; - - return $self->_relationships->{$rel}; -} - =head1 NAME DBIx::Class::Relationship - Inter-table relationships diff --git a/lib/DBIx/Class/Relationship/Base.pm b/lib/DBIx/Class/Relationship/Base.pm index ce7555b..9a979b8 100644 --- a/lib/DBIx/Class/Relationship/Base.pm +++ b/lib/DBIx/Class/Relationship/Base.pm @@ -72,28 +72,15 @@ created, which calls C for the relationship. =cut sub add_relationship { - my ($class, $rel, $f_class, $cond, $attrs) = @_; - die "Can't create relationship without join condition" unless $cond; - $attrs ||= {}; - eval "require $f_class;"; - if ($@) { - $class->throw($@) unless $@ =~ /Can't locate/; - } - my %rels = %{ $class->_relationships }; - $rels{$rel} = { class => $f_class, - cond => $cond, - attrs => $attrs }; - $class->_relationships(\%rels); - - return unless eval { $f_class->can('columns'); }; # Foreign class not loaded - eval { $class->_resolve_join($rel, 'me') }; - - if ($@) { # If the resolve failed, back out and re-throw the error - delete $rels{$rel}; # - $class->_relationships(\%rels); - $class->throw("Error creating relationship $rel: $@"); - } - 1; + shift->result_source->add_relationship(@_); +} + +sub relationships { + shift->result_source->relationships(@_); +} + +sub relationship_info { + shift->result_source->relationship_info(@_); } sub _resolve_join { @@ -108,6 +95,7 @@ sub _resolve_join { $class->throw("No idea how to resolve join reftype ".ref $join); } else { my $rel_obj = $class->relationship_info($join); + #use Data::Dumper; warn Dumper($class->result_source) unless $rel_obj; $class->throw("No such relationship ${join}") unless $rel_obj; my $j_class = $rel_obj->{class}; my %join = (_action => 'join', diff --git a/lib/DBIx/Class/ResultSet.pm b/lib/DBIx/Class/ResultSet.pm index 3d514cc..a33e22f 100644 --- a/lib/DBIx/Class/ResultSet.pm +++ b/lib/DBIx/Class/ResultSet.pm @@ -59,11 +59,11 @@ sub new { $seen{$j} = 1; } } - push(@{$attrs->{from}}, $source->result_class->_resolve_join($join, $attrs->{alias})); + push(@{$attrs->{from}}, $source->resolve_join($join, $attrs->{alias})); } $attrs->{group_by} ||= $attrs->{select} if delete $attrs->{distinct}; foreach my $pre (@{delete $attrs->{prefetch} || []}) { - push(@{$attrs->{from}}, $source->result_class->_resolve_join($pre, $attrs->{alias})) + push(@{$attrs->{from}}, $source->resolve_join($pre, $attrs->{alias})) unless $seen{$pre}; my @pre = map { "$pre.$_" } diff --git a/lib/DBIx/Class/ResultSource.pm b/lib/DBIx/Class/ResultSource.pm index c122ddb..335eb5c 100644 --- a/lib/DBIx/Class/ResultSource.pm +++ b/lib/DBIx/Class/ResultSource.pm @@ -11,7 +11,7 @@ use base qw/DBIx::Class/; __PACKAGE__->load_components(qw/AccessorGroup/); __PACKAGE__->mk_group_accessors('simple' => - qw/_ordered_columns _columns _primaries name resultset_class result_class schema from/); + qw/_ordered_columns _columns _primaries name resultset_class result_class schema from _relationships/); =head1 NAME @@ -35,6 +35,7 @@ sub new { $new->{resultset_class} ||= 'DBIx::Class::ResultSet'; $new->{_ordered_columns} ||= []; $new->{_columns} ||= {}; + $new->{_relationships} ||= {}; $new->{name} ||= "!!NAME NOT SET!!"; return $new; } @@ -172,6 +173,122 @@ Returns the storage handle for the current schema sub storage { shift->schema->storage; } +=head2 add_relationship + + $source->add_relationship('relname', 'related_source', $cond, $attrs); + +The relation name can be arbitrary, but must be unique for each relationship +attached to this result source. 'related_source' should be the name with +which the related result source was registered with the current schema +(for simple schemas this is usally either Some::Namespace::Foo or just Foo) + +The condition needs to be an SQL::Abstract-style representation of the join +between the tables. For example, if you're creating a rel from Foo to Bar, + + { 'foreign.foo_id' => 'self.id' } + +will result in the JOIN clause + + foo me JOIN bar bar ON bar.foo_id = me.id + +You can specify as many foreign => self mappings as necessary. + +Valid attributes are as follows: + +=over 4 + +=item join_type + +Explicitly specifies the type of join to use in the relationship. Any SQL +join type is valid, e.g. C or C. It will be placed in the SQL +command immediately before C. + +=item proxy + +An arrayref containing a list of accessors in the foreign class to proxy in +the main class. If, for example, you do the following: + + __PACKAGE__->might_have(bar => 'Bar', undef, { proxy => qw[/ margle /] }); + +Then, assuming Bar has an accessor named margle, you can do: + + my $obj = Foo->find(1); + $obj->margle(10); # set margle; Bar object is created if it doesn't exist + +=item accessor + +Specifies the type of accessor that should be created for the relationship. +Valid values are C (for when there is only a single related object), +C (when there can be many), and C (for when there is a single +related object, but you also want the relationship accessor to double as +a column accessor). For C accessors, an add_to_* method is also +created, which calls C for the relationship. + +=back + +=cut + +sub add_relationship { + my ($self, $rel, $f_source_name, $cond, $attrs) = @_; + die "Can't create relationship without join condition" unless $cond; + $attrs ||= {}; + my %rels = %{ $self->_relationships }; + $rels{$rel} = { class => $f_source_name, + cond => $cond, + attrs => $attrs }; + $self->_relationships(\%rels); + + my $f_source = $self->schema->source($f_source_name); + unless ($f_source) { + eval "require $f_source_name;"; + if ($@) { + die $@ unless $@ =~ /Can't locate/; + } + $f_source = $f_source_name->result_source; + } + return unless $f_source; # Can't test rel without f_source + + eval { $self->resolve_join($rel, 'me') }; + + if ($@) { # If the resolve failed, back out and re-throw the error + delete $rels{$rel}; # + $self->_relationships(\%rels); + die "Error creating relationship $rel: $@"; + } + 1; +} + +=head2 relationships() + +Returns all valid relationship names for this source + +=cut + +sub relationships { + return keys %{shift->_relationships}; +} + +=head2 relationship_info($relname) + +Returns the relationship information for the specified relationship name + +=cut + +sub relationship_info { + my ($self, $rel) = @_; + return $self->_relationships->{$rel}; +} + +=head2 resolve_join($relation) + +Returns the join structure required for the related result source + +=cut + +sub resolve_join { + shift->result_class->_resolve_join(@_); +} + 1; =head1 AUTHORS diff --git a/lib/DBIx/Class/Schema.pm b/lib/DBIx/Class/Schema.pm index 678fe5e..0c0ceb8 100644 --- a/lib/DBIx/Class/Schema.pm +++ b/lib/DBIx/Class/Schema.pm @@ -109,7 +109,8 @@ Returns the result source object for the registered name sub source { my ($self, $class) = @_; - return $self->class_registrations->{$class}->result_source; + return $self->class_registrations->{$class}->result_source + if $self->class_registrations->{$class}; } =head2 resultset @@ -181,6 +182,7 @@ sub load_classes { die $@ unless $@ =~ /Can't locate/; } $class->register_class($comp => $comp_class); + #$class->register_class($comp_class => $comp_class); } } } diff --git a/t/cdbi-sweet-t/08pager.t b/t/cdbi-sweet-t/08pager.t index ab5211a..ea77d81 100644 --- a/t/cdbi-sweet-t/08pager.t +++ b/t/cdbi-sweet-t/08pager.t @@ -10,7 +10,7 @@ plan tests => 10; use lib 't/lib'; -use_ok('DBICTest'); +use_ok('DBICTest::HelperRels'); DBICTest::CD->load_components(qw/CDBICompat::Pager/); diff --git a/t/cdbi-t/01-columns.t b/t/cdbi-t/01-columns.t index faaf713..09cae07 100644 --- a/t/cdbi-t/01-columns.t +++ b/t/cdbi-t/01-columns.t @@ -7,8 +7,7 @@ use Test::More tests => 24; #----------------------------------------------------------------------- package State; -use base 'DBIx::Class'; -State->load_components(qw/CDBICompat Core/); +use base 'DBIx::Class::Test::SQLite'; State->table('State'); State->columns(Essential => qw/Abbreviation Name/); @@ -34,8 +33,7 @@ sub Snowfall { 1 } package City; -use base 'DBIx::Class'; -City->load_components(qw/CDBICompat Core/); +use base 'DBIx::Class::Test::SQLite'; City->table('City'); City->columns(All => qw/Name State Population/); @@ -44,8 +42,7 @@ City->has_a(State => 'State'); #------------------------------------------------------------------------- package CD; -use base 'DBIx::Class'; -CD->load_components(qw/CDBICompat Core/); +use base 'DBIx::Class::Test::SQLite'; CD->table('CD'); CD->columns('All' => qw/artist title length/); diff --git a/t/lib/DBICTest.pm b/t/lib/DBICTest.pm index bcca718..0afc604 100755 --- a/t/lib/DBICTest.pm +++ b/t/lib/DBICTest.pm @@ -1,131 +1 @@ -use strict; -use warnings; -use DBICTest::Schema; - -my $db_file = "t/var/DBIxClass.db"; - -unlink($db_file) if -e $db_file; -unlink($db_file . "-journal") if -e $db_file . "-journal"; -mkdir("t/var") unless -d "t/var"; - -my $dsn = "dbi:SQLite:${db_file}"; - -my $schema = DBICTest::Schema->compose_connection('DBICTest' => $dsn); - -my $dbh = DBI->connect($dsn); - -my $sql = <do($_) for split(/\n\n/, $sql); - -$schema->storage->dbh->do("PRAGMA synchronous = OFF"); - 1; diff --git a/t/lib/DBICTest/BasicRels.pm b/t/lib/DBICTest/BasicRels.pm index c98c3ea..9ee0938 100644 --- a/t/lib/DBICTest/BasicRels.pm +++ b/t/lib/DBICTest/BasicRels.pm @@ -2,5 +2,6 @@ package DBICTest::BasicRels; use DBICTest::Schema; use DBICTest::Schema::BasicRels; +use DBICTest::Setup; 1; diff --git a/t/lib/DBICTest/HelperRels.pm b/t/lib/DBICTest/HelperRels.pm index 7887bd5..2dec167 100644 --- a/t/lib/DBICTest/HelperRels.pm +++ b/t/lib/DBICTest/HelperRels.pm @@ -2,5 +2,6 @@ package DBICTest::HelperRels; use DBICTest::Schema; use DBICTest::Schema::HelperRels; +use DBICTest::Setup; 1; diff --git a/t/lib/DBICTest/Schema/BasicRels.pm b/t/lib/DBICTest/Schema/BasicRels.pm index 13948af..0d01ff9 100644 --- a/t/lib/DBICTest/Schema/BasicRels.pm +++ b/t/lib/DBICTest/Schema/BasicRels.pm @@ -19,6 +19,7 @@ DBICTest::Schema::Artist->add_relationship( DBICTest::Schema::CD->add_relationship( artist => 'DBICTest::Schema::Artist', { 'foreign.artistid' => 'self.artist' }, + { accessor => 'filter' }, ); DBICTest::Schema::CD->add_relationship( tracks => 'DBICTest::Schema::Track', @@ -34,7 +35,7 @@ DBICTest::Schema::CD->add_relationship( DBICTest::Schema::CD->add_relationship( liner_notes => 'DBICTest::Schema::LinerNotes', { 'foreign.liner_id' => 'self.cdid' }, - { join_type => 'LEFT' } + { join_type => 'LEFT', accessor => 'single' } ); DBICTest::Schema::CD->add_relationship( cd_to_producer => 'DBICTest::Schema::CD_to_Producer', diff --git a/t/run/06relationship.tl b/t/run/06relationship.tl index ab35be0..0d691a0 100644 --- a/t/run/06relationship.tl +++ b/t/run/06relationship.tl @@ -93,7 +93,7 @@ SKIP: { # try to add a bogus relationship using the wrong cols eval { DBICTest::Schema::Artist->add_relationship( - tracks => 'DBICTest::Track', + tracks => 'DBICTest::Schema::Track', { 'foreign.cd' => 'self.cdid' } ); }; diff --git a/t/run/16joins.tl b/t/run/16joins.tl index 20a6214..cab0a93 100644 --- a/t/run/16joins.tl +++ b/t/run/16joins.tl @@ -96,17 +96,6 @@ cmp_ok( $rs->count, '==', 1, "Single record in resultset"); is($rs->first->name, 'We Are Goth', 'Correct record returned'); -DBICTest::Schema::CD->add_relationship( - artist => 'DBICTest::Schema::Artist', - { 'foreign.artistid' => 'self.artist' }, - { accessor => 'filter' }, -); - -DBICTest::Schema::CD->add_relationship( - liner_notes => 'DBICTest::Schema::LinerNotes', - { 'foreign.liner_id' => 'self.cdid' }, - { join_type => 'LEFT', accessor => 'single' }); - $rs = DBICTest->class("CD")->search( { 'artist.name' => 'Caterwauler McCrae' }, { prefetch => [ qw/artist liner_notes/ ],