support coderef for relationship_attrs
[dbsrgits/DBIx-Class-Schema-Loader.git] / t / 45relationships.t
1 use strict;
2 use Test::More;
3 use Test::Exception;
4 use Try::Tiny;
5 use lib qw(t/lib);
6 use make_dbictest_db;
7
8 use DBIx::Class::Schema::Loader;
9
10 my $schema_counter = 0;
11
12 # test skip_relationships
13 my $regular = schema_with();
14 is( ref($regular->source('Bar')->relationship_info('fooref')), 'HASH',
15     'regularly-made schema has fooref rel',
16   );
17 my $skip_rel = schema_with( skip_relationships => 1 );
18 is_deeply( $skip_rel->source('Bar')->relationship_info('fooref'), undef,
19     'skip_relationships blocks generation of fooref rel',
20   );
21
22 # test hashref as rel_name_map
23 my $hash_relationship = schema_with(
24     rel_name_map => {
25         fooref => "got_fooref",
26         bars   => "ignored",
27         Foo    => {
28             bars => "got_bars",
29             fooref => "ignored",
30         },
31     }
32 );
33 is( ref($hash_relationship->source('Foo')->relationship_info('got_bars')),
34     'HASH',
35     'single level hash in rel_name_map picked up correctly'
36   );
37 is( ref($hash_relationship->source('Bar')->relationship_info('got_fooref')),
38     'HASH',
39     'double level hash in rel_name_map picked up correctly'
40   );
41
42 # test coderef as rel_name_map
43 my $code_relationship = schema_with(
44     rel_name_map => sub {
45         my ($args) = @_;
46
47         if ($args->{local_moniker} eq 'Foo') {
48             is_deeply(
49                 $args,
50                 {
51                     name           => 'bars',
52                     type           => 'has_many',
53                     local_class    =>
54                         "DBICTest::Schema::${schema_counter}::Result::Foo",
55                     local_moniker  => 'Foo',
56                     local_columns  => ['fooid'],
57                     remote_class   =>
58                         "DBICTest::Schema::${schema_counter}::Result::Bar",
59                     remote_moniker => 'Bar',
60                     remote_columns => ['fooref'],
61                 },
62                 'correct args for Foo passed'
63               );
64             return 'bars_caught';
65         }
66         elsif ($args->{local_moniker} eq 'Bar') {
67             is_deeply(
68                 $args,
69                 {
70                     name           => 'fooref',
71                     type           => 'belongs_to',
72                     local_class    =>
73                         "DBICTest::Schema::${schema_counter}::Result::Bar",
74                     local_moniker  => 'Bar',
75                     local_columns  => ['fooref'],
76                     remote_class   =>
77                         "DBICTest::Schema::${schema_counter}::Result::Foo",
78                     remote_moniker => 'Foo',
79                     remote_columns => ['fooid'],
80                 },
81                 'correct args for Foo passed'
82               );
83         
84             return 'fooref_caught';
85         }
86     }
87   );
88 is( ref($code_relationship->source('Foo')->relationship_info('bars_caught')),
89     'HASH',
90     'rel_name_map overrode local_info correctly'
91   );
92 is( ref($code_relationship->source('Bar')->relationship_info('fooref_caught')),
93     'HASH',
94     'rel_name_map overrode remote_info correctly'
95   );
96
97
98
99 # test relationship_attrs
100 throws_ok {
101     schema_with( relationship_attrs => 'laughably invalid!!!' );
102 } qr/relationship_attrs/, 'throws error for invalid (scalar) relationship_attrs';
103
104 throws_ok {
105     schema_with( relationship_attrs => [qw/laughably invalid/] );
106 } qr/relationship_attrs/, 'throws error for invalid (arrayref) relationship_attrs';
107
108 {
109     my $nodelete = schema_with( relationship_attrs =>
110                                 {
111                                  all        => { cascade_delete => 0 },
112                                  belongs_to => { cascade_delete => 1 },
113                                 },
114                               );
115
116     my $bars_info   = $nodelete->source('Foo')->relationship_info('bars');
117     #use Data::Dumper;
118     #die Dumper([ $nodelete->source('Foo')->relationships() ]);
119     my $fooref_info = $nodelete->source('Bar')->relationship_info('fooref');
120     is( ref($fooref_info), 'HASH',
121         'fooref rel is present',
122       );
123     is( $bars_info->{attrs}->{cascade_delete}, 0,
124         'relationship_attrs settings seem to be getting through to the generated rels',
125       );
126     is( $fooref_info->{attrs}->{cascade_delete}, 1,
127         'belongs_to in relationship_attrs overrides all def',
128       );
129 }
130
131 # test relationship_attrs coderef
132 {
133     my $relationship_attrs_coderef_invoked = 0;
134     my $schema;
135
136     lives_ok {
137         $schema = schema_with(relationship_attrs => sub {
138             my %p = @_;
139
140             $relationship_attrs_coderef_invoked++;
141
142             if ($p{rel_name} eq 'bars') {
143                 is $p{local_table},  'foo', 'correct local_table';
144                 is_deeply $p{local_cols}, [ 'fooid' ], 'correct local_cols';
145                 is $p{remote_table}, 'bar', 'correct remote_table';
146                 is_deeply $p{remote_cols}, [ 'fooref' ], 'correct remote_cols';
147                 is_deeply $p{attrs}, {
148                     cascade_delete => 0,
149                     cascade_copy   => 0,
150                 }, "got default rel attrs for $p{rel_name} in $p{local_table}";
151
152                 like $p{local_source}->result_class,
153                     qr/^DBICTest::Schema::\d+::Result::Foo\z/,
154                     'correct local source';
155
156                 like $p{remote_source}->result_class,
157                     qr/^DBICTest::Schema::\d+::Result::Bar\z/,
158                     'correct remote source';
159  
160                 $p{attrs}{snoopy} = 1;
161
162                 return $p{attrs};
163             }
164             elsif ($p{rel_name} eq 'fooref') {
165                 is $p{local_table},  'bar', 'correct local_table';
166                 is_deeply $p{local_cols}, [ 'fooref' ], 'correct local_cols';
167                 is $p{remote_table}, 'foo', 'correct remote_table';
168                 is_deeply $p{remote_cols}, [ 'fooid' ], 'correct remote_cols';
169                 is_deeply $p{attrs}, {
170                     on_delete     => 'NO ACTION',
171                     on_update     => 'NO ACTION',
172                     is_deferrable => 0,
173                 }, "got correct rel attrs for $p{rel_name} in $p{local_table}";
174
175                 like $p{local_source}->result_class,
176                     qr/^DBICTest::Schema::\d+::Result::Bar\z/,
177                     'correct local source';
178
179                 like $p{remote_source}->result_class,
180                     qr/^DBICTest::Schema::\d+::Result::Foo\z/,
181                     'correct remote source';
182  
183                 $p{attrs}{scooby} = 1;
184
185                 return $p{attrs};
186             }
187             else {
188                 fail "unknown rel $p{rel_name} in $p{local_table}";
189             }
190         });
191     } 'dumping schema with coderef relationship_attrs survived';
192
193     is $relationship_attrs_coderef_invoked, 2,
194         'relationship_attrs coderef was invoked correct number of times';
195
196     is ((try { $schema->source('Foo')->relationship_info('bars')->{attrs}{snoopy} }) || undef, 1,
197         "correct relationship attributes for 'bars' in 'Foo'");
198
199     is ((try { $schema->source('Bar')->relationship_info('fooref')->{attrs}{scooby} }) || undef, 1,
200         "correct relationship attributes for 'fooref' in 'Bar'");
201 }
202
203 done_testing;
204
205 #### generates a new schema with the given opts every time it's called
206 sub schema_with {
207     $schema_counter++;
208     DBIx::Class::Schema::Loader::make_schema_at(
209             'DBICTest::Schema::'.$schema_counter,
210             { naming => 'current', @_ },
211             [ $make_dbictest_db::dsn ],
212     );
213     "DBICTest::Schema::$schema_counter"->clone;
214 }