Introduce columns_info, switch a large portion of the code over
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / ResultSource.pm
CommitLineData
9c992ba1 1package DBIx::Class::ResultSource;
2
3use strict;
4use warnings;
5
6use DBIx::Class::ResultSet;
aec3eff1 7use DBIx::Class::ResultSourceHandle;
1a58752c 8
9use DBIx::Class::Exception;
701da8c4 10use Carp::Clan qw/^DBIx::Class/;
ed7ab0f4 11use Try::Tiny;
6298a324 12use List::Util 'first';
fd323bf1 13use namespace::clean;
6da5894c 14
9c992ba1 15use base qw/DBIx::Class/;
9c992ba1 16
aa1088bf 17__PACKAGE__->mk_group_accessors('simple' => qw/_ordered_columns
18 _columns _primaries _unique_constraints name resultset_attributes
acbe81cf 19 schema from _relationships column_info_from_storage source_info
f89bb832 20 source_name sqlt_deploy_callback/);
aa1088bf 21
fac560c2 22__PACKAGE__->mk_group_accessors('component_class' => qw/resultset_class
b0dd0e03 23 result_class/);
9c992ba1 24
75d07914 25=head1 NAME
9c992ba1 26
27DBIx::Class::ResultSource - Result source object
28
29=head1 SYNOPSIS
30
16ccb4fe 31 # Create a table based result source, in a result class.
32
33 package MyDB::Schema::Result::Artist;
d88ecca6 34 use base qw/DBIx::Class::Core/;
16ccb4fe 35
16ccb4fe 36 __PACKAGE__->table('artist');
37 __PACKAGE__->add_columns(qw/ artistid name /);
38 __PACKAGE__->set_primary_key('artistid');
39 __PACKAGE__->has_many(cds => 'MyDB::Schema::Result::CD');
40
41 1;
42
43 # Create a query (view) based result source, in a result class
44 package MyDB::Schema::Result::Year2000CDs;
d88ecca6 45 use base qw/DBIx::Class::Core/;
16ccb4fe 46
d88ecca6 47 __PACKAGE__->load_components('InflateColumn::DateTime');
16ccb4fe 48 __PACKAGE__->table_class('DBIx::Class::ResultSource::View');
49
50 __PACKAGE__->table('year2000cds');
51 __PACKAGE__->result_source_instance->is_virtual(1);
52 __PACKAGE__->result_source_instance->view_definition(
53 "SELECT cdid, artist, title FROM cd WHERE year ='2000'"
54 );
55
56
9c992ba1 57=head1 DESCRIPTION
58
16ccb4fe 59A ResultSource is an object that represents a source of data for querying.
60
61This class is a base class for various specialised types of result
62sources, for example L<DBIx::Class::ResultSource::Table>. Table is the
63default result source type, so one is created for you when defining a
64result class as described in the synopsis above.
65
d88ecca6 66More specifically, the L<DBIx::Class::Core> base class pulls in the
67L<DBIx::Class::ResultSourceProxy::Table> component, which defines
68the L<table|DBIx::Class::ResultSourceProxy::Table/table> method.
69When called, C<table> creates and stores an instance of
16ccb4fe 70L<DBIx::Class::ResultSoure::Table>. Luckily, to use tables as result
71sources, you don't need to remember any of this.
72
73Result sources representing select queries, or views, can also be
74created, see L<DBIx::Class::ResultSource::View> for full details.
75
76=head2 Finding result source objects
77
78As mentioned above, a result source instance is created and stored for
79you when you define a L<Result Class|DBIx::Class::Manual::Glossary/Result Class>.
80
81You can retrieve the result source at runtime in the following ways:
82
83=over
84
85=item From a Schema object:
86
87 $schema->source($source_name);
88
89=item From a Row object:
9c992ba1 90
16ccb4fe 91 $row->result_source;
92
93=item From a ResultSet object:
94
95 $rs->result_source;
96
97=back
00be2e0b 98
9c992ba1 99=head1 METHODS
100
7eb4ecc8 101=pod
102
9c992ba1 103=cut
104
105sub new {
106 my ($class, $attrs) = @_;
107 $class = ref $class if ref $class;
04786a4c 108
6b051e14 109 my $new = bless { %{$attrs || {}} }, $class;
9c992ba1 110 $new->{resultset_class} ||= 'DBIx::Class::ResultSet';
5ac6a044 111 $new->{resultset_attributes} = { %{$new->{resultset_attributes} || {}} };
6da5894c 112 $new->{_ordered_columns} = [ @{$new->{_ordered_columns}||[]}];
113 $new->{_columns} = { %{$new->{_columns}||{}} };
114 $new->{_relationships} = { %{$new->{_relationships}||{}} };
9c992ba1 115 $new->{name} ||= "!!NAME NOT SET!!";
5afa2a15 116 $new->{_columns_info_loaded} ||= 0;
f89bb832 117 $new->{sqlt_deploy_callback} ||= "default_sqlt_deploy_hook";
9c992ba1 118 return $new;
119}
120
988bf309 121=pod
122
5ac6a044 123=head2 add_columns
124
391ccf38 125=over
126
127=item Arguments: @columns
128
129=item Return value: The ResultSource object
130
131=back
132
843f6bc1 133 $source->add_columns(qw/col1 col2 col3/);
5ac6a044 134
843f6bc1 135 $source->add_columns('col1' => \%col1_info, 'col2' => \%col2_info, ...);
5ac6a044 136
16ccb4fe 137Adds columns to the result source. If supplied colname => hashref
138pairs, uses the hashref as the L</column_info> for that column. Repeated
139calls of this method will add more columns, not replace them.
5ac6a044 140
5d9d9e87 141The column names given will be created as accessor methods on your
7e51afbf 142L<DBIx::Class::Row> objects. You can change the name of the accessor
5d9d9e87 143by supplying an L</accessor> in the column_info hash.
144
157ce0cf 145If a column name beginning with a plus sign ('+col1') is provided, the
146attributes provided will be merged with any existing attributes for the
147column, with the new attributes taking precedence in the case that an
fd323bf1 148attribute already exists. Using this without a hashref
157ce0cf 149(C<< $source->add_columns(qw/+col1 +col2/) >>) is legal, but useless --
150it does the same thing it would do without the plus.
151
2053ab2a 152The contents of the column_info are not set in stone. The following
153keys are currently recognised/used by DBIx::Class:
988bf309 154
155=over 4
156
75d07914 157=item accessor
988bf309 158
16ccb4fe 159 { accessor => '_name' }
160
161 # example use, replace standard accessor with one of your own:
162 sub name {
163 my ($self, $value) = @_;
164
165 die "Name cannot contain digits!" if($value =~ /\d/);
166 $self->_name($value);
167
168 return $self->_name();
169 }
170
5d9d9e87 171Use this to set the name of the accessor method for this column. If unset,
988bf309 172the name of the column will be used.
173
174=item data_type
175
16ccb4fe 176 { data_type => 'integer' }
177
178This contains the column type. It is automatically filled if you use the
179L<SQL::Translator::Producer::DBIx::Class::File> producer, or the
fd323bf1 180L<DBIx::Class::Schema::Loader> module.
988bf309 181
2053ab2a 182Currently there is no standard set of values for the data_type. Use
183whatever your database supports.
988bf309 184
185=item size
186
16ccb4fe 187 { size => 20 }
188
988bf309 189The length of your column, if it is a column type that can have a size
16ccb4fe 190restriction. This is currently only used to create tables from your
191schema, see L<DBIx::Class::Schema/deploy>.
988bf309 192
193=item is_nullable
194
16ccb4fe 195 { is_nullable => 1 }
196
197Set this to a true value for a columns that is allowed to contain NULL
198values, default is false. This is currently only used to create tables
199from your schema, see L<DBIx::Class::Schema/deploy>.
988bf309 200
201=item is_auto_increment
202
16ccb4fe 203 { is_auto_increment => 1 }
204
2053ab2a 205Set this to a true value for a column whose value is somehow
16ccb4fe 206automatically set, defaults to false. This is used to determine which
207columns to empty when cloning objects using
208L<DBIx::Class::Row/copy>. It is also used by
d7be2784 209L<DBIx::Class::Schema/deploy>.
988bf309 210
26a29815 211=item is_numeric
212
16ccb4fe 213 { is_numeric => 1 }
214
26a29815 215Set this to a true or false value (not C<undef>) to explicitly specify
216if this column contains numeric data. This controls how set_column
217decides whether to consider a column dirty after an update: if
0bad1823 218C<is_numeric> is true a numeric comparison C<< != >> will take place
26a29815 219instead of the usual C<eq>
220
221If not specified the storage class will attempt to figure this out on
222first access to the column, based on the column C<data_type>. The
223result will be cached in this attribute.
224
988bf309 225=item is_foreign_key
226
16ccb4fe 227 { is_foreign_key => 1 }
228
2053ab2a 229Set this to a true value for a column that contains a key from a
16ccb4fe 230foreign table, defaults to false. This is currently only used to
231create tables from your schema, see L<DBIx::Class::Schema/deploy>.
988bf309 232
233=item default_value
234
16ccb4fe 235 { default_value => \'now()' }
236
237Set this to the default value which will be inserted into a column by
238the database. Can contain either a value or a function (use a
4858fea7 239reference to a scalar e.g. C<\'now()'> if you want a function). This
16ccb4fe 240is currently only used to create tables from your schema, see
241L<DBIx::Class::Schema/deploy>.
988bf309 242
a4fcda00 243See the note on L<DBIx::Class::Row/new> for more information about possible
244issues related to db-side default values.
245
988bf309 246=item sequence
247
16ccb4fe 248 { sequence => 'my_table_seq' }
249
2053ab2a 250Set this on a primary key column to the name of the sequence used to
251generate a new key value. If not specified, L<DBIx::Class::PK::Auto>
252will attempt to retrieve the name of the sequence from the database
253automatically.
988bf309 254
838ef78d 255=item auto_nextval
256
ca791b95 257Set this to a true value for a column whose value is retrieved automatically
258from a sequence or function (if supported by your Storage driver.) For a
259sequence, if you do not use a trigger to get the nextval, you have to set the
260L</sequence> value as well.
261
262Also set this for MSSQL columns with the 'uniqueidentifier'
e1958268 263L<data_type|DBIx::Class::ResultSource/data_type> whose values you want to
264automatically generate using C<NEWID()>, unless they are a primary key in which
265case this will be done anyway.
838ef78d 266
190615a7 267=item extra
d7be2784 268
269This is used by L<DBIx::Class::Schema/deploy> and L<SQL::Translator>
190615a7 270to add extra non-generic data to the column. For example: C<< extra
d7be2784 271=> { unsigned => 1} >> is used by the MySQL producer to set an integer
272column to unsigned. For more details, see
273L<SQL::Translator::Producer::MySQL>.
274
988bf309 275=back
276
5ac6a044 277=head2 add_column
278
391ccf38 279=over
280
16ccb4fe 281=item Arguments: $colname, \%columninfo?
391ccf38 282
283=item Return value: 1/0 (true/false)
284
285=back
286
16ccb4fe 287 $source->add_column('col' => \%info);
5ac6a044 288
391ccf38 289Add a single column and optional column info. Uses the same column
290info keys as L</add_columns>.
5ac6a044 291
292=cut
293
9c992ba1 294sub add_columns {
295 my ($self, @cols) = @_;
8e04bf91 296 $self->_ordered_columns(\@cols) unless $self->_ordered_columns;
002a359a 297
20518cb4 298 my @added;
299 my $columns = $self->_columns;
9c992ba1 300 while (my $col = shift @cols) {
157ce0cf 301 my $column_info = {};
302 if ($col =~ s/^\+//) {
303 $column_info = $self->column_info($col);
304 }
305
8e04bf91 306 # If next entry is { ... } use that for the column info, if not
307 # use an empty hashref
157ce0cf 308 if (ref $cols[0]) {
309 my $new_info = shift(@cols);
310 %$column_info = (%$column_info, %$new_info);
311 }
20518cb4 312 push(@added, $col) unless exists $columns->{$col};
20518cb4 313 $columns->{$col} = $column_info;
9c992ba1 314 }
20518cb4 315 push @{ $self->_ordered_columns }, @added;
30126ac7 316 return $self;
9c992ba1 317}
318
b25e9fa0 319sub add_column { shift->add_columns(@_); } # DO NOT CHANGE THIS TO GLOB
9c992ba1 320
3842b955 321=head2 has_column
322
391ccf38 323=over
324
325=item Arguments: $colname
326
327=item Return value: 1/0 (true/false)
328
329=back
330
843f6bc1 331 if ($source->has_column($colname)) { ... }
988bf309 332
2053ab2a 333Returns true if the source has a column of this name, false otherwise.
988bf309 334
335=cut
9c992ba1 336
337sub has_column {
338 my ($self, $column) = @_;
339 return exists $self->_columns->{$column};
340}
341
87c4e602 342=head2 column_info
9c992ba1 343
391ccf38 344=over
345
346=item Arguments: $colname
347
348=item Return value: Hashref of info
349
350=back
351
843f6bc1 352 my $info = $source->column_info($col);
9c992ba1 353
391ccf38 354Returns the column metadata hashref for a column, as originally passed
16ccb4fe 355to L</add_columns>. See L</add_columns> above for information on the
356contents of the hashref.
9c992ba1 357
988bf309 358=cut
9c992ba1 359
360sub column_info {
361 my ($self, $column) = @_;
75d07914 362 $self->throw_exception("No such column $column")
701da8c4 363 unless exists $self->_columns->{$column};
52416317 364
75d07914 365 if ( ! $self->_columns->{$column}{data_type}
366 and ! $self->{_columns_info_loaded}
52416317 367 and $self->column_info_from_storage
368 and $self->schema and my $stor = $self->storage )
8e04bf91 369 {
370 $self->{_columns_info_loaded}++;
52b420dd 371
ed7ab0f4 372 # try for the case of storage without table
52b420dd 373 try {
52416317 374 my $info = $stor->columns_info_for( $self->from );
375 my $lc_info = { map
376 { (lc $_) => $info->{$_} }
377 ( keys %$info )
378 };
379
8e04bf91 380 foreach my $col ( keys %{$self->_columns} ) {
d51f93c8 381 $self->_columns->{$col} = {
382 %{ $self->_columns->{$col} },
383 %{ $info->{$col} || $lc_info->{lc $col} || {} }
384 };
a953d8d9 385 }
52b420dd 386 };
a953d8d9 387 }
52416317 388
9c992ba1 389 return $self->_columns->{$column};
390}
391
392=head2 columns
393
391ccf38 394=over
395
396=item Arguments: None
397
398=item Return value: Ordered list of column names
399
400=back
401
402 my @column_names = $source->columns;
20518cb4 403
391ccf38 404Returns all column names in the order they were declared to L</add_columns>.
87f0da6a 405
406=cut
9c992ba1 407
408sub columns {
8e04bf91 409 my $self = shift;
aa1088bf 410 $self->throw_exception(
411 "columns() is a read-only accessor, did you mean add_columns()?"
9851dada 412 ) if @_;
701da8c4 413 return @{$self->{_ordered_columns}||[]};
571dced3 414}
415
52416317 416=head2 columns_info
417
418=over
419
420=item Arguments: \@colnames ?
421
422=item Return value: Hashref of column name/info pairs
423
424=back
425
426 my $columns_info = $source->columns_info;
427
428Like L</column_info> but returns information for the requested columns. If
429the optional column-list arrayref is ommitted it returns info on all columns
430currently defined on the ResultSource via L</add_columns>.
431
432=cut
433
434sub columns_info {
435 my ($self, $columns) = @_;
436
437 my $colinfo = $self->_columns;
438
439 if (
440 first { ! $_->{data_type} } values %$colinfo
441 and
442 ! $self->{_columns_info_loaded}
443 and
444 $self->column_info_from_storage
445 and
446 $self->schema
447 and
448 my $stor = $self->storage
449 ) {
450 $self->{_columns_info_loaded}++;
451
452 # try for the case of storage without table
453 try {
454 my $info = $stor->columns_info_for( $self->from );
455 my $lc_info = { map
456 { (lc $_) => $info->{$_} }
457 ( keys %$info )
458 };
459
460 foreach my $col ( keys %$colinfo ) {
461 $colinfo->{$col} = {
462 %{ $colinfo->{$col} },
463 %{ $info->{$col} || $lc_info->{lc $col} || {} }
464 };
465 }
466 };
467 }
468
469 my %ret;
470
471 if ($columns) {
472 for (@$columns) {
473 if (my $inf = $colinfo->{$_}) {
474 $ret{$_} = $inf;
475 }
476 else {
477 $self->throw_exception( sprintf (
478 "No such column '%s' on source %s",
479 $_,
480 $self->source_name,
481 ));
482 }
483 }
484 }
485 else {
486 %ret = %$colinfo;
487 }
488
489 return \%ret;
490}
491
002a359a 492=head2 remove_columns
493
391ccf38 494=over
002a359a 495
391ccf38 496=item Arguments: @colnames
497
498=item Return value: undefined
499
500=back
501
502 $source->remove_columns(qw/col1 col2 col3/);
503
504Removes the given list of columns by name, from the result source.
505
506B<Warning>: Removing a column that is also used in the sources primary
507key, or in one of the sources unique constraints, B<will> result in a
508broken result source.
002a359a 509
510=head2 remove_column
511
391ccf38 512=over
513
514=item Arguments: $colname
515
516=item Return value: undefined
517
518=back
002a359a 519
391ccf38 520 $source->remove_column('col');
521
522Remove a single column by name from the result source, similar to
523L</remove_columns>.
524
525B<Warning>: Removing a column that is also used in the sources primary
526key, or in one of the sources unique constraints, B<will> result in a
527broken result source.
002a359a 528
529=cut
530
531sub remove_columns {
4738027b 532 my ($self, @to_remove) = @_;
002a359a 533
4738027b 534 my $columns = $self->_columns
535 or return;
002a359a 536
4738027b 537 my %to_remove;
538 for (@to_remove) {
a918d901 539 delete $columns->{$_};
4738027b 540 ++$to_remove{$_};
541 }
002a359a 542
4738027b 543 $self->_ordered_columns([ grep { not $to_remove{$_} } @{$self->_ordered_columns} ]);
002a359a 544}
545
b25e9fa0 546sub remove_column { shift->remove_columns(@_); } # DO NOT CHANGE THIS TO GLOB
002a359a 547
87c4e602 548=head2 set_primary_key
549
27f01d1f 550=over 4
551
ebc77b53 552=item Arguments: @cols
27f01d1f 553
391ccf38 554=item Return value: undefined
555
27f01d1f 556=back
87f0da6a 557
16ccb4fe 558Defines one or more columns as primary key for this source. Must be
391ccf38 559called after L</add_columns>.
87f0da6a 560
391ccf38 561Additionally, defines a L<unique constraint|add_unique_constraint>
562named C<primary>.
87f0da6a 563
90f250bc 564Note: you normally do want to define a primary key on your sources
565B<even if the underlying database table does not have a primary key>.
566See
0c1a4a15 567L<DBIx::Class::Manual::Intro/The Significance and Importance of Primary Keys>
90f250bc 568for more info.
988bf309 569
87f0da6a 570=cut
9c992ba1 571
572sub set_primary_key {
573 my ($self, @cols) = @_;
574 # check if primary key columns are valid columns
8e04bf91 575 foreach my $col (@cols) {
576 $self->throw_exception("No such column $col on table " . $self->name)
577 unless $self->has_column($col);
9c992ba1 578 }
579 $self->_primaries(\@cols);
87f0da6a 580
581 $self->add_unique_constraint(primary => \@cols);
9c992ba1 582}
583
87f0da6a 584=head2 primary_columns
585
391ccf38 586=over 4
587
588=item Arguments: None
589
590=item Return value: Ordered list of primary column names
591
592=back
593
594Read-only accessor which returns the list of primary keys, supplied by
595L</set_primary_key>.
30126ac7 596
87f0da6a 597=cut
9c992ba1 598
599sub primary_columns {
600 return @{shift->_primaries||[]};
601}
602
b1d8e3fd 603# a helper method that will automatically die with a descriptive message if
604# no pk is defined on the source in question. For internal use to save
605# on if @pks... boilerplate
e8fb771b 606sub _pri_cols {
607 my $self = shift;
608 my @pcols = $self->primary_columns
609 or $self->throw_exception (sprintf(
455a33cb 610 "Operation requires a primary key to be declared on '%s' via set_primary_key",
7f505c17 611 # source_name is set only after schema-registration
612 $self->source_name || $self->result_class || $self->name || 'Unknown source...?',
e8fb771b 613 ));
614 return @pcols;
615}
616
89170201 617=head2 sequence
618
619Manually define the correct sequence for your table, to avoid the overhead
620associated with looking up the sequence automatically. The supplied sequence
621will be applied to the L</column_info> of each L<primary_key|/set_primary_key>
622
623=over 4
624
625=item Arguments: $sequence_name
626
627=item Return value: undefined
628
629=back
630
631=cut
632
633sub sequence {
52416317 634 my ($self,$seq) = @_;
635
636 my $rsrc = $self->result_source;
637 my @pks = $rsrc->primary_columns
638 or next;
639
640 $_->{sequence} = $seq
641 for values %{ $rsrc->columns_info (\@pks) };
89170201 642}
643
644
87f0da6a 645=head2 add_unique_constraint
646
391ccf38 647=over 4
648
16ccb4fe 649=item Arguments: $name?, \@colnames
391ccf38 650
651=item Return value: undefined
652
653=back
654
87f0da6a 655Declare a unique constraint on this source. Call once for each unique
58b5bb8c 656constraint.
27f01d1f 657
658 # For UNIQUE (column1, column2)
659 __PACKAGE__->add_unique_constraint(
660 constraint_name => [ qw/column1 column2/ ],
661 );
87f0da6a 662
368a5228 663Alternatively, you can specify only the columns:
664
665 __PACKAGE__->add_unique_constraint([ qw/column1 column2/ ]);
666
16ccb4fe 667This will result in a unique constraint named
668C<table_column1_column2>, where C<table> is replaced with the table
669name.
368a5228 670
16ccb4fe 671Unique constraints are used, for example, when you pass the constraint
672name as the C<key> attribute to L<DBIx::Class::ResultSet/find>. Then
673only columns in the constraint are searched.
58b5bb8c 674
391ccf38 675Throws an error if any of the given column names do not yet exist on
676the result source.
677
87f0da6a 678=cut
679
680sub add_unique_constraint {
368a5228 681 my $self = shift;
034d0be4 682
683 if (@_ > 2) {
684 $self->throw_exception(
685 'add_unique_constraint() does not accept multiple constraints, use '
686 . 'add_unique_constraints() instead'
687 );
688 }
689
368a5228 690 my $cols = pop @_;
034d0be4 691 if (ref $cols ne 'ARRAY') {
692 $self->throw_exception (
693 'Expecting an arrayref of constraint columns, got ' . ($cols||'NOTHING')
694 );
695 }
696
697 my $name = shift @_;
368a5228 698
699 $name ||= $self->name_unique_constraint($cols);
87f0da6a 700
8e04bf91 701 foreach my $col (@$cols) {
702 $self->throw_exception("No such column $col on table " . $self->name)
703 unless $self->has_column($col);
87f0da6a 704 }
705
706 my %unique_constraints = $self->unique_constraints;
707 $unique_constraints{$name} = $cols;
708 $self->_unique_constraints(\%unique_constraints);
709}
710
034d0be4 711=head2 add_unique_constraints
712
713=over 4
714
715=item Arguments: @constraints
716
717=item Return value: undefined
718
719=back
720
721Declare multiple unique constraints on this source.
722
723 __PACKAGE__->add_unique_constraints(
724 constraint_name1 => [ qw/column1 column2/ ],
725 constraint_name2 => [ qw/column2 column3/ ],
726 );
727
728Alternatively, you can specify only the columns:
729
730 __PACKAGE__->add_unique_constraints(
731 [ qw/column1 column2/ ],
732 [ qw/column3 column4/ ]
733 );
734
735This will result in unique constraints named C<table_column1_column2> and
736C<table_column3_column4>, where C<table> is replaced with the table name.
737
738Throws an error if any of the given column names do not yet exist on
739the result source.
740
741See also L</add_unique_constraint>.
742
743=cut
744
745sub add_unique_constraints {
746 my $self = shift;
747 my @constraints = @_;
748
749 if ( !(@constraints % 2) && first { ref $_ ne 'ARRAY' } @constraints ) {
750 # with constraint name
751 while (my ($name, $constraint) = splice @constraints, 0, 2) {
752 $self->add_unique_constraint($name => $constraint);
753 }
754 }
755 else {
756 # no constraint name
757 foreach my $constraint (@constraints) {
758 $self->add_unique_constraint($constraint);
759 }
760 }
761}
762
d9c74322 763=head2 name_unique_constraint
368a5228 764
391ccf38 765=over 4
766
6515609b 767=item Arguments: \@colnames
391ccf38 768
769=item Return value: Constraint name
770
771=back
772
773 $source->table('mytable');
6515609b 774 $source->name_unique_constraint(['col1', 'col2']);
391ccf38 775 # returns
776 'mytable_col1_col2'
777
778Return a name for a unique constraint containing the specified
779columns. The name is created by joining the table name and each column
780name, using an underscore character.
368a5228 781
782For example, a constraint on a table named C<cd> containing the columns
783C<artist> and C<title> would result in a constraint name of C<cd_artist_title>.
784
391ccf38 785This is used by L</add_unique_constraint> if you do not specify the
786optional constraint name.
787
368a5228 788=cut
789
790sub name_unique_constraint {
791 my ($self, $cols) = @_;
792
3e6c1131 793 my $name = $self->name;
4678e9da 794 $name = $$name if (ref $name eq 'SCALAR');
3e6c1131 795
796 return join '_', $name, @$cols;
368a5228 797}
798
87f0da6a 799=head2 unique_constraints
800
391ccf38 801=over 4
802
803=item Arguments: None
804
805=item Return value: Hash of unique constraint data
806
807=back
808
809 $source->unique_constraints();
810
16ccb4fe 811Read-only accessor which returns a hash of unique constraints on this
812source.
391ccf38 813
814The hash is keyed by constraint name, and contains an arrayref of
815column names as values.
87f0da6a 816
817=cut
818
819sub unique_constraints {
820 return %{shift->_unique_constraints||{}};
821}
822
e6a0e17c 823=head2 unique_constraint_names
824
391ccf38 825=over 4
826
827=item Arguments: None
828
829=item Return value: Unique constraint names
830
831=back
832
833 $source->unique_constraint_names();
834
e6a0e17c 835Returns the list of unique constraint names defined on this source.
836
837=cut
838
839sub unique_constraint_names {
840 my ($self) = @_;
841
842 my %unique_constraints = $self->unique_constraints;
843
844 return keys %unique_constraints;
845}
846
847=head2 unique_constraint_columns
848
391ccf38 849=over 4
850
851=item Arguments: $constraintname
852
853=item Return value: List of constraint columns
854
855=back
856
857 $source->unique_constraint_columns('myconstraint');
858
e6a0e17c 859Returns the list of columns that make up the specified unique constraint.
860
861=cut
862
863sub unique_constraint_columns {
864 my ($self, $constraint_name) = @_;
865
866 my %unique_constraints = $self->unique_constraints;
867
868 $self->throw_exception(
869 "Unknown unique constraint $constraint_name on '" . $self->name . "'"
870 ) unless exists $unique_constraints{$constraint_name};
871
872 return @{ $unique_constraints{$constraint_name} };
873}
874
880c075b 875=head2 sqlt_deploy_callback
876
877=over
878
879=item Arguments: $callback
880
881=back
882
883 __PACKAGE__->sqlt_deploy_callback('mycallbackmethod');
884
885An accessor to set a callback to be called during deployment of
886the schema via L<DBIx::Class::Schema/create_ddl_dir> or
887L<DBIx::Class::Schema/deploy>.
888
889The callback can be set as either a code reference or the name of a
890method in the current result class.
891
892If not set, the L</default_sqlt_deploy_hook> is called.
893
894Your callback will be passed the $source object representing the
895ResultSource instance being deployed, and the
896L<SQL::Translator::Schema::Table> object being created from it. The
897callback can be used to manipulate the table object or add your own
898customised indexes. If you need to manipulate a non-table object, use
899the L<DBIx::Class::Schema/sqlt_deploy_hook>.
900
901See L<DBIx::Class::Manual::Cookbook/Adding Indexes And Functions To
902Your SQL> for examples.
903
904This sqlt deployment callback can only be used to manipulate
905SQL::Translator objects as they get turned into SQL. To execute
906post-deploy statements which SQL::Translator does not currently
907handle, override L<DBIx::Class::Schema/deploy> in your Schema class
908and call L<dbh_do|DBIx::Class::Storage::DBI/dbh_do>.
909
910=head2 default_sqlt_deploy_hook
911
912=over
913
914=item Arguments: $source, $sqlt_table
915
916=item Return value: undefined
917
918=back
919
920This is the sensible default for L</sqlt_deploy_callback>.
921
922If a method named C<sqlt_deploy_hook> exists in your Result class, it
923will be called and passed the current C<$source> and the
924C<$sqlt_table> being deployed.
925
926=cut
927
928sub default_sqlt_deploy_hook {
929 my $self = shift;
930
931 my $class = $self->result_class;
932
933 if ($class and $class->can('sqlt_deploy_hook')) {
934 $class->sqlt_deploy_hook(@_);
935 }
936}
937
938sub _invoke_sqlt_deploy_hook {
939 my $self = shift;
940 if ( my $hook = $self->sqlt_deploy_callback) {
941 $self->$hook(@_);
942 }
943}
944
843f6bc1 945=head2 resultset
946
947=over 4
948
949=item Arguments: None
950
951=item Return value: $resultset
952
953=back
954
955Returns a resultset for the given source. This will initially be created
956on demand by calling
957
958 $self->resultset_class->new($self, $self->resultset_attributes)
959
960but is cached from then on unless resultset_class changes.
961
962=head2 resultset_class
963
964=over 4
965
966=item Arguments: $classname
967
968=item Return value: $classname
969
970=back
971
16ccb4fe 972 package My::Schema::ResultSet::Artist;
843f6bc1 973 use base 'DBIx::Class::ResultSet';
974 ...
975
16ccb4fe 976 # In the result class
977 __PACKAGE__->resultset_class('My::Schema::ResultSet::Artist');
978
979 # Or in code
980 $source->resultset_class('My::Schema::ResultSet::Artist');
843f6bc1 981
7e51afbf 982Set the class of the resultset. This is useful if you want to create your
843f6bc1 983own resultset methods. Create your own class derived from
984L<DBIx::Class::ResultSet>, and set it here. If called with no arguments,
985this method returns the name of the existing resultset class, if one
986exists.
987
988=head2 resultset_attributes
989
990=over 4
991
992=item Arguments: \%attrs
993
994=item Return value: \%attrs
995
996=back
997
16ccb4fe 998 # In the result class
999 __PACKAGE__->resultset_attributes({ order_by => [ 'id' ] });
1000
1001 # Or in code
843f6bc1 1002 $source->resultset_attributes({ order_by => [ 'id' ] });
1003
1004Store a collection of resultset attributes, that will be set on every
1005L<DBIx::Class::ResultSet> produced from this result source. For a full
1006list see L<DBIx::Class::ResultSet/ATTRIBUTES>.
1007
1008=cut
1009
1010sub resultset {
1011 my $self = shift;
1012 $self->throw_exception(
1013 'resultset does not take any arguments. If you want another resultset, '.
1014 'call it on the schema instead.'
1015 ) if scalar @_;
1016
1017 return $self->resultset_class->new(
1018 $self,
1019 {
1020 %{$self->{resultset_attributes}},
1021 %{$self->schema->default_resultset_attributes}
1022 },
1023 );
1024}
1025
1026=head2 source_name
1027
1028=over 4
1029
1030=item Arguments: $source_name
1031
1032=item Result value: $source_name
1033
1034=back
1035
1036Set an alternate name for the result source when it is loaded into a schema.
1037This is useful if you want to refer to a result source by a name other than
1038its class name.
1039
1040 package ArchivedBooks;
1041 use base qw/DBIx::Class/;
1042 __PACKAGE__->table('books_archive');
1043 __PACKAGE__->source_name('Books');
1044
1045 # from your schema...
1046 $schema->resultset('Books')->find(1);
1047
9c992ba1 1048=head2 from
1049
391ccf38 1050=over 4
1051
1052=item Arguments: None
1053
1054=item Return value: FROM clause
1055
1056=back
1057
1058 my $from_clause = $source->from();
1059
9c992ba1 1060Returns an expression of the source to be supplied to storage to specify
2053ab2a 1061retrieval from this source. In the case of a database, the required FROM
1062clause contents.
9c992ba1 1063
f9b7bd6e 1064=head2 schema
1065
391ccf38 1066=over 4
1067
1068=item Arguments: None
1069
1070=item Return value: A schema object
1071
1072=back
1073
1074 my $schema = $source->schema();
1075
fd323bf1 1076Returns the L<DBIx::Class::Schema> object that this result source
391ccf38 1077belongs to.
9c992ba1 1078
1079=head2 storage
1080
391ccf38 1081=over 4
1082
1083=item Arguments: None
1084
1085=item Return value: A Storage object
1086
1087=back
1088
1089 $source->storage->debug(1);
1090
75d07914 1091Returns the storage handle for the current schema.
988bf309 1092
1093See also: L<DBIx::Class::Storage>
9c992ba1 1094
1095=cut
1096
1097sub storage { shift->schema->storage; }
1098
8452e496 1099=head2 add_relationship
1100
391ccf38 1101=over 4
1102
1103=item Arguments: $relname, $related_source_name, \%cond, [ \%attrs ]
1104
1105=item Return value: 1/true if it succeeded
1106
1107=back
1108
8452e496 1109 $source->add_relationship('relname', 'related_source', $cond, $attrs);
1110
391ccf38 1111L<DBIx::Class::Relationship> describes a series of methods which
1112create pre-defined useful types of relationships. Look there first
1113before using this method directly.
1114
24d67825 1115The relationship name can be arbitrary, but must be unique for each
1116relationship attached to this result source. 'related_source' should
1117be the name with which the related result source was registered with
1118the current schema. For example:
8452e496 1119
24d67825 1120 $schema->source('Book')->add_relationship('reviews', 'Review', {
1121 'foreign.book_id' => 'self.id',
1122 });
1123
2053ab2a 1124The condition C<$cond> needs to be an L<SQL::Abstract>-style
24d67825 1125representation of the join between the tables. For example, if you're
391ccf38 1126creating a relation from Author to Book,
988bf309 1127
1128 { 'foreign.author_id' => 'self.id' }
1129
1130will result in the JOIN clause
1131
1132 author me JOIN book foreign ON foreign.author_id = me.id
1133
8452e496 1134You can specify as many foreign => self mappings as necessary.
1135
988bf309 1136Valid attributes are as follows:
1137
1138=over 4
1139
1140=item join_type
1141
1142Explicitly specifies the type of join to use in the relationship. Any
1143SQL join type is valid, e.g. C<LEFT> or C<RIGHT>. It will be placed in
1144the SQL command immediately before C<JOIN>.
1145
1146=item proxy
1147
24d67825 1148An arrayref containing a list of accessors in the foreign class to proxy in
1149the main class. If, for example, you do the following:
002a359a 1150
24d67825 1151 CD->might_have(liner_notes => 'LinerNotes', undef, {
1152 proxy => [ qw/notes/ ],
1153 });
002a359a 1154
24d67825 1155Then, assuming LinerNotes has an accessor named notes, you can do:
988bf309 1156
24d67825 1157 my $cd = CD->find(1);
2053ab2a 1158 # set notes -- LinerNotes object is created if it doesn't exist
1159 $cd->notes('Notes go here');
988bf309 1160
1161=item accessor
1162
1163Specifies the type of accessor that should be created for the
75d07914 1164relationship. Valid values are C<single> (for when there is only a single
1165related object), C<multi> (when there can be many), and C<filter> (for
1166when there is a single related object, but you also want the relationship
1167accessor to double as a column accessor). For C<multi> accessors, an
1168add_to_* method is also created, which calls C<create_related> for the
988bf309 1169relationship.
1170
8452e496 1171=back
1172
391ccf38 1173Throws an exception if the condition is improperly supplied, or cannot
6d0ee587 1174be resolved.
391ccf38 1175
8452e496 1176=cut
1177
1178sub add_relationship {
1179 my ($self, $rel, $f_source_name, $cond, $attrs) = @_;
27f01d1f 1180 $self->throw_exception("Can't create relationship without join condition")
1181 unless $cond;
8452e496 1182 $attrs ||= {};
87772e46 1183
eba322a7 1184 # Check foreign and self are right in cond
1185 if ( (ref $cond ||'') eq 'HASH') {
1186 for (keys %$cond) {
1187 $self->throw_exception("Keys of condition should be of form 'foreign.col', not '$_'")
1188 if /\./ && !/^foreign\./;
1189 }
1190 }
1191
8452e496 1192 my %rels = %{ $self->_relationships };
1193 $rels{$rel} = { class => $f_source_name,
87772e46 1194 source => $f_source_name,
8452e496 1195 cond => $cond,
1196 attrs => $attrs };
1197 $self->_relationships(\%rels);
1198
30126ac7 1199 return $self;
87772e46 1200
52b420dd 1201# XXX disabled. doesn't work properly currently. skip in tests.
953a18ef 1202
8452e496 1203 my $f_source = $self->schema->source($f_source_name);
1204 unless ($f_source) {
c037c03a 1205 $self->ensure_class_loaded($f_source_name);
8452e496 1206 $f_source = $f_source_name->result_source;
87772e46 1207 #my $s_class = ref($self->schema);
1208 #$f_source_name =~ m/^${s_class}::(.*)$/;
1209 #$self->schema->register_class(($1 || $f_source_name), $f_source_name);
1210 #$f_source = $self->schema->source($f_source_name);
8452e496 1211 }
1212 return unless $f_source; # Can't test rel without f_source
1213
ed7ab0f4 1214 try { $self->_resolve_join($rel, 'me', {}, []) }
1215 catch {
1216 # If the resolve failed, back out and re-throw the error
52b420dd 1217 delete $rels{$rel};
8452e496 1218 $self->_relationships(\%rels);
ed7ab0f4 1219 $self->throw_exception("Error creating relationship $rel: $_");
1220 };
52b420dd 1221
8452e496 1222 1;
1223}
1224
87c4e602 1225=head2 relationships
8452e496 1226
391ccf38 1227=over 4
1228
1229=item Arguments: None
1230
1231=item Return value: List of relationship names
1232
1233=back
1234
1235 my @relnames = $source->relationships();
1236
2053ab2a 1237Returns all relationship names for this source.
8452e496 1238
1239=cut
1240
1241sub relationships {
1242 return keys %{shift->_relationships};
1243}
1244
87c4e602 1245=head2 relationship_info
1246
27f01d1f 1247=over 4
1248
ebc77b53 1249=item Arguments: $relname
27f01d1f 1250
391ccf38 1251=item Return value: Hashref of relation data,
1252
27f01d1f 1253=back
8452e496 1254
2053ab2a 1255Returns a hash of relationship information for the specified relationship
391ccf38 1256name. The keys/values are as specified for L</add_relationship>.
8452e496 1257
1258=cut
1259
1260sub relationship_info {
1261 my ($self, $rel) = @_;
1262 return $self->_relationships->{$rel};
75d07914 1263}
8452e496 1264
87c4e602 1265=head2 has_relationship
1266
27f01d1f 1267=over 4
1268
ebc77b53 1269=item Arguments: $rel
27f01d1f 1270
391ccf38 1271=item Return value: 1/0 (true/false)
1272
27f01d1f 1273=back
953a18ef 1274
2053ab2a 1275Returns true if the source has a relationship of this name, false otherwise.
988bf309 1276
1277=cut
953a18ef 1278
1279sub has_relationship {
1280 my ($self, $rel) = @_;
1281 return exists $self->_relationships->{$rel};
1282}
1283
de60a93d 1284=head2 reverse_relationship_info
1285
1286=over 4
1287
1288=item Arguments: $relname
1289
391ccf38 1290=item Return value: Hashref of relationship data
1291
de60a93d 1292=back
1293
391ccf38 1294Looks through all the relationships on the source this relationship
1295points to, looking for one whose condition is the reverse of the
1296condition on this relationship.
1297
1298A common use of this is to find the name of the C<belongs_to> relation
1299opposing a C<has_many> relation. For definition of these look in
1300L<DBIx::Class::Relationship>.
1301
1302The returned hashref is keyed by the name of the opposing
faaba25f 1303relationship, and contains its data in the same manner as
391ccf38 1304L</relationship_info>.
de60a93d 1305
1306=cut
1307
1308sub reverse_relationship_info {
1309 my ($self, $rel) = @_;
1310 my $rel_info = $self->relationship_info($rel);
1311 my $ret = {};
1312
1313 return $ret unless ((ref $rel_info->{cond}) eq 'HASH');
1314
1315 my @cond = keys(%{$rel_info->{cond}});
1316 my @refkeys = map {/^\w+\.(\w+)$/} @cond;
1317 my @keys = map {$rel_info->{cond}->{$_} =~ /^\w+\.(\w+)$/} @cond;
bab77431 1318
de60a93d 1319 # Get the related result source for this relationship
1320 my $othertable = $self->related_source($rel);
1321
1322 # Get all the relationships for that source that related to this source
1323 # whose foreign column set are our self columns on $rel and whose self
bab77431 1324 # columns are our foreign columns on $rel.
de60a93d 1325 my @otherrels = $othertable->relationships();
1326 my $otherrelationship;
1327 foreach my $otherrel (@otherrels) {
1328 my $otherrel_info = $othertable->relationship_info($otherrel);
1329
1330 my $back = $othertable->related_source($otherrel);
f3fb2641 1331 next unless $back->source_name eq $self->source_name;
de60a93d 1332
1333 my @othertestconds;
1334
1335 if (ref $otherrel_info->{cond} eq 'HASH') {
1336 @othertestconds = ($otherrel_info->{cond});
1337 }
1338 elsif (ref $otherrel_info->{cond} eq 'ARRAY') {
1339 @othertestconds = @{$otherrel_info->{cond}};
1340 }
1341 else {
1342 next;
1343 }
1344
1345 foreach my $othercond (@othertestconds) {
1346 my @other_cond = keys(%$othercond);
1347 my @other_refkeys = map {/^\w+\.(\w+)$/} @other_cond;
1348 my @other_keys = map {$othercond->{$_} =~ /^\w+\.(\w+)$/} @other_cond;
6d0ee587 1349 next if (!$self->_compare_relationship_keys(\@refkeys, \@other_keys) ||
1350 !$self->_compare_relationship_keys(\@other_refkeys, \@keys));
de60a93d 1351 $ret->{$otherrel} = $otherrel_info;
1352 }
1353 }
1354 return $ret;
1355}
1356
de60a93d 1357sub compare_relationship_keys {
6d0ee587 1358 carp 'compare_relationship_keys is a private method, stop calling it';
1359 my $self = shift;
1360 $self->_compare_relationship_keys (@_);
1361}
1362
1363# Returns true if both sets of keynames are the same, false otherwise.
1364sub _compare_relationship_keys {
de60a93d 1365 my ($self, $keys1, $keys2) = @_;
1366
1367 # Make sure every keys1 is in keys2
1368 my $found;
1369 foreach my $key (@$keys1) {
1370 $found = 0;
1371 foreach my $prim (@$keys2) {
1372 if ($prim eq $key) {
1373 $found = 1;
1374 last;
1375 }
1376 }
1377 last unless $found;
1378 }
1379
1380 # Make sure every key2 is in key1
1381 if ($found) {
1382 foreach my $prim (@$keys2) {
1383 $found = 0;
1384 foreach my $key (@$keys1) {
1385 if ($prim eq $key) {
1386 $found = 1;
1387 last;
1388 }
1389 }
1390 last unless $found;
1391 }
1392 }
1393
1394 return $found;
1395}
1396
6d0ee587 1397# Returns the {from} structure used to express JOIN conditions
1398sub _resolve_join {
8a3fa4ae 1399 my ($self, $join, $alias, $seen, $jpath, $parent_force_left) = @_;
1979278e 1400
1401 # we need a supplied one, because we do in-place modifications, no returns
6d0ee587 1402 $self->throw_exception ('You must supply a seen hashref as the 3rd argument to _resolve_join')
88a66388 1403 unless ref $seen eq 'HASH';
1979278e 1404
88a66388 1405 $self->throw_exception ('You must supply a joinpath arrayref as the 4th argument to _resolve_join')
1406 unless ref $jpath eq 'ARRAY';
1407
38f42d85 1408 $jpath = [@$jpath]; # copy
1979278e 1409
8a3fa4ae 1410 if (not defined $join) {
1411 return ();
1412 }
1413 elsif (ref $join eq 'ARRAY') {
caac1708 1414 return
1415 map {
8a3fa4ae 1416 $self->_resolve_join($_, $alias, $seen, $jpath, $parent_force_left);
caac1708 1417 } @$join;
8a3fa4ae 1418 }
1419 elsif (ref $join eq 'HASH') {
1420
1421 my @ret;
1422 for my $rel (keys %$join) {
1423
1424 my $rel_info = $self->relationship_info($rel)
455a33cb 1425 or $self->throw_exception("No such relationship '$rel' on " . $self->source_name);
8a3fa4ae 1426
1427 my $force_left = $parent_force_left;
1428 $force_left ||= lc($rel_info->{attrs}{join_type}||'') eq 'left';
1429
1430 # the actual seen value will be incremented by the recursion
6c0230de 1431 my $as = $self->storage->relname_to_table_alias(
1432 $rel, ($seen->{$rel} && $seen->{$rel} + 1)
1433 );
1979278e 1434
8a3fa4ae 1435 push @ret, (
1436 $self->_resolve_join($rel, $alias, $seen, [@$jpath], $force_left),
1437 $self->related_source($rel)->_resolve_join(
38f42d85 1438 $join->{$rel}, $as, $seen, [@$jpath, { $rel => $as }], $force_left
8a3fa4ae 1439 )
1440 );
1441 }
1442 return @ret;
096395af 1443
8a3fa4ae 1444 }
1445 elsif (ref $join) {
1446 $self->throw_exception("No idea how to resolve join reftype ".ref $join);
1447 }
1448 else {
489709af 1449 my $count = ++$seen->{$join};
6c0230de 1450 my $as = $self->storage->relname_to_table_alias(
1451 $join, ($count > 1 && $count)
1452 );
1979278e 1453
8a3fa4ae 1454 my $rel_info = $self->relationship_info($join)
455a33cb 1455 or $self->throw_exception("No such relationship $join on " . $self->source_name);
ba61fa2a 1456
1457 my $rel_src = $self->related_source($join);
1458 return [ { $as => $rel_src->from,
35ec0366 1459 -source_handle => $rel_src->handle,
8a3fa4ae 1460 -join_type => $parent_force_left
1461 ? 'left'
1462 : $rel_info->{attrs}{join_type}
1463 ,
38f42d85 1464 -join_path => [@$jpath, { $join => $as } ],
b82c8a28 1465 -is_single => (
1466 $rel_info->{attrs}{accessor}
1467 &&
6298a324 1468 first { $rel_info->{attrs}{accessor} eq $_ } (qw/single filter/)
b82c8a28 1469 ),
ba61fa2a 1470 -alias => $as,
1979278e 1471 -relation_chain_depth => $seen->{-relation_chain_depth} || 0,
1472 },
6d0ee587 1473 $self->_resolve_condition($rel_info->{cond}, $as, $alias) ];
953a18ef 1474 }
1475}
1476
370f2ba2 1477sub pk_depends_on {
6d0ee587 1478 carp 'pk_depends_on is a private method, stop calling it';
1479 my $self = shift;
1480 $self->_pk_depends_on (@_);
1481}
1482
1483# Determines whether a relation is dependent on an object from this source
1484# having already been inserted. Takes the name of the relationship and a
1485# hashref of columns of the related object.
1486sub _pk_depends_on {
370f2ba2 1487 my ($self, $relname, $rel_data) = @_;
370f2ba2 1488
c39b48e5 1489 my $relinfo = $self->relationship_info($relname);
1490
1491 # don't assume things if the relationship direction is specified
1492 return $relinfo->{attrs}{is_foreign_key_constraint}
1493 if exists ($relinfo->{attrs}{is_foreign_key_constraint});
1494
1495 my $cond = $relinfo->{cond};
370f2ba2 1496 return 0 unless ref($cond) eq 'HASH';
1497
1498 # map { foreign.foo => 'self.bar' } to { bar => 'foo' }
370f2ba2 1499 my $keyhash = { map { my $x = $_; $x =~ s/.*\.//; $x; } reverse %$cond };
1500
1501 # assume anything that references our PK probably is dependent on us
1502 # rather than vice versa, unless the far side is (a) defined or (b)
1503 # auto-increment
370f2ba2 1504 my $rel_source = $self->related_source($relname);
1505
1506 foreach my $p ($self->primary_columns) {
1507 if (exists $keyhash->{$p}) {
1508 unless (defined($rel_data->{$keyhash->{$p}})
1509 || $rel_source->column_info($keyhash->{$p})
1510 ->{is_auto_increment}) {
1511 return 0;
1512 }
1513 }
1514 }
1515
1516 return 1;
1517}
1518
6d0ee587 1519sub resolve_condition {
1520 carp 'resolve_condition is a private method, stop calling it';
1521 my $self = shift;
1522 $self->_resolve_condition (@_);
1523}
953a18ef 1524
6d0ee587 1525# Resolves the passed condition to a concrete query fragment. If given an alias,
1526# returns a join condition; if given an object, inverts that object to produce
1527# a related conditional from that object.
8c368cf3 1528our $UNRESOLVABLE_CONDITION = \'1 = 0';
1529
6d0ee587 1530sub _resolve_condition {
489709af 1531 my ($self, $cond, $as, $for) = @_;
953a18ef 1532 if (ref $cond eq 'HASH') {
1533 my %ret;
bd054cb4 1534 foreach my $k (keys %{$cond}) {
1535 my $v = $cond->{$k};
953a18ef 1536 # XXX should probably check these are valid columns
27f01d1f 1537 $k =~ s/^foreign\.// ||
75d07914 1538 $self->throw_exception("Invalid rel cond key ${k}");
27f01d1f 1539 $v =~ s/^self\.// ||
75d07914 1540 $self->throw_exception("Invalid rel cond val ${v}");
953a18ef 1541 if (ref $for) { # Object
3842b955 1542 #warn "$self $k $for $v";
370f2ba2 1543 unless ($for->has_column_loaded($v)) {
1544 if ($for->in_storage) {
8bbfe6b2 1545 $self->throw_exception(sprintf
5c89c897 1546 "Unable to resolve relationship '%s' from object %s: column '%s' not "
1547 . 'loaded from storage (or not passed to new() prior to insert()). You '
1548 . 'probably need to call ->discard_changes to get the server-side defaults '
1549 . 'from the database.',
8bbfe6b2 1550 $as,
971beb94 1551 $for,
5c89c897 1552 $v,
a4fcda00 1553 );
370f2ba2 1554 }
68f3b0dd 1555 return $UNRESOLVABLE_CONDITION;
370f2ba2 1556 }
1557 $ret{$k} = $for->get_column($v);
1558 #$ret{$k} = $for->get_column($v) if $for->has_column_loaded($v);
3842b955 1559 #warn %ret;
2c037e6b 1560 } elsif (!defined $for) { # undef, i.e. "no object"
1561 $ret{$k} = undef;
2ec8e594 1562 } elsif (ref $as eq 'HASH') { # reverse hashref
1563 $ret{$v} = $as->{$k};
fde6e28e 1564 } elsif (ref $as) { # reverse object
1565 $ret{$v} = $as->get_column($k);
2c037e6b 1566 } elsif (!defined $as) { # undef, i.e. "no reverse object"
1567 $ret{$v} = undef;
953a18ef 1568 } else {
489709af 1569 $ret{"${as}.${k}"} = "${for}.${v}";
953a18ef 1570 }
953a18ef 1571 }
1572 return \%ret;
5efe4c79 1573 } elsif (ref $cond eq 'ARRAY') {
6d0ee587 1574 return [ map { $self->_resolve_condition($_, $as, $for) } @$cond ];
953a18ef 1575 } else {
35c77aa3 1576 die("Can't handle condition $cond yet :(");
87772e46 1577 }
1578}
1579
988bf309 1580
6d0ee587 1581# Accepts one or more relationships for the current source and returns an
1582# array of column names for each of those relationships. Column names are
1583# prefixed relative to the current source, in accordance with where they appear
38f42d85 1584# in the supplied relationships.
b3e8ac9b 1585
6d0ee587 1586sub _resolve_prefetch {
1979278e 1587 my ($self, $pre, $alias, $alias_map, $order, $collapse, $pref_path) = @_;
1588 $pref_path ||= [];
1589
8a3fa4ae 1590 if (not defined $pre) {
1591 return ();
1592 }
1593 elsif( ref $pre eq 'ARRAY' ) {
0f66a01b 1594 return
6d0ee587 1595 map { $self->_resolve_prefetch( $_, $alias, $alias_map, $order, $collapse, [ @$pref_path ] ) }
0f66a01b 1596 @$pre;
b3e8ac9b 1597 }
1598 elsif( ref $pre eq 'HASH' ) {
1599 my @ret =
1600 map {
6d0ee587 1601 $self->_resolve_prefetch($_, $alias, $alias_map, $order, $collapse, [ @$pref_path ] ),
1602 $self->related_source($_)->_resolve_prefetch(
1979278e 1603 $pre->{$_}, "${alias}.$_", $alias_map, $order, $collapse, [ @$pref_path, $_] )
0f66a01b 1604 } keys %$pre;
b3e8ac9b 1605 return @ret;
1606 }
1607 elsif( ref $pre ) {
a86b1efe 1608 $self->throw_exception(
1609 "don't know how to resolve prefetch reftype ".ref($pre));
b3e8ac9b 1610 }
1611 else {
1979278e 1612 my $p = $alias_map;
1613 $p = $p->{$_} for (@$pref_path, $pre);
1614
1615 $self->throw_exception (
5e8cb53c 1616 "Unable to resolve prefetch '$pre' - join alias map does not contain an entry for path: "
1979278e 1617 . join (' -> ', @$pref_path, $pre)
1618 ) if (ref $p->{-join_aliases} ne 'ARRAY' or not @{$p->{-join_aliases}} );
88a66388 1619
1979278e 1620 my $as = shift @{$p->{-join_aliases}};
1621
b3e8ac9b 1622 my $rel_info = $self->relationship_info( $pre );
455a33cb 1623 $self->throw_exception( $self->source_name . " has no such relationship '$pre'" )
a86b1efe 1624 unless $rel_info;
37f23589 1625 my $as_prefix = ($alias =~ /^.*?\.(.+)$/ ? $1.'.' : '');
a86b1efe 1626 my $rel_source = $self->related_source($pre);
0f66a01b 1627
b82c8a28 1628 if ($rel_info->{attrs}{accessor} && $rel_info->{attrs}{accessor} eq 'multi') {
0f66a01b 1629 $self->throw_exception(
1630 "Can't prefetch has_many ${pre} (join cond too complex)")
1631 unless ref($rel_info->{cond}) eq 'HASH';
cb136e67 1632 my $dots = @{[$as_prefix =~ m/\./g]} + 1; # +1 to match the ".${as_prefix}"
1633 if (my ($fail) = grep { @{[$_ =~ m/\./g]} == $dots }
1634 keys %{$collapse}) {
1635 my ($last) = ($fail =~ /([^\.]+)$/);
616b461d 1636 carp (
1637 "Prefetching multiple has_many rels ${last} and ${pre} "
1638 .(length($as_prefix)
1639 ? "at the same level (${as_prefix}) "
1640 : "at top level "
1641 )
2e251255 1642 . 'will explode the number of row objects retrievable via ->next or ->all. '
616b461d 1643 . 'Use at your own risk.'
1644 );
cb136e67 1645 }
b25e9fa0 1646 #my @col = map { (/^self\.(.+)$/ ? ("${as_prefix}.$1") : ()); }
1647 # values %{$rel_info->{cond}};
b1d8e3fd 1648 $collapse->{".${as_prefix}${pre}"} = [ $rel_source->_pri_cols ];
b25e9fa0 1649 # action at a distance. prepending the '.' allows simpler code
1650 # in ResultSet->_collapse_result
37f23589 1651 my @key = map { (/^foreign\.(.+)$/ ? ($1) : ()); }
0f66a01b 1652 keys %{$rel_info->{cond}};
d2fcb9b3 1653 push @$order, map { "${as}.$_" } @key;
fd323bf1 1654
d2fcb9b3 1655 if (my $rel_order = $rel_info->{attrs}{order_by}) {
1656 # this is kludgy and incomplete, I am well aware
1657 # but the parent method is going away entirely anyway
1658 # so sod it
1659 my $sql_maker = $self->storage->sql_maker;
1660 my ($orig_ql, $orig_qr) = $sql_maker->_quote_chars;
1661 my $sep = $sql_maker->name_sep;
1662
1663 # install our own quoter, so we can catch unqualified stuff
1664 local $sql_maker->{quote_char} = ["\x00", "\xFF"];
1665
1666 my $quoted_prefix = "\x00${as}\xFF";
1667
1668 for my $chunk ( $sql_maker->_order_by_chunks ($rel_order) ) {
1669 my @bind;
1670 ($chunk, @bind) = @$chunk if ref $chunk;
1671
1672 $chunk = "${quoted_prefix}${sep}${chunk}"
1673 unless $chunk =~ /\Q$sep/;
1674
1675 $chunk =~ s/\x00/$orig_ql/g;
1676 $chunk =~ s/\xFF/$orig_qr/g;
1677 push @$order, \[$chunk, @bind];
1678 }
1679 }
0f66a01b 1680 }
1681
489709af 1682 return map { [ "${as}.$_", "${as_prefix}${pre}.$_", ] }
a86b1efe 1683 $rel_source->columns;
b3e8ac9b 1684 }
1685}
953a18ef 1686
87c4e602 1687=head2 related_source
1688
27f01d1f 1689=over 4
1690
ebc77b53 1691=item Arguments: $relname
27f01d1f 1692
391ccf38 1693=item Return value: $source
1694
27f01d1f 1695=back
87772e46 1696
2053ab2a 1697Returns the result source object for the given relationship.
87772e46 1698
1699=cut
1700
1701sub related_source {
1702 my ($self, $rel) = @_;
aea52c85 1703 if( !$self->has_relationship( $rel ) ) {
455a33cb 1704 $self->throw_exception("No such relationship '$rel' on " . $self->source_name);
aea52c85 1705 }
87772e46 1706 return $self->schema->source($self->relationship_info($rel)->{source});
8452e496 1707}
1708
77254782 1709=head2 related_class
1710
27f01d1f 1711=over 4
1712
ebc77b53 1713=item Arguments: $relname
27f01d1f 1714
391ccf38 1715=item Return value: $classname
1716
27f01d1f 1717=back
77254782 1718
2053ab2a 1719Returns the class name for objects in the given relationship.
77254782 1720
1721=cut
1722
1723sub related_class {
1724 my ($self, $rel) = @_;
1725 if( !$self->has_relationship( $rel ) ) {
455a33cb 1726 $self->throw_exception("No such relationship '$rel' on " . $self->source_name);
77254782 1727 }
1728 return $self->schema->class($self->relationship_info($rel)->{source});
1729}
1730
aec3eff1 1731=head2 handle
1732
fd323bf1 1733Obtain a new handle to this source. Returns an instance of a
aec3eff1 1734L<DBIx::Class::ResultSourceHandle>.
1735
1736=cut
1737
1738sub handle {
24c349e8 1739 return DBIx::Class::ResultSourceHandle->new({
aec3eff1 1740 schema => $_[0]->schema,
3441fd57 1741 source_moniker => $_[0]->source_name
aec3eff1 1742 });
1743}
1744
701da8c4 1745=head2 throw_exception
1746
2053ab2a 1747See L<DBIx::Class::Schema/"throw_exception">.
701da8c4 1748
1749=cut
1750
1751sub throw_exception {
1752 my $self = shift;
1a58752c 1753
0b4926ce 1754 if (defined $self->schema) {
701da8c4 1755 $self->schema->throw_exception(@_);
1a58752c 1756 }
1757 else {
1758 DBIx::Class::Exception->throw(@_);
701da8c4 1759 }
1760}
1761
843f6bc1 1762=head2 source_info
d2f3e87b 1763
843f6bc1 1764Stores a hashref of per-source metadata. No specific key names
1765have yet been standardized, the examples below are purely hypothetical
1766and don't actually accomplish anything on their own:
391ccf38 1767
843f6bc1 1768 __PACKAGE__->source_info({
1769 "_tablespace" => 'fast_disk_array_3',
1770 "_engine" => 'InnoDB',
1771 });
391ccf38 1772
843f6bc1 1773=head2 new
391ccf38 1774
843f6bc1 1775 $class->new();
391ccf38 1776
843f6bc1 1777 $class->new({attribute_name => value});
d2f3e87b 1778
843f6bc1 1779Creates a new ResultSource object. Not normally called directly by end users.
391ccf38 1780
843f6bc1 1781=head2 column_info_from_storage
1782
1783=over
1784
1785=item Arguments: 1/0 (default: 0)
1786
1787=item Return value: 1/0
1788
1789=back
1790
880c075b 1791 __PACKAGE__->column_info_from_storage(1);
1792
843f6bc1 1793Enables the on-demand automatic loading of the above column
c1300297 1794metadata from storage as necessary. This is *deprecated*, and
843f6bc1 1795should not be used. It will be removed before 1.0.
1796
f89bb832 1797
9c992ba1 1798=head1 AUTHORS
1799
1800Matt S. Trout <mst@shadowcatsystems.co.uk>
1801
1802=head1 LICENSE
1803
1804You may distribute this code under the same terms as Perl itself.
1805
1806=cut
1807
b25e9fa0 18081;