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