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;
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
=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 {
$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',
$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.$_" }
__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
$new->{resultset_class} ||= 'DBIx::Class::ResultSet';
$new->{_ordered_columns} ||= [];
$new->{_columns} ||= {};
+ $new->{_relationships} ||= {};
$new->{name} ||= "!!NAME NOT SET!!";
return $new;
}
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<LEFT> or C<RIGHT>. It will be placed in the SQL
+command immediately before C<JOIN>.
+
+=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<single> (for when there is only a single related object),
+C<multi> (when there can be many), and C<filter> (for when there is a single
+related object, but you also want the relationship accessor to double as
+a column accessor). For C<multi> accessors, an add_to_* method is also
+created, which calls C<create_related> 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
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
die $@ unless $@ =~ /Can't locate/;
}
$class->register_class($comp => $comp_class);
+ #$class->register_class($comp_class => $comp_class);
}
}
}
use lib 't/lib';
-use_ok('DBICTest');
+use_ok('DBICTest::HelperRels');
DBICTest::CD->load_components(qw/CDBICompat::Pager/);
#-----------------------------------------------------------------------
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/);
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/);
#-------------------------------------------------------------------------
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/);
-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 = <<EOSQL;
-CREATE TABLE artist (artistid INTEGER NOT NULL PRIMARY KEY, name VARCHAR);
-
-CREATE TABLE cd (cdid INTEGER NOT NULL PRIMARY KEY, artist INTEGER NOT NULL,
- title VARCHAR, year VARCHAR);
-
-CREATE TABLE liner_notes (liner_id INTEGER NOT NULL PRIMARY KEY, notes VARCHAR);
-
-CREATE TABLE track (trackid INTEGER NOT NULL PRIMARY KEY, cd INTEGER NOT NULL,
- position INTEGER NOT NULL, title VARCHAR);
-
-CREATE TABLE tags (tagid INTEGER NOT NULL PRIMARY KEY, cd INTEGER NOT NULL,
- tag VARCHAR);
-
-CREATE TABLE twokeys (artist INTEGER NOT NULL, cd INTEGER NOT NULL,
- PRIMARY KEY (artist, cd) );
-
-CREATE TABLE fourkeys (foo INTEGER NOT NULL, bar INTEGER NOT NULL,
- hello INTEGER NOT NULL, goodbye INTEGER NOT NULL,
- PRIMARY KEY (foo, bar, hello, goodbye) );
-
-CREATE TABLE onekey (id INTEGER NOT NULL PRIMARY KEY,
- artist INTEGER NOT NULL, cd INTEGER NOT NULL );
-
-CREATE TABLE self_ref (id INTEGER NOT NULL PRIMARY KEY,
- name VARCHAR );
-
-CREATE TABLE self_ref_alias (self_ref INTEGER NOT NULL, alias INTEGER NOT NULL,
- PRIMARY KEY( self_ref, alias ) );
-
-CREATE TABLE producer (producerid INTEGER NOT NULL PRIMARY KEY, name VARCHAR);
-
-CREATE TABLE cd_to_producer (cd INTEGER NOT NULL, producer INTEGER NOT NULL);
-
-INSERT INTO artist (artistid, name) VALUES (1, 'Caterwauler McCrae');
-
-INSERT INTO artist (artistid, name) VALUES (2, 'Random Boy Band');
-
-INSERT INTO artist (artistid, name) VALUES (3, 'We Are Goth');
-
-INSERT INTO cd (cdid, artist, title, year)
- VALUES (1, 1, "Spoonful of bees", 1999);
-
-INSERT INTO cd (cdid, artist, title, year)
- VALUES (2, 1, "Forkful of bees", 2001);
-
-INSERT INTO cd (cdid, artist, title, year)
- VALUES (3, 1, "Caterwaulin' Blues", 1997);
-
-INSERT INTO cd (cdid, artist, title, year)
- VALUES (4, 2, "Generic Manufactured Singles", 2001);
-
-INSERT INTO cd (cdid, artist, title, year)
- VALUES (5, 3, "Come Be Depressed With Us", 1998);
-
-INSERT INTO liner_notes (liner_id, notes)
- VALUES (2, "Buy Whiskey!");
-
-INSERT INTO liner_notes (liner_id, notes)
- VALUES (4, "Buy Merch!");
-
-INSERT INTO liner_notes (liner_id, notes)
- VALUES (5, "Kill Yourself!");
-
-INSERT INTO tags (tagid, cd, tag) VALUES (1, 1, "Blue");
-
-INSERT INTO tags (tagid, cd, tag) VALUES (2, 2, "Blue");
-
-INSERT INTO tags (tagid, cd, tag) VALUES (3, 3, "Blue");
-
-INSERT INTO tags (tagid, cd, tag) VALUES (4, 5, "Blue");
-
-INSERT INTO tags (tagid, cd, tag) VALUES (5, 2, "Cheesy");
-
-INSERT INTO tags (tagid, cd, tag) VALUES (6, 4, "Cheesy");
-
-INSERT INTO tags (tagid, cd, tag) VALUES (7, 5, "Cheesy");
-
-INSERT INTO tags (tagid, cd, tag) VALUES (8, 2, "Shiny");
-
-INSERT INTO tags (tagid, cd, tag) VALUES (9, 4, "Shiny");
-
-INSERT INTO twokeys (artist, cd) VALUES (1, 1);
-
-INSERT INTO twokeys (artist, cd) VALUES (1, 2);
-
-INSERT INTO twokeys (artist, cd) VALUES (2, 2);
-
-INSERT INTO fourkeys (foo, bar, hello, goodbye) VALUES (1, 2, 3, 4);
-
-INSERT INTO fourkeys (foo, bar, hello, goodbye) VALUES (5, 4, 3, 6);
-
-INSERT INTO onekey (id, artist, cd) VALUES (1, 1, 1);
-
-INSERT INTO onekey (id, artist, cd) VALUES (2, 1, 2);
-
-INSERT INTO onekey (id, artist, cd) VALUES (3, 2, 2);
-
-INSERT INTO self_ref (id, name) VALUES (1, 'First');
-
-INSERT INTO self_ref (id, name) VALUES (2, 'Second');
-
-INSERT INTO self_ref_alias (self_ref, alias) VALUES (1, 2);
-
-INSERT INTO producer (producerid, name) VALUES (1, 'Matt S Trout');
-
-INSERT INTO cd_to_producer (cd, producer) VALUES (1, 1);
-
-EOSQL
-
-$dbh->do($_) for split(/\n\n/, $sql);
-
-$schema->storage->dbh->do("PRAGMA synchronous = OFF");
-
1;
use DBICTest::Schema;
use DBICTest::Schema::BasicRels;
+use DBICTest::Setup;
1;
use DBICTest::Schema;
use DBICTest::Schema::HelperRels;
+use DBICTest::Setup;
1;
DBICTest::Schema::CD->add_relationship(
artist => 'DBICTest::Schema::Artist',
{ 'foreign.artistid' => 'self.artist' },
+ { accessor => 'filter' },
);
DBICTest::Schema::CD->add_relationship(
tracks => 'DBICTest::Schema::Track',
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',
# 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' }
);
};
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/ ],