From: Brandon Black Date: Fri, 27 Jan 2006 16:54:19 +0000 (+0000) Subject: fixed multi-fk checking for postgres (misdetection of multiple single-fks on one... X-Git-Tag: 0.03000~38 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=4ce226568294f7e05815527cbf9089f9cab8a458;p=dbsrgits%2FDBIx-Class-Schema-Loader.git fixed multi-fk checking for postgres (misdetection of multiple single-fks on one table), fixed inline and implicit fks for sqlite. mysql needs similar fixes for implicit FKs --- diff --git a/lib/DBIx/Class/Schema/Loader/Generic.pm b/lib/DBIx/Class/Schema/Loader/Generic.pm index 9445084..52f8fc3 100644 --- a/lib/DBIx/Class/Schema/Loader/Generic.pm +++ b/lib/DBIx/Class/Schema/Loader/Generic.pm @@ -192,36 +192,51 @@ sub _loader_make_relations { $table_relname = Lingua::EN::Inflect::PL($table_relname); } - # for single-column case, set the relname to the column name, - # to make filter accessors work - if(scalar keys %$cond == 1) { - my ($col) = keys %$cond; - $other_relname = $cond->{$col}; - } + if(ref($cond) eq 'HASH') { + # for single-column case, set the relname to the column name, + # to make filter accessors work + if(scalar keys %$cond == 1) { + my ($col) = keys %$cond; + $other_relname = $cond->{$col}; + } - my $rev_cond = { reverse %$cond }; + my $rev_cond = { reverse %$cond }; - my $cond_printable = _loader_stringify_hash($cond) - if $class->_loader_debug; - my $rev_cond_printable = _loader_stringify_hash($rev_cond) - if $class->_loader_debug; + my $cond_printable = _loader_stringify_hash($cond) + if $class->_loader_debug; + my $rev_cond_printable = _loader_stringify_hash($rev_cond) + if $class->_loader_debug; - warn qq/\# Belongs_to relationship\n/ if $class->_loader_debug; + warn qq/\# Belongs_to relationship\n/ if $class->_loader_debug; - warn qq/$table_class->belongs_to( '$other_relname' => '$other_class',/ - . qq/$cond_printable);\n\n/ - if $class->_loader_debug; + warn qq/$table_class->belongs_to( '$other_relname' => '$other_class',/ + . qq/$cond_printable);\n\n/ + if $class->_loader_debug; - $table_class->belongs_to( $other_relname => $other_class, $cond); + $table_class->belongs_to( $other_relname => $other_class, $cond); - warn qq/\# Has_many relationship\n/ if $class->_loader_debug; + warn qq/\# Has_many relationship\n/ if $class->_loader_debug; - warn qq/$other_class->has_many( '$table_relname' => '$table_class',/ - . qq/$rev_cond_printable);\n\n/ - . qq/);\n\n/ - if $class->_loader_debug; + warn qq/$other_class->has_many( '$table_relname' => '$table_class',/ + . qq/$rev_cond_printable);\n\n/ + . qq/);\n\n/ + if $class->_loader_debug; - $other_class->has_many( $table_relname => $table_class, $rev_cond); + $other_class->has_many( $table_relname => $table_class, $rev_cond); + } + else { # implicit stuff, just a col name + warn qq/\# Belongs_to relationship\n/ if $class->_loader_debug; + warn qq/$table_class->belongs_to( '$cond' => '$other_class' );\n\n/ + if $class->_loader_debug; + $table_class->belongs_to( $cond => $other_class ); + + warn qq/\# Has_many relationship\n/ if $class->_loader_debug; + warn qq/$other_class->has_many( '$table_relname' => '$table_class',/ + . qq/$cond);\n\n/ + if $class->_loader_debug; + + $other_class->has_many( $table_relname => $table_class, $cond); + } } # Load and setup classes @@ -290,14 +305,18 @@ sub _loader_relationships { my $uk_tbl = lc $raw_rel->{UK_TABLE_NAME}; my $uk_col = lc $raw_rel->{UK_COLUMN_NAME}; my $fk_col = lc $raw_rel->{FK_COLUMN_NAME}; + my $relid = lc $raw_rel->{UK_NAME}; $uk_tbl =~ s/$quoter//g; $uk_col =~ s/$quoter//g; $fk_col =~ s/$quoter//g; - $rels->{$uk_tbl}->{$uk_col} = $fk_col; + $relid =~ s/$quoter//g; + $rels->{$relid}->{tbl} = $uk_tbl; + $rels->{$relid}->{cols}->{$uk_col} = $fk_col; } - foreach my $reltbl (keys %$rels) { - my $cond = $rels->{$reltbl}; + foreach my $relid (keys %$rels) { + my $reltbl = $rels->{$relid}->{tbl}; + my $cond = $rels->{$relid}->{cols}; eval { $class->_loader_make_relations( $table, $reltbl, $cond ) }; warn qq/\# belongs_to_many failed "$@"\n\n/ if $@ && $class->_loader_debug; diff --git a/lib/DBIx/Class/Schema/Loader/SQLite.pm b/lib/DBIx/Class/Schema/Loader/SQLite.pm index 5aa7d11..7139e3f 100644 --- a/lib/DBIx/Class/Schema/Loader/SQLite.pm +++ b/lib/DBIx/Class/Schema/Loader/SQLite.pm @@ -75,8 +75,8 @@ SELECT sql FROM sqlite_master WHERE tbl_name = ? $col =~ s/^\s+//gs; # Grab reference - if( $col =~ /^(.*)\s+REFERENCES\s+(\w+)\s*\((.*)\)/i ) { - chomp $col; + chomp $col; + if( $col =~ /^(.*)\s+REFERENCES\s+(\w+) (?: \s* \( (.*) \) )? /ix ) { my ($cols, $f_table, $f_cols) = ($1, $2, $3); @@ -88,15 +88,20 @@ SELECT sql FROM sqlite_master WHERE tbl_name = ? $cols =~ s/\s+.*$//; } - my @cols = map { s/\s*//g; $_ } split(/\s*,\s*/,$cols); - my @f_cols = map { s/\s*//g; $_ } split(/\s*,\s*/,$f_cols); - - die "Mismatched column count in rel for $table => $f_table" - if @cols != @f_cols; - - my $cond = {}; - for(my $i = 0 ; $i < @cols; $i++) { - $cond->{$f_cols[$i]} = $cols[$i]; + my $cond; + + if($f_cols) { + my @cols = map { s/\s*//g; $_ } split(/\s*,\s*/,$cols); + my @f_cols = map { s/\s*//g; $_ } split(/\s*,\s*/,$f_cols); + die "Mismatched column count in rel for $table => $f_table" + if @cols != @f_cols; + $cond = {}; + for(my $i = 0 ; $i < @cols; $i++) { + $cond->{$f_cols[$i]} = $cols[$i]; + } + } + else { + $cond = $cols; } eval { $class->_loader_make_relations( $table, $f_table, $cond ) }; diff --git a/lib/DBIx/Class/Schema/Loader/mysql.pm b/lib/DBIx/Class/Schema/Loader/mysql.pm index bb0eedd..24c3f35 100644 --- a/lib/DBIx/Class/Schema/Loader/mysql.pm +++ b/lib/DBIx/Class/Schema/Loader/mysql.pm @@ -51,7 +51,7 @@ sub _loader_relationships { $sth->execute; my $table_def = $sth->fetchrow_arrayref->[1] || ''; - my (@reldata) = ($table_def =~ /CONSTRAINT `.*` FOREIGN KEY \(`(.*)`\) REFERENCES `(.*)` \(`(.*)`\)/g); + my (@reldata) = ($table_def =~ /CONSTRAINT `.*` FOREIGN KEY \(`(.*)`\) REFERENCES `(.*)` \(`(.*)`\)/ig); while (scalar @reldata > 0) { my $cols = shift @reldata; diff --git a/t/11mysql_common.t b/t/11mysql_common.t index 3d49663..df7b08e 100644 --- a/t/11mysql_common.t +++ b/t/11mysql_common.t @@ -17,6 +17,7 @@ my $tester = dbixcsl_common_tests->new( user => $user, password => $password, skip_rels => $test_innodb ? 0 : $skip_rels_msg, + no_inline_rels => 1, ); if( !$database || !$user ) { diff --git a/t/dbixcsl_common_tests.pm b/t/dbixcsl_common_tests.pm index 3bf8726..93da837 100644 --- a/t/dbixcsl_common_tests.pm +++ b/t/dbixcsl_common_tests.pm @@ -36,7 +36,7 @@ sub skip_tests { sub run_tests { my $self = shift; - plan tests => 27; + plan tests => 32; $self->create(); @@ -83,7 +83,7 @@ sub run_tests { is( $obj2->id, 2 ); SKIP: { - skip $self->{skip_rels}, 20 if $self->{skip_rels}; + skip $self->{skip_rels}, 25 if $self->{skip_rels}; my $moniker3 = $conn->moniker('loader_test3'); my $rsobj3 = $conn->resultset($moniker3); @@ -116,14 +116,14 @@ sub run_tests { my $obj5 = $rsobj5->find( id1 => 1, id2 => 1 ); is( ref( $obj5->id2 ), '' ); - # mulit-col fk def (works for some, not others...) + # mulit-col fk def my $obj6 = $rsobj6->find(1); - isa_ok( $obj6->loader_test2, "$schema_class\::$moniker2" ); - is( ref( $obj6->loader_test5 ), "$schema_class\::$moniker5"); + isa_ok( $obj6->loader_test2, "$schema_class\::$moniker2"); + isa_ok( $obj6->loader_test5, "$schema_class\::$moniker5"); # fk that references a non-pk key (UNIQUE) my $obj8 = $rsobj8->find(1); - isa_ok( $obj8->loader_test7, "$schema_class\::$moniker7" ); + isa_ok( $obj8->loader_test7, "$schema_class\::$moniker7"); # from Chisel's tests... SKIP: { @@ -169,6 +169,24 @@ sub run_tests { 'found same $rsobj11 object we expected' ); } } + + SKIP: { + skip 'This vendor cannot do inline relationship definitions', 5 + if $self->{no_inline_rels}; + + my $moniker12 = $conn->moniker('loader_test12'); + my $rsobj12 = $conn->resultset($moniker12); + my $moniker13 = $conn->moniker('loader_test13'); + my $rsobj13 = $conn->resultset($moniker13); + + isa_ok( $rsobj12, "DBIx::Class::ResultSet" ); + isa_ok( $rsobj13, "DBIx::Class::ResultSet" ); + + my $obj13 = $rsobj13->find(1); + isa_ok( $obj13->id, "$schema_class\::$moniker12" ); + isa_ok( $obj13->loader_test12, "$schema_class\::$moniker12"); + isa_ok( $obj13->dat, "$schema_class\::$moniker12"); + } } } @@ -322,6 +340,30 @@ sub create { q{ REFERENCES loader_test11 (id11) }), ); + my @statements_inline_rels = ( + qq{ + CREATE TABLE loader_test12 ( + id INTEGER NOT NULL PRIMARY KEY, + id2 VARCHAR(8) NOT NULL UNIQUE, + dat VARCHAR(8) UNIQUE + ) $self->{innodb} + }, + + q{ INSERT INTO loader_test12 (id,id2,dat) VALUES (1,'aaa','bbb') }, + + qq{ + CREATE TABLE loader_test13 ( + id INTEGER NOT NULL PRIMARY KEY REFERENCES loader_test12, + loader_test12 VARCHAR(8) NOT NULL REFERENCES loader_test12 (id2), + dat VARCHAR(8) REFERENCES loader_test12 (dat) + ) $self->{innodb} + }, + + (q{ INSERT INTO loader_test13 (id,loader_test12,dat) } . + q{ VALUES (1,'aaa','bbb') }), + ); + + $self->drop_tables; $self->{created} = 1; @@ -339,6 +381,9 @@ sub create { unless($self->{vendor} =~ /sqlite/i) { $dbh->do($_) for (@statements_advanced); } + unless($self->{no_inline_rels}) { + $dbh->do($_) for (@statements_inline_rels); + } } $dbh->disconnect(); } @@ -368,6 +413,11 @@ sub drop_tables { loader_test10 /; + my @tables_inline_rels = qw/ + loader_test13 + loader_test12 + /; + my $drop_fk_mysql = q{ALTER TABLE loader_test10 DROP FOREIGN KEY loader_test11_fk;}; @@ -387,6 +437,9 @@ sub drop_tables { } $dbh->do("DROP TABLE $_") for (@tables_advanced); } + unless($self->{no_inline_rels}) { + $dbh->do("DROP TABLE $_") for (@tables_inline_rels); + } } $dbh->do("DROP TABLE $_") for (@tables); $dbh->disconnect;