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