64a9a6cd3666591cde9de1ed221376b58c0d71c8
[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::Fast Class::C3::Componentised/;
6 use Class::C3;
7 use Carp::Clan qw/^DBIx::Class/;
8 use DBIx::Class::Schema::Loader::RelBuilder;
9 use Data::Dump qw/ dump /;
10 use POSIX qw//;
11 use File::Spec qw//;
12 use Cwd qw//;
13 use Digest::MD5 qw//;
14 use Lingua::EN::Inflect::Number qw//;
15 use File::Temp qw//;
16 use Class::Unload;
17 require DBIx::Class;
18
19 our $VERSION = '0.04999_11';
20
21 __PACKAGE__->mk_ro_accessors(qw/
22                                 schema
23                                 schema_class
24
25                                 exclude
26                                 constraint
27                                 additional_classes
28                                 additional_base_classes
29                                 left_base_classes
30                                 components
31                                 resultset_components
32                                 skip_relationships
33                                 moniker_map
34                                 inflect_singular
35                                 inflect_plural
36                                 debug
37                                 dump_directory
38                                 dump_overwrite
39                                 really_erase_my_files
40                                 use_namespaces
41                                 result_namespace
42                                 resultset_namespace
43                                 default_resultset_class
44                                 schema_base_class
45                                 result_base_class
46
47                                 db_schema
48                                 _tables
49                                 classes
50                                 monikers
51                                 dynamic
52                              /);
53
54 __PACKAGE__->mk_accessors(qw/
55                                 version_to_dump
56                                 schema_version_to_dump
57 /);
58
59 =head1 NAME
60
61 DBIx::Class::Schema::Loader::Base - Base DBIx::Class::Schema::Loader Implementation.
62
63 =head1 SYNOPSIS
64
65 See L<DBIx::Class::Schema::Loader>
66
67 =head1 DESCRIPTION
68
69 This is the base class for the storage-specific C<DBIx::Class::Schema::*>
70 classes, and implements the common functionality between them.
71
72 =head1 CONSTRUCTOR OPTIONS
73
74 These constructor options are the base options for
75 L<DBIx::Class::Schema::Loader/loader_options>.  Available constructor options are:
76
77 =head2 skip_relationships
78
79 Skip setting up relationships.  The default is to attempt the loading
80 of relationships.
81
82 =head2 naming
83
84 Static schemas (ones dumped to disk) will, by default, use the new-style 0.05XXX
85 relationship names and singularized Results, unless you're overwriting an
86 existing dump made by a 0.04XXX version of L<DBIx::Class::Schema::Loader>, in
87 which case the backward compatible RelBuilder will be activated, and
88 singularization will be turned off.
89
90 Specifying
91
92     naming => 'v5'
93
94 will disable the backward-compatible RelBuilder and use
95 the new-style relationship names along with singularized Results, even when
96 overwriting a dump made with an earlier version.
97
98 The option also takes a hashref:
99
100     naming => { relationships => 'v5', results => 'v4' }
101
102 The values can be:
103
104 =over 4
105
106 =item current
107
108 Latest default style, whatever that happens to be.
109
110 =item v5
111
112 Version 0.05XXX style.
113
114 =item v4
115
116 Version 0.04XXX style.
117
118 =back
119
120 Dynamic schemas will always default to the 0.04XXX relationship names and won't
121 singularize Results for backward compatibility, to activate the new RelBuilder
122 and singularization put this in your C<Schema.pm> file:
123
124     __PACKAGE__->naming('current');
125
126 Or if you prefer to use 0.05XXX features but insure that nothing breaks in the
127 next major version upgrade:
128
129     __PACKAGE__->naming('v5');
130
131 =head2 debug
132
133 If set to true, each constructive L<DBIx::Class> statement the loader
134 decides to execute will be C<warn>-ed before execution.
135
136 =head2 db_schema
137
138 Set the name of the schema to load (schema in the sense that your database
139 vendor means it).  Does not currently support loading more than one schema
140 name.
141
142 =head2 constraint
143
144 Only load tables matching regex.  Best specified as a qr// regex.
145
146 =head2 exclude
147
148 Exclude tables matching regex.  Best specified as a qr// regex.
149
150 =head2 moniker_map
151
152 Overrides the default table name to moniker translation.  Can be either
153 a hashref of table keys and moniker values, or a coderef for a translator
154 function taking a single scalar table name argument and returning
155 a scalar moniker.  If the hash entry does not exist, or the function
156 returns a false value, the code falls back to default behavior
157 for that table name.
158
159 The default behavior is: C<join '', map ucfirst, split /[\W_]+/, lc $table>,
160 which is to say: lowercase everything, split up the table name into chunks
161 anywhere a non-alpha-numeric character occurs, change the case of first letter
162 of each chunk to upper case, and put the chunks back together.  Examples:
163
164     Table Name  | Moniker Name
165     ---------------------------
166     luser       | Luser
167     luser_group | LuserGroup
168     luser-opts  | LuserOpts
169
170 =head2 inflect_plural
171
172 Just like L</moniker_map> above (can be hash/code-ref, falls back to default
173 if hash key does not exist or coderef returns false), but acts as a map
174 for pluralizing relationship names.  The default behavior is to utilize
175 L<Lingua::EN::Inflect::Number/to_PL>.
176
177 =head2 inflect_singular
178
179 As L</inflect_plural> above, but for singularizing relationship names.
180 Default behavior is to utilize L<Lingua::EN::Inflect::Number/to_S>.
181
182 =head2 schema_base_class
183
184 Base class for your schema classes. Defaults to 'DBIx::Class::Schema'.
185
186 =head2 result_base_class
187
188 Base class for your table classes (aka result classes). Defaults to 'DBIx::Class'.
189
190 =head2 additional_base_classes
191
192 List of additional base classes all of your table classes will use.
193
194 =head2 left_base_classes
195
196 List of additional base classes all of your table classes will use
197 that need to be leftmost.
198
199 =head2 additional_classes
200
201 List of additional classes which all of your table classes will use.
202
203 =head2 components
204
205 List of additional components to be loaded into all of your table
206 classes.  A good example would be C<ResultSetManager>.
207
208 =head2 resultset_components
209
210 List of additional ResultSet components to be loaded into your table
211 classes.  A good example would be C<AlwaysRS>.  Component
212 C<ResultSetManager> will be automatically added to the above
213 C<components> list if this option is set.
214
215 =head2 use_namespaces
216
217 Generate result class names suitable for
218 L<DBIx::Class::Schema/load_namespaces> and call that instead of
219 L<DBIx::Class::Schema/load_classes>. When using this option you can also
220 specify any of the options for C<load_namespaces> (i.e. C<result_namespace>,
221 C<resultset_namespace>, C<default_resultset_class>), and they will be added
222 to the call (and the generated result class names adjusted appropriately).
223
224 =head2 dump_directory
225
226 This option is designed to be a tool to help you transition from this
227 loader to a manually-defined schema when you decide it's time to do so.
228
229 The value of this option is a perl libdir pathname.  Within
230 that directory this module will create a baseline manual
231 L<DBIx::Class::Schema> module set, based on what it creates at runtime
232 in memory.
233
234 The created schema class will have the same classname as the one on
235 which you are setting this option (and the ResultSource classes will be
236 based on this name as well).
237
238 Normally you wouldn't hard-code this setting in your schema class, as it
239 is meant for one-time manual usage.
240
241 See L<DBIx::Class::Schema::Loader/dump_to_dir> for examples of the
242 recommended way to access this functionality.
243
244 =head2 dump_overwrite
245
246 Deprecated.  See L</really_erase_my_files> below, which does *not* mean
247 the same thing as the old C<dump_overwrite> setting from previous releases.
248
249 =head2 really_erase_my_files
250
251 Default false.  If true, Loader will unconditionally delete any existing
252 files before creating the new ones from scratch when dumping a schema to disk.
253
254 The default behavior is instead to only replace the top portion of the
255 file, up to and including the final stanza which contains
256 C<# DO NOT MODIFY THIS OR ANYTHING ABOVE!>
257 leaving any customizations you placed after that as they were.
258
259 When C<really_erase_my_files> is not set, if the output file already exists,
260 but the aforementioned final stanza is not found, or the checksum
261 contained there does not match the generated contents, Loader will
262 croak and not touch the file.
263
264 You should really be using version control on your schema classes (and all
265 of the rest of your code for that matter).  Don't blame me if a bug in this
266 code wipes something out when it shouldn't have, you've been warned.
267
268 =head1 METHODS
269
270 None of these methods are intended for direct invocation by regular
271 users of L<DBIx::Class::Schema::Loader>.  Anything you can find here
272 can also be found via standard L<DBIx::Class::Schema> methods somehow.
273
274 =cut
275
276 # ensure that a peice of object data is a valid arrayref, creating
277 # an empty one or encapsulating whatever's there.
278 sub _ensure_arrayref {
279     my $self = shift;
280
281     foreach (@_) {
282         $self->{$_} ||= [];
283         $self->{$_} = [ $self->{$_} ]
284             unless ref $self->{$_} eq 'ARRAY';
285     }
286 }
287
288 =head2 new
289
290 Constructor for L<DBIx::Class::Schema::Loader::Base>, used internally
291 by L<DBIx::Class::Schema::Loader>.
292
293 =cut
294
295 sub new {
296     my ( $class, %args ) = @_;
297
298     my $self = { %args };
299
300     bless $self => $class;
301
302     $self->_ensure_arrayref(qw/additional_classes
303                                additional_base_classes
304                                left_base_classes
305                                components
306                                resultset_components
307                               /);
308
309     push(@{$self->{components}}, 'ResultSetManager')
310         if @{$self->{resultset_components}};
311
312     $self->{monikers} = {};
313     $self->{classes} = {};
314
315     $self->{schema_class} ||= ( ref $self->{schema} || $self->{schema} );
316     $self->{schema} ||= $self->{schema_class};
317
318     croak "dump_overwrite is deprecated.  Please read the"
319         . " DBIx::Class::Schema::Loader::Base documentation"
320             if $self->{dump_overwrite};
321
322     $self->{dynamic} = ! $self->{dump_directory};
323     $self->{temp_directory} ||= File::Temp::tempdir( 'dbicXXXX',
324                                                      TMPDIR  => 1,
325                                                      CLEANUP => 1,
326                                                    );
327
328     $self->{dump_directory} ||= $self->{temp_directory};
329
330     $self->version_to_dump($DBIx::Class::Schema::Loader::VERSION);
331     $self->schema_version_to_dump($DBIx::Class::Schema::Loader::VERSION);
332
333     $self->_check_back_compat;
334
335     $self;
336 }
337
338 sub _check_back_compat {
339     my ($self) = @_;
340
341 # dynamic schemas will always be in 0.04006 mode
342     if ($self->dynamic) {
343         no strict 'refs';
344         my $class = ref $self || $self;
345         require DBIx::Class::Schema::Loader::Compat::v0_040;
346         unshift @{"${class}::ISA"},
347             'DBIx::Class::Schema::Loader::Compat::v0_040';
348         Class::C3::reinitialize;
349 # just in case, though no one is likely to dump a dynamic schema
350         $self->schema_version_to_dump('0.04006');
351         return;
352     }
353
354 # otherwise check if we need backcompat mode for a static schema
355     my $filename = $self->_get_dump_filename($self->schema_class);
356     return unless -e $filename;
357
358     open(my $fh, '<', $filename)
359         or croak "Cannot open '$filename' for reading: $!";
360
361     while (<$fh>) {
362         if (/^# Created by DBIx::Class::Schema::Loader v((\d+)\.(\d+))/) {
363             my $real_ver = $1;
364             my $ver      = "v${2}_${3}";
365             while (1) {
366                 my $compat_class = "DBIx::Class::Schema::Loader::Compat::${ver}";
367                 if ($self->load_optional_class($compat_class)) {
368                     no strict 'refs';
369                     my $class = ref $self || $self;
370                     unshift @{"${class}::ISA"}, $compat_class;
371                     Class::C3::reinitialize;
372                     $self->schema_version_to_dump($real_ver);
373                     last;
374                 }
375                 $ver =~ s/\d\z// or last;
376             }
377             last;
378         }
379     }
380     close $fh;
381 }
382
383 sub _find_file_in_inc {
384     my ($self, $file) = @_;
385
386     foreach my $prefix (@INC) {
387         my $fullpath = File::Spec->catfile($prefix, $file);
388         return $fullpath if -f $fullpath
389             and Cwd::abs_path($fullpath) ne
390                 Cwd::abs_path(File::Spec->catfile($self->dump_directory, $file)) || '';
391     }
392
393     return;
394 }
395
396 sub _class_path {
397     my ($self, $class) = @_;
398
399     my $class_path = $class;
400     $class_path =~ s{::}{/}g;
401     $class_path .= '.pm';
402
403     return $class_path;
404 }
405
406 sub _find_class_in_inc {
407     my ($self, $class) = @_;
408
409     return $self->_find_file_in_inc($self->_class_path($class));
410 }
411
412 sub _load_external {
413     my ($self, $class) = @_;
414
415     my $real_inc_path = $self->_find_class_in_inc($class);
416
417     return if !$real_inc_path;
418
419     # If we make it to here, we loaded an external definition
420     warn qq/# Loaded external class definition for '$class'\n/
421         if $self->debug;
422
423     open(my $fh, '<', $real_inc_path)
424         or croak "Failed to open '$real_inc_path' for reading: $!";
425     $self->_ext_stmt($class,
426          qq|# These lines were loaded from '$real_inc_path' found in \@INC.\n|
427         .qq|# They are now part of the custom portion of this file\n|
428         .qq|# for you to hand-edit.  If you do not either delete\n|
429         .qq|# this section or remove that file from \@INC, this section\n|
430         .qq|# will be repeated redundantly when you re-create this\n|
431         .qq|# file again via Loader!\n|
432     );
433     while(<$fh>) {
434         chomp;
435         $self->_ext_stmt($class, $_);
436     }
437     $self->_ext_stmt($class,
438         qq|# End of lines loaded from '$real_inc_path' |
439     );
440     close($fh)
441         or croak "Failed to close $real_inc_path: $!";
442
443     if ($self->dynamic) { # load the class too
444         # turn off redefined warnings
445         local $SIG{__WARN__} = sub {};
446         do $real_inc_path;
447         die $@ if $@;
448     }
449 }
450
451 =head2 load
452
453 Does the actual schema-construction work.
454
455 =cut
456
457 sub load {
458     my $self = shift;
459
460     $self->_load_tables($self->_tables_list);
461 }
462
463 =head2 rescan
464
465 Arguments: schema
466
467 Rescan the database for newly added tables.  Does
468 not process drops or changes.  Returns a list of
469 the newly added table monikers.
470
471 The schema argument should be the schema class
472 or object to be affected.  It should probably
473 be derived from the original schema_class used
474 during L</load>.
475
476 =cut
477
478 sub rescan {
479     my ($self, $schema) = @_;
480
481     $self->{schema} = $schema;
482     $self->_relbuilder->{schema} = $schema;
483
484     my @created;
485     my @current = $self->_tables_list;
486     foreach my $table ($self->_tables_list) {
487         if(!exists $self->{_tables}->{$table}) {
488             push(@created, $table);
489         }
490     }
491
492     my $loaded = $self->_load_tables(@created);
493
494     return map { $self->monikers->{$_} } @$loaded;
495 }
496
497 sub _relbuilder {
498     my ($self) = @_;
499
500     return if $self->{skip_relationships};
501
502     $self->{relbuilder} ||= DBIx::Class::Schema::Loader::RelBuilder->new(
503         $self->schema, $self->inflect_plural, $self->inflect_singular
504     );
505 }
506
507 sub _load_tables {
508     my ($self, @tables) = @_;
509
510     # First, use _tables_list with constraint and exclude
511     #  to get a list of tables to operate on
512
513     my $constraint   = $self->constraint;
514     my $exclude      = $self->exclude;
515
516     @tables = grep { /$constraint/ } @tables if $constraint;
517     @tables = grep { ! /$exclude/ } @tables if $exclude;
518
519     # Save the new tables to the tables list
520     foreach (@tables) {
521         $self->{_tables}->{$_} = 1;
522     }
523
524     $self->_make_src_class($_) for @tables;
525     $self->_setup_src_meta($_) for @tables;
526
527     if(!$self->skip_relationships) {
528         # The relationship loader needs a working schema
529         $self->{quiet} = 1;
530         local $self->{dump_directory} = $self->{temp_directory};
531         $self->_reload_classes(\@tables);
532         $self->_load_relationships($_) for @tables;
533         $self->{quiet} = 0;
534
535         # Remove that temp dir from INC so it doesn't get reloaded
536         @INC = grep { $_ ne $self->{dump_directory} } @INC;
537     }
538
539     $self->_load_external($_)
540         for map { $self->classes->{$_} } @tables;
541
542     # Reload without unloading first to preserve any symbols from external
543     # packages.
544     $self->_reload_classes(\@tables, 0);
545
546     # Drop temporary cache
547     delete $self->{_cache};
548
549     return \@tables;
550 }
551
552 sub _reload_classes {
553     my ($self, $tables, $unload) = @_;
554
555     my @tables = @$tables;
556     $unload = 1 unless defined $unload;
557
558     # so that we don't repeat custom sections
559     @INC = grep $_ ne $self->dump_directory, @INC;
560
561     $self->_dump_to_dir(map { $self->classes->{$_} } @tables);
562
563     unshift @INC, $self->dump_directory;
564     
565     my @to_register;
566     my %have_source = map { $_ => $self->schema->source($_) }
567         $self->schema->sources;
568
569     for my $table (@tables) {
570         my $moniker = $self->monikers->{$table};
571         my $class = $self->classes->{$table};
572         
573         {
574             no warnings 'redefine';
575             local *Class::C3::reinitialize = sub {};
576             use warnings;
577
578             Class::Unload->unload($class) if $unload;
579             my ($source, $resultset_class);
580             if (
581                 ($source = $have_source{$moniker})
582                 && ($resultset_class = $source->resultset_class)
583                 && ($resultset_class ne 'DBIx::Class::ResultSet')
584             ) {
585                 my $has_file = Class::Inspector->loaded_filename($resultset_class);
586                 Class::Unload->unload($resultset_class) if $unload;
587                 $self->_reload_class($resultset_class) if $has_file;
588             }
589             $self->_reload_class($class);
590         }
591         push @to_register, [$moniker, $class];
592     }
593
594     Class::C3->reinitialize;
595     for (@to_register) {
596         $self->schema->register_class(@$_);
597     }
598 }
599
600 # We use this instead of ensure_class_loaded when there are package symbols we
601 # want to preserve.
602 sub _reload_class {
603     my ($self, $class) = @_;
604
605     my $class_path = $self->_class_path($class);
606     delete $INC{ $class_path };
607     eval "require $class;";
608 }
609
610 sub _get_dump_filename {
611     my ($self, $class) = (@_);
612
613     $class =~ s{::}{/}g;
614     return $self->dump_directory . q{/} . $class . q{.pm};
615 }
616
617 sub _ensure_dump_subdirs {
618     my ($self, $class) = (@_);
619
620     my @name_parts = split(/::/, $class);
621     pop @name_parts; # we don't care about the very last element,
622                      # which is a filename
623
624     my $dir = $self->dump_directory;
625     while (1) {
626         if(!-d $dir) {
627             mkdir($dir) or croak "mkdir('$dir') failed: $!";
628         }
629         last if !@name_parts;
630         $dir = File::Spec->catdir($dir, shift @name_parts);
631     }
632 }
633
634 sub _dump_to_dir {
635     my ($self, @classes) = @_;
636
637     my $schema_class = $self->schema_class;
638     my $schema_base_class = $self->schema_base_class || 'DBIx::Class::Schema';
639
640     my $target_dir = $self->dump_directory;
641     warn "Dumping manual schema for $schema_class to directory $target_dir ...\n"
642         unless $self->{dynamic} or $self->{quiet};
643
644     my $schema_text =
645           qq|package $schema_class;\n\n|
646         . qq|# Created by DBIx::Class::Schema::Loader\n|
647         . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|
648         . qq|use strict;\nuse warnings;\n\n|
649         . qq|use base '$schema_base_class';\n\n|;
650
651     if ($self->use_namespaces) {
652         $schema_text .= qq|__PACKAGE__->load_namespaces|;
653         my $namespace_options;
654         for my $attr (qw(result_namespace
655                          resultset_namespace
656                          default_resultset_class)) {
657             if ($self->$attr) {
658                 $namespace_options .= qq|    $attr => '| . $self->$attr . qq|',\n|
659             }
660         }
661         $schema_text .= qq|(\n$namespace_options)| if $namespace_options;
662         $schema_text .= qq|;\n|;
663     }
664     else {
665         $schema_text .= qq|__PACKAGE__->load_classes;\n|;
666     }
667
668     {
669         local $self->{version_to_dump} = $self->schema_version_to_dump;
670         $self->_write_classfile($schema_class, $schema_text);
671     }
672
673     my $result_base_class = $self->result_base_class || 'DBIx::Class';
674
675     foreach my $src_class (@classes) {
676         my $src_text = 
677               qq|package $src_class;\n\n|
678             . qq|# Created by DBIx::Class::Schema::Loader\n|
679             . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|
680             . qq|use strict;\nuse warnings;\n\n|
681             . qq|use base '$result_base_class';\n\n|;
682
683         $self->_write_classfile($src_class, $src_text);
684     }
685
686     warn "Schema dump completed.\n" unless $self->{dynamic} or $self->{quiet};
687
688 }
689
690 sub _sig_comment {
691     my ($self, $version, $ts) = @_;
692     return qq|\n\n# Created by DBIx::Class::Schema::Loader|
693          . qq| v| . $version
694          . q| @ | . $ts 
695          . qq|\n# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:|;
696 }
697
698 sub _write_classfile {
699     my ($self, $class, $text) = @_;
700
701     my $filename = $self->_get_dump_filename($class);
702     $self->_ensure_dump_subdirs($class);
703
704     if (-f $filename && $self->really_erase_my_files) {
705         warn "Deleting existing file '$filename' due to "
706             . "'really_erase_my_files' setting\n" unless $self->{quiet};
707         unlink($filename);
708     }    
709
710     my ($custom_content, $old_md5, $old_ver, $old_ts) = $self->_get_custom_content($class, $filename);
711
712     $text .= qq|$_\n|
713         for @{$self->{_dump_storage}->{$class} || []};
714
715     # Check and see if the dump is infact differnt
716
717     my $compare_to;
718     if ($old_md5) {
719       $compare_to = $text . $self->_sig_comment($old_ver, $old_ts);
720       
721
722       if (Digest::MD5::md5_base64($compare_to) eq $old_md5) {
723         return;
724       }
725     }
726
727     $text .= $self->_sig_comment(
728       $self->version_to_dump,
729       POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime)
730     );
731
732     open(my $fh, '>', $filename)
733         or croak "Cannot open '$filename' for writing: $!";
734
735     # Write the top half and its MD5 sum
736     print $fh $text . Digest::MD5::md5_base64($text) . "\n";
737
738     # Write out anything loaded via external partial class file in @INC
739     print $fh qq|$_\n|
740         for @{$self->{_ext_storage}->{$class} || []};
741
742     # Write out any custom content the user has added
743     print $fh $custom_content;
744
745     close($fh)
746         or croak "Error closing '$filename': $!";
747 }
748
749 sub _default_custom_content {
750     return qq|\n\n# You can replace this text with custom|
751          . qq| content, and it will be preserved on regeneration|
752          . qq|\n1;\n|;
753 }
754
755 sub _get_custom_content {
756     my ($self, $class, $filename) = @_;
757
758     return ($self->_default_custom_content) if ! -f $filename;
759
760     open(my $fh, '<', $filename)
761         or croak "Cannot open '$filename' for reading: $!";
762
763     my $mark_re = 
764         qr{^(# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:)([A-Za-z0-9/+]{22})\n};
765
766     my $buffer = '';
767     my ($md5, $ts, $ver);
768     while(<$fh>) {
769         if(!$md5 && /$mark_re/) {
770             $md5 = $2;
771             my $line = $1;
772
773             # Pull out the previous version and timestamp
774             ($ver, $ts) = $buffer =~ m/# Created by DBIx::Class::Schema::Loader v(.*?) @ (.*?)$/s;
775
776             $buffer .= $line;
777             croak "Checksum mismatch in '$filename'"
778                 if Digest::MD5::md5_base64($buffer) ne $md5;
779
780             $buffer = '';
781         }
782         else {
783             $buffer .= $_;
784         }
785     }
786
787     croak "Cannot not overwrite '$filename' without 'really_erase_my_files',"
788         . " it does not appear to have been generated by Loader"
789             if !$md5;
790
791     # Default custom content:
792     $buffer ||= $self->_default_custom_content;
793
794     return ($buffer, $md5, $ver, $ts);
795 }
796
797 sub _use {
798     my $self = shift;
799     my $target = shift;
800
801     foreach (@_) {
802         warn "$target: use $_;" if $self->debug;
803         $self->_raw_stmt($target, "use $_;");
804     }
805 }
806
807 sub _inject {
808     my $self = shift;
809     my $target = shift;
810     my $schema_class = $self->schema_class;
811
812     my $blist = join(q{ }, @_);
813     warn "$target: use base qw/ $blist /;" if $self->debug && @_;
814     $self->_raw_stmt($target, "use base qw/ $blist /;") if @_;
815 }
816
817 # Create class with applicable bases, setup monikers, etc
818 sub _make_src_class {
819     my ($self, $table) = @_;
820
821     my $schema       = $self->schema;
822     my $schema_class = $self->schema_class;
823
824     my $table_moniker = $self->_table2moniker($table);
825     my @result_namespace = ($schema_class);
826     if ($self->use_namespaces) {
827         my $result_namespace = $self->result_namespace || 'Result';
828         if ($result_namespace =~ /^\+(.*)/) {
829             # Fully qualified namespace
830             @result_namespace =  ($1)
831         }
832         else {
833             # Relative namespace
834             push @result_namespace, $result_namespace;
835         }
836     }
837     my $table_class = join(q{::}, @result_namespace, $table_moniker);
838
839     my $table_normalized = lc $table;
840     $self->classes->{$table} = $table_class;
841     $self->classes->{$table_normalized} = $table_class;
842     $self->monikers->{$table} = $table_moniker;
843     $self->monikers->{$table_normalized} = $table_moniker;
844
845     $self->_use   ($table_class, @{$self->additional_classes});
846     $self->_inject($table_class, @{$self->left_base_classes});
847
848     $self->_dbic_stmt($table_class, 'load_components', @{$self->components}, 'Core');
849
850     $self->_dbic_stmt($table_class, 'load_resultset_components', @{$self->resultset_components})
851         if @{$self->resultset_components};
852     $self->_inject($table_class, @{$self->additional_base_classes});
853 }
854
855 # Set up metadata (cols, pks, etc)
856 sub _setup_src_meta {
857     my ($self, $table) = @_;
858
859     my $schema       = $self->schema;
860     my $schema_class = $self->schema_class;
861
862     my $table_class = $self->classes->{$table};
863     my $table_moniker = $self->monikers->{$table};
864
865     my $table_name = $table;
866     my $name_sep   = $self->schema->storage->sql_maker->name_sep;
867
868     if ($name_sep && $table_name =~ /\Q$name_sep\E/) {
869         $table_name = \ $self->_quote_table_name($table_name);
870     }
871
872     $self->_dbic_stmt($table_class,'table',$table_name);
873
874     my $cols = $self->_table_columns($table);
875     my $col_info;
876     eval { $col_info = $self->_columns_info_for($table) };
877     if($@) {
878         $self->_dbic_stmt($table_class,'add_columns',@$cols);
879     }
880     else {
881         if ($self->_is_case_sensitive) {
882             for my $col (keys %$col_info) {
883                 $col_info->{$col}{accessor} = lc $col
884                     if $col ne lc($col);
885             }
886         } else {
887             $col_info = { map { lc($_), $col_info->{$_} } keys %$col_info };
888         }
889
890         my $fks = $self->_table_fk_info($table);
891
892         for my $fkdef (@$fks) {
893             for my $col (@{ $fkdef->{local_columns} }) {
894                 $col_info->{$col}{is_foreign_key} = 1;
895             }
896         }
897         $self->_dbic_stmt(
898             $table_class,
899             'add_columns',
900             map { $_, ($col_info->{$_}||{}) } @$cols
901         );
902     }
903
904     my %uniq_tag; # used to eliminate duplicate uniqs
905
906     my $pks = $self->_table_pk_info($table) || [];
907     @$pks ? $self->_dbic_stmt($table_class,'set_primary_key',@$pks)
908           : carp("$table has no primary key");
909     $uniq_tag{ join("\0", @$pks) }++ if @$pks; # pk is a uniq
910
911     my $uniqs = $self->_table_uniq_info($table) || [];
912     for (@$uniqs) {
913         my ($name, $cols) = @$_;
914         next if $uniq_tag{ join("\0", @$cols) }++; # skip duplicates
915         $self->_dbic_stmt($table_class,'add_unique_constraint', $name, $cols);
916     }
917
918 }
919
920 =head2 tables
921
922 Returns a sorted list of loaded tables, using the original database table
923 names.
924
925 =cut
926
927 sub tables {
928     my $self = shift;
929
930     return keys %{$self->_tables};
931 }
932
933 # Make a moniker from a table
934 sub _default_table2moniker {
935     my ($self, $table) = @_;
936
937     return join '', map ucfirst, split /[\W_]+/,
938         Lingua::EN::Inflect::Number::to_S(lc $table);
939 }
940
941 sub _table2moniker {
942     my ( $self, $table ) = @_;
943
944     my $moniker;
945
946     if( ref $self->moniker_map eq 'HASH' ) {
947         $moniker = $self->moniker_map->{$table};
948     }
949     elsif( ref $self->moniker_map eq 'CODE' ) {
950         $moniker = $self->moniker_map->($table);
951     }
952
953     $moniker ||= $self->_default_table2moniker($table);
954
955     return $moniker;
956 }
957
958 sub _load_relationships {
959     my ($self, $table) = @_;
960
961     my $tbl_fk_info = $self->_table_fk_info($table);
962     foreach my $fkdef (@$tbl_fk_info) {
963         $fkdef->{remote_source} =
964             $self->monikers->{delete $fkdef->{remote_table}};
965     }
966     my $tbl_uniq_info = $self->_table_uniq_info($table);
967
968     my $local_moniker = $self->monikers->{$table};
969     my $rel_stmts = $self->_relbuilder->generate_code($local_moniker, $tbl_fk_info, $tbl_uniq_info);
970
971     foreach my $src_class (sort keys %$rel_stmts) {
972         my $src_stmts = $rel_stmts->{$src_class};
973         foreach my $stmt (@$src_stmts) {
974             $self->_dbic_stmt($src_class,$stmt->{method},@{$stmt->{args}});
975         }
976     }
977 }
978
979 # Overload these in driver class:
980
981 # Returns an arrayref of column names
982 sub _table_columns { croak "ABSTRACT METHOD" }
983
984 # Returns arrayref of pk col names
985 sub _table_pk_info { croak "ABSTRACT METHOD" }
986
987 # Returns an arrayref of uniqs [ [ foo => [ col1, col2 ] ], [ bar => [ ... ] ] ]
988 sub _table_uniq_info { croak "ABSTRACT METHOD" }
989
990 # Returns an arrayref of foreign key constraints, each
991 #   being a hashref with 3 keys:
992 #   local_columns (arrayref), remote_columns (arrayref), remote_table
993 sub _table_fk_info { croak "ABSTRACT METHOD" }
994
995 # Returns an array of lower case table names
996 sub _tables_list { croak "ABSTRACT METHOD" }
997
998 # Execute a constructive DBIC class method, with debug/dump_to_dir hooks.
999 sub _dbic_stmt {
1000     my $self = shift;
1001     my $class = shift;
1002     my $method = shift;
1003     if ( $method eq 'table' ) {
1004         my ($table) = @_;
1005         $self->_pod( $class, "=head1 NAME" );
1006         my $table_descr = $class;
1007         if ( $self->can('_table_comment') ) {
1008             my $comment = $self->_table_comment($table);
1009             $table_descr .= " - " . $comment if $comment;
1010         }
1011         $self->{_class2table}{ $class } = $table;
1012         $self->_pod( $class, $table_descr );
1013         $self->_pod_cut( $class );
1014     } elsif ( $method eq 'add_columns' ) {
1015         $self->_pod( $class, "=head1 ACCESSORS" );
1016         my $i = 0;
1017         foreach ( @_ ) {
1018             $i++;
1019             next unless $i % 2;
1020             $self->_pod( $class, '=head2 ' . $_  );
1021             my $comment;
1022             $comment = $self->_column_comment( $self->{_class2table}{$class}, ($i - 1) / 2 + 1  ) if $self->can('_column_comment');
1023             $self->_pod( $class, $comment ) if $comment;
1024         }
1025         $self->_pod_cut( $class );
1026     } elsif ( $method =~ /^(belongs_to|has_many|might_have)$/ ) {
1027         $self->_pod( $class, "=head1 RELATIONS" ) unless $self->{_relations_started} { $class } ;
1028         my ( $accessor, $rel_class ) = @_;
1029         $self->_pod( $class, "=head2 $accessor" );
1030         $self->_pod( $class, 'Type: ' . $method );
1031         $self->_pod( $class, "Related object: L<$rel_class>" );
1032         $self->_pod_cut( $class );
1033         $self->{_relations_started} { $class } = 1;
1034     }
1035     my $args = dump(@_);
1036     $args = '(' . $args . ')' if @_ < 2;
1037     my $stmt = $method . $args . q{;};
1038
1039     warn qq|$class\->$stmt\n| if $self->debug;
1040     $self->_raw_stmt($class, '__PACKAGE__->' . $stmt);
1041     return;
1042 }
1043
1044 # Stores a POD documentation
1045 sub _pod {
1046     my ($self, $class, $stmt) = @_;
1047     $self->_raw_stmt( $class, "\n" . $stmt  );
1048 }
1049
1050 sub _pod_cut {
1051     my ($self, $class ) = @_;
1052     $self->_raw_stmt( $class, "\n=cut\n" );
1053 }
1054
1055
1056 # Store a raw source line for a class (for dumping purposes)
1057 sub _raw_stmt {
1058     my ($self, $class, $stmt) = @_;
1059     push(@{$self->{_dump_storage}->{$class}}, $stmt);
1060 }
1061
1062 # Like above, but separately for the externally loaded stuff
1063 sub _ext_stmt {
1064     my ($self, $class, $stmt) = @_;
1065     push(@{$self->{_ext_storage}->{$class}}, $stmt);
1066 }
1067
1068 sub _quote_table_name {
1069     my ($self, $table) = @_;
1070
1071     my $qt = $self->schema->storage->sql_maker->quote_char;
1072
1073     return $table unless $qt;
1074
1075     if (ref $qt) {
1076         return $qt->[0] . $table . $qt->[1];
1077     }
1078
1079     return $qt . $table . $qt;
1080 }
1081
1082 sub _is_case_sensitive { 0 }
1083
1084 =head2 monikers
1085
1086 Returns a hashref of loaded table to moniker mappings.  There will
1087 be two entries for each table, the original name and the "normalized"
1088 name, in the case that the two are different (such as databases
1089 that like uppercase table names, or preserve your original mixed-case
1090 definitions, or what-have-you).
1091
1092 =head2 classes
1093
1094 Returns a hashref of table to class mappings.  In some cases it will
1095 contain multiple entries per table for the original and normalized table
1096 names, as above in L</monikers>.
1097
1098 =head1 SEE ALSO
1099
1100 L<DBIx::Class::Schema::Loader>
1101
1102 =head1 AUTHOR
1103
1104 See L<DBIx::Class::Schema::Loader/CONTRIBUTORS>.
1105
1106 =head1 LICENSE
1107
1108 This library is free software; you can redistribute it and/or modify it under
1109 the same terms as Perl itself.
1110
1111 =cut
1112
1113 1;