From: Robert Buels Date: Fri, 1 Jan 2010 04:45:18 +0000 (+0000) Subject: added relationship_attrs option, plus tests for it X-Git-Tag: 0.04999_13~8^2~1 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=c8c270209107babd57443af8a29aaf3d4546705f;p=dbsrgits%2FDBIx-Class-Schema-Loader.git added relationship_attrs option, plus tests for it --- diff --git a/lib/DBIx/Class/Schema/Loader/Base.pm b/lib/DBIx/Class/Schema/Loader/Base.pm index d2275ea..721816c 100644 --- a/lib/DBIx/Class/Schema/Loader/Base.pm +++ b/lib/DBIx/Class/Schema/Loader/Base.pm @@ -46,6 +46,8 @@ __PACKAGE__->mk_group_ro_accessors('simple', qw/ result_base_class overwrite_modifications + relationship_attrs + db_schema _tables classes @@ -153,6 +155,26 @@ next major version upgrade: __PACKAGE__->naming('v5'); +=head2 relationship_attrs + +Hashref of attributes to pass to each generated relationship, listed +by type. Also supports relationship type 'all', containing options to +pass to all generated relationships. Attributes set for more specific +relationship types override those set in 'all'. + +For example: + + relationship_attrs => { + all => { cascade_delete => 0 }, + has_many => { cascade_delete => 1 }, + }, + +will set the C option to 0 for all generated relationships, +except for C, which will have cascade_delete as 1. + +NOTE: this option is not supported if v4 backward-compatible naming is +set either globally (naming => 'v4') or just for relationships. + =head2 debug If set to true, each constructive L statement the loader @@ -656,8 +678,11 @@ sub _relbuilder { ); } - $self->{relbuilder} ||= DBIx::Class::Schema::Loader::RelBuilder->new( - $self->schema, $self->inflect_plural, $self->inflect_singular + $self->{relbuilder} ||= DBIx::Class::Schema::Loader::RelBuilder->new ( + $self->schema, + $self->inflect_plural, + $self->inflect_singular, + $self->relationship_attrs, ); } diff --git a/lib/DBIx/Class/Schema/Loader/RelBuilder.pm b/lib/DBIx/Class/Schema/Loader/RelBuilder.pm index 1261149..f105fc9 100644 --- a/lib/DBIx/Class/Schema/Loader/RelBuilder.pm +++ b/lib/DBIx/Class/Schema/Loader/RelBuilder.pm @@ -76,17 +76,23 @@ arguments, like so: =cut sub new { - my ( $class, $schema, $inflect_pl, $inflect_singular ) = @_; + + my ( $class, $schema, $inflect_pl, $inflect_singular, $rel_attrs ) = @_; my $self = { schema => $schema, inflect_plural => $inflect_pl, inflect_singular => $inflect_singular, + relationship_attrs => $rel_attrs, }; - bless $self => $class; + # validate the relationship_attrs arg + if( defined $self->{relationship_attrs} ) { + ref($self->{relationship_attrs}) eq 'HASH' + or croak "relationship_attrs must be a hashref"; + } - $self; + return bless $self => $class; } @@ -122,6 +128,23 @@ sub _inflect_singular { return Lingua::EN::Inflect::Number::to_S($relname); } +# 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 +sub _relationship_attrs { + my ( $self, $reltype ) = @_; + my $r = $self->{relationship_attrs}; + return unless $r && ( $r->{all} || $r->{$reltype} ); + + my %composite = %{ $r->{all} || {} }; + if( my $specific = $r->{$reltype} ) { + while( my ($k,$v) = each %$specific ) { + $composite{$k} = $v; + } + } + return \%composite; +} + sub _array_eq { my ($a, $b) = @_; @@ -152,11 +175,17 @@ sub _uniq_fk_rel { sub _remote_attrs { my ($self, $local_moniker, $local_cols) = @_; - # If the referring column is nullable, make 'belongs_to' an outer join: + # get our base set of attrs from _relationship_attrs, if present + my $attrs = $self->_relationship_attrs('belongs_to') || {}; + + # If the referring column is nullable, make 'belongs_to' an + # outer join, unless explicitly set by relationship_attrs my $nullable = grep { $self->{schema}->source($local_moniker)->column_info($_)->{is_nullable} } @$local_cols; + $attrs->{join_type} = 'LEFT' + if $nullable && !defined $attrs->{join_type}; - return $nullable ? { join_type => 'LEFT' } : (); + return $attrs; } sub _remote_relname { @@ -252,6 +281,7 @@ sub generate_code { args => [ $local_relname, $local_class, \%rev_cond, + $self->_relationship_attrs($remote_method), ], } ); diff --git a/t/45relationships.t b/t/45relationships.t new file mode 100644 index 0000000..f3ae061 --- /dev/null +++ b/t/45relationships.t @@ -0,0 +1,60 @@ +use strict; +use Test::More tests => 6; +use Test::Exception; +use lib qw(t/lib); +use make_dbictest_db; + +use DBIx::Class::Schema::Loader; + +# test skip_relationships +my $regular = schema_with(); +is( ref($regular->source('Bar')->relationship_info('fooref')), 'HASH', + 'regularly-made schema has fooref rel', + ); +my $skip_rel = schema_with( skip_relationships => 1 ); +is_deeply( $skip_rel->source('Bar')->relationship_info('fooref'), undef, + 'skip_relationships blocks generation of fooref rel', + ); + + +# test relationship_attrs +throws_ok { + schema_with( relationship_attrs => 'laughably invalid!!!' ); +} qr/relationship_attrs/, 'throws error for invalid relationship_attrs'; + + +{ + my $nodelete = schema_with( relationship_attrs => + { + all => { cascade_delete => 0 }, + belongs_to => { cascade_delete => 1 }, + }, + ); + + my $bars_info = $nodelete->source('Foo')->relationship_info('bars'); + #use Data::Dumper; + #die Dumper([ $nodelete->source('Foo')->relationships() ]); + my $fooref_info = $nodelete->source('Bar')->relationship_info('fooref'); + is( ref($fooref_info), 'HASH', + 'fooref rel is present', + ); + is( $bars_info->{attrs}->{cascade_delete}, 0, + 'relationship_attrs settings seem to be getting through to the generated rels', + ); + is( $fooref_info->{attrs}->{cascade_delete}, 1, + 'belongs_to in relationship_attrs overrides all def', + ); +} + + +#### generates a new schema with the given opts every time it's called +my $schema_counter = 0; +sub schema_with { + $schema_counter++; + DBIx::Class::Schema::Loader::make_schema_at( + 'DBICTest::Schema::'.$schema_counter, + { naming => 'current', @_ }, + [ $make_dbictest_db::dsn ], + ); + "DBICTest::Schema::$schema_counter"->clone; +}