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