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