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