1 package DBIx::Class::ResultSource;
6 use DBIx::Class::ResultSet;
10 use base qw/DBIx::Class/;
11 __PACKAGE__->load_components(qw/AccessorGroup/);
13 __PACKAGE__->mk_group_accessors('simple' =>
14 qw/_ordered_columns _columns _primaries name resultset_class result_class schema from _relationships/);
18 DBIx::Class::ResultSource - Result source object
24 A ResultSource is a component of a schema from which results can be directly
25 retrieved, most usually a table (see L<DBIx::Class::ResultSource::Table>)
32 my ($class, $attrs) = @_;
33 $class = ref $class if ref $class;
34 my $new = bless({ %{$attrs || {}} }, $class);
35 $new->{resultset_class} ||= 'DBIx::Class::ResultSet';
36 $new->{_ordered_columns} ||= [];
37 $new->{_columns} ||= {};
38 $new->{_relationships} ||= {};
39 $new->{name} ||= "!!NAME NOT SET!!";
44 my ($self, @cols) = @_;
45 $self->_ordered_columns( \@cols )
46 if !$self->_ordered_columns;
48 my $columns = $self->_columns;
49 while (my $col = shift @cols) {
51 my $column_info = ref $cols[0] ? shift(@cols) : {};
52 # If next entry is { ... } use that for the column info, if not
53 # use an empty hashref
55 push(@added, $col) unless exists $columns->{$col};
57 $columns->{$col} = $column_info;
59 push @{ $self->_ordered_columns }, @added;
63 *add_column = \&add_columns;
67 $table->add_columns(qw/col1 col2 col3/);
69 $table->add_columns('col1' => \%col1_info, 'col2' => \%col2_info, ...);
71 Adds columns to the result source. If supplied key => hashref pairs uses
72 the hashref as the column_info for that column.
76 $table->add_column('col' => \%info?);
78 Convenience alias to add_columns
84 return $self->resultset_class->new($self);
89 if ($obj->has_column($col)) { ... }
91 Returns 1 if the source has a column of this name, 0 otherwise.
96 my ($self, $column) = @_;
97 return exists $self->_columns->{$column};
102 my $info = $obj->column_info($col);
104 Returns the column metadata hashref for a column.
109 my ($self, $column) = @_;
110 croak "No such column $column" unless exists $self->_columns->{$column};
111 if ( (! $self->_columns->{$column}->{data_type})
112 && $self->schema && $self->storage() ){
114 ############ eval for the case of storage without table
116 $info = $self->storage->columns_info_for ( $self->from() );
119 for my $col ( keys %{$self->_columns} ){
120 for my $i ( keys %{$info->{$col}} ){
121 $self->_columns()->{$col}->{$i} = $info->{$col}->{$i};
126 return $self->_columns->{$column};
131 my @column_names = $obj->columns;
133 Returns all column names in the order they were declared to add_columns
138 croak "columns() is a read-only accessor, did you mean add_columns()?" if (@_ > 1);
139 return @{shift->{_ordered_columns}||[]};
142 =head2 set_primary_key(@cols)
144 Defines one or more columns as primary key for this source. Should be
145 called after C<add_columns>.
149 sub set_primary_key {
150 my ($self, @cols) = @_;
151 # check if primary key columns are valid columns
153 $self->throw("No such column $_ on table ".$self->name)
154 unless $self->has_column($_);
156 $self->_primaries(\@cols);
159 =head2 primary_columns
161 Read-only accessor which returns the list of primary keys.
165 sub primary_columns {
166 return @{shift->_primaries||[]};
171 Returns an expression of the source to be supplied to storage to specify
172 retrieval from this source; in the case of a database the required FROM clause
179 Returns the storage handle for the current schema
183 sub storage { shift->schema->storage; }
185 =head2 add_relationship
187 $source->add_relationship('relname', 'related_source', $cond, $attrs);
189 The relation name can be arbitrary, but must be unique for each relationship
190 attached to this result source. 'related_source' should be the name with
191 which the related result source was registered with the current schema
192 (for simple schemas this is usally either Some::Namespace::Foo or just Foo)
194 The condition needs to be an SQL::Abstract-style representation of the join
195 between the tables. For example, if you're creating a rel from Foo to Bar,
197 { 'foreign.foo_id' => 'self.id' }
199 will result in the JOIN clause
201 foo me JOIN bar bar ON bar.foo_id = me.id
203 You can specify as many foreign => self mappings as necessary.
205 Valid attributes are as follows:
211 Explicitly specifies the type of join to use in the relationship. Any SQL
212 join type is valid, e.g. C<LEFT> or C<RIGHT>. It will be placed in the SQL
213 command immediately before C<JOIN>.
217 An arrayref containing a list of accessors in the foreign class to proxy in
218 the main class. If, for example, you do the following:
220 __PACKAGE__->might_have(bar => 'Bar', undef, { proxy => qw[/ margle /] });
222 Then, assuming Bar has an accessor named margle, you can do:
224 my $obj = Foo->find(1);
225 $obj->margle(10); # set margle; Bar object is created if it doesn't exist
229 Specifies the type of accessor that should be created for the relationship.
230 Valid values are C<single> (for when there is only a single related object),
231 C<multi> (when there can be many), and C<filter> (for when there is a single
232 related object, but you also want the relationship accessor to double as
233 a column accessor). For C<multi> accessors, an add_to_* method is also
234 created, which calls C<create_related> for the relationship.
240 sub add_relationship {
241 my ($self, $rel, $f_source_name, $cond, $attrs) = @_;
242 croak "Can't create relationship without join condition" unless $cond;
245 my %rels = %{ $self->_relationships };
246 $rels{$rel} = { class => $f_source_name,
247 source => $f_source_name,
250 $self->_relationships(\%rels);
254 # XXX disabled. doesn't work properly currently. skip in tests.
256 my $f_source = $self->schema->source($f_source_name);
258 eval "require $f_source_name;";
260 die $@ unless $@ =~ /Can't locate/;
262 $f_source = $f_source_name->result_source;
263 #my $s_class = ref($self->schema);
264 #$f_source_name =~ m/^${s_class}::(.*)$/;
265 #$self->schema->register_class(($1 || $f_source_name), $f_source_name);
266 #$f_source = $self->schema->source($f_source_name);
268 return unless $f_source; # Can't test rel without f_source
270 eval { $self->resolve_join($rel, 'me') };
272 if ($@) { # If the resolve failed, back out and re-throw the error
273 delete $rels{$rel}; #
274 $self->_relationships(\%rels);
275 croak "Error creating relationship $rel: $@";
280 =head2 relationships()
282 Returns all valid relationship names for this source
287 return keys %{shift->_relationships};
290 =head2 relationship_info($relname)
292 Returns the relationship information for the specified relationship name
296 sub relationship_info {
297 my ($self, $rel) = @_;
298 return $self->_relationships->{$rel};
301 =head2 has_relationship($rel)
303 Returns 1 if the source has a relationship of this name, 0 otherwise.
307 sub has_relationship {
308 my ($self, $rel) = @_;
309 return exists $self->_relationships->{$rel};
312 =head2 resolve_join($relation)
314 Returns the join structure required for the related result source
319 my ($self, $join, $alias) = @_;
320 if (ref $join eq 'ARRAY') {
321 return map { $self->resolve_join($_, $alias) } @$join;
322 } elsif (ref $join eq 'HASH') {
323 return map { $self->resolve_join($_, $alias),
324 $self->related_source($_)->resolve_join($join->{$_}, $_) }
326 } elsif (ref $join) {
327 croak ("No idea how to resolve join reftype ".ref $join);
329 my $rel_info = $self->relationship_info($join);
330 croak("No such relationship ${join}") unless $rel_info;
331 my $type = $rel_info->{attrs}{join_type} || '';
332 return [ { $join => $self->related_source($join)->from,
333 -join_type => $type },
334 $self->resolve_condition($rel_info->{cond}, $join, $alias) ];
338 =head2 resolve_condition($cond, $rel, $alias|$object)
340 Resolves the passed condition to a concrete query fragment. If given an alias,
341 returns a join condition; if given an object, inverts that object to produce
342 a related conditional from that object.
346 sub resolve_condition {
347 my ($self, $cond, $rel, $for) = @_;
349 if (ref $cond eq 'HASH') {
351 while (my ($k, $v) = each %{$cond}) {
352 # XXX should probably check these are valid columns
353 $k =~ s/^foreign\.// || croak "Invalid rel cond key ${k}";
354 $v =~ s/^self\.// || croak "Invalid rel cond val ${v}";
355 if (ref $for) { # Object
356 #warn "$self $k $for $v";
357 $ret{$k} = $for->get_column($v);
360 $ret{"${rel}.${k}"} = "${for}.${v}";
364 } elsif (ref $cond eq 'ARRAY') {
365 return [ map { $self->resolve_condition($_, $rel, $for) } @$cond ];
367 die("Can't handle this yet :(");
372 =head2 related_source($relname)
374 Returns the result source for the given relationship
379 my ($self, $rel) = @_;
380 return $self->schema->source($self->relationship_info($rel)->{source});
387 Matt S. Trout <mst@shadowcatsystems.co.uk>
391 You may distribute this code under the same terms as Perl itself.