Expand/fortify the handling of attributes
[dbsrgits/DBIx-Class-Historic.git] / lib / DBIx / Class / Schema.pm
1 package DBIx::Class::Schema;
2
3 use strict;
4 use warnings;
5
6 use base 'DBIx::Class';
7 use mro 'c3';
8
9 use DBIx::Class::Carp;
10 use Try::Tiny;
11 use Scalar::Util qw/weaken blessed/;
12 use DBIx::Class::_Util qw(
13   refcount quote_sub scope_guard
14   is_exception dbic_internal_try
15   fail_on_internal_call
16 );
17 use Devel::GlobalDestruction;
18 use namespace::clean;
19
20 __PACKAGE__->mk_group_accessors( inherited => qw( storage exception_action ) );
21 __PACKAGE__->mk_classaccessor('class_mappings' => {});
22 __PACKAGE__->mk_classaccessor('source_registrations' => {});
23 __PACKAGE__->mk_classaccessor('storage_type' => '::DBI');
24 __PACKAGE__->mk_classaccessor('stacktrace' => $ENV{DBIC_TRACE} || 0);
25 __PACKAGE__->mk_classaccessor('default_resultset_attributes' => {});
26
27 =head1 NAME
28
29 DBIx::Class::Schema - composable schemas
30
31 =head1 SYNOPSIS
32
33   package Library::Schema;
34   use base qw/DBIx::Class::Schema/;
35
36   # load all Result classes in Library/Schema/Result/
37   __PACKAGE__->load_namespaces();
38
39   package Library::Schema::Result::CD;
40   use base qw/DBIx::Class::Core/;
41
42   __PACKAGE__->load_components(qw/InflateColumn::DateTime/); # for example
43   __PACKAGE__->table('cd');
44
45   # Elsewhere in your code:
46   my $schema1 = Library::Schema->connect(
47     $dsn,
48     $user,
49     $password,
50     { AutoCommit => 1 },
51   );
52
53   my $schema2 = Library::Schema->connect($coderef_returning_dbh);
54
55   # fetch objects using Library::Schema::Result::DVD
56   my $resultset = $schema1->resultset('DVD')->search( ... );
57   my @dvd_objects = $schema2->resultset('DVD')->search( ... );
58
59 =head1 DESCRIPTION
60
61 Creates database classes based on a schema. This is the recommended way to
62 use L<DBIx::Class> and allows you to use more than one concurrent connection
63 with your classes.
64
65 NB: If you're used to L<Class::DBI> it's worth reading the L</SYNOPSIS>
66 carefully, as DBIx::Class does things a little differently. Note in
67 particular which module inherits off which.
68
69 =head1 SETUP METHODS
70
71 =head2 load_namespaces
72
73 =over 4
74
75 =item Arguments: %options?
76
77 =back
78
79   package MyApp::Schema;
80   __PACKAGE__->load_namespaces();
81
82   __PACKAGE__->load_namespaces(
83      result_namespace => 'Res',
84      resultset_namespace => 'RSet',
85      default_resultset_class => '+MyApp::Othernamespace::RSet',
86   );
87
88 With no arguments, this method uses L<Module::Find> to load all of the
89 Result and ResultSet classes under the namespace of the schema from
90 which it is called.  For example, C<My::Schema> will by default find
91 and load Result classes named C<My::Schema::Result::*> and ResultSet
92 classes named C<My::Schema::ResultSet::*>.
93
94 ResultSet classes are associated with Result class of the same name.
95 For example, C<My::Schema::Result::CD> will get the ResultSet class
96 C<My::Schema::ResultSet::CD> if it is present.
97
98 Both Result and ResultSet namespaces are configurable via the
99 C<result_namespace> and C<resultset_namespace> options.
100
101 Another option, C<default_resultset_class> specifies a custom default
102 ResultSet class for Result classes with no corresponding ResultSet.
103
104 All of the namespace and classname options are by default relative to
105 the schema classname.  To specify a fully-qualified name, prefix it
106 with a literal C<+>.  For example, C<+Other::NameSpace::Result>.
107
108 =head3 Warnings
109
110 You will be warned if ResultSet classes are discovered for which there
111 are no matching Result classes like this:
112
113   load_namespaces found ResultSet class $classname with no corresponding Result class
114
115 If a ResultSource instance is found to already have a ResultSet class set
116 using L<resultset_class|DBIx::Class::ResultSource/resultset_class> to some
117 other class, you will be warned like this:
118
119   We found ResultSet class '$rs_class' for '$result_class', but it seems
120   that you had already set '$result_class' to use '$rs_set' instead
121
122 =head3 Examples
123
124   # load My::Schema::Result::CD, My::Schema::Result::Artist,
125   #    My::Schema::ResultSet::CD, etc...
126   My::Schema->load_namespaces;
127
128   # Override everything to use ugly names.
129   # In this example, if there is a My::Schema::Res::Foo, but no matching
130   #   My::Schema::RSets::Foo, then Foo will have its
131   #   resultset_class set to My::Schema::RSetBase
132   My::Schema->load_namespaces(
133     result_namespace => 'Res',
134     resultset_namespace => 'RSets',
135     default_resultset_class => 'RSetBase',
136   );
137
138   # Put things in other namespaces
139   My::Schema->load_namespaces(
140     result_namespace => '+Some::Place::Results',
141     resultset_namespace => '+Another::Place::RSets',
142   );
143
144 To search multiple namespaces for either Result or ResultSet classes,
145 use an arrayref of namespaces for that option.  In the case that the
146 same result (or resultset) class exists in multiple namespaces, later
147 entries in the list of namespaces will override earlier ones.
148
149   My::Schema->load_namespaces(
150     # My::Schema::Results_C::Foo takes precedence over My::Schema::Results_B::Foo :
151     result_namespace => [ 'Results_A', 'Results_B', 'Results_C' ],
152     resultset_namespace => [ '+Some::Place::RSets', 'RSets' ],
153   );
154
155 =cut
156
157 # Pre-pends our classname to the given relative classname or
158 #   class namespace, unless there is a '+' prefix, which will
159 #   be stripped.
160 sub _expand_relative_name {
161   my ($class, $name) = @_;
162   $name =~ s/^\+// or $name = "${class}::${name}";
163   return $name;
164 }
165
166 # Finds all modules in the supplied namespace, or if omitted in the
167 # namespace of $class. Untaints all findings as they can be assumed
168 # to be safe
169 sub _findallmod {
170   require Module::Find;
171   return map
172     { $_ =~ /(.+)/ }   # untaint result
173     Module::Find::findallmod( $_[1] || ref $_[0] || $_[0] )
174   ;
175 }
176
177 # returns a hash of $shortname => $fullname for every package
178 # found in the given namespaces ($shortname is with the $fullname's
179 # namespace stripped off)
180 sub _map_namespaces {
181   my ($me, $namespaces) = @_;
182
183   my %res;
184   for my $ns (@$namespaces) {
185     $res{ substr($_, length "${ns}::") } = $_
186       for $me->_findallmod($ns);
187   }
188
189   \%res;
190 }
191
192 # returns the result_source_instance for the passed class/object,
193 # or dies with an informative message (used by load_namespaces)
194 sub _ns_get_rsrc_instance {
195   my $me = shift;
196   my $rs_class = ref ($_[0]) || $_[0];
197
198   return dbic_internal_try {
199     $rs_class->result_source_instance
200   } catch {
201     $me->throw_exception (
202       "Attempt to load_namespaces() class $rs_class failed - are you sure this is a real Result Class?: $_"
203     );
204   };
205 }
206
207 sub load_namespaces {
208   my ($class, %args) = @_;
209
210   my $result_namespace = delete $args{result_namespace} || 'Result';
211   my $resultset_namespace = delete $args{resultset_namespace} || 'ResultSet';
212
213   my $default_resultset_class = delete $args{default_resultset_class};
214
215   $default_resultset_class = $class->_expand_relative_name($default_resultset_class)
216     if $default_resultset_class;
217
218   $class->throw_exception('load_namespaces: unknown option(s): '
219     . join(q{,}, map { qq{'$_'} } keys %args))
220       if scalar keys %args;
221
222   for my $arg ($result_namespace, $resultset_namespace) {
223     $arg = [ $arg ] if ( $arg and ! ref $arg );
224
225     $class->throw_exception('load_namespaces: namespace arguments must be '
226       . 'a simple string or an arrayref')
227         if ref($arg) ne 'ARRAY';
228
229     $_ = $class->_expand_relative_name($_) for (@$arg);
230   }
231
232   my $results_by_source_name = $class->_map_namespaces($result_namespace);
233   my $resultsets_by_source_name = $class->_map_namespaces($resultset_namespace);
234
235   my @to_register;
236   {
237     no warnings qw/redefine/;
238     local *Class::C3::reinitialize = sub { } if DBIx::Class::_ENV_::OLD_MRO;
239     use warnings qw/redefine/;
240
241     # ensure classes are loaded and attached in inheritance order
242     for my $result_class (values %$results_by_source_name) {
243       $class->ensure_class_loaded($result_class);
244     }
245     my %inh_idx;
246     my @source_names_by_subclass_last = sort {
247
248       ($inh_idx{$a} ||=
249         scalar @{mro::get_linear_isa( $results_by_source_name->{$a} )}
250       )
251
252           <=>
253
254       ($inh_idx{$b} ||=
255         scalar @{mro::get_linear_isa( $results_by_source_name->{$b} )}
256       )
257
258     } keys(%$results_by_source_name);
259
260     foreach my $source_name (@source_names_by_subclass_last) {
261       my $result_class = $results_by_source_name->{$source_name};
262
263       my $preset_resultset_class = $class->_ns_get_rsrc_instance ($result_class)->resultset_class;
264       my $found_resultset_class = delete $resultsets_by_source_name->{$source_name};
265
266       if($preset_resultset_class && $preset_resultset_class ne 'DBIx::Class::ResultSet') {
267         if($found_resultset_class && $found_resultset_class ne $preset_resultset_class) {
268           carp "We found ResultSet class '$found_resultset_class' matching '$results_by_source_name->{$source_name}', but it seems "
269              . "that you had already set the '$results_by_source_name->{$source_name}' resultet to '$preset_resultset_class' instead";
270         }
271       }
272       # elsif - there may be *no* default_resultset_class, in which case we fallback to
273       # DBIx::Class::Resultset and there is nothing to check
274       elsif($found_resultset_class ||= $default_resultset_class) {
275         $class->ensure_class_loaded($found_resultset_class);
276         if(!$found_resultset_class->isa("DBIx::Class::ResultSet")) {
277             carp "load_namespaces found ResultSet class '$found_resultset_class' that does not subclass DBIx::Class::ResultSet";
278         }
279
280         $class->_ns_get_rsrc_instance ($result_class)->resultset_class($found_resultset_class);
281       }
282
283       my $source_name = $class->_ns_get_rsrc_instance ($result_class)->source_name || $source_name;
284
285       push(@to_register, [ $source_name, $result_class ]);
286     }
287   }
288
289   foreach (sort keys %$resultsets_by_source_name) {
290     carp "load_namespaces found ResultSet class '$resultsets_by_source_name->{$_}' "
291         .'with no corresponding Result class';
292   }
293
294   Class::C3->reinitialize if DBIx::Class::_ENV_::OLD_MRO;
295
296   $class->register_class(@$_) for (@to_register);
297
298   return;
299 }
300
301 =head2 load_classes
302
303 =over 4
304
305 =item Arguments: @classes?, { $namespace => [ @classes ] }+
306
307 =back
308
309 L</load_classes> is an alternative method to L</load_namespaces>, both of
310 which serve similar purposes, each with different advantages and disadvantages.
311 In the general case you should use L</load_namespaces>, unless you need to
312 be able to specify that only specific classes are loaded at runtime.
313
314 With no arguments, this method uses L<Module::Find> to find all classes under
315 the schema's namespace. Otherwise, this method loads the classes you specify
316 (using L<use>), and registers them (using L</"register_class">).
317
318 It is possible to comment out classes with a leading C<#>, but note that perl
319 will think it's a mistake (trying to use a comment in a qw list), so you'll
320 need to add C<no warnings 'qw';> before your load_classes call.
321
322 If any classes found do not appear to be Result class files, you will
323 get the following warning:
324
325    Failed to load $comp_class. Can't find source_name method. Is
326    $comp_class really a full DBIC result class? Fix it, move it elsewhere,
327    or make your load_classes call more specific.
328
329 Example:
330
331   My::Schema->load_classes(); # loads My::Schema::CD, My::Schema::Artist,
332                               # etc. (anything under the My::Schema namespace)
333
334   # loads My::Schema::CD, My::Schema::Artist, Other::Namespace::Producer but
335   # not Other::Namespace::LinerNotes nor My::Schema::Track
336   My::Schema->load_classes(qw/ CD Artist #Track /, {
337     Other::Namespace => [qw/ Producer #LinerNotes /],
338   });
339
340 =cut
341
342 sub load_classes {
343   my ($class, @params) = @_;
344
345   my %comps_for;
346
347   if (@params) {
348     foreach my $param (@params) {
349       if (ref $param eq 'ARRAY') {
350         # filter out commented entries
351         my @modules = grep { $_ !~ /^#/ } @$param;
352
353         push (@{$comps_for{$class}}, @modules);
354       }
355       elsif (ref $param eq 'HASH') {
356         # more than one namespace possible
357         for my $comp ( keys %$param ) {
358           # filter out commented entries
359           my @modules = grep { $_ !~ /^#/ } @{$param->{$comp}};
360
361           push (@{$comps_for{$comp}}, @modules);
362         }
363       }
364       else {
365         # filter out commented entries
366         push (@{$comps_for{$class}}, $param) if $param !~ /^#/;
367       }
368     }
369   } else {
370     my @comp = map { substr $_, length "${class}::"  }
371                  $class->_findallmod($class);
372     $comps_for{$class} = \@comp;
373   }
374
375   my @to_register;
376   {
377     no warnings qw/redefine/;
378     local *Class::C3::reinitialize = sub { } if DBIx::Class::_ENV_::OLD_MRO;
379     use warnings qw/redefine/;
380
381     foreach my $prefix (keys %comps_for) {
382       foreach my $comp (@{$comps_for{$prefix}||[]}) {
383         my $comp_class = "${prefix}::${comp}";
384         $class->ensure_class_loaded($comp_class);
385
386         my $snsub = $comp_class->can('source_name');
387         if(! $snsub ) {
388           carp "Failed to load $comp_class. Can't find source_name method. Is $comp_class really a full DBIC result class? Fix it, move it elsewhere, or make your load_classes call more specific.";
389           next;
390         }
391         $comp = $snsub->($comp_class) || $comp;
392
393         push(@to_register, [ $comp, $comp_class ]);
394       }
395     }
396   }
397   Class::C3->reinitialize if DBIx::Class::_ENV_::OLD_MRO;
398
399   foreach my $to (@to_register) {
400     $class->register_class(@$to);
401   }
402 }
403
404 =head2 storage_type
405
406 =over 4
407
408 =item Arguments: $storage_type|{$storage_type, \%args}
409
410 =item Return Value: $storage_type|{$storage_type, \%args}
411
412 =item Default value: DBIx::Class::Storage::DBI
413
414 =back
415
416 Set the storage class that will be instantiated when L</connect> is called.
417 If the classname starts with C<::>, the prefix C<DBIx::Class::Storage> is
418 assumed by L</connect>.
419
420 You want to use this to set subclasses of L<DBIx::Class::Storage::DBI>
421 in cases where the appropriate subclass is not autodetected.
422
423 If your storage type requires instantiation arguments, those are
424 defined as a second argument in the form of a hashref and the entire
425 value needs to be wrapped into an arrayref or a hashref.  We support
426 both types of refs here in order to play nice with your
427 Config::[class] or your choice. See
428 L<DBIx::Class::Storage::DBI::Replicated> for an example of this.
429
430 =head2 exception_action
431
432 =over 4
433
434 =item Arguments: $code_reference
435
436 =item Return Value: $code_reference
437
438 =item Default value: None
439
440 =back
441
442 When L</throw_exception> is invoked and L</exception_action> is set to a code
443 reference, this reference will be called instead of
444 L<DBIx::Class::Exception/throw>, with the exception message passed as the only
445 argument.
446
447 Your custom throw code B<must> rethrow the exception, as L</throw_exception> is
448 an integral part of DBIC's internal execution control flow.
449
450 Example:
451
452    package My::Schema;
453    use base qw/DBIx::Class::Schema/;
454    use My::ExceptionClass;
455    __PACKAGE__->exception_action(sub { My::ExceptionClass->throw(@_) });
456    __PACKAGE__->load_classes;
457
458    # or:
459    my $schema_obj = My::Schema->connect( .... );
460    $schema_obj->exception_action(sub { My::ExceptionClass->throw(@_) });
461
462 =head2 stacktrace
463
464 =over 4
465
466 =item Arguments: boolean
467
468 =back
469
470 Whether L</throw_exception> should include stack trace information.
471 Defaults to false normally, but defaults to true if C<$ENV{DBIC_TRACE}>
472 is true.
473
474 =head2 sqlt_deploy_hook
475
476 =over
477
478 =item Arguments: $sqlt_schema
479
480 =back
481
482 An optional sub which you can declare in your own Schema class that will get
483 passed the L<SQL::Translator::Schema> object when you deploy the schema via
484 L</create_ddl_dir> or L</deploy>.
485
486 For an example of what you can do with this, see
487 L<DBIx::Class::Manual::Cookbook/Adding Indexes And Functions To Your SQL>.
488
489 Note that sqlt_deploy_hook is called by L</deployment_statements>, which in turn
490 is called before L</deploy>. Therefore the hook can be used only to manipulate
491 the L<SQL::Translator::Schema> object before it is turned into SQL fed to the
492 database. If you want to execute post-deploy statements which can not be generated
493 by L<SQL::Translator>, the currently suggested method is to overload L</deploy>
494 and use L<dbh_do|DBIx::Class::Storage::DBI/dbh_do>.
495
496 =head1 METHODS
497
498 =head2 connect
499
500 =over 4
501
502 =item Arguments: @connectinfo
503
504 =item Return Value: $new_schema
505
506 =back
507
508 Creates and returns a new Schema object. The connection info set on it
509 is used to create a new instance of the storage backend and set it on
510 the Schema object.
511
512 See L<DBIx::Class::Storage::DBI/"connect_info"> for DBI-specific
513 syntax on the C<@connectinfo> argument, or L<DBIx::Class::Storage> in
514 general.
515
516 Note that C<connect_info> expects an arrayref of arguments, but
517 C<connect> does not. C<connect> wraps its arguments in an arrayref
518 before passing them to C<connect_info>.
519
520 =head3 Overloading
521
522 C<connect> is a convenience method. It is equivalent to calling
523 $schema->clone->connection(@connectinfo). To write your own overloaded
524 version, overload L</connection> instead.
525
526 =cut
527
528 sub connect {
529   DBIx::Class::_ENV_::ASSERT_NO_INTERNAL_INDIRECT_CALLS and fail_on_internal_call;
530   shift->clone->connection(@_);
531 }
532
533 =head2 resultset
534
535 =over 4
536
537 =item Arguments: L<$source_name|DBIx::Class::ResultSource/source_name>
538
539 =item Return Value: L<$resultset|DBIx::Class::ResultSet>
540
541 =back
542
543   my $rs = $schema->resultset('DVD');
544
545 Returns the L<DBIx::Class::ResultSet> object for the registered source
546 name.
547
548 =cut
549
550 sub resultset {
551   my ($self, $source_name) = @_;
552   $self->throw_exception('resultset() expects a source name')
553     unless defined $source_name;
554   return $self->source($source_name)->resultset;
555 }
556
557 =head2 sources
558
559 =over 4
560
561 =item Return Value: L<@source_names|DBIx::Class::ResultSource/source_name>
562
563 =back
564
565   my @source_names = $schema->sources;
566
567 Lists names of all the sources registered on this Schema object.
568
569 =cut
570
571 sub sources { keys %{shift->source_registrations} }
572
573 =head2 source
574
575 =over 4
576
577 =item Arguments: L<$source_name|DBIx::Class::ResultSource/source_name>
578
579 =item Return Value: L<$result_source|DBIx::Class::ResultSource>
580
581 =back
582
583   my $source = $schema->source('Book');
584
585 Returns the L<DBIx::Class::ResultSource> object for the registered
586 source name.
587
588 =cut
589
590 sub source {
591   my $self = shift;
592
593   $self->throw_exception("source() expects a source name")
594     unless @_;
595
596   my $source_name = shift;
597
598   my $sreg = $self->source_registrations;
599   return $sreg->{$source_name} if exists $sreg->{$source_name};
600
601   # if we got here, they probably passed a full class name
602   my $mapped = $self->class_mappings->{$source_name};
603   $self->throw_exception("Can't find source for ${source_name}")
604     unless $mapped && exists $sreg->{$mapped};
605   return $sreg->{$mapped};
606 }
607
608 =head2 class
609
610 =over 4
611
612 =item Arguments: L<$source_name|DBIx::Class::ResultSource/source_name>
613
614 =item Return Value: $classname
615
616 =back
617
618   my $class = $schema->class('CD');
619
620 Retrieves the Result class name for the given source name.
621
622 =cut
623
624 sub class {
625   return shift->source(shift)->result_class;
626 }
627
628 =head2 txn_do
629
630 =over 4
631
632 =item Arguments: C<$coderef>, @coderef_args?
633
634 =item Return Value: The return value of $coderef
635
636 =back
637
638 Executes C<$coderef> with (optional) arguments C<@coderef_args> atomically,
639 returning its result (if any). Equivalent to calling $schema->storage->txn_do.
640 See L<DBIx::Class::Storage/"txn_do"> for more information.
641
642 This interface is preferred over using the individual methods L</txn_begin>,
643 L</txn_commit>, and L</txn_rollback> below.
644
645 WARNING: If you are connected with C<< AutoCommit => 0 >> the transaction is
646 considered nested, and you will still need to call L</txn_commit> to write your
647 changes when appropriate. You will also want to connect with C<< auto_savepoint =>
648 1 >> to get partial rollback to work, if the storage driver for your database
649 supports it.
650
651 Connecting with C<< AutoCommit => 1 >> is recommended.
652
653 =cut
654
655 sub txn_do {
656   my $self = shift;
657
658   $self->storage or $self->throw_exception
659     ('txn_do called on $schema without storage');
660
661   $self->storage->txn_do(@_);
662 }
663
664 =head2 txn_scope_guard
665
666 Runs C<txn_scope_guard> on the schema's storage. See
667 L<DBIx::Class::Storage/txn_scope_guard>.
668
669 =cut
670
671 sub txn_scope_guard {
672   my $self = shift;
673
674   $self->storage or $self->throw_exception
675     ('txn_scope_guard called on $schema without storage');
676
677   $self->storage->txn_scope_guard(@_);
678 }
679
680 =head2 txn_begin
681
682 Begins a transaction (does nothing if AutoCommit is off). Equivalent to
683 calling $schema->storage->txn_begin. See
684 L<DBIx::Class::Storage/"txn_begin"> for more information.
685
686 =cut
687
688 sub txn_begin {
689   my $self = shift;
690
691   $self->storage or $self->throw_exception
692     ('txn_begin called on $schema without storage');
693
694   $self->storage->txn_begin;
695 }
696
697 =head2 txn_commit
698
699 Commits the current transaction. Equivalent to calling
700 $schema->storage->txn_commit. See L<DBIx::Class::Storage/"txn_commit">
701 for more information.
702
703 =cut
704
705 sub txn_commit {
706   my $self = shift;
707
708   $self->storage or $self->throw_exception
709     ('txn_commit called on $schema without storage');
710
711   $self->storage->txn_commit;
712 }
713
714 =head2 txn_rollback
715
716 Rolls back the current transaction. Equivalent to calling
717 $schema->storage->txn_rollback. See
718 L<DBIx::Class::Storage/"txn_rollback"> for more information.
719
720 =cut
721
722 sub txn_rollback {
723   my $self = shift;
724
725   $self->storage or $self->throw_exception
726     ('txn_rollback called on $schema without storage');
727
728   $self->storage->txn_rollback;
729 }
730
731 =head2 storage
732
733   my $storage = $schema->storage;
734
735 Returns the L<DBIx::Class::Storage> object for this Schema. Grab this
736 if you want to turn on SQL statement debugging at runtime, or set the
737 quote character. For the default storage, the documentation can be
738 found in L<DBIx::Class::Storage::DBI>.
739
740 =head2 populate
741
742 =over 4
743
744 =item Arguments: L<$source_name|DBIx::Class::ResultSource/source_name>, [ \@column_list, \@row_values+ ] | [ \%col_data+ ]
745
746 =item Return Value: L<\@result_objects|DBIx::Class::Manual::ResultClass> (scalar context) | L<@result_objects|DBIx::Class::Manual::ResultClass> (list context)
747
748 =back
749
750 A convenience shortcut to L<DBIx::Class::ResultSet/populate>. Equivalent to:
751
752  $schema->resultset($source_name)->populate([...]);
753
754 =over 4
755
756 =item NOTE
757
758 The context of this method call has an important effect on what is
759 submitted to storage. In void context data is fed directly to fastpath
760 insertion routines provided by the underlying storage (most often
761 L<DBI/execute_for_fetch>), bypassing the L<new|DBIx::Class::Row/new> and
762 L<insert|DBIx::Class::Row/insert> calls on the
763 L<Result|DBIx::Class::Manual::ResultClass> class, including any
764 augmentation of these methods provided by components. For example if you
765 are using something like L<DBIx::Class::UUIDColumns> to create primary
766 keys for you, you will find that your PKs are empty.  In this case you
767 will have to explicitly force scalar or list context in order to create
768 those values.
769
770 =back
771
772 =cut
773
774 sub populate {
775   DBIx::Class::_ENV_::ASSERT_NO_INTERNAL_INDIRECT_CALLS and fail_on_internal_call;
776
777   my ($self, $name, $data) = @_;
778   my $rs = $self->resultset($name)
779     or $self->throw_exception("'$name' is not a resultset");
780
781   return $rs->populate($data);
782 }
783
784 =head2 connection
785
786 =over 4
787
788 =item Arguments: @args
789
790 =item Return Value: $new_schema
791
792 =back
793
794 Similar to L</connect> except sets the storage object and connection
795 data in-place on the Schema class. You should probably be calling
796 L</connect> to get a proper Schema object instead.
797
798 =head3 Overloading
799
800 Overload C<connection> to change the behaviour of C<connect>.
801
802 =cut
803
804 sub connection {
805   my ($self, @info) = @_;
806   return $self if !@info && $self->storage;
807
808   my ($storage_class, $args) = ref $self->storage_type
809     ? $self->_normalize_storage_type($self->storage_type)
810     : $self->storage_type
811   ;
812
813   $storage_class =~ s/^::/DBIx::Class::Storage::/;
814
815   dbic_internal_try {
816     $self->ensure_class_loaded ($storage_class);
817   }
818   catch {
819     $self->throw_exception(
820       "Unable to load storage class ${storage_class}: $_"
821     );
822   };
823
824   my $storage = $storage_class->new( $self => $args||{} );
825   $storage->connect_info(\@info);
826   $self->storage($storage);
827   return $self;
828 }
829
830 sub _normalize_storage_type {
831   my ($self, $storage_type) = @_;
832   if(ref $storage_type eq 'ARRAY') {
833     return @$storage_type;
834   } elsif(ref $storage_type eq 'HASH') {
835     return %$storage_type;
836   } else {
837     $self->throw_exception('Unsupported REFTYPE given: '. ref $storage_type);
838   }
839 }
840
841 =head2 compose_namespace
842
843 =over 4
844
845 =item Arguments: $target_namespace, $additional_base_class?
846
847 =item Return Value: $new_schema
848
849 =back
850
851 For each L<DBIx::Class::ResultSource> in the schema, this method creates a
852 class in the target namespace (e.g. $target_namespace::CD,
853 $target_namespace::Artist) that inherits from the corresponding classes
854 attached to the current schema.
855
856 It also attaches a corresponding L<DBIx::Class::ResultSource> object to the
857 new $schema object. If C<$additional_base_class> is given, the new composed
858 classes will inherit from first the corresponding class from the current
859 schema then the base class.
860
861 For example, for a schema with My::Schema::CD and My::Schema::Artist classes,
862
863   $schema->compose_namespace('My::DB', 'Base::Class');
864   print join (', ', @My::DB::CD::ISA) . "\n";
865   print join (', ', @My::DB::Artist::ISA) ."\n";
866
867 will produce the output
868
869   My::Schema::CD, Base::Class
870   My::Schema::Artist, Base::Class
871
872 =cut
873
874 sub compose_namespace {
875   my ($self, $target, $base) = @_;
876
877   my $schema = $self->clone;
878
879   $schema->source_registrations({});
880
881   # the original class-mappings must remain - otherwise
882   # reverse_relationship_info will not work
883   #$schema->class_mappings({});
884
885   {
886     no warnings qw/redefine/;
887     local *Class::C3::reinitialize = sub { } if DBIx::Class::_ENV_::OLD_MRO;
888     use warnings qw/redefine/;
889
890     foreach my $source_name ($self->sources) {
891       my $orig_source = $self->source($source_name);
892
893       my $target_class = "${target}::${source_name}";
894       $self->inject_base($target_class, $orig_source->result_class, ($base || ()) );
895
896       # register_source examines result_class, and then returns us a clone
897       my $new_source = $schema->register_source($source_name, bless
898         { %$orig_source, result_class => $target_class },
899         ref $orig_source,
900       );
901
902       if ($target_class->can('result_source_instance')) {
903         # give the class a schema-less source copy
904         $target_class->result_source_instance( bless
905           { %$new_source, schema => ref $new_source->{schema} || $new_source->{schema} },
906           ref $new_source,
907         );
908       }
909     }
910
911     # Legacy stuff, not inserting INDIRECT assertions
912     quote_sub "${target}::${_}" => "shift->schema->$_(\@_)"
913       for qw(class source resultset);
914   }
915
916   Class::C3->reinitialize() if DBIx::Class::_ENV_::OLD_MRO;
917
918   return $schema;
919 }
920
921 sub setup_connection_class {
922   my ($class, $target, @info) = @_;
923   $class->inject_base($target => 'DBIx::Class::DB');
924   #$target->load_components('DB');
925   $target->connection(@info);
926 }
927
928 =head2 svp_begin
929
930 Creates a new savepoint (does nothing outside a transaction).
931 Equivalent to calling $schema->storage->svp_begin.  See
932 L<DBIx::Class::Storage/"svp_begin"> for more information.
933
934 =cut
935
936 sub svp_begin {
937   my ($self, $name) = @_;
938
939   $self->storage or $self->throw_exception
940     ('svp_begin called on $schema without storage');
941
942   $self->storage->svp_begin($name);
943 }
944
945 =head2 svp_release
946
947 Releases a savepoint (does nothing outside a transaction).
948 Equivalent to calling $schema->storage->svp_release.  See
949 L<DBIx::Class::Storage/"svp_release"> for more information.
950
951 =cut
952
953 sub svp_release {
954   my ($self, $name) = @_;
955
956   $self->storage or $self->throw_exception
957     ('svp_release called on $schema without storage');
958
959   $self->storage->svp_release($name);
960 }
961
962 =head2 svp_rollback
963
964 Rollback to a savepoint (does nothing outside a transaction).
965 Equivalent to calling $schema->storage->svp_rollback.  See
966 L<DBIx::Class::Storage/"svp_rollback"> for more information.
967
968 =cut
969
970 sub svp_rollback {
971   my ($self, $name) = @_;
972
973   $self->storage or $self->throw_exception
974     ('svp_rollback called on $schema without storage');
975
976   $self->storage->svp_rollback($name);
977 }
978
979 =head2 clone
980
981 =over 4
982
983 =item Arguments: %attrs?
984
985 =item Return Value: $new_schema
986
987 =back
988
989 Clones the schema and its associated result_source objects and returns the
990 copy. The resulting copy will have the same attributes as the source schema,
991 except for those attributes explicitly overridden by the provided C<%attrs>.
992
993 =cut
994
995 sub clone {
996   my $self = shift;
997
998   my $clone = {
999       (ref $self ? %$self : ()),
1000       (@_ == 1 && ref $_[0] eq 'HASH' ? %{ $_[0] } : @_),
1001   };
1002   bless $clone, (ref $self || $self);
1003
1004   $clone->$_(undef) for qw/class_mappings source_registrations storage/;
1005
1006   $clone->_copy_state_from($self);
1007
1008   return $clone;
1009 }
1010
1011 # Needed in Schema::Loader - if you refactor, please make a compatibility shim
1012 # -- Caelum
1013 sub _copy_state_from {
1014   my ($self, $from) = @_;
1015
1016   $self->class_mappings({ %{$from->class_mappings} });
1017   $self->source_registrations({ %{$from->source_registrations} });
1018
1019   foreach my $source_name ($from->sources) {
1020     my $source = $from->source($source_name);
1021     my $new = $source->new($source);
1022     # we use extra here as we want to leave the class_mappings as they are
1023     # but overwrite the source_registrations entry with the new source
1024     $self->register_extra_source($source_name => $new);
1025   }
1026
1027   if ($from->storage) {
1028     $self->storage($from->storage);
1029     $self->storage->set_schema($self);
1030   }
1031 }
1032
1033 =head2 throw_exception
1034
1035 =over 4
1036
1037 =item Arguments: $message
1038
1039 =back
1040
1041 Throws an exception. Obeys the exemption rules of L<DBIx::Class::Carp> to report
1042 errors from outer-user's perspective. See L</exception_action> for details on overriding
1043 this method's behavior.  If L</stacktrace> is turned on, C<throw_exception>'s
1044 default behavior will provide a detailed stack trace.
1045
1046 =cut
1047
1048 sub throw_exception {
1049   my ($self, @args) = @_;
1050
1051   if (
1052     ! DBIx::Class::_Util::in_internal_try()
1053       and
1054     my $act = $self->exception_action
1055   ) {
1056
1057     my $guard_disarmed;
1058
1059     my $guard = scope_guard {
1060       return if $guard_disarmed;
1061       local $SIG{__WARN__};
1062       Carp::cluck("
1063                     !!! DBIx::Class INTERNAL PANIC !!!
1064
1065 The exception_action() handler installed on '$self'
1066 aborted the stacktrace below via a longjmp (either via Return::Multilevel or
1067 plain goto, or Scope::Upper or something equally nefarious). There currently
1068 is nothing safe DBIx::Class can do, aside from displaying this error. A future
1069 version ( 0.082900, when available ) will reduce the cases in which the
1070 handler is invoked, but this is neither a complete solution, nor can it do
1071 anything for other software that might be affected by a similar problem.
1072
1073                       !!! FIX YOUR ERROR HANDLING !!!
1074
1075 This guard was activated beginning"
1076       );
1077     };
1078
1079     dbic_internal_try {
1080       # if it throws - good, we'll assign to @args in the end
1081       # if it doesn't - do different things depending on RV truthiness
1082       if( $act->(@args) ) {
1083         $args[0] = (
1084           "Invocation of the exception_action handler installed on $self did *not*"
1085         .' result in an exception. DBIx::Class is unable to function without a reliable'
1086         .' exception mechanism, ensure your exception_action does not hide exceptions'
1087         ." (original error: $args[0])"
1088         );
1089       }
1090       else {
1091         carp_unique (
1092           "The exception_action handler installed on $self returned false instead"
1093         .' of throwing an exception. This behavior has been deprecated, adjust your'
1094         .' handler to always rethrow the supplied error'
1095         );
1096       }
1097
1098       1;
1099     }
1100     catch {
1101       # We call this to get the necessary warnings emitted and disregard the RV
1102       # as it's definitely an exception if we got as far as this catch{} block
1103       is_exception(
1104         $args[0] = $_
1105       );
1106     };
1107
1108     # Done guarding against https://github.com/PerlDancer/Dancer2/issues/1125
1109     $guard_disarmed = 1;
1110   }
1111
1112   DBIx::Class::Exception->throw( $args[0], $self->stacktrace );
1113 }
1114
1115 =head2 deploy
1116
1117 =over 4
1118
1119 =item Arguments: \%sqlt_args, $dir
1120
1121 =back
1122
1123 Attempts to deploy the schema to the current storage using L<SQL::Translator>.
1124
1125 See L<SQL::Translator/METHODS> for a list of values for C<\%sqlt_args>.
1126 The most common value for this would be C<< { add_drop_table => 1 } >>
1127 to have the SQL produced include a C<DROP TABLE> statement for each table
1128 created. For quoting purposes supply C<quote_identifiers>.
1129
1130 Additionally, the DBIx::Class parser accepts a C<sources> parameter as a hash
1131 ref or an array ref, containing a list of source to deploy. If present, then
1132 only the sources listed will get deployed. Furthermore, you can use the
1133 C<add_fk_index> parser parameter to prevent the parser from creating an index for each
1134 FK.
1135
1136 =cut
1137
1138 sub deploy {
1139   my ($self, $sqltargs, $dir) = @_;
1140   $self->throw_exception("Can't deploy without storage") unless $self->storage;
1141   $self->storage->deploy($self, undef, $sqltargs, $dir);
1142 }
1143
1144 =head2 deployment_statements
1145
1146 =over 4
1147
1148 =item Arguments: See L<DBIx::Class::Storage::DBI/deployment_statements>
1149
1150 =item Return Value: $listofstatements
1151
1152 =back
1153
1154 A convenient shortcut to
1155 C<< $self->storage->deployment_statements($self, @args) >>.
1156 Returns the statements used by L</deploy> and
1157 L<DBIx::Class::Storage/deploy>.
1158
1159 =cut
1160
1161 sub deployment_statements {
1162   my $self = shift;
1163
1164   $self->throw_exception("Can't generate deployment statements without a storage")
1165     if not $self->storage;
1166
1167   $self->storage->deployment_statements($self, @_);
1168 }
1169
1170 =head2 create_ddl_dir
1171
1172 =over 4
1173
1174 =item Arguments: See L<DBIx::Class::Storage::DBI/create_ddl_dir>
1175
1176 =back
1177
1178 A convenient shortcut to
1179 C<< $self->storage->create_ddl_dir($self, @args) >>.
1180
1181 Creates an SQL file based on the Schema, for each of the specified
1182 database types, in the given directory.
1183
1184 =cut
1185
1186 sub create_ddl_dir {
1187   my $self = shift;
1188
1189   $self->throw_exception("Can't create_ddl_dir without storage") unless $self->storage;
1190   $self->storage->create_ddl_dir($self, @_);
1191 }
1192
1193 =head2 ddl_filename
1194
1195 =over 4
1196
1197 =item Arguments: $database-type, $version, $directory, $preversion
1198
1199 =item Return Value: $normalised_filename
1200
1201 =back
1202
1203   my $filename = $table->ddl_filename($type, $version, $dir, $preversion)
1204
1205 This method is called by C<create_ddl_dir> to compose a file name out of
1206 the supplied directory, database type and version number. The default file
1207 name format is: C<$dir$schema-$version-$type.sql>.
1208
1209 You may override this method in your schema if you wish to use a different
1210 format.
1211
1212  WARNING
1213
1214  Prior to DBIx::Class version 0.08100 this method had a different signature:
1215
1216     my $filename = $table->ddl_filename($type, $dir, $version, $preversion)
1217
1218  In recent versions variables $dir and $version were reversed in order to
1219  bring the signature in line with other Schema/Storage methods. If you
1220  really need to maintain backward compatibility, you can do the following
1221  in any overriding methods:
1222
1223     ($dir, $version) = ($version, $dir) if ($DBIx::Class::VERSION < 0.08100);
1224
1225 =cut
1226
1227 sub ddl_filename {
1228   my ($self, $type, $version, $dir, $preversion) = @_;
1229
1230   $version = "$preversion-$version" if $preversion;
1231
1232   my $class = blessed($self) || $self;
1233   $class =~ s/::/-/g;
1234
1235   return "$dir/$class-$version-$type.sql";
1236 }
1237
1238 =head2 thaw
1239
1240 Provided as the recommended way of thawing schema objects. You can call
1241 C<Storable::thaw> directly if you wish, but the thawed objects will not have a
1242 reference to any schema, so are rather useless.
1243
1244 =cut
1245
1246 sub thaw {
1247   my ($self, $obj) = @_;
1248   local $DBIx::Class::ResultSourceHandle::thaw_schema = $self;
1249   return Storable::thaw($obj);
1250 }
1251
1252 =head2 freeze
1253
1254 This doesn't actually do anything beyond calling L<nfreeze|Storable/SYNOPSIS>,
1255 it is just provided here for symmetry.
1256
1257 =cut
1258
1259 sub freeze {
1260   return Storable::nfreeze($_[1]);
1261 }
1262
1263 =head2 dclone
1264
1265 =over 4
1266
1267 =item Arguments: $object
1268
1269 =item Return Value: dcloned $object
1270
1271 =back
1272
1273 Recommended way of dcloning L<DBIx::Class::Row> and L<DBIx::Class::ResultSet>
1274 objects so their references to the schema object
1275 (which itself is B<not> cloned) are properly maintained.
1276
1277 =cut
1278
1279 sub dclone {
1280   my ($self, $obj) = @_;
1281   local $DBIx::Class::ResultSourceHandle::thaw_schema = $self;
1282   return Storable::dclone($obj);
1283 }
1284
1285 =head2 schema_version
1286
1287 Returns the current schema class' $VERSION in a normalised way.
1288
1289 =cut
1290
1291 sub schema_version {
1292   my ($self) = @_;
1293   my $class = ref($self)||$self;
1294
1295   # does -not- use $schema->VERSION
1296   # since that varies in results depending on if version.pm is installed, and if
1297   # so the perl or XS versions. If you want this to change, bug the version.pm
1298   # author to make vpp and vxs behave the same.
1299
1300   my $version;
1301   {
1302     no strict 'refs';
1303     $version = ${"${class}::VERSION"};
1304   }
1305   return $version;
1306 }
1307
1308
1309 =head2 register_class
1310
1311 =over 4
1312
1313 =item Arguments: $source_name, $component_class
1314
1315 =back
1316
1317 This method is called by L</load_namespaces> and L</load_classes> to install the found classes into your Schema. You should be using those instead of this one.
1318
1319 You will only need this method if you have your Result classes in
1320 files which are not named after the packages (or all in the same
1321 file). You may also need it to register classes at runtime.
1322
1323 Registers a class which isa DBIx::Class::ResultSourceProxy. Equivalent to
1324 calling:
1325
1326   $schema->register_source($source_name, $component_class->result_source_instance);
1327
1328 =cut
1329
1330 sub register_class {
1331   my ($self, $source_name, $to_register) = @_;
1332   $self->register_source($source_name => $to_register->result_source_instance);
1333 }
1334
1335 =head2 register_source
1336
1337 =over 4
1338
1339 =item Arguments: $source_name, L<$result_source|DBIx::Class::ResultSource>
1340
1341 =back
1342
1343 This method is called by L</register_class>.
1344
1345 Registers the L<DBIx::Class::ResultSource> in the schema with the given
1346 source name.
1347
1348 =cut
1349
1350 sub register_source { shift->_register_source(@_) }
1351
1352 =head2 unregister_source
1353
1354 =over 4
1355
1356 =item Arguments: $source_name
1357
1358 =back
1359
1360 Removes the L<DBIx::Class::ResultSource> from the schema for the given source name.
1361
1362 =cut
1363
1364 sub unregister_source { shift->_unregister_source(@_) }
1365
1366 =head2 register_extra_source
1367
1368 =over 4
1369
1370 =item Arguments: $source_name, L<$result_source|DBIx::Class::ResultSource>
1371
1372 =back
1373
1374 As L</register_source> but should be used if the result class already
1375 has a source and you want to register an extra one.
1376
1377 =cut
1378
1379 sub register_extra_source { shift->_register_source(@_, { extra => 1 }) }
1380
1381 sub _register_source {
1382   my ($self, $source_name, $source, $params) = @_;
1383
1384   $source = $source->new({ %$source, source_name => $source_name });
1385
1386   $source->schema($self);
1387   weaken $source->{schema} if ref($self);
1388
1389   my %reg = %{$self->source_registrations};
1390   $reg{$source_name} = $source;
1391   $self->source_registrations(\%reg);
1392
1393   return $source if $params->{extra};
1394
1395   my $rs_class = $source->result_class;
1396   if ($rs_class and my $rsrc = dbic_internal_try { $rs_class->result_source_instance } ) {
1397     my %map = %{$self->class_mappings};
1398     if (
1399       exists $map{$rs_class}
1400         and
1401       $map{$rs_class} ne $source_name
1402         and
1403       $rsrc ne $_[2]  # orig_source
1404     ) {
1405       carp
1406         "$rs_class already had a registered source which was replaced by this call. "
1407       . 'Perhaps you wanted register_extra_source(), though it is more likely you did '
1408       . 'something wrong.'
1409       ;
1410     }
1411
1412     $map{$rs_class} = $source_name;
1413     $self->class_mappings(\%map);
1414   }
1415
1416   return $source;
1417 }
1418
1419 my $global_phase_destroy;
1420 sub DESTROY {
1421   ### NO detected_reinvoked_destructor check
1422   ### This code very much relies on being called multuple times
1423
1424   return if $global_phase_destroy ||= in_global_destruction;
1425
1426   my $self = shift;
1427   my $srcs = $self->source_registrations;
1428
1429   for my $source_name (keys %$srcs) {
1430     # find first source that is not about to be GCed (someone other than $self
1431     # holds a reference to it) and reattach to it, weakening our own link
1432     #
1433     # during global destruction (if we have not yet bailed out) this should throw
1434     # which will serve as a signal to not try doing anything else
1435     # however beware - on older perls the exception seems randomly untrappable
1436     # due to some weird race condition during thread joining :(((
1437     if (length ref $srcs->{$source_name} and refcount($srcs->{$source_name}) > 1) {
1438       local $SIG{__DIE__} if $SIG{__DIE__};
1439       local $@;
1440       eval {
1441         $srcs->{$source_name}->schema($self);
1442         weaken $srcs->{$source_name};
1443         1;
1444       } or do {
1445         $global_phase_destroy = 1;
1446       };
1447
1448       last;
1449     }
1450   }
1451
1452   # Dummy NEXTSTATE ensuring the all temporaries on the stack are garbage
1453   # collected before leaving this scope. Depending on the code above, this
1454   # may very well be just a preventive measure guarding future modifications
1455   undef;
1456 }
1457
1458 sub _unregister_source {
1459     my ($self, $source_name) = @_;
1460     my %reg = %{$self->source_registrations};
1461
1462     my $source = delete $reg{$source_name};
1463     $self->source_registrations(\%reg);
1464     if ($source->result_class) {
1465         my %map = %{$self->class_mappings};
1466         delete $map{$source->result_class};
1467         $self->class_mappings(\%map);
1468     }
1469 }
1470
1471
1472 =head2 compose_connection (DEPRECATED)
1473
1474 =over 4
1475
1476 =item Arguments: $target_namespace, @db_info
1477
1478 =item Return Value: $new_schema
1479
1480 =back
1481
1482 DEPRECATED. You probably wanted compose_namespace.
1483
1484 Actually, you probably just wanted to call connect.
1485
1486 =begin hidden
1487
1488 (hidden due to deprecation)
1489
1490 Calls L<DBIx::Class::Schema/"compose_namespace"> to the target namespace,
1491 calls L<DBIx::Class::Schema/connection> with @db_info on the new schema,
1492 then injects the L<DBix::Class::ResultSetProxy> component and a
1493 resultset_instance classdata entry on all the new classes, in order to support
1494 $target_namespaces::$class->search(...) method calls.
1495
1496 This is primarily useful when you have a specific need for class method access
1497 to a connection. In normal usage it is preferred to call
1498 L<DBIx::Class::Schema/connect> and use the resulting schema object to operate
1499 on L<DBIx::Class::ResultSet> objects with L<DBIx::Class::Schema/resultset> for
1500 more information.
1501
1502 =end hidden
1503
1504 =cut
1505
1506 sub compose_connection {
1507   my ($self, $target, @info) = @_;
1508
1509   carp_once "compose_connection deprecated as of 0.08000"
1510     unless $INC{"DBIx/Class/CDBICompat.pm"};
1511
1512   dbic_internal_try {
1513     require DBIx::Class::ResultSetProxy;
1514   }
1515   catch {
1516     $self->throw_exception
1517       ("No arguments to load_classes and couldn't load DBIx::Class::ResultSetProxy ($_)")
1518   };
1519
1520   if ($self eq $target) {
1521     # Pathological case, largely caused by the docs on early C::M::DBIC::Plain
1522     foreach my $source_name ($self->sources) {
1523       my $source = $self->source($source_name);
1524       my $class = $source->result_class;
1525       $self->inject_base($class, 'DBIx::Class::ResultSetProxy');
1526       $class->mk_classaccessor(resultset_instance => $source->resultset);
1527       $class->mk_classaccessor(class_resolver => $self);
1528     }
1529     $self->connection(@info);
1530     return $self;
1531   }
1532
1533   my $schema = $self->compose_namespace($target, 'DBIx::Class::ResultSetProxy');
1534   quote_sub "${target}::schema", '$s', { '$s' => \$schema };
1535
1536   $schema->connection(@info);
1537   foreach my $source_name ($schema->sources) {
1538     my $source = $schema->source($source_name);
1539     my $class = $source->result_class;
1540     #warn "$source_name $class $source ".$source->storage;
1541     $class->mk_classaccessor(result_source_instance => $source);
1542     $class->mk_classaccessor(resultset_instance => $source->resultset);
1543     $class->mk_classaccessor(class_resolver => $schema);
1544   }
1545   return $schema;
1546 }
1547
1548 =head1 FURTHER QUESTIONS?
1549
1550 Check the list of L<additional DBIC resources|DBIx::Class/GETTING HELP/SUPPORT>.
1551
1552 =head1 COPYRIGHT AND LICENSE
1553
1554 This module is free software L<copyright|DBIx::Class/COPYRIGHT AND LICENSE>
1555 by the L<DBIx::Class (DBIC) authors|DBIx::Class/AUTHORS>. You can
1556 redistribute it and/or modify it under the same terms as the
1557 L<DBIx::Class library|DBIx::Class/COPYRIGHT AND LICENSE>.
1558
1559 =cut
1560
1561 1;