add test for bad view in mssql
[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//;
af31090c 15use File::Temp qw//;
16use Class::Unload;
996be9ee 17require DBIx::Class;
18
1fa18849 19our $VERSION = '0.04999_13';
32f784fc 20
3d95f9ff 21__PACKAGE__->mk_group_ro_accessors('simple', qw/
996be9ee 22 schema
23 schema_class
24
25 exclude
26 constraint
27 additional_classes
28 additional_base_classes
29 left_base_classes
30 components
31 resultset_components
59cfa251 32 skip_relationships
0ca61324 33 skip_load_external
996be9ee 34 moniker_map
35 inflect_singular
36 inflect_plural
37 debug
38 dump_directory
d65cda9e 39 dump_overwrite
28b4691d 40 really_erase_my_files
f44ecc2f 41 result_namespace
42 resultset_namespace
43 default_resultset_class
9c9c2f2b 44 schema_base_class
45 result_base_class
639a1367 46 overwrite_modifications
996be9ee 47
c8c27020 48 relationship_attrs
49
996be9ee 50 db_schema
51 _tables
52 classes
f53dcdf0 53 _upgrading_classes
996be9ee 54 monikers
106a976a 55 dynamic
a8d229ff 56 naming
65e705c3 57/);
58
996be9ee 59
3d95f9ff 60__PACKAGE__->mk_group_accessors('simple', qw/
01012543 61 version_to_dump
1c95b304 62 schema_version_to_dump
f53dcdf0 63 _upgrading_from
f22644d7 64 _upgrading_from_load_classes
65 use_namespaces
01012543 66/);
67
996be9ee 68=head1 NAME
69
70DBIx::Class::Schema::Loader::Base - Base DBIx::Class::Schema::Loader Implementation.
71
72=head1 SYNOPSIS
73
74See L<DBIx::Class::Schema::Loader>
75
76=head1 DESCRIPTION
77
78This is the base class for the storage-specific C<DBIx::Class::Schema::*>
79classes, and implements the common functionality between them.
80
81=head1 CONSTRUCTOR OPTIONS
82
83These constructor options are the base options for
29ddb54c 84L<DBIx::Class::Schema::Loader/loader_options>. Available constructor options are:
3953cbee 85
59cfa251 86=head2 skip_relationships
996be9ee 87
59cfa251 88Skip setting up relationships. The default is to attempt the loading
89of relationships.
996be9ee 90
0ca61324 91=head2 skip_load_external
92
93Skip loading of other classes in @INC. The default is to merge all other classes
94with the same name found in @INC into the schema file we are creating.
95
9a95164d 96=head2 naming
97
98Static schemas (ones dumped to disk) will, by default, use the new-style 0.05XXX
99relationship names and singularized Results, unless you're overwriting an
100existing dump made by a 0.04XXX version of L<DBIx::Class::Schema::Loader>, in
101which case the backward compatible RelBuilder will be activated, and
102singularization will be turned off.
103
104Specifying
105
106 naming => 'v5'
107
108will disable the backward-compatible RelBuilder and use
109the new-style relationship names along with singularized Results, even when
110overwriting a dump made with an earlier version.
111
112The option also takes a hashref:
113
a8d229ff 114 naming => { relationships => 'v5', monikers => 'v4' }
115
116The keys are:
117
118=over 4
119
120=item relationships
121
122How to name relationship accessors.
123
124=item monikers
125
126How to name Result classes.
127
128=back
9a95164d 129
130The values can be:
131
132=over 4
133
134=item current
135
136Latest default style, whatever that happens to be.
137
138=item v5
139
140Version 0.05XXX style.
141
142=item v4
143
144Version 0.04XXX style.
145
146=back
147
148Dynamic schemas will always default to the 0.04XXX relationship names and won't
149singularize Results for backward compatibility, to activate the new RelBuilder
150and singularization put this in your C<Schema.pm> file:
151
152 __PACKAGE__->naming('current');
153
154Or if you prefer to use 0.05XXX features but insure that nothing breaks in the
155next major version upgrade:
156
157 __PACKAGE__->naming('v5');
158
c8c27020 159=head2 relationship_attrs
160
161Hashref of attributes to pass to each generated relationship, listed
162by type. Also supports relationship type 'all', containing options to
163pass to all generated relationships. Attributes set for more specific
164relationship types override those set in 'all'.
165
166For example:
167
168 relationship_attrs => {
169 all => { cascade_delete => 0 },
170 has_many => { cascade_delete => 1 },
171 },
172
173will set the C<cascade_delete> option to 0 for all generated relationships,
174except for C<has_many>, which will have cascade_delete as 1.
175
176NOTE: this option is not supported if v4 backward-compatible naming is
177set either globally (naming => 'v4') or just for relationships.
178
996be9ee 179=head2 debug
180
181If set to true, each constructive L<DBIx::Class> statement the loader
182decides to execute will be C<warn>-ed before execution.
183
d65cda9e 184=head2 db_schema
185
186Set the name of the schema to load (schema in the sense that your database
187vendor means it). Does not currently support loading more than one schema
188name.
189
996be9ee 190=head2 constraint
191
192Only load tables matching regex. Best specified as a qr// regex.
193
194=head2 exclude
195
196Exclude tables matching regex. Best specified as a qr// regex.
197
198=head2 moniker_map
199
8f9d7ce5 200Overrides the default table name to moniker translation. Can be either
201a hashref of table keys and moniker values, or a coderef for a translator
996be9ee 202function taking a single scalar table name argument and returning
203a scalar moniker. If the hash entry does not exist, or the function
204returns a false value, the code falls back to default behavior
205for that table name.
206
9cc8e7e1 207The default behavior is to singularize the table name, and: C<join '', map
208ucfirst, split /[\W_]+/, lc $table>, which is to say: lowercase everything,
209split up the table name into chunks anywhere a non-alpha-numeric character
210occurs, change the case of first letter of each chunk to upper case, and put
211the chunks back together. Examples:
996be9ee 212
213 Table Name | Moniker Name
214 ---------------------------
215 luser | Luser
216 luser_group | LuserGroup
48b8d687 217 luser-opts | LuserOpt
996be9ee 218
219=head2 inflect_plural
220
221Just like L</moniker_map> above (can be hash/code-ref, falls back to default
222if hash key does not exist or coderef returns false), but acts as a map
223for pluralizing relationship names. The default behavior is to utilize
224L<Lingua::EN::Inflect::Number/to_PL>.
225
226=head2 inflect_singular
227
228As L</inflect_plural> above, but for singularizing relationship names.
229Default behavior is to utilize L<Lingua::EN::Inflect::Number/to_S>.
230
9c9c2f2b 231=head2 schema_base_class
232
233Base class for your schema classes. Defaults to 'DBIx::Class::Schema'.
234
235=head2 result_base_class
236
2229729e 237Base class for your table classes (aka result classes). Defaults to
238'DBIx::Class::Core'.
9c9c2f2b 239
996be9ee 240=head2 additional_base_classes
241
242List of additional base classes all of your table classes will use.
243
244=head2 left_base_classes
245
246List of additional base classes all of your table classes will use
247that need to be leftmost.
248
249=head2 additional_classes
250
251List of additional classes which all of your table classes will use.
252
253=head2 components
254
255List of additional components to be loaded into all of your table
256classes. A good example would be C<ResultSetManager>.
257
258=head2 resultset_components
259
8f9d7ce5 260List of additional ResultSet components to be loaded into your table
996be9ee 261classes. A good example would be C<AlwaysRS>. Component
262C<ResultSetManager> will be automatically added to the above
263C<components> list if this option is set.
264
f44ecc2f 265=head2 use_namespaces
266
f22644d7 267This is now the default, to go back to L<DBIx::Class::Schema/load_classes> pass
268a C<0>.
269
f44ecc2f 270Generate result class names suitable for
271L<DBIx::Class::Schema/load_namespaces> and call that instead of
272L<DBIx::Class::Schema/load_classes>. When using this option you can also
273specify any of the options for C<load_namespaces> (i.e. C<result_namespace>,
274C<resultset_namespace>, C<default_resultset_class>), and they will be added
275to the call (and the generated result class names adjusted appropriately).
276
996be9ee 277=head2 dump_directory
278
279This option is designed to be a tool to help you transition from this
280loader to a manually-defined schema when you decide it's time to do so.
281
282The value of this option is a perl libdir pathname. Within
283that directory this module will create a baseline manual
284L<DBIx::Class::Schema> module set, based on what it creates at runtime
285in memory.
286
287The created schema class will have the same classname as the one on
288which you are setting this option (and the ResultSource classes will be
7cab3ab7 289based on this name as well).
996be9ee 290
8f9d7ce5 291Normally you wouldn't hard-code this setting in your schema class, as it
996be9ee 292is meant for one-time manual usage.
293
294See L<DBIx::Class::Schema::Loader/dump_to_dir> for examples of the
295recommended way to access this functionality.
296
d65cda9e 297=head2 dump_overwrite
298
28b4691d 299Deprecated. See L</really_erase_my_files> below, which does *not* mean
300the same thing as the old C<dump_overwrite> setting from previous releases.
301
302=head2 really_erase_my_files
303
7cab3ab7 304Default false. If true, Loader will unconditionally delete any existing
305files before creating the new ones from scratch when dumping a schema to disk.
306
307The default behavior is instead to only replace the top portion of the
308file, up to and including the final stanza which contains
309C<# DO NOT MODIFY THIS OR ANYTHING ABOVE!>
310leaving any customizations you placed after that as they were.
311
28b4691d 312When C<really_erase_my_files> is not set, if the output file already exists,
7cab3ab7 313but the aforementioned final stanza is not found, or the checksum
314contained there does not match the generated contents, Loader will
315croak and not touch the file.
d65cda9e 316
28b4691d 317You should really be using version control on your schema classes (and all
318of the rest of your code for that matter). Don't blame me if a bug in this
319code wipes something out when it shouldn't have, you've been warned.
320
639a1367 321=head2 overwrite_modifications
322
323Default false. If false, when updating existing files, Loader will
324refuse to modify any Loader-generated code that has been modified
325since its last run (as determined by the checksum Loader put in its
326comment lines).
327
328If true, Loader will discard any manual modifications that have been
329made to Loader-generated code.
330
331Again, you should be using version control on your schema classes. Be
332careful with this option.
333
996be9ee 334=head1 METHODS
335
336None of these methods are intended for direct invocation by regular
337users of L<DBIx::Class::Schema::Loader>. Anything you can find here
338can also be found via standard L<DBIx::Class::Schema> methods somehow.
339
340=cut
341
66afce69 342use constant CURRENT_V => 'v5';
343
996be9ee 344# ensure that a peice of object data is a valid arrayref, creating
345# an empty one or encapsulating whatever's there.
346sub _ensure_arrayref {
347 my $self = shift;
348
349 foreach (@_) {
350 $self->{$_} ||= [];
351 $self->{$_} = [ $self->{$_} ]
352 unless ref $self->{$_} eq 'ARRAY';
353 }
354}
355
356=head2 new
357
358Constructor for L<DBIx::Class::Schema::Loader::Base>, used internally
359by L<DBIx::Class::Schema::Loader>.
360
361=cut
362
363sub new {
364 my ( $class, %args ) = @_;
365
366 my $self = { %args };
367
368 bless $self => $class;
369
996be9ee 370 $self->_ensure_arrayref(qw/additional_classes
371 additional_base_classes
372 left_base_classes
373 components
374 resultset_components
375 /);
376
377 push(@{$self->{components}}, 'ResultSetManager')
378 if @{$self->{resultset_components}};
379
380 $self->{monikers} = {};
381 $self->{classes} = {};
f53dcdf0 382 $self->{_upgrading_classes} = {};
996be9ee 383
996be9ee 384 $self->{schema_class} ||= ( ref $self->{schema} || $self->{schema} );
385 $self->{schema} ||= $self->{schema_class};
386
28b4691d 387 croak "dump_overwrite is deprecated. Please read the"
388 . " DBIx::Class::Schema::Loader::Base documentation"
389 if $self->{dump_overwrite};
390
af31090c 391 $self->{dynamic} = ! $self->{dump_directory};
79193756 392 $self->{temp_directory} ||= File::Temp::tempdir( 'dbicXXXX',
af31090c 393 TMPDIR => 1,
394 CLEANUP => 1,
395 );
396
79193756 397 $self->{dump_directory} ||= $self->{temp_directory};
398
01012543 399 $self->version_to_dump($DBIx::Class::Schema::Loader::VERSION);
1c95b304 400 $self->schema_version_to_dump($DBIx::Class::Schema::Loader::VERSION);
01012543 401
66afce69 402 if ((not ref $self->naming) && defined $self->naming) {
9cc8e7e1 403 my $naming_ver = $self->naming;
a8d229ff 404 $self->{naming} = {
405 relationships => $naming_ver,
406 monikers => $naming_ver,
407 };
408 }
409
66afce69 410 if ($self->naming) {
411 for (values %{ $self->naming }) {
412 $_ = CURRENT_V if $_ eq 'current';
413 }
414 }
415 $self->{naming} ||= {};
416
7824616e 417 $self->_check_back_compat;
9c465d2c 418
f22644d7 419 $self->use_namespaces(1) unless defined $self->use_namespaces;
420
7824616e 421 $self;
422}
af31090c 423
7824616e 424sub _check_back_compat {
425 my ($self) = @_;
e8ad6491 426
a8d229ff 427# dynamic schemas will always be in 0.04006 mode, unless overridden
106a976a 428 if ($self->dynamic) {
fb3bb595 429# just in case, though no one is likely to dump a dynamic schema
1c95b304 430 $self->schema_version_to_dump('0.04006');
a8d229ff 431
66afce69 432 if (not %{ $self->naming }) {
433 warn <<EOF unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
434
435Dynamic schema detected, will run in 0.04006 mode.
436
437Set the 'naming' attribute or the SCHEMA_LOADER_BACKCOMPAT environment variable
438to disable this warning.
a0e0a56a 439
805dbe0a 440Also consider setting 'use_namespaces => 1' if/when upgrading.
441
a0e0a56a 442See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 for more
443details.
66afce69 444EOF
445 }
f53dcdf0 446 else {
447 $self->_upgrading_from('v4');
448 }
66afce69 449
a8d229ff 450 $self->naming->{relationships} ||= 'v4';
451 $self->naming->{monikers} ||= 'v4';
452
805dbe0a 453 if ($self->use_namespaces) {
454 $self->_upgrading_from_load_classes(1);
455 }
456 else {
457 $self->use_namespaces(0);
458 }
f22644d7 459
01012543 460 return;
461 }
462
463# otherwise check if we need backcompat mode for a static schema
7824616e 464 my $filename = $self->_get_dump_filename($self->schema_class);
465 return unless -e $filename;
466
467 open(my $fh, '<', $filename)
468 or croak "Cannot open '$filename' for reading: $!";
469
f22644d7 470 my $load_classes = 0;
471
7824616e 472 while (<$fh>) {
f22644d7 473 if (/^__PACKAGE__->load_classes;/) {
474 $load_classes = 1;
805dbe0a 475 } elsif (my ($real_ver) =
476 /^# Created by DBIx::Class::Schema::Loader v(\d+\.\d+)/) {
477
478 if ($load_classes && (not defined $self->use_namespaces)) {
479 warn <<"EOF" unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
480
481'load_classes;' static schema detected, turning off use_namespaces.
482
483Set the 'use_namespaces' attribute or the SCHEMA_LOADER_BACKCOMPAT environment
484variable to disable this warning.
485
486See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 for more
487details.
488EOF
489 $self->use_namespaces(0);
490 }
491 elsif ($load_classes && $self->use_namespaces) {
492 $self->use_namespaces(1);
493 $self->_upgrading_from_load_classes(1);
494 }
a8d229ff 495
a8d229ff 496 # XXX when we go past .0 this will need fixing
497 my ($v) = $real_ver =~ /([1-9])/;
498 $v = "v$v";
499
b24cb177 500 last if $v eq CURRENT_V || $real_ver =~ /^0\.\d\d999/;
a0e0a56a 501
502 if (not %{ $self->naming }) {
503 warn <<"EOF" unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
504
505Version $real_ver static schema detected, turning on backcompat mode.
506
507Set the 'naming' attribute or the SCHEMA_LOADER_BACKCOMPAT environment variable
508to disable this warning.
509
510See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 for more
511details.
512EOF
513 }
f53dcdf0 514 else {
515 $self->_upgrading_from($v);
68d49e50 516 last;
f53dcdf0 517 }
a0e0a56a 518
a8d229ff 519 $self->naming->{relationships} ||= $v;
520 $self->naming->{monikers} ||= $v;
521
a0e0a56a 522 $self->schema_version_to_dump($real_ver);
523
f22644d7 524 $self->use_namespaces(0) unless defined $self->use_namespaces;
525
7824616e 526 last;
527 }
528 }
529 close $fh;
996be9ee 530}
531
419a2eeb 532sub _find_file_in_inc {
533 my ($self, $file) = @_;
534
535 foreach my $prefix (@INC) {
af31090c 536 my $fullpath = File::Spec->catfile($prefix, $file);
537 return $fullpath if -f $fullpath
538 and Cwd::abs_path($fullpath) ne
00fb1678 539 (Cwd::abs_path(File::Spec->catfile($self->dump_directory, $file)) || '');
419a2eeb 540 }
541
542 return;
543}
544
fb3bb595 545sub _class_path {
f96ef30f 546 my ($self, $class) = @_;
547
548 my $class_path = $class;
549 $class_path =~ s{::}{/}g;
550 $class_path .= '.pm';
551
fb3bb595 552 return $class_path;
553}
554
555sub _find_class_in_inc {
556 my ($self, $class) = @_;
557
558 return $self->_find_file_in_inc($self->_class_path($class));
559}
560
b24cb177 561sub _rewrite_old_classnames {
562 my ($self, $code) = @_;
563
564 return $code unless $self->_upgrading_from;
565
566 my %old_classes = reverse %{ $self->_upgrading_classes };
567
568 my $re = join '|', keys %old_classes;
569 $re = qr/\b($re)\b/;
570
68d49e50 571 $code =~ s/$re/$old_classes{$1} || $1/eg;
b24cb177 572
573 return $code;
574}
575
fb3bb595 576sub _load_external {
577 my ($self, $class) = @_;
578
0ca61324 579 return if $self->{skip_load_external};
580
ffc705f3 581 # so that we don't load our own classes, under any circumstances
582 local *INC = [ grep $_ ne $self->dump_directory, @INC ];
583
fb3bb595 584 my $real_inc_path = $self->_find_class_in_inc($class);
f96ef30f 585
ffc705f3 586 my $old_class = $self->_upgrading_classes->{$class}
587 if $self->_upgrading_from;
588
589 my $old_real_inc_path = $self->_find_class_in_inc($old_class)
590 if $old_class && $old_class ne $class;
591
592 return unless $real_inc_path || $old_real_inc_path;
593
594 if ($real_inc_path) {
595 # If we make it to here, we loaded an external definition
596 warn qq/# Loaded external class definition for '$class'\n/
597 if $self->debug;
598
599 open(my $fh, '<', $real_inc_path)
600 or croak "Failed to open '$real_inc_path' for reading: $!";
b24cb177 601 my $code = do { local $/; <$fh> };
ffc705f3 602 close($fh)
603 or croak "Failed to close $real_inc_path: $!";
b24cb177 604 $code = $self->_rewrite_old_classnames($code);
ffc705f3 605
606 if ($self->dynamic) { # load the class too
607 # kill redefined warnings
502b65d4 608 my $warn_handler = $SIG{__WARN__} || sub { warn @_ };
ffc705f3 609 local $SIG{__WARN__} = sub {
502b65d4 610 $warn_handler->(@_)
611 unless $_[0] =~ /^Subroutine \S+ redefined/;
ffc705f3 612 };
b24cb177 613 eval $code;
ffc705f3 614 die $@ if $@;
615 }
b24cb177 616
617 $self->_ext_stmt($class,
618 qq|# These lines were loaded from '$real_inc_path' found in \@INC.\n|
619 .qq|# They are now part of the custom portion of this file\n|
620 .qq|# for you to hand-edit. If you do not either delete\n|
621 .qq|# this section or remove that file from \@INC, this section\n|
622 .qq|# will be repeated redundantly when you re-create this\n|
e770e9ce 623 .qq|# file again via Loader! See skip_load_external to disable\n|
624 .qq|# this feature.\n|
b24cb177 625 );
626 chomp $code;
627 $self->_ext_stmt($class, $code);
628 $self->_ext_stmt($class,
629 qq|# End of lines loaded from '$real_inc_path' |
630 );
996be9ee 631 }
106a976a 632
ffc705f3 633 if ($old_real_inc_path) {
634 open(my $fh, '<', $old_real_inc_path)
635 or croak "Failed to open '$old_real_inc_path' for reading: $!";
636 $self->_ext_stmt($class, <<"EOF");
637
30a4c064 638# These lines were loaded from '$old_real_inc_path',
639# based on the Result class name that would have been created by an 0.04006
640# version of the Loader. For a static schema, this happens only once during
e770e9ce 641# upgrade. See skip_load_external to disable this feature.
ffc705f3 642EOF
b24cb177 643
644 my $code = do {
645 local ($/, @ARGV) = (undef, $old_real_inc_path); <>
646 };
647 $code = $self->_rewrite_old_classnames($code);
648
ffc705f3 649 if ($self->dynamic) {
650 warn <<"EOF";
651
652Detected external content in '$old_real_inc_path', a class name that would have
653been used by an 0.04006 version of the Loader.
654
655* PLEASE RENAME THIS CLASS: from '$old_class' to '$class', as that is the
656new name of the Result.
657EOF
658 # kill redefined warnings
502b65d4 659 my $warn_handler = $SIG{__WARN__} || sub { warn @_ };
ffc705f3 660 local $SIG{__WARN__} = sub {
502b65d4 661 $warn_handler->(@_)
662 unless $_[0] =~ /^Subroutine \S+ redefined/;
ffc705f3 663 };
ffc705f3 664 eval $code;
665 die $@ if $@;
666 }
667
b24cb177 668 chomp $code;
669 $self->_ext_stmt($class, $code);
ffc705f3 670 $self->_ext_stmt($class,
671 qq|# End of lines loaded from '$old_real_inc_path' |
672 );
9e8033c1 673 }
996be9ee 674}
675
676=head2 load
677
678Does the actual schema-construction work.
679
680=cut
681
682sub load {
683 my $self = shift;
684
b97c2c1e 685 $self->_load_tables($self->_tables_list);
686}
687
688=head2 rescan
689
a60b5b8d 690Arguments: schema
691
b97c2c1e 692Rescan the database for newly added tables. Does
a60b5b8d 693not process drops or changes. Returns a list of
694the newly added table monikers.
695
696The schema argument should be the schema class
697or object to be affected. It should probably
698be derived from the original schema_class used
699during L</load>.
b97c2c1e 700
701=cut
702
703sub rescan {
a60b5b8d 704 my ($self, $schema) = @_;
705
706 $self->{schema} = $schema;
7824616e 707 $self->_relbuilder->{schema} = $schema;
b97c2c1e 708
709 my @created;
710 my @current = $self->_tables_list;
711 foreach my $table ($self->_tables_list) {
712 if(!exists $self->{_tables}->{$table}) {
713 push(@created, $table);
714 }
715 }
716
c39e3507 717 my $loaded = $self->_load_tables(@created);
a60b5b8d 718
c39e3507 719 return map { $self->monikers->{$_} } @$loaded;
b97c2c1e 720}
721
7824616e 722sub _relbuilder {
66afce69 723 no warnings 'uninitialized';
7824616e 724 my ($self) = @_;
3fed44ca 725
726 return if $self->{skip_relationships};
727
a8d229ff 728 if ($self->naming->{relationships} eq 'v4') {
729 require DBIx::Class::Schema::Loader::RelBuilder::Compat::v0_040;
730 return $self->{relbuilder} ||=
731 DBIx::Class::Schema::Loader::RelBuilder::Compat::v0_040->new(
732 $self->schema, $self->inflect_plural, $self->inflect_singular
733 );
734 }
735
c8c27020 736 $self->{relbuilder} ||= DBIx::Class::Schema::Loader::RelBuilder->new (
737 $self->schema,
738 $self->inflect_plural,
739 $self->inflect_singular,
740 $self->relationship_attrs,
7824616e 741 );
742}
743
b97c2c1e 744sub _load_tables {
745 my ($self, @tables) = @_;
746
f96ef30f 747 # First, use _tables_list with constraint and exclude
748 # to get a list of tables to operate on
749
750 my $constraint = $self->constraint;
751 my $exclude = $self->exclude;
f96ef30f 752
b97c2c1e 753 @tables = grep { /$constraint/ } @tables if $constraint;
754 @tables = grep { ! /$exclude/ } @tables if $exclude;
f96ef30f 755
b97c2c1e 756 # Save the new tables to the tables list
a60b5b8d 757 foreach (@tables) {
758 $self->{_tables}->{$_} = 1;
759 }
f96ef30f 760
af31090c 761 $self->_make_src_class($_) for @tables;
f96ef30f 762 $self->_setup_src_meta($_) for @tables;
763
e8ad6491 764 if(!$self->skip_relationships) {
181cc907 765 # The relationship loader needs a working schema
af31090c 766 $self->{quiet} = 1;
79193756 767 local $self->{dump_directory} = $self->{temp_directory};
106a976a 768 $self->_reload_classes(\@tables);
e8ad6491 769 $self->_load_relationships($_) for @tables;
af31090c 770 $self->{quiet} = 0;
79193756 771
772 # Remove that temp dir from INC so it doesn't get reloaded
ffc705f3 773 @INC = grep $_ ne $self->dump_directory, @INC;
e8ad6491 774 }
775
f96ef30f 776 $self->_load_external($_)
75451704 777 for map { $self->classes->{$_} } @tables;
f96ef30f 778
106a976a 779 # Reload without unloading first to preserve any symbols from external
780 # packages.
781 $self->_reload_classes(\@tables, 0);
996be9ee 782
5223f24a 783 # Drop temporary cache
784 delete $self->{_cache};
785
c39e3507 786 return \@tables;
996be9ee 787}
788
af31090c 789sub _reload_classes {
106a976a 790 my ($self, $tables, $unload) = @_;
791
792 my @tables = @$tables;
793 $unload = 1 unless defined $unload;
181cc907 794
4daef04f 795 # so that we don't repeat custom sections
796 @INC = grep $_ ne $self->dump_directory, @INC;
797
181cc907 798 $self->_dump_to_dir(map { $self->classes->{$_} } @tables);
e9b8719e 799
800 unshift @INC, $self->dump_directory;
af31090c 801
706ef173 802 my @to_register;
803 my %have_source = map { $_ => $self->schema->source($_) }
804 $self->schema->sources;
805
181cc907 806 for my $table (@tables) {
807 my $moniker = $self->monikers->{$table};
808 my $class = $self->classes->{$table};
0ae6b65d 809
810 {
811 no warnings 'redefine';
812 local *Class::C3::reinitialize = sub {};
813 use warnings;
814
106a976a 815 Class::Unload->unload($class) if $unload;
706ef173 816 my ($source, $resultset_class);
817 if (
818 ($source = $have_source{$moniker})
819 && ($resultset_class = $source->resultset_class)
820 && ($resultset_class ne 'DBIx::Class::ResultSet')
821 ) {
822 my $has_file = Class::Inspector->loaded_filename($resultset_class);
106a976a 823 Class::Unload->unload($resultset_class) if $unload;
824 $self->_reload_class($resultset_class) if $has_file;
0ae6b65d 825 }
106a976a 826 $self->_reload_class($class);
af31090c 827 }
706ef173 828 push @to_register, [$moniker, $class];
829 }
af31090c 830
706ef173 831 Class::C3->reinitialize;
832 for (@to_register) {
833 $self->schema->register_class(@$_);
af31090c 834 }
835}
836
106a976a 837# We use this instead of ensure_class_loaded when there are package symbols we
838# want to preserve.
839sub _reload_class {
840 my ($self, $class) = @_;
841
842 my $class_path = $self->_class_path($class);
843 delete $INC{ $class_path };
f53dcdf0 844
845# kill redefined warnings
502b65d4 846 my $warn_handler = $SIG{__WARN__} || sub { warn @_ };
f53dcdf0 847 local $SIG{__WARN__} = sub {
502b65d4 848 $warn_handler->(@_)
849 unless $_[0] =~ /^Subroutine \S+ redefined/;
f53dcdf0 850 };
106a976a 851 eval "require $class;";
852}
853
996be9ee 854sub _get_dump_filename {
855 my ($self, $class) = (@_);
856
857 $class =~ s{::}{/}g;
858 return $self->dump_directory . q{/} . $class . q{.pm};
859}
860
861sub _ensure_dump_subdirs {
862 my ($self, $class) = (@_);
863
864 my @name_parts = split(/::/, $class);
dd03ee1a 865 pop @name_parts; # we don't care about the very last element,
866 # which is a filename
867
996be9ee 868 my $dir = $self->dump_directory;
7cab3ab7 869 while (1) {
870 if(!-d $dir) {
25328cc4 871 mkdir($dir) or croak "mkdir('$dir') failed: $!";
996be9ee 872 }
7cab3ab7 873 last if !@name_parts;
874 $dir = File::Spec->catdir($dir, shift @name_parts);
996be9ee 875 }
876}
877
878sub _dump_to_dir {
af31090c 879 my ($self, @classes) = @_;
996be9ee 880
fc2b71fd 881 my $schema_class = $self->schema_class;
9c9c2f2b 882 my $schema_base_class = $self->schema_base_class || 'DBIx::Class::Schema';
996be9ee 883
e9b8719e 884 my $target_dir = $self->dump_directory;
af31090c 885 warn "Dumping manual schema for $schema_class to directory $target_dir ...\n"
886 unless $self->{dynamic} or $self->{quiet};
996be9ee 887
7cab3ab7 888 my $schema_text =
889 qq|package $schema_class;\n\n|
b4dcbcc5 890 . qq|# Created by DBIx::Class::Schema::Loader\n|
891 . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|
7cab3ab7 892 . qq|use strict;\nuse warnings;\n\n|
9c9c2f2b 893 . qq|use base '$schema_base_class';\n\n|;
f44ecc2f 894
f44ecc2f 895 if ($self->use_namespaces) {
896 $schema_text .= qq|__PACKAGE__->load_namespaces|;
897 my $namespace_options;
898 for my $attr (qw(result_namespace
899 resultset_namespace
900 default_resultset_class)) {
901 if ($self->$attr) {
902 $namespace_options .= qq| $attr => '| . $self->$attr . qq|',\n|
903 }
904 }
905 $schema_text .= qq|(\n$namespace_options)| if $namespace_options;
906 $schema_text .= qq|;\n|;
907 }
908 else {
909 $schema_text .= qq|__PACKAGE__->load_classes;\n|;
f44ecc2f 910 }
996be9ee 911
1c95b304 912 {
913 local $self->{version_to_dump} = $self->schema_version_to_dump;
68d49e50 914 $self->_write_classfile($schema_class, $schema_text, 1);
1c95b304 915 }
996be9ee 916
2229729e 917 my $result_base_class = $self->result_base_class || 'DBIx::Class::Core';
9c9c2f2b 918
af31090c 919 foreach my $src_class (@classes) {
7cab3ab7 920 my $src_text =
921 qq|package $src_class;\n\n|
b4dcbcc5 922 . qq|# Created by DBIx::Class::Schema::Loader\n|
923 . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|
7cab3ab7 924 . qq|use strict;\nuse warnings;\n\n|
9c9c2f2b 925 . qq|use base '$result_base_class';\n\n|;
996be9ee 926
7cab3ab7 927 $self->_write_classfile($src_class, $src_text);
02356864 928 }
996be9ee 929
af31090c 930 warn "Schema dump completed.\n" unless $self->{dynamic} or $self->{quiet};
931
7cab3ab7 932}
933
79193756 934sub _sig_comment {
935 my ($self, $version, $ts) = @_;
936 return qq|\n\n# Created by DBIx::Class::Schema::Loader|
937 . qq| v| . $version
938 . q| @ | . $ts
939 . qq|\n# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:|;
940}
941
7cab3ab7 942sub _write_classfile {
68d49e50 943 my ($self, $class, $text, $is_schema) = @_;
7cab3ab7 944
945 my $filename = $self->_get_dump_filename($class);
946 $self->_ensure_dump_subdirs($class);
947
28b4691d 948 if (-f $filename && $self->really_erase_my_files) {
7cab3ab7 949 warn "Deleting existing file '$filename' due to "
af31090c 950 . "'really_erase_my_files' setting\n" unless $self->{quiet};
7cab3ab7 951 unlink($filename);
952 }
953
79193756 954 my ($custom_content, $old_md5, $old_ver, $old_ts) = $self->_get_custom_content($class, $filename);
17ca645f 955
e1373c52 956 if (my $old_class = $self->_upgrading_classes->{$class}) {
957 my $old_filename = $self->_get_dump_filename($old_class);
f53dcdf0 958
e1373c52 959 my ($old_custom_content) = $self->_get_custom_content(
960 $old_class, $old_filename, 0 # do not add default comment
961 );
ffc705f3 962
e1373c52 963 $old_custom_content =~ s/\n\n# You can replace.*\n1;\n//;
f53dcdf0 964
e1373c52 965 if ($old_custom_content) {
966 $custom_content =
967 "\n" . $old_custom_content . "\n" . $custom_content;
f53dcdf0 968 }
e1373c52 969
970 unlink $old_filename;
f53dcdf0 971 }
972
b24cb177 973 $custom_content = $self->_rewrite_old_classnames($custom_content);
974
7cab3ab7 975 $text .= qq|$_\n|
976 for @{$self->{_dump_storage}->{$class} || []};
977
79193756 978 # Check and see if the dump is infact differnt
979
980 my $compare_to;
981 if ($old_md5) {
982 $compare_to = $text . $self->_sig_comment($old_ver, $old_ts);
983
984
985 if (Digest::MD5::md5_base64($compare_to) eq $old_md5) {
68d49e50 986 return unless $self->_upgrading_from && $is_schema;
79193756 987 }
988 }
989
990 $text .= $self->_sig_comment(
01012543 991 $self->version_to_dump,
79193756 992 POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime)
993 );
7cab3ab7 994
995 open(my $fh, '>', $filename)
996 or croak "Cannot open '$filename' for writing: $!";
997
998 # Write the top half and its MD5 sum
a4476f41 999 print $fh $text . Digest::MD5::md5_base64($text) . "\n";
7cab3ab7 1000
1001 # Write out anything loaded via external partial class file in @INC
1002 print $fh qq|$_\n|
1003 for @{$self->{_ext_storage}->{$class} || []};
1004
1eea4fb1 1005 # Write out any custom content the user has added
7cab3ab7 1006 print $fh $custom_content;
1007
1008 close($fh)
e9b8719e 1009 or croak "Error closing '$filename': $!";
7cab3ab7 1010}
1011
79193756 1012sub _default_custom_content {
1013 return qq|\n\n# You can replace this text with custom|
1014 . qq| content, and it will be preserved on regeneration|
1015 . qq|\n1;\n|;
1016}
1017
7cab3ab7 1018sub _get_custom_content {
ffc705f3 1019 my ($self, $class, $filename, $add_default) = @_;
1020
1021 $add_default = 1 unless defined $add_default;
7cab3ab7 1022
79193756 1023 return ($self->_default_custom_content) if ! -f $filename;
1024
7cab3ab7 1025 open(my $fh, '<', $filename)
1026 or croak "Cannot open '$filename' for reading: $!";
1027
1028 my $mark_re =
419a2eeb 1029 qr{^(# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:)([A-Za-z0-9/+]{22})\n};
7cab3ab7 1030
7cab3ab7 1031 my $buffer = '';
79193756 1032 my ($md5, $ts, $ver);
7cab3ab7 1033 while(<$fh>) {
79193756 1034 if(!$md5 && /$mark_re/) {
1035 $md5 = $2;
1036 my $line = $1;
1037
1038 # Pull out the previous version and timestamp
1039 ($ver, $ts) = $buffer =~ m/# Created by DBIx::Class::Schema::Loader v(.*?) @ (.*?)$/s;
1040
1041 $buffer .= $line;
b4cc5793 1042 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 1043 if !$self->overwrite_modifications && Digest::MD5::md5_base64($buffer) ne $md5;
7cab3ab7 1044
1045 $buffer = '';
1046 }
1047 else {
1048 $buffer .= $_;
1049 }
996be9ee 1050 }
1051
28b4691d 1052 croak "Cannot not overwrite '$filename' without 'really_erase_my_files',"
419a2eeb 1053 . " it does not appear to have been generated by Loader"
79193756 1054 if !$md5;
5ef3c771 1055
79193756 1056 # Default custom content:
ffc705f3 1057 $buffer ||= $self->_default_custom_content if $add_default;
5ef3c771 1058
79193756 1059 return ($buffer, $md5, $ver, $ts);
996be9ee 1060}
1061
1062sub _use {
1063 my $self = shift;
1064 my $target = shift;
1065
1066 foreach (@_) {
cb54990b 1067 warn "$target: use $_;" if $self->debug;
996be9ee 1068 $self->_raw_stmt($target, "use $_;");
996be9ee 1069 }
1070}
1071
1072sub _inject {
1073 my $self = shift;
1074 my $target = shift;
1075 my $schema_class = $self->schema_class;
1076
af31090c 1077 my $blist = join(q{ }, @_);
1078 warn "$target: use base qw/ $blist /;" if $self->debug && @_;
1079 $self->_raw_stmt($target, "use base qw/ $blist /;") if @_;
996be9ee 1080}
1081
f96ef30f 1082# Create class with applicable bases, setup monikers, etc
1083sub _make_src_class {
1084 my ($self, $table) = @_;
996be9ee 1085
a13b2803 1086 my $schema = $self->schema;
1087 my $schema_class = $self->schema_class;
996be9ee 1088
f96ef30f 1089 my $table_moniker = $self->_table2moniker($table);
f44ecc2f 1090 my @result_namespace = ($schema_class);
1091 if ($self->use_namespaces) {
1092 my $result_namespace = $self->result_namespace || 'Result';
1093 if ($result_namespace =~ /^\+(.*)/) {
1094 # Fully qualified namespace
1095 @result_namespace = ($1)
1096 }
1097 else {
1098 # Relative namespace
1099 push @result_namespace, $result_namespace;
1100 }
1101 }
1102 my $table_class = join(q{::}, @result_namespace, $table_moniker);
996be9ee 1103
805dbe0a 1104 if ((my $upgrading_v = $self->_upgrading_from)
1105 || $self->_upgrading_from_load_classes) {
1106 local $self->naming->{monikers} = $upgrading_v
1107 if $upgrading_v;
1108
1109 my @result_namespace = @result_namespace;
1110 @result_namespace = ($schema_class)
1111 if $self->_upgrading_from_load_classes;
f53dcdf0 1112
1113 my $old_class = join(q{::}, @result_namespace,
1114 $self->_table2moniker($table));
1115
68d49e50 1116 $self->_upgrading_classes->{$table_class} = $old_class
1117 unless $table_class eq $old_class;
f53dcdf0 1118 }
1119
f96ef30f 1120 my $table_normalized = lc $table;
1121 $self->classes->{$table} = $table_class;
1122 $self->classes->{$table_normalized} = $table_class;
1123 $self->monikers->{$table} = $table_moniker;
1124 $self->monikers->{$table_normalized} = $table_moniker;
996be9ee 1125
f96ef30f 1126 $self->_use ($table_class, @{$self->additional_classes});
af31090c 1127 $self->_inject($table_class, @{$self->left_base_classes});
996be9ee 1128
2229729e 1129 if (my @components = @{ $self->components }) {
1130 $self->_dbic_stmt($table_class, 'load_components', @components);
1131 }
996be9ee 1132
f96ef30f 1133 $self->_dbic_stmt($table_class, 'load_resultset_components', @{$self->resultset_components})
1134 if @{$self->resultset_components};
af31090c 1135 $self->_inject($table_class, @{$self->additional_base_classes});
f96ef30f 1136}
996be9ee 1137
af31090c 1138# Set up metadata (cols, pks, etc)
f96ef30f 1139sub _setup_src_meta {
1140 my ($self, $table) = @_;
996be9ee 1141
f96ef30f 1142 my $schema = $self->schema;
1143 my $schema_class = $self->schema_class;
a13b2803 1144
f96ef30f 1145 my $table_class = $self->classes->{$table};
1146 my $table_moniker = $self->monikers->{$table};
996be9ee 1147
ff30991a 1148 my $table_name = $table;
1149 my $name_sep = $self->schema->storage->sql_maker->name_sep;
1150
c177d483 1151 if ($name_sep && $table_name =~ /\Q$name_sep\E/) {
ff30991a 1152 $table_name = \ $self->_quote_table_name($table_name);
1153 }
1154
1155 $self->_dbic_stmt($table_class,'table',$table_name);
996be9ee 1156
f96ef30f 1157 my $cols = $self->_table_columns($table);
1158 my $col_info;
1159 eval { $col_info = $self->_columns_info_for($table) };
1160 if($@) {
1161 $self->_dbic_stmt($table_class,'add_columns',@$cols);
1162 }
1163 else {
0906d55b 1164 if ($self->_is_case_sensitive) {
1165 for my $col (keys %$col_info) {
1166 $col_info->{$col}{accessor} = lc $col
1167 if $col ne lc($col);
1168 }
1169 } else {
1170 $col_info = { map { lc($_), $col_info->{$_} } keys %$col_info };
c9373b79 1171 }
1172
e7213f4f 1173 my $fks = $self->_table_fk_info($table);
565335e6 1174
e7213f4f 1175 for my $fkdef (@$fks) {
1176 for my $col (@{ $fkdef->{local_columns} }) {
565335e6 1177 $col_info->{$col}{is_foreign_key} = 1;
e7213f4f 1178 }
1179 }
f96ef30f 1180 $self->_dbic_stmt(
1181 $table_class,
1182 'add_columns',
565335e6 1183 map { $_, ($col_info->{$_}||{}) } @$cols
f96ef30f 1184 );
996be9ee 1185 }
1186
d70c335f 1187 my %uniq_tag; # used to eliminate duplicate uniqs
1188
f96ef30f 1189 my $pks = $self->_table_pk_info($table) || [];
1190 @$pks ? $self->_dbic_stmt($table_class,'set_primary_key',@$pks)
1191 : carp("$table has no primary key");
d70c335f 1192 $uniq_tag{ join("\0", @$pks) }++ if @$pks; # pk is a uniq
996be9ee 1193
f96ef30f 1194 my $uniqs = $self->_table_uniq_info($table) || [];
d70c335f 1195 for (@$uniqs) {
1196 my ($name, $cols) = @$_;
1197 next if $uniq_tag{ join("\0", @$cols) }++; # skip duplicates
1198 $self->_dbic_stmt($table_class,'add_unique_constraint', $name, $cols);
1199 }
1200
996be9ee 1201}
1202
1203=head2 tables
1204
1205Returns a sorted list of loaded tables, using the original database table
1206names.
1207
1208=cut
1209
1210sub tables {
1211 my $self = shift;
1212
b97c2c1e 1213 return keys %{$self->_tables};
996be9ee 1214}
1215
1216# Make a moniker from a table
c39e403e 1217sub _default_table2moniker {
66afce69 1218 no warnings 'uninitialized';
c39e403e 1219 my ($self, $table) = @_;
1220
a8d229ff 1221 if ($self->naming->{monikers} eq 'v4') {
1222 return join '', map ucfirst, split /[\W_]+/, lc $table;
1223 }
1224
c39e403e 1225 return join '', map ucfirst, split /[\W_]+/,
1226 Lingua::EN::Inflect::Number::to_S(lc $table);
1227}
1228
996be9ee 1229sub _table2moniker {
1230 my ( $self, $table ) = @_;
1231
1232 my $moniker;
1233
1234 if( ref $self->moniker_map eq 'HASH' ) {
1235 $moniker = $self->moniker_map->{$table};
1236 }
1237 elsif( ref $self->moniker_map eq 'CODE' ) {
1238 $moniker = $self->moniker_map->($table);
1239 }
1240
c39e403e 1241 $moniker ||= $self->_default_table2moniker($table);
996be9ee 1242
1243 return $moniker;
1244}
1245
1246sub _load_relationships {
e8ad6491 1247 my ($self, $table) = @_;
996be9ee 1248
e8ad6491 1249 my $tbl_fk_info = $self->_table_fk_info($table);
1250 foreach my $fkdef (@$tbl_fk_info) {
1251 $fkdef->{remote_source} =
1252 $self->monikers->{delete $fkdef->{remote_table}};
996be9ee 1253 }
26f1c8c9 1254 my $tbl_uniq_info = $self->_table_uniq_info($table);
996be9ee 1255
e8ad6491 1256 my $local_moniker = $self->monikers->{$table};
7824616e 1257 my $rel_stmts = $self->_relbuilder->generate_code($local_moniker, $tbl_fk_info, $tbl_uniq_info);
996be9ee 1258
996be9ee 1259 foreach my $src_class (sort keys %$rel_stmts) {
1260 my $src_stmts = $rel_stmts->{$src_class};
1261 foreach my $stmt (@$src_stmts) {
1262 $self->_dbic_stmt($src_class,$stmt->{method},@{$stmt->{args}});
1263 }
1264 }
1265}
1266
1267# Overload these in driver class:
1268
1269# Returns an arrayref of column names
1270sub _table_columns { croak "ABSTRACT METHOD" }
1271
1272# Returns arrayref of pk col names
1273sub _table_pk_info { croak "ABSTRACT METHOD" }
1274
1275# Returns an arrayref of uniqs [ [ foo => [ col1, col2 ] ], [ bar => [ ... ] ] ]
1276sub _table_uniq_info { croak "ABSTRACT METHOD" }
1277
1278# Returns an arrayref of foreign key constraints, each
1279# being a hashref with 3 keys:
1280# local_columns (arrayref), remote_columns (arrayref), remote_table
1281sub _table_fk_info { croak "ABSTRACT METHOD" }
1282
1283# Returns an array of lower case table names
1284sub _tables_list { croak "ABSTRACT METHOD" }
1285
1286# Execute a constructive DBIC class method, with debug/dump_to_dir hooks.
1287sub _dbic_stmt {
bf654ab9 1288 my $self = shift;
1289 my $class = shift;
996be9ee 1290 my $method = shift;
bf654ab9 1291
1292 # generate the pod for this statement, storing it with $self->_pod
1293 $self->_make_pod( $class, $method, @_ );
1294
1295 my $args = dump(@_);
1296 $args = '(' . $args . ')' if @_ < 2;
1297 my $stmt = $method . $args . q{;};
1298
1299 warn qq|$class\->$stmt\n| if $self->debug;
1300 $self->_raw_stmt($class, '__PACKAGE__->' . $stmt);
1301 return;
1302}
1303
1304# generates the accompanying pod for a DBIC class method statement,
1305# storing it with $self->_pod
1306sub _make_pod {
1307 my $self = shift;
1308 my $class = shift;
1309 my $method = shift;
1310
fbcfebdd 1311 if ( $method eq 'table' ) {
1312 my ($table) = @_;
1313 $self->_pod( $class, "=head1 NAME" );
1314 my $table_descr = $class;
1315 if ( $self->can('_table_comment') ) {
1316 my $comment = $self->_table_comment($table);
1317 $table_descr .= " - " . $comment if $comment;
1318 }
1319 $self->{_class2table}{ $class } = $table;
1320 $self->_pod( $class, $table_descr );
1321 $self->_pod_cut( $class );
1322 } elsif ( $method eq 'add_columns' ) {
1323 $self->_pod( $class, "=head1 ACCESSORS" );
79a00530 1324 my $col_counter = 0;
1325 my @cols = @_;
1326 while( my ($name,$attrs) = splice @cols,0,2 ) {
1327 $col_counter++;
1328 $self->_pod( $class, '=head2 ' . $name );
1329 $self->_pod( $class,
1330 join "\n", map {
1331 my $s = $attrs->{$_};
1332 $s = !defined $s ? 'undef' :
1333 length($s) == 0 ? '(empty string)' :
1334 $s;
1335
1336 " $_: $s"
1337 } sort keys %$attrs,
1338 );
1339
1340 if( $self->can('_column_comment')
1341 and my $comment = $self->_column_comment( $self->{_class2table}{$class}, $col_counter)
1342 ) {
1343 $self->_pod( $class, $comment );
1344 }
fbcfebdd 1345 }
1346 $self->_pod_cut( $class );
1347 } elsif ( $method =~ /^(belongs_to|has_many|might_have)$/ ) {
1348 $self->_pod( $class, "=head1 RELATIONS" ) unless $self->{_relations_started} { $class } ;
1349 my ( $accessor, $rel_class ) = @_;
1350 $self->_pod( $class, "=head2 $accessor" );
1351 $self->_pod( $class, 'Type: ' . $method );
1352 $self->_pod( $class, "Related object: L<$rel_class>" );
1353 $self->_pod_cut( $class );
1354 $self->{_relations_started} { $class } = 1;
1355 }
996be9ee 1356}
1357
fbcfebdd 1358# Stores a POD documentation
1359sub _pod {
1360 my ($self, $class, $stmt) = @_;
1361 $self->_raw_stmt( $class, "\n" . $stmt );
1362}
1363
1364sub _pod_cut {
1365 my ($self, $class ) = @_;
1366 $self->_raw_stmt( $class, "\n=cut\n" );
1367}
1368
1369
996be9ee 1370# Store a raw source line for a class (for dumping purposes)
1371sub _raw_stmt {
1372 my ($self, $class, $stmt) = @_;
af31090c 1373 push(@{$self->{_dump_storage}->{$class}}, $stmt);
996be9ee 1374}
1375
7cab3ab7 1376# Like above, but separately for the externally loaded stuff
1377sub _ext_stmt {
1378 my ($self, $class, $stmt) = @_;
af31090c 1379 push(@{$self->{_ext_storage}->{$class}}, $stmt);
7cab3ab7 1380}
1381
565335e6 1382sub _quote_table_name {
1383 my ($self, $table) = @_;
1384
1385 my $qt = $self->schema->storage->sql_maker->quote_char;
1386
c177d483 1387 return $table unless $qt;
1388
565335e6 1389 if (ref $qt) {
1390 return $qt->[0] . $table . $qt->[1];
1391 }
1392
1393 return $qt . $table . $qt;
1394}
1395
1396sub _is_case_sensitive { 0 }
1397
ffc705f3 1398# remove the dump dir from @INC on destruction
1399sub DESTROY {
1400 my $self = shift;
1401
1402 @INC = grep $_ ne $self->dump_directory, @INC;
1403}
1404
996be9ee 1405=head2 monikers
1406
8f9d7ce5 1407Returns a hashref of loaded table to moniker mappings. There will
996be9ee 1408be two entries for each table, the original name and the "normalized"
1409name, in the case that the two are different (such as databases
1410that like uppercase table names, or preserve your original mixed-case
1411definitions, or what-have-you).
1412
1413=head2 classes
1414
8f9d7ce5 1415Returns a hashref of table to class mappings. In some cases it will
996be9ee 1416contain multiple entries per table for the original and normalized table
1417names, as above in L</monikers>.
1418
1419=head1 SEE ALSO
1420
1421L<DBIx::Class::Schema::Loader>
1422
be80bba7 1423=head1 AUTHOR
1424
9cc8e7e1 1425See L<DBIx::Class::Schema::Loader/AUTHOR> and L<DBIx::Class::Schema::Loader/CONTRIBUTORS>.
be80bba7 1426
1427=head1 LICENSE
1428
1429This library is free software; you can redistribute it and/or modify it under
1430the same terms as Perl itself.
1431
996be9ee 1432=cut
1433
14341;