83fa077c82532b4f67262612cd39f319188eec5a
[dbsrgits/DBIx-Class-Schema-Loader.git] / lib / DBIx / Class / Schema / Loader / Base.pm
1 package DBIx::Class::Schema::Loader::Base;
2
3 use strict;
4 use warnings;
5 use base qw/Class::Accessor::Grouped Class::C3::Componentised/;
6 use mro 'c3';
7 use Carp::Clan qw/^DBIx::Class/;
8 use DBIx::Class::Schema::Loader::RelBuilder;
9 use Data::Dump qw/ dump /;
10 use POSIX qw//;
11 use File::Spec qw//;
12 use Cwd qw//;
13 use Digest::MD5 qw//;
14 use Lingua::EN::Inflect::Number qw//;
15 use Lingua::EN::Inflect::Phrase qw//;
16 use File::Temp qw//;
17 use Class::Unload;
18 use Class::Inspector ();
19 use Scalar::Util 'looks_like_number';
20 use File::Slurp 'slurp';
21 use DBIx::Class::Schema::Loader::Utils qw/split_name dumper_squashed eval_without_redefine_warnings/;
22 use DBIx::Class::Schema::Loader::Optional::Dependencies ();
23 use Try::Tiny;
24 use DBIx::Class ();
25 use Class::Load 'load_class';
26 use namespace::clean;
27
28 our $VERSION = '0.07009';
29
30 __PACKAGE__->mk_group_ro_accessors('simple', qw/
31                                 schema
32                                 schema_class
33
34                                 exclude
35                                 constraint
36                                 additional_classes
37                                 additional_base_classes
38                                 left_base_classes
39                                 components
40                                 skip_relationships
41                                 skip_load_external
42                                 moniker_map
43                                 col_accessor_map
44                                 custom_column_info
45                                 inflect_singular
46                                 inflect_plural
47                                 debug
48                                 dump_directory
49                                 dump_overwrite
50                                 really_erase_my_files
51                                 resultset_namespace
52                                 default_resultset_class
53                                 schema_base_class
54                                 result_base_class
55                                 use_moose
56                                 overwrite_modifications
57
58                                 relationship_attrs
59
60                                 db_schema
61                                 _tables
62                                 classes
63                                 _upgrading_classes
64                                 monikers
65                                 dynamic
66                                 naming
67                                 datetime_timezone
68                                 datetime_locale
69                                 config_file
70                                 loader_class
71                                 qualify_objects
72 /);
73
74
75 __PACKAGE__->mk_group_accessors('simple', qw/
76                                 version_to_dump
77                                 schema_version_to_dump
78                                 _upgrading_from
79                                 _upgrading_from_load_classes
80                                 _downgrading_to_load_classes
81                                 _rewriting_result_namespace
82                                 use_namespaces
83                                 result_namespace
84                                 generate_pod
85                                 pod_comment_mode
86                                 pod_comment_spillover_length
87                                 preserve_case
88                                 col_collision_map
89                                 rel_collision_map
90                                 real_dump_directory
91                                 result_component_map
92                                 datetime_undef_if_invalid
93                                 _result_class_methods
94 /);
95
96 =head1 NAME
97
98 DBIx::Class::Schema::Loader::Base - Base DBIx::Class::Schema::Loader Implementation.
99
100 =head1 SYNOPSIS
101
102 See L<DBIx::Class::Schema::Loader>
103
104 =head1 DESCRIPTION
105
106 This is the base class for the storage-specific C<DBIx::Class::Schema::*>
107 classes, and implements the common functionality between them.
108
109 =head1 CONSTRUCTOR OPTIONS
110
111 These constructor options are the base options for
112 L<DBIx::Class::Schema::Loader/loader_options>.  Available constructor options are:
113
114 =head2 skip_relationships
115
116 Skip setting up relationships.  The default is to attempt the loading
117 of relationships.
118
119 =head2 skip_load_external
120
121 Skip loading of other classes in @INC. The default is to merge all other classes
122 with the same name found in @INC into the schema file we are creating.
123
124 =head2 naming
125
126 Static schemas (ones dumped to disk) will, by default, use the new-style
127 relationship names and singularized Results, unless you're overwriting an
128 existing dump made by an older version of L<DBIx::Class::Schema::Loader>, in
129 which case the backward compatible RelBuilder will be activated, and the
130 appropriate monikerization used.
131
132 Specifying
133
134     naming => 'current'
135
136 will disable the backward-compatible RelBuilder and use
137 the new-style relationship names along with singularized Results, even when
138 overwriting a dump made with an earlier version.
139
140 The option also takes a hashref:
141
142     naming => { relationships => 'v7', monikers => 'v7' }
143
144 The keys are:
145
146 =over 4
147
148 =item relationships
149
150 How to name relationship accessors.
151
152 =item monikers
153
154 How to name Result classes.
155
156 =item column_accessors
157
158 How to name column accessors in Result classes.
159
160 =back
161
162 The values can be:
163
164 =over 4
165
166 =item current
167
168 Latest style, whatever that happens to be.
169
170 =item v4
171
172 Unsingularlized monikers, C<has_many> only relationships with no _id stripping.
173
174 =item v5
175
176 Monikers singularized as whole words, C<might_have> relationships for FKs on
177 C<UNIQUE> constraints, C<_id> stripping for belongs_to relationships.
178
179 Some of the C<_id> stripping edge cases in C<0.05003> have been reverted for
180 the v5 RelBuilder.
181
182 =item v6
183
184 All monikers and relationships are inflected using
185 L<Lingua::EN::Inflect::Phrase>, and there is more aggressive C<_id> stripping
186 from relationship names.
187
188 In general, there is very little difference between v5 and v6 schemas.
189
190 =item v7
191
192 This mode is identical to C<v6> mode, except that monikerization of CamelCase
193 table names is also done correctly.
194
195 CamelCase column names in case-preserving mode will also be handled correctly
196 for relationship name inflection. See L</preserve_case>.
197
198 In this mode, CamelCase L</column_accessors> are normalized based on case
199 transition instead of just being lowercased, so C<FooId> becomes C<foo_id>.
200
201 If you don't have any CamelCase table or column names, you can upgrade without
202 breaking any of your code.
203
204 =back
205
206 Dynamic schemas will always default to the 0.04XXX relationship names and won't
207 singularize Results for backward compatibility, to activate the new RelBuilder
208 and singularization put this in your C<Schema.pm> file:
209
210     __PACKAGE__->naming('current');
211
212 Or if you prefer to use 0.07XXX features but insure that nothing breaks in the
213 next major version upgrade:
214
215     __PACKAGE__->naming('v7');
216
217 =head2 generate_pod
218
219 By default POD will be generated for columns and relationships, using database
220 metadata for the text if available and supported.
221
222 Reading database metadata (e.g. C<COMMENT ON TABLE some_table ...>) is only
223 supported for Postgres right now.
224
225 Set this to C<0> to turn off all POD generation.
226
227 =head2 pod_comment_mode
228
229 Controls where table comments appear in the generated POD. Smaller table
230 comments are appended to the C<NAME> section of the documentation, and larger
231 ones are inserted into C<DESCRIPTION> instead. You can force a C<DESCRIPTION>
232 section to be generated with the comment always, only use C<NAME>, or choose
233 the length threshold at which the comment is forced into the description.
234
235 =over 4
236
237 =item name
238
239 Use C<NAME> section only.
240
241 =item description
242
243 Force C<DESCRIPTION> always.
244
245 =item auto
246
247 Use C<DESCRIPTION> if length > L</pod_comment_spillover_length>, this is the
248 default.
249
250 =back
251
252 =head2 pod_comment_spillover_length
253
254 When pod_comment_mode is set to C<auto>, this is the length of the comment at
255 which it will be forced into a separate description section.
256
257 The default is C<60>
258
259 =head2 relationship_attrs
260
261 Hashref of attributes to pass to each generated relationship, listed
262 by type.  Also supports relationship type 'all', containing options to
263 pass to all generated relationships.  Attributes set for more specific
264 relationship types override those set in 'all'.
265
266 For example:
267
268   relationship_attrs => {
269     belongs_to => { is_deferrable => 0 },
270   },
271
272 use this to turn off DEFERRABLE on your foreign key constraints.
273
274 =head2 debug
275
276 If set to true, each constructive L<DBIx::Class> statement the loader
277 decides to execute will be C<warn>-ed before execution.
278
279 =head2 db_schema
280
281 Set the name of the schema to load (schema in the sense that your database
282 vendor means it).  Does not currently support loading more than one schema
283 name.
284
285 =head2 constraint
286
287 Only load tables matching regex.  Best specified as a qr// regex.
288
289 =head2 exclude
290
291 Exclude tables matching regex.  Best specified as a qr// regex.
292
293 =head2 moniker_map
294
295 Overrides the default table name to moniker translation.  Can be either
296 a hashref of table keys and moniker values, or a coderef for a translator
297 function taking a single scalar table name argument and returning
298 a scalar moniker.  If the hash entry does not exist, or the function
299 returns a false value, the code falls back to default behavior
300 for that table name.
301
302 The default behavior is to split on case transition and non-alphanumeric
303 boundaries, singularize the resulting phrase, then join the titlecased words
304 together. Examples:
305
306     Table Name       | Moniker Name
307     ---------------------------------
308     luser            | Luser
309     luser_group      | LuserGroup
310     luser-opts       | LuserOpt
311     stations_visited | StationVisited
312     routeChange      | RouteChange
313
314 =head2 col_accessor_map
315
316 Same as moniker_map, but for column accessor names.  If a coderef is
317 passed, the code is called with arguments of
318
319    the name of the column in the underlying database,
320    default accessor name that DBICSL would ordinarily give this column,
321    {
322       table_class     => name of the DBIC class we are building,
323       table_moniker   => calculated moniker for this table (after moniker_map if present),
324       table_name      => name of the database table,
325       full_table_name => schema-qualified name of the database table (RDBMS specific),
326       schema_class    => name of the schema class we are building,
327       column_info     => hashref of column info (data_type, is_nullable, etc),
328     }
329
330 =head2 inflect_plural
331
332 Just like L</moniker_map> above (can be hash/code-ref, falls back to default
333 if hash key does not exist or coderef returns false), but acts as a map
334 for pluralizing relationship names.  The default behavior is to utilize
335 L<Lingua::EN::Inflect::Phrase/to_PL>.
336
337 =head2 inflect_singular
338
339 As L</inflect_plural> above, but for singularizing relationship names.
340 Default behavior is to utilize L<Lingua::EN::Inflect::Phrase/to_S>.
341
342 =head2 schema_base_class
343
344 Base class for your schema classes. Defaults to 'DBIx::Class::Schema'.
345
346 =head2 result_base_class
347
348 Base class for your table classes (aka result classes). Defaults to
349 'DBIx::Class::Core'.
350
351 =head2 additional_base_classes
352
353 List of additional base classes all of your table classes will use.
354
355 =head2 left_base_classes
356
357 List of additional base classes all of your table classes will use
358 that need to be leftmost.
359
360 =head2 additional_classes
361
362 List of additional classes which all of your table classes will use.
363
364 =head2 components
365
366 List of additional components to be loaded into all of your table
367 classes.  A good example would be
368 L<InflateColumn::DateTime|DBIx::Class::InflateColumn::DateTime>
369
370 =head2 result_component_map
371
372 A hashref of moniker keys and component values.  Unlike C<components>, which loads the
373 given components into every table class, this option allows you to load certain
374 components for specified tables.  For example:
375
376   result_component_map => {
377       StationVisited => '+YourApp::Schema::Component::StationVisited',
378       RouteChange    => [
379                             '+YourApp::Schema::Component::RouteChange',
380                             'InflateColumn::DateTime',
381                         ],
382   }
383   
384 You may use this in conjunction with C<components>.
385
386 =head2 use_namespaces
387
388 This is now the default, to go back to L<DBIx::Class::Schema/load_classes> pass
389 a C<0>.
390
391 Generate result class names suitable for
392 L<DBIx::Class::Schema/load_namespaces> and call that instead of
393 L<DBIx::Class::Schema/load_classes>. When using this option you can also
394 specify any of the options for C<load_namespaces> (i.e. C<result_namespace>,
395 C<resultset_namespace>, C<default_resultset_class>), and they will be added
396 to the call (and the generated result class names adjusted appropriately).
397
398 =head2 dump_directory
399
400 The value of this option is a perl libdir pathname.  Within
401 that directory this module will create a baseline manual
402 L<DBIx::Class::Schema> module set, based on what it creates at runtime.
403
404 The created schema class will have the same classname as the one on
405 which you are setting this option (and the ResultSource classes will be
406 based on this name as well).
407
408 Normally you wouldn't hard-code this setting in your schema class, as it
409 is meant for one-time manual usage.
410
411 See L<DBIx::Class::Schema::Loader/dump_to_dir> for examples of the
412 recommended way to access this functionality.
413
414 =head2 dump_overwrite
415
416 Deprecated.  See L</really_erase_my_files> below, which does *not* mean
417 the same thing as the old C<dump_overwrite> setting from previous releases.
418
419 =head2 really_erase_my_files
420
421 Default false.  If true, Loader will unconditionally delete any existing
422 files before creating the new ones from scratch when dumping a schema to disk.
423
424 The default behavior is instead to only replace the top portion of the
425 file, up to and including the final stanza which contains
426 C<# DO NOT MODIFY THE FIRST PART OF THIS FILE>
427 leaving any customizations you placed after that as they were.
428
429 When C<really_erase_my_files> is not set, if the output file already exists,
430 but the aforementioned final stanza is not found, or the checksum
431 contained there does not match the generated contents, Loader will
432 croak and not touch the file.
433
434 You should really be using version control on your schema classes (and all
435 of the rest of your code for that matter).  Don't blame me if a bug in this
436 code wipes something out when it shouldn't have, you've been warned.
437
438 =head2 overwrite_modifications
439
440 Default false.  If false, when updating existing files, Loader will
441 refuse to modify any Loader-generated code that has been modified
442 since its last run (as determined by the checksum Loader put in its
443 comment lines).
444
445 If true, Loader will discard any manual modifications that have been
446 made to Loader-generated code.
447
448 Again, you should be using version control on your schema classes.  Be
449 careful with this option.
450
451 =head2 custom_column_info
452
453 Hook for adding extra attributes to the
454 L<column_info|DBIx::Class::ResultSource/column_info> for a column.
455
456 Must be a coderef that returns a hashref with the extra attributes.
457
458 Receives the table name, column name and column_info.
459
460 For example:
461
462   custom_column_info => sub {
463       my ($table_name, $column_name, $column_info) = @_;
464
465       if ($column_name eq 'dog' && $column_info->{default_value} eq 'snoopy') {
466           return { is_snoopy => 1 };
467       }
468   },
469
470 This attribute can also be used to set C<inflate_datetime> on a non-datetime
471 column so it also receives the L</datetime_timezone> and/or L</datetime_locale>.
472
473 =head2 datetime_timezone
474
475 Sets the timezone attribute for L<DBIx::Class::InflateColumn::DateTime> for all
476 columns with the DATE/DATETIME/TIMESTAMP data_types.
477
478 =head2 datetime_locale
479
480 Sets the locale attribute for L<DBIx::Class::InflateColumn::DateTime> for all
481 columns with the DATE/DATETIME/TIMESTAMP data_types.
482
483 =head2 datetime_undef_if_invalid
484
485 Pass a C<0> for this option when using MySQL if you B<DON'T> want C<<
486 datetime_undef_if_invalid => 1 >> in your column info for DATE, DATETIME and
487 TIMESTAMP columns.
488
489 The default is recommended to deal with data such as C<00/00/00> which
490 sometimes ends up in such columns in MySQL.
491
492 =head2 config_file
493
494 File in Perl format, which should return a HASH reference, from which to read
495 loader options.
496
497 =head2 preserve_case
498
499 Usually column names are lowercased, to make them easier to work with in
500 L<DBIx::Class>. This option lets you turn this behavior off, if the driver
501 supports it.
502
503 Drivers for case sensitive databases like Sybase ASE or MSSQL with a
504 case-sensitive collation will turn this option on unconditionally.
505
506 Currently the drivers for SQLite, mysql, MSSQL and Firebird/InterBase support
507 setting this option.
508
509 =head2 qualify_objects
510
511 Set to true to prepend the L</db_schema> to table names for C<<
512 __PACKAGE__->table >> calls, and to some other things like Oracle sequences.
513
514 =head2 use_moose
515
516 Creates Schema and Result classes that use L<Moose>, L<MooseX::NonMoose> and
517 L<namespace::autoclean>. The default content after the md5 sum also makes the
518 classes immutable.
519
520 It is safe to upgrade your existing Schema to this option.
521
522 =head2 col_collision_map
523
524 This option controls how accessors for column names which collide with perl
525 methods are named. See L</COLUMN ACCESSOR COLLISIONS> for more information.
526
527 This option takes either a single L<sprintf|perlfunc/sprintf> format or a hashref of
528 strings which are compiled to regular expressions that map to
529 L<sprintf|perlfunc/sprintf> formats.
530
531 Examples:
532
533     col_collision_map => 'column_%s'
534
535     col_collision_map => { '(.*)' => 'column_%s' }
536
537     col_collision_map => { '(foo).*(bar)' => 'column_%s_%s' }
538
539 =head2 rel_collision_map
540
541 Works just like L</col_collision_map>, but for relationship names/accessors
542 rather than column names/accessors.
543
544 The default is to just append C<_rel> to the relationship name, see
545 L</RELATIONSHIP NAME COLLISIONS>.
546
547 =head1 METHODS
548
549 None of these methods are intended for direct invocation by regular
550 users of L<DBIx::Class::Schema::Loader>. Some are proxied via
551 L<DBIx::Class::Schema::Loader>.
552
553 =cut
554
555 my $CURRENT_V = 'v7';
556
557 my @CLASS_ARGS = qw(
558     schema_base_class result_base_class additional_base_classes
559     left_base_classes additional_classes components
560 );
561
562 # ensure that a peice of object data is a valid arrayref, creating
563 # an empty one or encapsulating whatever's there.
564 sub _ensure_arrayref {
565     my $self = shift;
566
567     foreach (@_) {
568         $self->{$_} ||= [];
569         $self->{$_} = [ $self->{$_} ]
570             unless ref $self->{$_} eq 'ARRAY';
571     }
572 }
573
574 =head2 new
575
576 Constructor for L<DBIx::Class::Schema::Loader::Base>, used internally
577 by L<DBIx::Class::Schema::Loader>.
578
579 =cut
580
581 sub new {
582     my ( $class, %args ) = @_;
583
584     if (exists $args{column_accessor_map}) {
585         $args{col_accessor_map} = delete $args{column_accessor_map};
586     }
587
588     my $self = { %args };
589
590     # don't lose undef options
591     for (values %$self) {
592         $_ = 0 unless defined $_;
593     }
594
595     bless $self => $class;
596
597     if (my $config_file = $self->config_file) {
598         my $config_opts = do $config_file;
599
600         croak "Error reading config from $config_file: $@" if $@;
601
602         croak "Config file $config_file must be a hashref" unless ref($config_opts) eq 'HASH';
603
604         while (my ($k, $v) = each %$config_opts) {
605             $self->{$k} = $v unless exists $self->{$k};
606         }
607     }
608
609     $self->_ensure_arrayref(qw/additional_classes
610                                additional_base_classes
611                                left_base_classes
612                                components
613                               /);
614
615     $self->_validate_class_args;
616
617     if ($self->result_component_map) {
618         my %rc_map = %{ $self->result_component_map };
619         foreach my $moniker (keys %rc_map) {
620             $rc_map{$moniker} = [ $rc_map{$moniker} ] unless ref $rc_map{$moniker};
621         }
622         $self->result_component_map(\%rc_map);
623     }
624     $self->_validate_result_component_map;
625
626     if ($self->use_moose) {
627         if (not DBIx::Class::Schema::Loader::Optional::Dependencies->req_ok_for('use_moose')) {
628             die sprintf "You must install the following CPAN modules to enable the use_moose option: %s.\n",
629                 DBIx::Class::Schema::Loader::Optional::Dependencies->req_missing_for('use_moose');
630         }
631     }
632
633     $self->{monikers} = {};
634     $self->{classes} = {};
635     $self->{_upgrading_classes} = {};
636
637     $self->{schema_class} ||= ( ref $self->{schema} || $self->{schema} );
638     $self->{schema} ||= $self->{schema_class};
639
640     croak "dump_overwrite is deprecated.  Please read the"
641         . " DBIx::Class::Schema::Loader::Base documentation"
642             if $self->{dump_overwrite};
643
644     $self->{dynamic} = ! $self->{dump_directory};
645     $self->{temp_directory} ||= File::Temp::tempdir( 'dbicXXXX',
646                                                      TMPDIR  => 1,
647                                                      CLEANUP => 1,
648                                                    );
649
650     $self->{dump_directory} ||= $self->{temp_directory};
651
652     $self->real_dump_directory($self->{dump_directory});
653
654     $self->version_to_dump($DBIx::Class::Schema::Loader::VERSION);
655     $self->schema_version_to_dump($DBIx::Class::Schema::Loader::VERSION);
656
657     if ((not ref $self->naming) && defined $self->naming) {
658         my $naming_ver = $self->naming;
659         $self->{naming} = {
660             relationships => $naming_ver,
661             monikers => $naming_ver,
662             column_accessors => $naming_ver,
663         };
664     }
665
666     if ($self->naming) {
667         for (values %{ $self->naming }) {
668             $_ = $CURRENT_V if $_ eq 'current';
669         }
670     }
671     $self->{naming} ||= {};
672
673     if ($self->custom_column_info && ref $self->custom_column_info ne 'CODE') {
674         croak 'custom_column_info must be a CODE ref';
675     }
676
677     $self->_check_back_compat;
678
679     $self->use_namespaces(1) unless defined $self->use_namespaces;
680     $self->generate_pod(1)   unless defined $self->generate_pod;
681     $self->pod_comment_mode('auto')         unless defined $self->pod_comment_mode;
682     $self->pod_comment_spillover_length(60) unless defined $self->pod_comment_spillover_length;
683
684     if (my $col_collision_map = $self->col_collision_map) {
685         if (my $reftype = ref $col_collision_map) {
686             if ($reftype ne 'HASH') {
687                 croak "Invalid type $reftype for option 'col_collision_map'";
688             }
689         }
690         else {
691             $self->col_collision_map({ '(.*)' => $col_collision_map });
692         }
693     }
694
695     $self;
696 }
697
698 sub _check_back_compat {
699     my ($self) = @_;
700
701 # dynamic schemas will always be in 0.04006 mode, unless overridden
702     if ($self->dynamic) {
703 # just in case, though no one is likely to dump a dynamic schema
704         $self->schema_version_to_dump('0.04006');
705
706         if (not %{ $self->naming }) {
707             warn <<EOF unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
708
709 Dynamic schema detected, will run in 0.04006 mode.
710
711 Set the 'naming' attribute or the SCHEMA_LOADER_BACKCOMPAT environment variable
712 to disable this warning.
713
714 Also consider setting 'use_namespaces => 1' if/when upgrading.
715
716 See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 for more
717 details.
718 EOF
719         }
720         else {
721             $self->_upgrading_from('v4');
722         }
723
724         $self->naming->{relationships} ||= 'v4';
725         $self->naming->{monikers}      ||= 'v4';
726
727         if ($self->use_namespaces) {
728             $self->_upgrading_from_load_classes(1);
729         }
730         else {
731             $self->use_namespaces(0);
732         }
733
734         return;
735     }
736
737 # otherwise check if we need backcompat mode for a static schema
738     my $filename = $self->_get_dump_filename($self->schema_class);
739     return unless -e $filename;
740
741     my ($old_gen, $old_md5, $old_ver, $old_ts, $old_custom) =
742       $self->_parse_generated_file($filename);
743
744     return unless $old_ver;
745
746     # determine if the existing schema was dumped with use_moose => 1
747     if (! defined $self->use_moose) {
748         $self->{use_moose} = 1 if $old_gen =~ /^ (?!\s*\#) use \s+ Moose/xm;
749     }
750
751     my $load_classes = ($old_gen =~ /^__PACKAGE__->load_classes;/m) ? 1 : 0;
752     my $result_namespace = do { ($old_gen =~ /result_namespace => '([^']+)'/) ? $1 : '' };
753
754     if ($load_classes && (not defined $self->use_namespaces)) {
755         warn <<"EOF"  unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
756
757 'load_classes;' static schema detected, turning off 'use_namespaces'.
758
759 Set the 'use_namespaces' attribute or the SCHEMA_LOADER_BACKCOMPAT environment
760 variable to disable this warning.
761
762 See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 for more
763 details.
764 EOF
765         $self->use_namespaces(0);
766     }
767     elsif ($load_classes && $self->use_namespaces) {
768         $self->_upgrading_from_load_classes(1);
769     }
770     elsif ((not $load_classes) && defined $self->use_namespaces && ! $self->use_namespaces) {
771         $self->_downgrading_to_load_classes(
772             $result_namespace || 'Result'
773         );
774     }
775     elsif ((not defined $self->use_namespaces) || $self->use_namespaces) {
776         if (not $self->result_namespace) {
777             $self->result_namespace($result_namespace || 'Result');
778         }
779         elsif ($result_namespace ne $self->result_namespace) {
780             $self->_rewriting_result_namespace(
781                 $result_namespace || 'Result'
782             );
783         }
784     }
785
786     # XXX when we go past .0 this will need fixing
787     my ($v) = $old_ver =~ /([1-9])/;
788     $v = "v$v";
789
790     return if ($v eq $CURRENT_V || $old_ver =~ /^0\.\d\d999/);
791
792     if (not %{ $self->naming }) {
793         warn <<"EOF" unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
794
795 Version $old_ver static schema detected, turning on backcompat mode.
796
797 Set the 'naming' attribute or the SCHEMA_LOADER_BACKCOMPAT environment variable
798 to disable this warning.
799
800 See: 'naming' in perldoc DBIx::Class::Schema::Loader::Base .
801
802 See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 if upgrading
803 from version 0.04006.
804 EOF
805
806         $self->naming->{relationships}    ||= $v;
807         $self->naming->{monikers}         ||= $v;
808         $self->naming->{column_accessors} ||= $v;
809
810         $self->schema_version_to_dump($old_ver);
811     }
812     else {
813         $self->_upgrading_from($v);
814     }
815 }
816
817 sub _validate_class_args {
818     my $self = shift;
819
820     foreach my $k (@CLASS_ARGS) {
821         next unless $self->$k;
822
823         my @classes = ref $self->$k eq 'ARRAY' ? @{ $self->$k } : $self->$k;
824         $self->_validate_classes($k, \@classes);
825     }
826 }
827
828 sub _validate_result_component_map {
829     my $self = shift;
830
831     my $map = $self->result_component_map;
832     return unless $map && ref $map eq 'HASH';
833
834     foreach my $classes (values %$map) {
835         $self->_validate_classes('result_component_map', [@$classes]);
836     }
837 }
838
839 sub _validate_classes {
840     my $self = shift;
841     my $key  = shift;
842     my $classes = shift;
843
844     foreach my $c (@$classes) {
845         # components default to being under the DBIx::Class namespace unless they
846         # are preceeded with a '+'
847         if ( $key =~ m/component/ && $c !~ s/^\+// ) {
848             $c = 'DBIx::Class::' . $c;
849         }
850
851         # 1 == installed, 0 == not installed, undef == invalid classname
852         my $installed = Class::Inspector->installed($c);
853         if ( defined($installed) ) {
854             if ( $installed == 0 ) {
855                 croak qq/$c, as specified in the loader option "$key", is not installed/;
856             }
857         } else {
858             croak qq/$c, as specified in the loader option "$key", is an invalid class name/;
859         }
860     }
861 }
862
863
864 sub _find_file_in_inc {
865     my ($self, $file) = @_;
866
867     foreach my $prefix (@INC) {
868         my $fullpath = File::Spec->catfile($prefix, $file);
869         return $fullpath if -f $fullpath
870             # abs_path throws on Windows for nonexistant files
871             and (try { Cwd::abs_path($fullpath) }) ne
872                ((try { Cwd::abs_path(File::Spec->catfile($self->dump_directory, $file)) }) || '');
873     }
874
875     return;
876 }
877
878 sub _class_path {
879     my ($self, $class) = @_;
880
881     my $class_path = $class;
882     $class_path =~ s{::}{/}g;
883     $class_path .= '.pm';
884
885     return $class_path;
886 }
887
888 sub _find_class_in_inc {
889     my ($self, $class) = @_;
890
891     return $self->_find_file_in_inc($self->_class_path($class));
892 }
893
894 sub _rewriting {
895     my $self = shift;
896
897     return $self->_upgrading_from
898         || $self->_upgrading_from_load_classes
899         || $self->_downgrading_to_load_classes
900         || $self->_rewriting_result_namespace
901     ;
902 }
903
904 sub _rewrite_old_classnames {
905     my ($self, $code) = @_;
906
907     return $code unless $self->_rewriting;
908
909     my %old_classes = reverse %{ $self->_upgrading_classes };
910
911     my $re = join '|', keys %old_classes;
912     $re = qr/\b($re)\b/;
913
914     $code =~ s/$re/$old_classes{$1} || $1/eg;
915
916     return $code;
917 }
918
919 sub _load_external {
920     my ($self, $class) = @_;
921
922     return if $self->{skip_load_external};
923
924     # so that we don't load our own classes, under any circumstances
925     local *INC = [ grep $_ ne $self->dump_directory, @INC ];
926
927     my $real_inc_path = $self->_find_class_in_inc($class);
928
929     my $old_class = $self->_upgrading_classes->{$class}
930         if $self->_rewriting;
931
932     my $old_real_inc_path = $self->_find_class_in_inc($old_class)
933         if $old_class && $old_class ne $class;
934
935     return unless $real_inc_path || $old_real_inc_path;
936
937     if ($real_inc_path) {
938         # If we make it to here, we loaded an external definition
939         warn qq/# Loaded external class definition for '$class'\n/
940             if $self->debug;
941
942         my $code = $self->_rewrite_old_classnames(scalar slurp $real_inc_path);
943
944         if ($self->dynamic) { # load the class too
945             eval_without_redefine_warnings($code);
946         }
947
948         $self->_ext_stmt($class,
949           qq|# These lines were loaded from '$real_inc_path' found in \@INC.\n|
950          .qq|# They are now part of the custom portion of this file\n|
951          .qq|# for you to hand-edit.  If you do not either delete\n|
952          .qq|# this section or remove that file from \@INC, this section\n|
953          .qq|# will be repeated redundantly when you re-create this\n|
954          .qq|# file again via Loader!  See skip_load_external to disable\n|
955          .qq|# this feature.\n|
956         );
957         chomp $code;
958         $self->_ext_stmt($class, $code);
959         $self->_ext_stmt($class,
960             qq|# End of lines loaded from '$real_inc_path' |
961         );
962     }
963
964     if ($old_real_inc_path) {
965         my $code = slurp $old_real_inc_path;
966
967         $self->_ext_stmt($class, <<"EOF");
968
969 # These lines were loaded from '$old_real_inc_path',
970 # based on the Result class name that would have been created by an older
971 # version of the Loader. For a static schema, this happens only once during
972 # upgrade. See skip_load_external to disable this feature.
973 EOF
974
975         $code = $self->_rewrite_old_classnames($code);
976
977         if ($self->dynamic) {
978             warn <<"EOF";
979
980 Detected external content in '$old_real_inc_path', a class name that would have
981 been used by an older version of the Loader.
982
983 * PLEASE RENAME THIS CLASS: from '$old_class' to '$class', as that is the
984 new name of the Result.
985 EOF
986             eval_without_redefine_warnings($code);
987         }
988
989         chomp $code;
990         $self->_ext_stmt($class, $code);
991         $self->_ext_stmt($class,
992             qq|# End of lines loaded from '$old_real_inc_path' |
993         );
994     }
995 }
996
997 =head2 load
998
999 Does the actual schema-construction work.
1000
1001 =cut
1002
1003 sub load {
1004     my $self = shift;
1005
1006     $self->_load_tables(
1007         $self->_tables_list({ constraint => $self->constraint, exclude => $self->exclude })
1008     );
1009 }
1010
1011 =head2 rescan
1012
1013 Arguments: schema
1014
1015 Rescan the database for changes. Returns a list of the newly added table
1016 monikers.
1017
1018 The schema argument should be the schema class or object to be affected.  It
1019 should probably be derived from the original schema_class used during L</load>.
1020
1021 =cut
1022
1023 sub rescan {
1024     my ($self, $schema) = @_;
1025
1026     $self->{schema} = $schema;
1027     $self->_relbuilder->{schema} = $schema;
1028
1029     my @created;
1030     my @current = $self->_tables_list({ constraint => $self->constraint, exclude => $self->exclude });
1031
1032     foreach my $table (@current) {
1033         if(!exists $self->{_tables}->{$table}) {
1034             push(@created, $table);
1035         }
1036     }
1037
1038     my %current;
1039     @current{@current} = ();
1040     foreach my $table (keys %{ $self->{_tables} }) {
1041         if (not exists $current{$table}) {
1042             $self->_unregister_source_for_table($table);
1043         }
1044     }
1045
1046     delete $self->{_dump_storage};
1047     delete $self->{_relations_started};
1048
1049     my $loaded = $self->_load_tables(@current);
1050
1051     return map { $self->monikers->{$_} } @created;
1052 }
1053
1054 sub _relbuilder {
1055     my ($self) = @_;
1056
1057     return if $self->{skip_relationships};
1058
1059     return $self->{relbuilder} ||= do {
1060
1061         no warnings 'uninitialized';
1062         my $relbuilder_suff =
1063             {qw{
1064                 v4  ::Compat::v0_040
1065                 v5  ::Compat::v0_05
1066                 v6  ::Compat::v0_06
1067             }}
1068             ->{ $self->naming->{relationships}};
1069
1070         my $relbuilder_class = 'DBIx::Class::Schema::Loader::RelBuilder'.$relbuilder_suff;
1071         load_class $relbuilder_class;
1072         $relbuilder_class->new( $self );
1073
1074     };
1075 }
1076
1077 sub _load_tables {
1078     my ($self, @tables) = @_;
1079
1080     # Save the new tables to the tables list
1081     foreach (@tables) {
1082         $self->{_tables}->{$_} = 1;
1083     }
1084
1085     $self->_make_src_class($_) for @tables;
1086
1087     # sanity-check for moniker clashes
1088     my $inverse_moniker_idx;
1089     for (keys %{$self->monikers}) {
1090       push @{$inverse_moniker_idx->{$self->monikers->{$_}}}, $_;
1091     }
1092
1093     my @clashes;
1094     for (keys %$inverse_moniker_idx) {
1095       my $tables = $inverse_moniker_idx->{$_};
1096       if (@$tables > 1) {
1097         push @clashes, sprintf ("tables %s reduced to the same source moniker '%s'",
1098           join (', ', map { "'$_'" } @$tables),
1099           $_,
1100         );
1101       }
1102     }
1103
1104     if (@clashes) {
1105       die   'Unable to load schema - chosen moniker/class naming style results in moniker clashes. '
1106           . 'Either change the naming style, or supply an explicit moniker_map: '
1107           . join ('; ', @clashes)
1108           . "\n"
1109       ;
1110     }
1111
1112
1113     $self->_setup_src_meta($_) for @tables;
1114
1115     if(!$self->skip_relationships) {
1116         # The relationship loader needs a working schema
1117         $self->{quiet} = 1;
1118         local $self->{dump_directory} = $self->{temp_directory};
1119         $self->_reload_classes(\@tables);
1120         $self->_load_relationships($_) for @tables;
1121         $self->_relbuilder->cleanup;
1122         $self->{quiet} = 0;
1123
1124         # Remove that temp dir from INC so it doesn't get reloaded
1125         @INC = grep $_ ne $self->dump_directory, @INC;
1126     }
1127
1128     $self->_load_external($_)
1129         for map { $self->classes->{$_} } @tables;
1130
1131     # Reload without unloading first to preserve any symbols from external
1132     # packages.
1133     $self->_reload_classes(\@tables, { unload => 0 });
1134
1135     # Drop temporary cache
1136     delete $self->{_cache};
1137
1138     return \@tables;
1139 }
1140
1141 sub _reload_classes {
1142     my ($self, $tables, $opts) = @_;
1143
1144     my @tables = @$tables;
1145
1146     my $unload = $opts->{unload};
1147     $unload = 1 unless defined $unload;
1148
1149     # so that we don't repeat custom sections
1150     @INC = grep $_ ne $self->dump_directory, @INC;
1151
1152     $self->_dump_to_dir(map { $self->classes->{$_} } @tables);
1153
1154     unshift @INC, $self->dump_directory;
1155     
1156     my @to_register;
1157     my %have_source = map { $_ => $self->schema->source($_) }
1158         $self->schema->sources;
1159
1160     for my $table (@tables) {
1161         my $moniker = $self->monikers->{$table};
1162         my $class = $self->classes->{$table};
1163         
1164         {
1165             no warnings 'redefine';
1166             local *Class::C3::reinitialize = sub {};  # to speed things up, reinitialized below
1167             use warnings;
1168
1169             if (my $mc = $self->_moose_metaclass($class)) {
1170                 $mc->make_mutable;
1171             }
1172             Class::Unload->unload($class) if $unload;
1173             my ($source, $resultset_class);
1174             if (
1175                 ($source = $have_source{$moniker})
1176                 && ($resultset_class = $source->resultset_class)
1177                 && ($resultset_class ne 'DBIx::Class::ResultSet')
1178             ) {
1179                 my $has_file = Class::Inspector->loaded_filename($resultset_class);
1180                 if (my $mc = $self->_moose_metaclass($resultset_class)) {
1181                     $mc->make_mutable;
1182                 }
1183                 Class::Unload->unload($resultset_class) if $unload;
1184                 $self->_reload_class($resultset_class) if $has_file;
1185             }
1186             $self->_reload_class($class);
1187         }
1188         push @to_register, [$moniker, $class];
1189     }
1190
1191     Class::C3->reinitialize;
1192     for (@to_register) {
1193         $self->schema->register_class(@$_);
1194     }
1195 }
1196
1197 sub _moose_metaclass {
1198   return undef unless $INC{'Class/MOP.pm'};   # if CMOP is not loaded the class could not have loaded in the 1st place
1199
1200   my $class = $_[1];
1201
1202   my $mc = try { Class::MOP::class_of($class) }
1203     or return undef;
1204
1205   return $mc->isa('Moose::Meta::Class') ? $mc : undef;
1206 }
1207
1208 # We use this instead of ensure_class_loaded when there are package symbols we
1209 # want to preserve.
1210 sub _reload_class {
1211     my ($self, $class) = @_;
1212
1213     my $class_path = $self->_class_path($class);
1214     delete $INC{ $class_path };
1215
1216 # kill redefined warnings
1217     try {
1218         eval_without_redefine_warnings ("require $class");
1219     }
1220     catch {
1221         my $source = slurp $self->_get_dump_filename($class);
1222         die "Failed to reload class $class: $_.\n\nCLASS SOURCE:\n\n$source";
1223     };
1224 }
1225
1226 sub _get_dump_filename {
1227     my ($self, $class) = (@_);
1228
1229     $class =~ s{::}{/}g;
1230     return $self->dump_directory . q{/} . $class . q{.pm};
1231 }
1232
1233 =head2 get_dump_filename
1234
1235 Arguments: class
1236
1237 Returns the full path to the file for a class that the class has been or will
1238 be dumped to. This is a file in a temp dir for a dynamic schema.
1239
1240 =cut
1241
1242 sub get_dump_filename {
1243     my ($self, $class) = (@_);
1244
1245     local $self->{dump_directory} = $self->real_dump_directory;
1246
1247     return $self->_get_dump_filename($class);
1248 }
1249
1250 sub _ensure_dump_subdirs {
1251     my ($self, $class) = (@_);
1252
1253     my @name_parts = split(/::/, $class);
1254     pop @name_parts; # we don't care about the very last element,
1255                      # which is a filename
1256
1257     my $dir = $self->dump_directory;
1258     while (1) {
1259         if(!-d $dir) {
1260             mkdir($dir) or croak "mkdir('$dir') failed: $!";
1261         }
1262         last if !@name_parts;
1263         $dir = File::Spec->catdir($dir, shift @name_parts);
1264     }
1265 }
1266
1267 sub _dump_to_dir {
1268     my ($self, @classes) = @_;
1269
1270     my $schema_class = $self->schema_class;
1271     my $schema_base_class = $self->schema_base_class || 'DBIx::Class::Schema';
1272
1273     my $target_dir = $self->dump_directory;
1274     warn "Dumping manual schema for $schema_class to directory $target_dir ...\n"
1275         unless $self->{dynamic} or $self->{quiet};
1276
1277     my $schema_text =
1278           qq|package $schema_class;\n\n|
1279         . qq|# Created by DBIx::Class::Schema::Loader\n|
1280         . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|;
1281
1282     if ($self->use_moose) {
1283         $schema_text.= qq|use Moose;\nuse namespace::autoclean;\nextends '$schema_base_class';\n\n|;
1284     }
1285     else {
1286         $schema_text .= qq|use strict;\nuse warnings;\n\nuse base '$schema_base_class';\n\n|;
1287     }
1288
1289     if ($self->use_namespaces) {
1290         $schema_text .= qq|__PACKAGE__->load_namespaces|;
1291         my $namespace_options;
1292
1293         my @attr = qw/resultset_namespace default_resultset_class/;
1294
1295         unshift @attr, 'result_namespace' unless (not $self->result_namespace) || $self->result_namespace eq 'Result';
1296
1297         for my $attr (@attr) {
1298             if ($self->$attr) {
1299                 $namespace_options .= qq|    $attr => '| . $self->$attr . qq|',\n|
1300             }
1301         }
1302         $schema_text .= qq|(\n$namespace_options)| if $namespace_options;
1303         $schema_text .= qq|;\n|;
1304     }
1305     else {
1306         $schema_text .= qq|__PACKAGE__->load_classes;\n|;
1307     }
1308
1309     {
1310         local $self->{version_to_dump} = $self->schema_version_to_dump;
1311         $self->_write_classfile($schema_class, $schema_text, 1);
1312     }
1313
1314     my $result_base_class = $self->result_base_class || 'DBIx::Class::Core';
1315
1316     foreach my $src_class (@classes) {
1317         my $src_text = 
1318               qq|package $src_class;\n\n|
1319             . qq|# Created by DBIx::Class::Schema::Loader\n|
1320             . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|
1321             . qq|use strict;\nuse warnings;\n\n|;
1322         if ($self->use_moose) {
1323             $src_text.= qq|use Moose;\nuse MooseX::NonMoose;\nuse namespace::autoclean;|;
1324
1325             # these options 'use base' which is compile time
1326             if (@{ $self->left_base_classes } || @{ $self->additional_base_classes }) {
1327                 $src_text .= qq|\nBEGIN { extends '$result_base_class' }\n\n|;
1328             }
1329             else {
1330                 $src_text .= qq|\nextends '$result_base_class';\n\n|;
1331             }
1332         }
1333         else {
1334              $src_text .= qq|use base '$result_base_class';\n\n|;
1335         }
1336         $self->_write_classfile($src_class, $src_text);
1337     }
1338
1339     # remove Result dir if downgrading from use_namespaces, and there are no
1340     # files left.
1341     if (my $result_ns = $self->_downgrading_to_load_classes
1342                         || $self->_rewriting_result_namespace) {
1343         my $result_namespace = $self->_result_namespace(
1344             $schema_class,
1345             $result_ns,
1346         );
1347
1348         (my $result_dir = $result_namespace) =~ s{::}{/}g;
1349         $result_dir = $self->dump_directory . '/' . $result_dir;
1350
1351         unless (my @files = glob "$result_dir/*") {
1352             rmdir $result_dir;
1353         }
1354     }
1355
1356     warn "Schema dump completed.\n" unless $self->{dynamic} or $self->{quiet};
1357
1358 }
1359
1360 sub _sig_comment {
1361     my ($self, $version, $ts) = @_;
1362     return qq|\n\n# Created by DBIx::Class::Schema::Loader|
1363          . qq| v| . $version
1364          . q| @ | . $ts 
1365          . qq|\n# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:|;
1366 }
1367
1368 sub _write_classfile {
1369     my ($self, $class, $text, $is_schema) = @_;
1370
1371     my $filename = $self->_get_dump_filename($class);
1372     $self->_ensure_dump_subdirs($class);
1373
1374     if (-f $filename && $self->really_erase_my_files) {
1375         warn "Deleting existing file '$filename' due to "
1376             . "'really_erase_my_files' setting\n" unless $self->{quiet};
1377         unlink($filename);
1378     }
1379
1380     my ($old_gen, $old_md5, $old_ver, $old_ts, $old_custom)
1381         = $self->_parse_generated_file($filename);
1382
1383     if (! $old_gen && -f $filename) {
1384         croak "Cannot overwrite '$filename' without 'really_erase_my_files',"
1385             . " it does not appear to have been generated by Loader"
1386     }
1387
1388     my $custom_content = $old_custom || '';
1389
1390     # prepend extra custom content from a *renamed* class (singularization effect)
1391     if (my $renamed_class = $self->_upgrading_classes->{$class}) {
1392         my $old_filename = $self->_get_dump_filename($renamed_class);
1393
1394         if (-f $old_filename) {
1395             my $extra_custom = ($self->_parse_generated_file ($old_filename))[4];
1396
1397             $extra_custom =~ s/\n\n# You can replace.*\n1;\n//;
1398
1399             $custom_content = join ("\n", '', $extra_custom, $custom_content)
1400                 if $extra_custom;
1401
1402             unlink $old_filename;
1403         }
1404     }
1405
1406     $custom_content ||= $self->_default_custom_content($is_schema);
1407
1408     # If upgrading to use_moose=1 replace default custom content with default Moose custom content.
1409     # If there is already custom content, which does not have the Moose content, add it.
1410     if ($self->use_moose) {
1411
1412         my $non_moose_custom_content = do {
1413             local $self->{use_moose} = 0;
1414             $self->_default_custom_content;
1415         };
1416
1417         if ($custom_content eq $non_moose_custom_content) {
1418             $custom_content = $self->_default_custom_content($is_schema);
1419         }
1420         elsif ($custom_content !~ /\Q@{[$self->_default_moose_custom_content($is_schema)]}\E/) {
1421             $custom_content .= $self->_default_custom_content($is_schema);
1422         }
1423     }
1424     elsif (defined $self->use_moose && $old_gen) {
1425         croak 'It is not possible to "downgrade" a schema that was loaded with use_moose => 1 to use_moose => 0, due to differing custom content'
1426             if $old_gen =~ /use \s+ MooseX?\b/x;
1427     }
1428
1429     $custom_content = $self->_rewrite_old_classnames($custom_content);
1430
1431     $text .= qq|$_\n|
1432         for @{$self->{_dump_storage}->{$class} || []};
1433
1434     # Check and see if the dump is infact differnt
1435
1436     my $compare_to;
1437     if ($old_md5) {
1438       $compare_to = $text . $self->_sig_comment($old_ver, $old_ts);
1439       if (Digest::MD5::md5_base64($compare_to) eq $old_md5) {
1440         return unless $self->_upgrading_from && $is_schema;
1441       }
1442     }
1443
1444     $text .= $self->_sig_comment(
1445       $self->version_to_dump,
1446       POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime)
1447     );
1448
1449     open(my $fh, '>', $filename)
1450         or croak "Cannot open '$filename' for writing: $!";
1451
1452     # Write the top half and its MD5 sum
1453     print $fh $text . Digest::MD5::md5_base64($text) . "\n";
1454
1455     # Write out anything loaded via external partial class file in @INC
1456     print $fh qq|$_\n|
1457         for @{$self->{_ext_storage}->{$class} || []};
1458
1459     # Write out any custom content the user has added
1460     print $fh $custom_content;
1461
1462     close($fh)
1463         or croak "Error closing '$filename': $!";
1464 }
1465
1466 sub _default_moose_custom_content {
1467     my ($self, $is_schema) = @_;
1468
1469     if (not $is_schema) {
1470         return qq|\n__PACKAGE__->meta->make_immutable;|;
1471     }
1472     
1473     return qq|\n__PACKAGE__->meta->make_immutable(inline_constructor => 0);|;
1474 }
1475
1476 sub _default_custom_content {
1477     my ($self, $is_schema) = @_;
1478     my $default = qq|\n\n# You can replace this text with custom|
1479          . qq| code or comments, and it will be preserved on regeneration|;
1480     if ($self->use_moose) {
1481         $default .= $self->_default_moose_custom_content($is_schema);
1482     }
1483     $default .= qq|\n1;\n|;
1484     return $default;
1485 }
1486
1487 sub _parse_generated_file {
1488     my ($self, $fn) = @_;
1489
1490     return unless -f $fn;
1491
1492     open(my $fh, '<', $fn)
1493         or croak "Cannot open '$fn' for reading: $!";
1494
1495     my $mark_re =
1496         qr{^(# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:)([A-Za-z0-9/+]{22})\n};
1497
1498     my ($md5, $ts, $ver, $gen);
1499     while(<$fh>) {
1500         if(/$mark_re/) {
1501             my $pre_md5 = $1;
1502             $md5 = $2;
1503
1504             # Pull out the version and timestamp from the line above
1505             ($ver, $ts) = $gen =~ m/^# Created by DBIx::Class::Schema::Loader v(.*?) @ (.*?)\Z/m;
1506
1507             $gen .= $pre_md5;
1508             croak "Checksum mismatch in '$fn', the auto-generated part of the file has been modified outside of this loader.  Aborting.\nIf you want to overwrite these modifications, set the 'overwrite_modifications' loader option.\n"
1509                 if !$self->overwrite_modifications && Digest::MD5::md5_base64($gen) ne $md5;
1510
1511             last;
1512         }
1513         else {
1514             $gen .= $_;
1515         }
1516     }
1517
1518     my $custom = do { local $/; <$fh> }
1519         if $md5;
1520
1521     close ($fh);
1522
1523     return ($gen, $md5, $ver, $ts, $custom);
1524 }
1525
1526 sub _use {
1527     my $self = shift;
1528     my $target = shift;
1529
1530     foreach (@_) {
1531         warn "$target: use $_;" if $self->debug;
1532         $self->_raw_stmt($target, "use $_;");
1533     }
1534 }
1535
1536 sub _inject {
1537     my $self = shift;
1538     my $target = shift;
1539
1540     my $blist = join(q{ }, @_);
1541
1542     return unless $blist;
1543
1544     warn "$target: use base qw/$blist/;" if $self->debug;
1545     $self->_raw_stmt($target, "use base qw/$blist/;");
1546 }
1547
1548 sub _result_namespace {
1549     my ($self, $schema_class, $ns) = @_;
1550     my @result_namespace;
1551
1552     if ($ns =~ /^\+(.*)/) {
1553         # Fully qualified namespace
1554         @result_namespace = ($1)
1555     }
1556     else {
1557         # Relative namespace
1558         @result_namespace = ($schema_class, $ns);
1559     }
1560
1561     return wantarray ? @result_namespace : join '::', @result_namespace;
1562 }
1563
1564 # Create class with applicable bases, setup monikers, etc
1565 sub _make_src_class {
1566     my ($self, $table) = @_;
1567
1568     my $schema       = $self->schema;
1569     my $schema_class = $self->schema_class;
1570
1571     my $table_moniker = $self->_table2moniker($table);
1572     my @result_namespace = ($schema_class);
1573     if ($self->use_namespaces) {
1574         my $result_namespace = $self->result_namespace || 'Result';
1575         @result_namespace = $self->_result_namespace(
1576             $schema_class,
1577             $result_namespace,
1578         );
1579     }
1580     my $table_class = join(q{::}, @result_namespace, $table_moniker);
1581
1582     if ((my $upgrading_v = $self->_upgrading_from)
1583             || $self->_rewriting) {
1584         local $self->naming->{monikers} = $upgrading_v
1585             if $upgrading_v;
1586
1587         my @result_namespace = @result_namespace;
1588         if ($self->_upgrading_from_load_classes) {
1589             @result_namespace = ($schema_class);
1590         }
1591         elsif (my $ns = $self->_downgrading_to_load_classes) {
1592             @result_namespace = $self->_result_namespace(
1593                 $schema_class,
1594                 $ns,
1595             );
1596         }
1597         elsif ($ns = $self->_rewriting_result_namespace) {
1598             @result_namespace = $self->_result_namespace(
1599                 $schema_class,
1600                 $ns,
1601             );
1602         }
1603
1604         my $old_class = join(q{::}, @result_namespace,
1605             $self->_table2moniker($table));
1606
1607         $self->_upgrading_classes->{$table_class} = $old_class
1608             unless $table_class eq $old_class;
1609     }
1610
1611 # this was a bad idea, should be ok now without it
1612 #    my $table_normalized = lc $table;
1613 #    $self->classes->{$table_normalized} = $table_class;
1614 #    $self->monikers->{$table_normalized} = $table_moniker;
1615
1616     $self->classes->{$table} = $table_class;
1617     $self->monikers->{$table} = $table_moniker;
1618
1619     $self->_use   ($table_class, @{$self->additional_classes});
1620     $self->_inject($table_class, @{$self->left_base_classes});
1621
1622     my @components = @{ $self->components || [] };
1623
1624     push @components, @{ $self->result_component_map->{$table_moniker} }
1625         if exists $self->result_component_map->{$table_moniker};
1626
1627     $self->_dbic_stmt($table_class, 'load_components', @components) if @components;
1628
1629     $self->_inject($table_class, @{$self->additional_base_classes});
1630 }
1631
1632 sub _is_result_class_method {
1633     my ($self, $name, $table_name) = @_;
1634
1635     my $table_moniker = $table_name ? $self->_table2moniker($table_name) : '';
1636
1637     if (not $self->_result_class_methods) {
1638         my (@methods, %methods);
1639         my $base       = $self->result_base_class || 'DBIx::Class::Core';
1640
1641         my @components = @{ $self->components || [] };
1642
1643         push @components, @{ $self->result_component_map->{$table_moniker} }
1644             if exists $self->result_component_map->{$table_moniker};
1645
1646         for my $c (@components) {
1647             $c = $c =~ /^\+/ ? substr($c,1) : "DBIx::Class::$c";
1648         }
1649
1650         for my $class ($base, @components, $self->use_moose ? 'Moose::Object' : ()) {
1651             load_class $class;
1652
1653             push @methods, @{ Class::Inspector->methods($class) || [] };
1654         }
1655
1656         push @methods, @{ Class::Inspector->methods('UNIVERSAL') };
1657
1658         @methods{@methods} = ();
1659
1660         # futureproof meta
1661         $methods{meta} = undef;
1662
1663         $self->_result_class_methods(\%methods);
1664     }
1665     my $result_methods = $self->_result_class_methods;
1666
1667     return exists $result_methods->{$name};
1668 }
1669
1670 sub _resolve_col_accessor_collisions {
1671     my ($self, $table, $col_info) = @_;
1672
1673     my $table_name = ref $table ? $$table : $table;
1674
1675     while (my ($col, $info) = each %$col_info) {
1676         my $accessor = $info->{accessor} || $col;
1677
1678         next if $accessor eq 'id'; # special case (very common column)
1679
1680         if ($self->_is_result_class_method($accessor, $table_name)) {
1681             my $mapped = 0;
1682
1683             if (my $map = $self->col_collision_map) {
1684                 for my $re (keys %$map) {
1685                     if (my @matches = $col =~ /$re/) {
1686                         $info->{accessor} = sprintf $map->{$re}, @matches;
1687                         $mapped = 1;
1688                     }
1689                 }
1690             }
1691
1692             if (not $mapped) {
1693                 warn <<"EOF";
1694 Column '$col' in table '$table_name' collides with an inherited method.
1695 See "COLUMN ACCESSOR COLLISIONS" in perldoc DBIx::Class::Schema::Loader::Base .
1696 EOF
1697                 $info->{accessor} = undef;
1698             }
1699         }
1700     }
1701 }
1702
1703 # use the same logic to run moniker_map, col_accessor_map, and
1704 # relationship_name_map
1705 sub _run_user_map {
1706     my ( $self, $map, $default_code, $ident, @extra ) = @_;
1707
1708     my $default_ident = $default_code->( $ident, @extra );
1709     my $new_ident;
1710     if( $map && ref $map eq 'HASH' ) {
1711         $new_ident = $map->{ $ident };
1712     }
1713     elsif( $map && ref $map eq 'CODE' ) {
1714         $new_ident = $map->( $ident, $default_ident, @extra );
1715     }
1716
1717     $new_ident ||= $default_ident;
1718
1719     return $new_ident;
1720 }
1721
1722 sub _default_column_accessor_name {
1723     my ( $self, $column_name ) = @_;
1724
1725     my $accessor_name = $column_name;
1726     $accessor_name =~ s/\W+/_/g;
1727
1728     if ((($self->naming->{column_accessors}||'') =~ /(\d+)/ && $1 < 7) || (not $self->preserve_case)) {
1729         # older naming just lc'd the col accessor and that's all.
1730         return lc $accessor_name;
1731     }
1732
1733     return join '_', map lc, split_name $column_name;
1734
1735 }
1736
1737 sub _make_column_accessor_name {
1738     my ($self, $column_name, $column_context_info ) = @_;
1739
1740     my $accessor = $self->_run_user_map(
1741         $self->col_accessor_map,
1742         sub { $self->_default_column_accessor_name( shift ) },
1743         $column_name,
1744         $column_context_info,
1745        );
1746
1747     return $accessor;
1748 }
1749
1750 # Set up metadata (cols, pks, etc)
1751 sub _setup_src_meta {
1752     my ($self, $table) = @_;
1753
1754     my $schema       = $self->schema;
1755     my $schema_class = $self->schema_class;
1756
1757     my $table_class = $self->classes->{$table};
1758     my $table_moniker = $self->monikers->{$table};
1759
1760     my $table_name = $table;
1761     my $name_sep   = $self->schema->storage->sql_maker->name_sep;
1762
1763     if ($name_sep && $table_name =~ /\Q$name_sep\E/) {
1764         $table_name = \ $self->_quote_table_name($table_name);
1765     }
1766
1767     my $full_table_name = ($self->qualify_objects ? ($self->db_schema . '.') : '') . (ref $table_name ? $$table_name : $table_name);
1768
1769     # be careful to not create refs Data::Dump can "optimize"
1770     $full_table_name    = \do {"".$full_table_name} if ref $table_name;
1771
1772     $self->_dbic_stmt($table_class, 'table', $full_table_name);
1773
1774     my $cols     = $self->_table_columns($table);
1775     my $col_info = $self->__columns_info_for($table);
1776
1777     ### generate all the column accessor names
1778     while (my ($col, $info) = each %$col_info) {
1779         # hashref of other info that could be used by
1780         # user-defined accessor map functions
1781         my $context = {
1782             table_class     => $table_class,
1783             table_moniker   => $table_moniker,
1784             table_name      => $table_name,
1785             full_table_name => $full_table_name,
1786             schema_class    => $schema_class,
1787             column_info     => $info,
1788         };
1789
1790         $info->{accessor} = $self->_make_column_accessor_name( $col, $context );
1791     }
1792
1793     $self->_resolve_col_accessor_collisions($full_table_name, $col_info);
1794
1795     # prune any redundant accessor names
1796     while (my ($col, $info) = each %$col_info) {
1797         no warnings 'uninitialized';
1798         delete $info->{accessor} if $info->{accessor} eq $col;
1799     }
1800
1801     my $fks = $self->_table_fk_info($table);
1802
1803     foreach my $fkdef (@$fks) {
1804         for my $col (@{ $fkdef->{local_columns} }) {
1805             $col_info->{$col}{is_foreign_key} = 1;
1806         }
1807     }
1808
1809     my $pks = $self->_table_pk_info($table) || [];
1810
1811     foreach my $pkcol (@$pks) {
1812         $col_info->{$pkcol}{is_nullable} = 0;
1813     }
1814
1815     $self->_dbic_stmt(
1816         $table_class,
1817         'add_columns',
1818         map { $_, ($col_info->{$_}||{}) } @$cols
1819     );
1820
1821     my %uniq_tag; # used to eliminate duplicate uniqs
1822
1823     @$pks ? $self->_dbic_stmt($table_class,'set_primary_key',@$pks)
1824           : carp("$table has no primary key");
1825     $uniq_tag{ join("\0", @$pks) }++ if @$pks; # pk is a uniq
1826
1827     my $uniqs = $self->_table_uniq_info($table) || [];
1828     for (@$uniqs) {
1829         my ($name, $cols) = @$_;
1830         next if $uniq_tag{ join("\0", @$cols) }++; # skip duplicates
1831         $self->_dbic_stmt($table_class,'add_unique_constraint', $name, $cols);
1832     }
1833
1834 }
1835
1836 sub __columns_info_for {
1837     my ($self, $table) = @_;
1838
1839     my $result = $self->_columns_info_for($table);
1840
1841     while (my ($col, $info) = each %$result) {
1842         $info = { %$info, %{ $self->_custom_column_info  ($table, $col, $info) } };
1843         $info = { %$info, %{ $self->_datetime_column_info($table, $col, $info) } };
1844
1845         $result->{$col} = $info;
1846     }
1847
1848     return $result;
1849 }
1850
1851 =head2 tables
1852
1853 Returns a sorted list of loaded tables, using the original database table
1854 names.
1855
1856 =cut
1857
1858 sub tables {
1859     my $self = shift;
1860
1861     return keys %{$self->_tables};
1862 }
1863
1864 # Make a moniker from a table
1865 sub _default_table2moniker {
1866     no warnings 'uninitialized';
1867     my ($self, $table) = @_;
1868
1869     if ($self->naming->{monikers} eq 'v4') {
1870         return join '', map ucfirst, split /[\W_]+/, lc $table;
1871     }
1872     elsif ($self->naming->{monikers} eq 'v5') {
1873         return join '', map ucfirst, split /[\W_]+/,
1874             Lingua::EN::Inflect::Number::to_S(lc $table);
1875     }
1876     elsif ($self->naming->{monikers} eq 'v6') {
1877         (my $as_phrase = lc $table) =~ s/_+/ /g;
1878         my $inflected = Lingua::EN::Inflect::Phrase::to_S($as_phrase);
1879
1880         return join '', map ucfirst, split /\W+/, $inflected;
1881     }
1882
1883     my @words = map lc, split_name $table;
1884     my $as_phrase = join ' ', @words;
1885
1886     my $inflected = Lingua::EN::Inflect::Phrase::to_S($as_phrase);
1887
1888     return join '', map ucfirst, split /\W+/, $inflected;
1889 }
1890
1891 sub _table2moniker {
1892     my ( $self, $table ) = @_;
1893
1894     $self->_run_user_map(
1895         $self->moniker_map,
1896         sub { $self->_default_table2moniker( shift ) },
1897         $table
1898        );
1899 }
1900
1901 sub _load_relationships {
1902     my ($self, $table) = @_;
1903
1904     my $tbl_fk_info = $self->_table_fk_info($table);
1905     foreach my $fkdef (@$tbl_fk_info) {
1906         $fkdef->{remote_source} =
1907             $self->monikers->{delete $fkdef->{remote_table}};
1908     }
1909     my $tbl_uniq_info = $self->_table_uniq_info($table);
1910
1911     my $local_moniker = $self->monikers->{$table};
1912     my $rel_stmts = $self->_relbuilder->generate_code($local_moniker, $tbl_fk_info, $tbl_uniq_info);
1913
1914     foreach my $src_class (sort keys %$rel_stmts) {
1915         my $src_stmts = $rel_stmts->{$src_class};
1916         foreach my $stmt (@$src_stmts) {
1917             $self->_dbic_stmt($src_class,$stmt->{method},@{$stmt->{args}});
1918         }
1919     }
1920 }
1921
1922 # Overload these in driver class:
1923
1924 # Returns an arrayref of column names
1925 sub _table_columns { croak "ABSTRACT METHOD" }
1926
1927 # Returns arrayref of pk col names
1928 sub _table_pk_info { croak "ABSTRACT METHOD" }
1929
1930 # Returns an arrayref of uniqs [ [ foo => [ col1, col2 ] ], [ bar => [ ... ] ] ]
1931 sub _table_uniq_info { croak "ABSTRACT METHOD" }
1932
1933 # Returns an arrayref of foreign key constraints, each
1934 #   being a hashref with 3 keys:
1935 #   local_columns (arrayref), remote_columns (arrayref), remote_table
1936 sub _table_fk_info { croak "ABSTRACT METHOD" }
1937
1938 # Returns an array of lower case table names
1939 sub _tables_list { croak "ABSTRACT METHOD" }
1940
1941 # Execute a constructive DBIC class method, with debug/dump_to_dir hooks.
1942 sub _dbic_stmt {
1943     my $self   = shift;
1944     my $class  = shift;
1945     my $method = shift;
1946
1947     # generate the pod for this statement, storing it with $self->_pod
1948     $self->_make_pod( $class, $method, @_ ) if $self->generate_pod;
1949
1950     my $args = dump(@_);
1951     $args = '(' . $args . ')' if @_ < 2;
1952     my $stmt = $method . $args . q{;};
1953
1954     warn qq|$class\->$stmt\n| if $self->debug;
1955     $self->_raw_stmt($class, '__PACKAGE__->' . $stmt);
1956     return;
1957 }
1958
1959 # generates the accompanying pod for a DBIC class method statement,
1960 # storing it with $self->_pod
1961 sub _make_pod {
1962     my $self   = shift;
1963     my $class  = shift;
1964     my $method = shift;
1965
1966     if ( $method eq 'table' ) {
1967         my ($table) = @_;
1968         my $pcm = $self->pod_comment_mode;
1969         my ($comment, $comment_overflows, $comment_in_name, $comment_in_desc);
1970         $comment = $self->__table_comment($table);
1971         $comment_overflows = ($comment and length $comment > $self->pod_comment_spillover_length);
1972         $comment_in_name   = ($pcm eq 'name' or ($pcm eq 'auto' and !$comment_overflows));
1973         $comment_in_desc   = ($pcm eq 'description' or ($pcm eq 'auto' and $comment_overflows));
1974         $self->_pod( $class, "=head1 NAME" );
1975         my $table_descr = $class;
1976         $table_descr .= " - " . $comment if $comment and $comment_in_name;
1977         $self->{_class2table}{ $class } = $table;
1978         $self->_pod( $class, $table_descr );
1979         if ($comment and $comment_in_desc) {
1980             $self->_pod( $class, "=head1 DESCRIPTION" );
1981             $self->_pod( $class, $comment );
1982         }
1983         $self->_pod_cut( $class );
1984     } elsif ( $method eq 'add_columns' ) {
1985         $self->_pod( $class, "=head1 ACCESSORS" );
1986         my $col_counter = 0;
1987         my @cols = @_;
1988         while( my ($name,$attrs) = splice @cols,0,2 ) {
1989             $col_counter++;
1990             $self->_pod( $class, '=head2 ' . $name  );
1991             $self->_pod( $class,
1992                 join "\n", map {
1993                     my $s = $attrs->{$_};
1994                     $s = !defined $s          ? 'undef'             :
1995                         length($s) == 0       ? '(empty string)'    :
1996                         ref($s) eq 'SCALAR'   ? $$s                 :
1997                         ref($s)               ? dumper_squashed $s  :
1998                         looks_like_number($s) ? $s                  : qq{'$s'};
1999
2000                     "  $_: $s"
2001                  } sort keys %$attrs,
2002             );
2003             if (my $comment = $self->__column_comment($self->{_class2table}{$class}, $col_counter, $name)) {
2004                 $self->_pod( $class, $comment );
2005             }
2006         }
2007         $self->_pod_cut( $class );
2008     } elsif ( $method =~ /^(belongs_to|has_many|might_have)$/ ) {
2009         $self->_pod( $class, "=head1 RELATIONS" ) unless $self->{_relations_started} { $class } ;
2010         my ( $accessor, $rel_class ) = @_;
2011         $self->_pod( $class, "=head2 $accessor" );
2012         $self->_pod( $class, 'Type: ' . $method );
2013         $self->_pod( $class, "Related object: L<$rel_class>" );
2014         $self->_pod_cut( $class );
2015         $self->{_relations_started} { $class } = 1;
2016     }
2017 }
2018
2019 sub _filter_comment {
2020     my ($self, $txt) = @_;
2021
2022     $txt = '' if not defined $txt;
2023
2024     $txt =~ s/(?:\015?\012|\015\012?)/\n/g;
2025
2026     return $txt;
2027 }
2028
2029 sub __table_comment {
2030     my $self = shift;
2031
2032     if (my $code = $self->can('_table_comment')) {
2033         return $self->_filter_comment($self->$code(@_));
2034     }
2035     
2036     return '';
2037 }
2038
2039 sub __column_comment {
2040     my $self = shift;
2041
2042     if (my $code = $self->can('_column_comment')) {
2043         return $self->_filter_comment($self->$code(@_));
2044     }
2045
2046     return '';
2047 }
2048
2049 # Stores a POD documentation
2050 sub _pod {
2051     my ($self, $class, $stmt) = @_;
2052     $self->_raw_stmt( $class, "\n" . $stmt  );
2053 }
2054
2055 sub _pod_cut {
2056     my ($self, $class ) = @_;
2057     $self->_raw_stmt( $class, "\n=cut\n" );
2058 }
2059
2060 # Store a raw source line for a class (for dumping purposes)
2061 sub _raw_stmt {
2062     my ($self, $class, $stmt) = @_;
2063     push(@{$self->{_dump_storage}->{$class}}, $stmt);
2064 }
2065
2066 # Like above, but separately for the externally loaded stuff
2067 sub _ext_stmt {
2068     my ($self, $class, $stmt) = @_;
2069     push(@{$self->{_ext_storage}->{$class}}, $stmt);
2070 }
2071
2072 sub _quote_table_name {
2073     my ($self, $table) = @_;
2074
2075     my $qt = $self->schema->storage->sql_maker->quote_char;
2076
2077     return $table unless $qt;
2078
2079     if (ref $qt) {
2080         return $qt->[0] . $table . $qt->[1];
2081     }
2082
2083     return $qt . $table . $qt;
2084 }
2085
2086 sub _custom_column_info {
2087     my ( $self, $table_name, $column_name, $column_info ) = @_;
2088
2089     if (my $code = $self->custom_column_info) {
2090         return $code->($table_name, $column_name, $column_info) || {};
2091     }
2092     return {};
2093 }
2094
2095 sub _datetime_column_info {
2096     my ( $self, $table_name, $column_name, $column_info ) = @_;
2097     my $result = {};
2098     my $type = $column_info->{data_type} || '';
2099     if ((grep $_, @{ $column_info }{map "inflate_$_", qw/date datetime timestamp/})
2100             or ($type =~ /date|timestamp/i)) {
2101         $result->{timezone} = $self->datetime_timezone if $self->datetime_timezone;
2102         $result->{locale}   = $self->datetime_locale   if $self->datetime_locale;
2103     }
2104     return $result;
2105 }
2106
2107 sub _lc {
2108     my ($self, $name) = @_;
2109
2110     return $self->preserve_case ? $name : lc($name);
2111 }
2112
2113 sub _uc {
2114     my ($self, $name) = @_;
2115
2116     return $self->preserve_case ? $name : uc($name);
2117 }
2118
2119 sub _unregister_source_for_table {
2120     my ($self, $table) = @_;
2121
2122     try {
2123         local $@;
2124         my $schema = $self->schema;
2125         # in older DBIC it's a private method
2126         my $unregister = $schema->can('unregister_source') || $schema->can('_unregister_source');
2127         $schema->$unregister($self->_table2moniker($table));
2128         delete $self->monikers->{$table};
2129         delete $self->classes->{$table};
2130         delete $self->_upgrading_classes->{$table};
2131         delete $self->{_tables}{$table};
2132     };
2133 }
2134
2135 # remove the dump dir from @INC on destruction
2136 sub DESTROY {
2137     my $self = shift;
2138
2139     @INC = grep $_ ne $self->dump_directory, @INC;
2140 }
2141
2142 =head2 monikers
2143
2144 Returns a hashref of loaded table to moniker mappings.  There will
2145 be two entries for each table, the original name and the "normalized"
2146 name, in the case that the two are different (such as databases
2147 that like uppercase table names, or preserve your original mixed-case
2148 definitions, or what-have-you).
2149
2150 =head2 classes
2151
2152 Returns a hashref of table to class mappings.  In some cases it will
2153 contain multiple entries per table for the original and normalized table
2154 names, as above in L</monikers>.
2155
2156 =head1 COLUMN ACCESSOR COLLISIONS
2157
2158 Occasionally you may have a column name that collides with a perl method, such
2159 as C<can>. In such cases, the default action is to set the C<accessor> of the
2160 column spec to C<undef>.
2161
2162 You can then name the accessor yourself by placing code such as the following
2163 below the md5:
2164
2165     __PACKAGE__->add_column('+can' => { accessor => 'my_can' });
2166
2167 Another option is to use the L</col_collision_map> option.
2168
2169 =head1 RELATIONSHIP NAME COLLISIONS
2170
2171 In very rare cases, you may get a collision between a generated relationship
2172 name and a method in your Result class, for example if you have a foreign key
2173 called C<belongs_to>.
2174
2175 This is a problem because relationship names are also relationship accessor
2176 methods in L<DBIx::Class>.
2177
2178 The default behavior is to append C<_rel> to the relationship name and print
2179 out a warning that refers to this text.
2180
2181 You can also control the renaming with the L</rel_collision_map> option.
2182
2183 =head1 SEE ALSO
2184
2185 L<DBIx::Class::Schema::Loader>
2186
2187 =head1 AUTHOR
2188
2189 See L<DBIx::Class::Schema::Loader/AUTHOR> and L<DBIx::Class::Schema::Loader/CONTRIBUTORS>.
2190
2191 =head1 LICENSE
2192
2193 This library is free software; you can redistribute it and/or modify it under
2194 the same terms as Perl itself.
2195
2196 =cut
2197
2198 1;
2199 # vim:et sts=4 sw=4 tw=0: