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