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