use Digest::MD5;
use File::Find 'find';
use Class::Unload ();
-use Data::Dumper::Concise;
+use DBIx::Class::Schema::Loader::Utils 'dumper_squashed';
use List::MoreUtils 'apply';
+use DBIx::Class::Schema::Loader::Optional::Dependencies ();
+use namespace::clean;
my $DUMP_DIR = './t/_common_dump';
rmtree $DUMP_DIR;
my $extra_count = $self->{extra}{count} || 0;
- plan tests => @connect_info * (178 + $extra_count + ($self->{data_type_tests}{test_count} || 0));
+ plan tests => @connect_info * (182 + $extra_count + ($self->{data_type_tests}{test_count} || 0));
foreach my $info_idx (0..$#connect_info) {
my $info = $connect_info[$info_idx];
my $self = shift;
my $dbh = $self->dbconnect(0);
- $dbh->do($_) for @{ $self->{extra}{pre_drop_ddl} || [] };
+
+ {
+ local $SIG{__WARN__} = sub {}; # postgres notices
+ $dbh->do($_) for @{ $self->{extra}{pre_drop_ddl} || [] };
+ }
+
$dbh->do("DROP TABLE $_") for @{ $self->{extra}{drop} || [] };
foreach my $data_type_table (@{ $self->{data_type_tests}{table_names} || [] }) {
my $debug = ($self->{verbose} > 1) ? 1 : 0;
+ my $use_moose = DBIx::Class::Schema::Loader::Optional::Dependencies->req_ok_for('use_moose');
+
my %loader_opts = (
constraint =>
- qr/^(?:\S+\.)?(?:(?:$self->{vendor}|extra)_)?loader_test[0-9]+(?!.*_)/i,
+ qr/^(?:\S+\.)?(?:(?:$self->{vendor}|extra)_?)?loader_?test[0-9]+(?!.*_)/i,
relationships => 1,
additional_classes => 'TestAdditional',
additional_base_classes => 'TestAdditionalBase',
dump_directory => $DUMP_DIR,
datetime_timezone => 'Europe/Berlin',
datetime_locale => 'de_DE',
+ use_moose => $use_moose,
%{ $self->{loader_options} || {} },
);
$warn_count++ for grep /\b(?!loader_test9)\w+ has no primary key/i, @loader_warnings;
+ $warn_count++ for grep { my $w = $_; grep $w =~ $_, @{ $self->{warnings} || [] } } @loader_warnings;
+
if ($standard_sources) {
if($self->{skip_rels}) {
SKIP: {
isa_ok( $rsobj35, "DBIx::Class::ResultSet" );
my @columns_lt2 = $class2->columns;
- is_deeply( \@columns_lt2, [ qw/id dat dat2 set_primary_key dbix_class_testcomponent/ ], "Column Ordering" );
+ is_deeply( \@columns_lt2, [ qw/id dat dat2 set_primary_key dbix_class_testcomponent meta/ ], "Column Ordering" );
is $class2->column_info('set_primary_key')->{accessor}, undef,
'accessor for column name that conflicts with a result base class method removed';
is $class2->column_info('dbix_class_testcomponent')->{accessor}, undef,
'accessor for column name that conflicts with a component class method removed';
+ is $class2->column_info('meta')->{accessor}, undef,
+ 'accessor for column name that conflicts with Moose removed';
+
my %uniq1 = $class1->unique_constraints;
my $uniq1_test = 0;
foreach my $ucname (keys %uniq1) {
'constant integer default',
);
+ is(
+ $class35->column_info('a_negative_int')->{default_value}, -42,
+ 'constant negative integer default',
+ );
+
cmp_ok(
$class35->column_info('a_double')->{default_value}, '==', 10.555,
'constant numeric default',
);
+ cmp_ok(
+ $class35->column_info('a_negative_double')->{default_value}, '==', -10.555,
+ 'constant negative numeric default',
+ );
+
my $function_default = $class35->column_info('a_function')->{default_value};
isa_ok( $function_default, 'SCALAR', 'default_value for function default' );
is $rsobj4->result_source->relationship_info('fkid_singular')->{attrs}{on_update}, 'CASCADE',
"on_update => 'CASCADE' on belongs_to by default";
- ok ((not exists $rsobj4->result_source->relationship_info('fkid_singular')->{attrs}{is_deferrable}),
- "is_deferrable => 1 not on belongs_to by default");
+ is $rsobj4->result_source->relationship_info('fkid_singular')->{attrs}{is_deferrable}, 1,
+ "is_deferrable => 1 on belongs_to by default";
ok ((not exists $rsobj4->result_source->relationship_info('fkid_singular')->{attrs}{cascade_delete}),
'belongs_to does not have cascade_delete');
my $find_cb = sub {
return if -d;
- return if $_ eq 'LoaderTest30.pm';
+ return if /^(?:LoaderTest30|LoaderTest1|LoaderTest2X)\.pm\z/;
open my $fh, '<', $_ or die "Could not open $_ for reading: $!";
binmode $fh;
find $find_cb, $DUMP_DIR;
- my $before_digest = $digest->digest;
+# system "rm -f /tmp/before_rescan/* /tmp/after_rescan/*";
+# system "cp t/_common_dump/DBIXCSL_Test/Schema/*.pm /tmp/before_rescan";
+
+ my $before_digest = $digest->b64digest;
$conn->storage->disconnect; # needed for Firebird and Informix
my $dbh = $self->dbconnect(1);
};
is_deeply(\@new, [ qw/LoaderTest30/ ], "Rescan");
+# system "cp t/_common_dump/DBIXCSL_Test/Schema/*.pm /tmp/after_rescan";
+
$digest = Digest::MD5->new;
find $find_cb, $DUMP_DIR;
- my $after_digest = $digest->digest;
+ my $after_digest = $digest->b64digest;
is $before_digest, $after_digest,
'dumped files are not rewritten when there is no modification';
# run extra tests
$self->{extra}{run}->($conn, $monikers, $classes) if $self->{extra}{run};
+ $self->test_preserve_case($conn);
+
$self->drop_tables unless $ENV{SCHEMA_LOADER_TESTS_NOCLEANUP};
$conn->storage->disconnect;
my %info = %{ $rsrc->column_info($col_name) };
delete @info{qw/is_nullable timezone locale sequence/};
- my $text_col_def = do {
- my $dd = Dumper;
- $dd->Indent(0);
- $dd->Values([\%info]);
- $dd->Dump;
- };
+ my $text_col_def = dumper_squashed \%info;
- my $text_expected_info = do {
- my $dd = Dumper;
- $dd->Indent(0);
- $dd->Values([$expected_info]);
- $dd->Dump;
- };
+ my $text_expected_info = dumper_squashed $expected_info;
is_deeply \%info, $expected_info,
"test column $col_name has definition: $text_col_def expecting: $text_expected_info";
}
}
+sub test_preserve_case {
+ my ($self, $conn) = @_;
+
+ my ($oqt, $cqt) = $self->get_oqt_cqt(always => 1); # open quote, close quote
+
+ my $dbh = $conn->storage->dbh;
+
+ {
+ # Silence annoying but harmless postgres "NOTICE: CREATE TABLE..."
+ local $SIG{__WARN__} = sub {
+ my $msg = shift;
+ warn $msg unless $msg =~ m{^NOTICE:\s+CREATE TABLE};
+ };
+
+ $dbh->do($_) for (
+qq|
+ CREATE TABLE ${oqt}LoaderTest40${cqt} (
+ ${oqt}Id${cqt} INTEGER NOT NULL PRIMARY KEY,
+ ${oqt}Foo3Bar${cqt} VARCHAR(100) NOT NULL
+ ) $self->{innodb}
+|,
+qq|
+ CREATE TABLE ${oqt}LoaderTest41${cqt} (
+ ${oqt}Id${cqt} INTEGER NOT NULL PRIMARY KEY,
+ ${oqt}LoaderTest40Id${cqt} INTEGER,
+ FOREIGN KEY (${oqt}LoaderTest40Id${cqt}) REFERENCES ${oqt}LoaderTest40${cqt} (${oqt}Id${cqt})
+ ) $self->{innodb}
+|,
+qq| INSERT INTO ${oqt}LoaderTest40${cqt} VALUES (1, 'foo') |,
+qq| INSERT INTO ${oqt}LoaderTest41${cqt} VALUES (1, 1) |,
+ );
+ }
+ $conn->storage->disconnect;
+
+ local $conn->_loader->{preserve_case} = 1;
+ $conn->_loader->_setup;
+
+ {
+ local $SIG{__WARN__} = sub {};
+ $conn->rescan;
+ }
+
+ if (not $self->{skip_rels}) {
+ is $conn->resultset('LoaderTest41')->find(1)->loader_test40->foo3_bar, 'foo',
+ 'rel and accessor for mixed-case column name in mixed case table';
+ }
+ else {
+ is $conn->resultset('LoaderTest40')->find(1)->foo3_bar, 'foo',
+ 'accessor for mixed-case column name in mixed case table';
+ }
+}
+
sub monikers_and_classes {
my ($self, $schema_class) = @_;
my ($monikers, $classes);
return $dbh;
}
+sub get_oqt_cqt {
+ my $self = shift;
+ my %opts = @_;
+
+ if ((not $opts{always}) && $self->{preserve_case_mode_is_exclusive}) {
+ return ('', '');
+ }
+
+ # XXX should get quote_char from the storage of an initialized loader.
+ my ($oqt, $cqt); # open quote, close quote
+ if (ref $self->{quote_char}) {
+ ($oqt, $cqt) = @{ $self->{quote_char} };
+ }
+ else {
+ $oqt = $cqt = $self->{quote_char} || '';
+ }
+
+ return ($oqt, $cqt);
+}
+
sub create {
my $self = shift;
dat2 VARCHAR(32) NOT NULL,
set_primary_key INTEGER $self->{null},
dbix_class_testcomponent INTEGER $self->{null},
+ meta INTEGER $self->{null},
UNIQUE (dat2, dat)
) $self->{innodb}
},
id INTEGER NOT NULL PRIMARY KEY,
a_varchar VARCHAR(100) DEFAULT 'foo',
an_int INTEGER DEFAULT 42,
+ a_negative_int INTEGER DEFAULT -42,
a_double DOUBLE PRECISION DEFAULT 10.555,
+ a_negative_double DOUBLE PRECISION DEFAULT -10.555,
a_function $self->{default_function_def}
) $self->{innodb}
},
);
# some DBs require mixed case identifiers to be quoted
- # XXX should get quote_char from the storage of an initialized loader.
- my ($oqt, $cqt); # open quote, close quote
- if (ref $self->{quote_char}) {
- ($oqt, $cqt) = @{ $self->{quote_char} };
- }
- else {
- $oqt = $cqt = $self->{quote_char} || '';
- }
+ my ($oqt, $cqt) = $self->get_oqt_cqt;
@statements_reltests = (
qq{
$dbh->do($_) foreach (@statements);
- $dbh->do($_) foreach (@{ $self->{data_type_tests}{ddl} || {} });
+ $dbh->do($_) foreach (@{ $self->{data_type_tests}{ddl} || [] });
unless($self->{skip_rels}) {
# hack for now, since DB2 doesn't like inline comments, and we need
my @tables_rescan = qw/ loader_test30 /;
+ my @tables_preserve_case_tests = qw/ LoaderTest41 LoaderTest40 /;
+
my $drop_fk_mysql =
q{ALTER TABLE loader_test10 DROP FOREIGN KEY loader_test11_fk};
my $dbh = $self->dbconnect(0);
- $dbh->do($_) for @{ $self->{extra}{pre_drop_ddl} || [] };
+ {
+ local $SIG{__WARN__} = sub {}; # postgres notices
+ $dbh->do($_) for @{ $self->{extra}{pre_drop_ddl} || [] };
+ }
+
$dbh->do("DROP TABLE $_") for @{ $self->{extra}{drop} || [] };
my $drop_auto_inc = $self->{auto_inc_drop_cb} || sub {};
unless($self->{skip_rels}) {
$dbh->do("DROP TABLE $_") for (@tables_reltests);
+ $dbh->do("DROP TABLE $_") for (@tables_reltests);
if($self->{vendor} =~ /mysql/i) {
$dbh->do($drop_fk_mysql);
}
$dbh->do("DROP TABLE $data_type_table");
}
+ my ($oqt, $cqt) = $self->get_oqt_cqt(always => 1);
+
+ $dbh->do("DROP TABLE ${oqt}${_}${cqt}") for @tables_preserve_case_tests;
+
$dbh->disconnect;
# fixup for Firebird
}
my %DATA_TYPE_MULTI_TABLE_OVERRIDES = (
- oracle => qr/\blong\b/,
- mssql => qr/\b(?:timestamp|rowversion)\b/,
+ oracle => qr/\blong\b/i,
+ mssql => qr/\b(?:timestamp|rowversion)\b/i,
+ informix => qr/\b(?:bigserial|serial8)\b/i,
);
sub setup_data_type_tests {
# split types into tables based on overrides
my (@types, @split_off_types, @first_table_types);
{
- no warnings 'uninitialized';
+ my $split_off_re = $DATA_TYPE_MULTI_TABLE_OVERRIDES{lc($self->{vendor})} || qr/(?!)/;
@types = keys %$types;
- @split_off_types = grep /$DATA_TYPE_MULTI_TABLE_OVERRIDES{lc($self->{vendor})}/i, @types;
- @first_table_types = grep !/$DATA_TYPE_MULTI_TABLE_OVERRIDES{lc($self->{vendor})}/i, @types;
+ @split_off_types = grep /$split_off_re/, @types;
+ @first_table_types = grep !/$split_off_re/, @types;
}
@types = +{ map +($_, $types->{$_}), @first_table_types },