=item * Informix, MSSQL, Sybase ASE
-C<database>, C<schema>, C<name>
+C<database>, C<schema>, C<name>
=back
'InflateColumn::DateTime',
],
}
-
+
You may use this in conjunction with L</components>.
=head2 result_roles
],
RouteChange => 'YourApp::Role::TripEvent',
}
-
+
You may use this in conjunction with L</result_roles>.
=head2 use_namespaces
}
$self->result_components_map($self->{result_component_map})
}
-
+
if (defined $self->{result_role_map}) {
if (defined $self->result_roles_map) {
croak "Specify only one of result_roles_map or result_role_map";
# check if there are still clashes
my %by_moniker;
-
+
while (my ($t, $m) = each %new_monikers) {
- push @{ $by_moniker{$m} }, $t;
+ push @{ $by_moniker{$m} }, $t;
}
foreach my $m (grep @{ $by_moniker{$_} } > 1, keys %by_moniker) {
$self->_dump_to_dir(map { $self->classes->{$_->sql_name} } @tables);
unshift @INC, $self->dump_directory;
-
+
my @to_register;
my %have_source = map { $_ => $self->schema->source($_) }
$self->schema->sources;
for my $table (@tables) {
my $moniker = $self->monikers->{$table->sql_name};
my $class = $self->classes->{$table->sql_name};
-
+
{
no warnings 'redefine';
local *Class::C3::reinitialize = sub {}; # to speed things up, reinitialized below
my $result_base_class = $self->result_base_class || 'DBIx::Class::Core';
foreach my $src_class (@classes) {
- my $src_text =
+ my $src_text =
qq|use utf8;\n|
. qq|package $src_class;\n\n|
. qq|# Created by DBIx::Class::Schema::Loader\n|
my ($self, $version, $ts) = @_;
return qq|\n\n# Created by DBIx::Class::Schema::Loader|
. qq| v| . $version
- . q| @ | . $ts
+ . q| @ | . $ts
. qq|\n# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:|;
}
if (not $is_schema) {
return qq|\n__PACKAGE__->meta->make_immutable;|;
}
-
+
return qq|\n__PACKAGE__->meta->make_immutable(inline_constructor => 0);|;
}
elsif ($method eq 'add_unique_constraint') {
$self->_pod($class, '=head1 UNIQUE CONSTRAINTS')
unless $self->{_uniqs_started}{$class};
-
+
my ($name, $cols) = @_;
$self->_pod($class, "=head2 C<$name>");
$self->_pod($class, '=over 4');
-
+
foreach my $col (@$cols) {
$self->_pod($class, "=item \* L</$col>");
}
elsif ($method eq 'set_primary_key') {
$self->_pod($class, "=head1 PRIMARY KEY");
$self->_pod($class, '=over 4');
-
+
foreach my $col (@_) {
$self->_pod($class, "=item \* L</$col>");
}
if (my $code = $self->can('_table_comment')) {
return $self->_filter_comment($self->$code(@_));
}
-
+
return '';
}
=head2 generate_code
-Arguments:
-
+Arguments:
+
[
[ local_moniker1 (scalar), fk_info1 (arrayref), uniq_info1 (arrayref) ]
[ local_moniker2 (scalar), fk_info2 (arrayref), uniq_info2 (arrayref) ]
},
} }
-# accessor for options to be passed to each generated relationship
-# type. take single argument, the relationship type name, and returns
-# either a hashref (if some options are set), or nothing
+# Accessor for options to be passed to each generated relationship type. takes
+# the relationship type name and optionally any attributes from the database
+# (such as FK ON DELETE/UPDATE and DEFERRABLE clauses), and returns a
+# hashref or undef if nothing is set.
+#
+# The attributes from the database override the default attributes, which in
+# turn are overridden by user supplied attributes.
sub _relationship_attrs {
- my ( $self, $reltype ) = @_;
+ my ( $self, $reltype, $db_attrs ) = @_;
my $r = $self->relationship_attrs;
my %composite = (
%{ $self->_default_relationship_attrs->{$reltype} || {} },
- %{ $r->{all} || {} }
+ %{ $db_attrs || {} },
+ %{ $r->{all} || {} },
+ %{ $r->{$reltype} || {} },
);
- if( my $specific = $r->{$reltype} ) {
- while( my ($k,$v) = each %$specific ) {
- $composite{$k} = $v;
- }
- }
- return \%composite;
+ return %composite ? \%composite : undef;
}
sub _strip_id_postfix {
}
sub _remote_attrs {
- my ($self, $local_moniker, $local_cols) = @_;
+ my ($self, $local_moniker, $local_cols, $fk_attrs) = @_;
- # get our base set of attrs from _relationship_attrs, if present
- my $attrs = $self->_relationship_attrs('belongs_to') || {};
+ # get our set of attrs from _relationship_attrs, which uses the FK attrs if available
+ my $attrs = $self->_relationship_attrs('belongs_to', $fk_attrs) || {};
# If any referring column is nullable, make 'belongs_to' an
# outer join, unless explicitly set by relationship_attrs
sub generate_code {
my ($self, $tables) = @_;
-
+
# make a copy to destroy
my @tables = @$tables;
args => [ $remote_relname,
$remote_class,
\%cond,
- $self->_remote_attrs($local_moniker, $local_cols),
+ $self->_remote_attrs($local_moniker, $local_cols, $rel->{attrs}),
],
extra => {
local_class => $local_class,
my $rel_name_mapped;
($relname_new, $rel_name_mapped) = $self->_rel_name_map($relname_new, $rel->{method}, $local_class, $local_moniker, \@from_cols, $to_class, $remote_moniker, \@to_cols);
-
+
my $mapped = $inflect_mapped || $rel_name_mapped;
warn <<"EOF" unless $mapped;
# DB2 and Firebird don't support 'field type NULL'
$self->{null} = 'NULL' unless defined $self->{null};
-
+
$self->{verbose} = $ENV{TEST_VERBOSE} || 0;
# Optional extra tables and tests
push @connect_info, [ @{$info}{qw/dsn user password connect_info_opts/ } ];
}
}
-
+
if ($ENV{SCHEMA_LOADER_TESTS_EXTRA_ONLY}) {
$self->run_only_extra_tests(\@connect_info);
return;
my $file_count = grep $_ =~ SOURCE_DDL, @{ $self->{extra}{create} || [] };
$file_count++; # schema
-
+
if (not ($self->{vendor} eq 'mssql' && $dbh->{Driver}{Name} eq 'Sybase')) {
$file_count++ for @{ $self->{data_type_tests}{table_names} || [] };
}
eval qq{
package @{[SCHEMA_CLASS]};
use base qw/DBIx::Class::Schema::Loader/;
-
+
__PACKAGE__->loader_options(\%loader_opts);
__PACKAGE__->connection(\@\$connect_info);
};
-
+
ok(!$@, "Loader initialization") or diag $@;
find sub { return if -d; $file_count++ }, DUMP_DIR;
$expected_count += grep $_ =~ SOURCE_DDL,
@{ $self->{extra}{create} || [] };
-
+
$expected_count -= grep /CREATE TABLE/, @statements_inline_rels
if $self->{skip_rels} || $self->{no_inline_rels};
-
+
$expected_count -= grep /CREATE TABLE/, @statements_implicit_rels
if $self->{skip_rels} || $self->{no_implicit_rels};
-
+
$expected_count -= grep /CREATE TABLE/, ($self->{vendor} =~ /sqlite/ ? @statements_advanced_sqlite : @statements_advanced), @statements_reltests
if $self->{skip_rels};
}
-
+
is $file_count, $expected_count, 'correct number of files generated';
-
+
my $warn_count = 2;
-
+
$warn_count++ for grep /^Bad table or view/, @loader_warnings;
-
+
$warn_count++ for grep /renaming \S+ relation/, @loader_warnings;
-
+
$warn_count++ for grep /\b(?!loader_test9)\w+ has no primary key/i, @loader_warnings;
$warn_count++ for grep /^Column '\w+' in table '\w+' collides with an inherited method\./, @loader_warnings;
my $moniker36 = $monikers->{loader_test36};
my $class36 = $classes->{loader_test36};
my $rsobj36 = $conn->resultset($moniker36);
-
+
isa_ok( $rsobj3, "DBIx::Class::ResultSet" );
isa_ok( $rsobj4, "DBIx::Class::ResultSet" );
isa_ok( $rsobj5, "DBIx::Class::ResultSet" );
ok ((not try { exists $rsobj3->result_source->relationship_info('loader_test4zes')->{attrs}{is_deferrable} }),
'has_many does not have is_deferrable');
- is try { $rsobj4->result_source->relationship_info('fkid_singular')->{attrs}{on_delete} }, 'CASCADE',
- "on_delete => 'CASCADE' on belongs_to by default";
+ like try { $rsobj4->result_source->relationship_info('fkid_singular')->{attrs}{on_delete} },
+ qr/^(?:CASCADE|RESTRICT)\z/,
+ "on_delete is either CASCADE or RESTRICT on belongs_to by default";
- is try { $rsobj4->result_source->relationship_info('fkid_singular')->{attrs}{on_update} }, 'CASCADE',
- "on_update => 'CASCADE' on belongs_to by default";
+ like try { $rsobj4->result_source->relationship_info('fkid_singular')->{attrs}{on_update} },
+ qr/^(?:CASCADE|RESTRICT)\z/,
+ "on_update is either CASCADE or RESTRICT on belongs_to by default";
is try { $rsobj4->result_source->relationship_info('fkid_singular')->{attrs}{is_deferrable} }, 1,
"is_deferrable => 1 on belongs_to by default";
my $rs_rel17 = try { $obj16->search_related('loader_test17_loader16_ones') };
isa_ok(try { $rs_rel17->single }, $class17);
is(try { $rs_rel17->single->id }, 3, "search_related with multiple FKs from same table");
-
+
# XXX test m:m 18 <- 20 -> 19
ok($class20->column_info('parent')->{is_foreign_key}, 'Foreign key detected');
ok($class20->column_info('child')->{is_foreign_key}, 'Foreign key detected');
-
+
# XXX test double-fk m:m 21 <- 22 -> 21
ok($class22->column_info('parent')->{is_foreign_key}, 'Foreign key detected');
ok($class22->column_info('child')->{is_foreign_key}, 'Foreign key detected');
ok($class32->column_info('rel1')->{is_foreign_key}, 'Foreign key detected');
ok($class32->column_info('rel2')->{is_foreign_key}, 'Foreign key detected');
-
+
my $obj32 = try { $rsobj32->find(1, { prefetch => [qw/rel1 rel2/] }) }
|| try { $rsobj32->search({ id => 1 }, { prefetch => [qw/rel1 rel2/] })->single }
|| $rsobj32->search({ id => 1 })->single;
SKIP: {
skip 'Previous eval block failed', 3 if $@;
-
+
my $results = $rsobj10->search({ subject => 'xyzzy' });
is( $results->count(), 1, 'No duplicate row created' );
my $class13 = $classes->{loader_test13};
my $rsobj13 = $conn->resultset($moniker13);
- isa_ok( $rsobj12, "DBIx::Class::ResultSet" );
+ isa_ok( $rsobj12, "DBIx::Class::ResultSet" );
isa_ok( $rsobj13, "DBIx::Class::ResultSet" );
ok($class13->column_info('id')->{is_foreign_key}, 'Foreign key detected');
my $class15 = $classes->{loader_test15};
my $rsobj15 = $conn->resultset($moniker15);
- isa_ok( $rsobj14, "DBIx::Class::ResultSet" );
+ isa_ok( $rsobj14, "DBIx::Class::ResultSet" );
isa_ok( $rsobj15, "DBIx::Class::ResultSet" );
ok($class15->column_info('loader_test14')->{is_foreign_key}, 'Foreign key detected');
$make_auto_inc->(qw/loader_test1s id/),
q{ INSERT INTO loader_test1s (dat) VALUES('foo') },
- q{ INSERT INTO loader_test1s (dat) VALUES('bar') },
- q{ INSERT INTO loader_test1s (dat) VALUES('baz') },
+ q{ INSERT INTO loader_test1s (dat) VALUES('bar') },
+ q{ INSERT INTO loader_test1s (dat) VALUES('baz') },
# also test method collision
# crumb_crisp_coating is for col_accessor_map tests
- qq{
+ qq{
CREATE TABLE loader_test2 (
id $self->{auto_inc_pk},
dat VARCHAR(32) NOT NULL,
},
$make_auto_inc->(qw/loader_test2 id/),
- q{ INSERT INTO loader_test2 (dat, dat2) VALUES('aaa', 'zzz') },
- q{ INSERT INTO loader_test2 (dat, dat2) VALUES('bbb', 'yyy') },
- q{ INSERT INTO loader_test2 (dat, dat2) VALUES('ccc', 'xxx') },
- q{ INSERT INTO loader_test2 (dat, dat2) VALUES('ddd', 'www') },
+ q{ INSERT INTO loader_test2 (dat, dat2) VALUES('aaa', 'zzz') },
+ q{ INSERT INTO loader_test2 (dat, dat2) VALUES('bbb', 'yyy') },
+ q{ INSERT INTO loader_test2 (dat, dat2) VALUES('ccc', 'xxx') },
+ q{ INSERT INTO loader_test2 (dat, dat2) VALUES('ddd', 'www') },
qq{
CREATE TABLE LOADER_test23 (
) $self->{innodb}
},
- q{ INSERT INTO loader_test3 (id,dat) VALUES(1,'aaa') },
- q{ INSERT INTO loader_test3 (id,dat) VALUES(2,'bbb') },
- q{ INSERT INTO loader_test3 (id,dat) VALUES(3,'ccc') },
- q{ INSERT INTO loader_test3 (id,dat) VALUES(4,'ddd') },
+ q{ INSERT INTO loader_test3 (id,dat) VALUES(1,'aaa') },
+ q{ INSERT INTO loader_test3 (id,dat) VALUES(2,'bbb') },
+ q{ INSERT INTO loader_test3 (id,dat) VALUES(3,'ccc') },
+ q{ INSERT INTO loader_test3 (id,dat) VALUES(4,'ddd') },
qq{
CREATE TABLE loader_test4 (
},
q{ INSERT INTO loader_test4 (id,fkid,dat,belongs_to,set_primary_key) VALUES(123,1,'aaa',1,1) },
- q{ INSERT INTO loader_test4 (id,fkid,dat,belongs_to,set_primary_key) VALUES(124,2,'bbb',2,2) },
+ q{ INSERT INTO loader_test4 (id,fkid,dat,belongs_to,set_primary_key) VALUES(124,2,'bbb',2,2) },
q{ INSERT INTO loader_test4 (id,fkid,dat,belongs_to,set_primary_key) VALUES(125,3,'ccc',3,3) },
q{ INSERT INTO loader_test4 (id,fkid,dat,belongs_to,set_primary_key) VALUES(126,4,'ddd',4,4) },
dat VARCHAR(8)
) $self->{innodb}
},
-
+
q{ INSERT INTO loader_test14 (id,dat) VALUES (123,'aaa') },
qq{
loader_test36
loader_test50
/;
-
+
my @tables_auto_inc = (
[ qw/loader_test1s id/ ],
[ qw/loader_test2 id/ ],
loader_test11
loader_test10
/;
-
+
my @tables_advanced_auto_inc = (
[ qw/loader_test10 id10/ ],
[ qw/loader_test11 id11/ ],
foreach my $table (keys %drop_constraints) {
# for MSSQL
- $dbh->do("ALTER TABLE $table DROP $drop_constraints{$table}");
+ $dbh->do("ALTER TABLE $table DROP $drop_constraints{$table}");
# for Sybase and Access
- $dbh->do("ALTER TABLE $table DROP CONSTRAINT $drop_constraints{$table}");
+ $dbh->do("ALTER TABLE $table DROP CONSTRAINT $drop_constraints{$table}");
# for MySQL
- $dbh->do("ALTER TABLE $table DROP FOREIGN KEY $drop_constraints{$table}");
+ $dbh->do("ALTER TABLE $table DROP FOREIGN KEY $drop_constraints{$table}");
}
$self->drop_table($dbh, $_) for (@tables_reltests);
$table_name = lc ( $table_name );
$column_name = lc ( $column_name );
- if ( $table_name eq 'loader_test35'
- and $column_name eq 'an_int'
+ if ( $table_name eq 'loader_test35'
+ and $column_name eq 'an_int'
){
return { is_numeric => 1 }
}
- # Set inflate_datetime or inflate_date to check
+ # Set inflate_datetime or inflate_date to check
# datetime_timezone and datetime_locale
if ( $table_name eq 'loader_test36' ){
- return { inflate_datetime => 1 } if
+ return { inflate_datetime => 1 } if
( $column_name eq 'b_char_as_data' );
- return { inflate_date => 1 } if
+ return { inflate_date => 1 } if
( $column_name eq 'c_char_as_data' );
}
$type_alias =~ s/\W//g;
my $col_name = 'col_' . $type_alias;
-
+
if (@size) {
my $size_name = join '_', apply { s/\W//g } @size;