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