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