9 my $from_storage_ran = 0;
10 my $to_storage_ran = 0;
11 my $schema = DBICTest->init_schema( no_populate => 1 );
12 DBICTest::Schema::Artist->load_components(qw(FilterColumn InflateColumn));
13 DBICTest::Schema::Artist->filter_column(charfield => {
14 filter_from_storage => sub { $from_storage_ran++; defined $_[1] ? $_[1] * 2 : undef },
15 filter_to_storage => sub { $to_storage_ran++; defined $_[1] ? $_[1] / 2 : undef },
17 Class::C3->reinitialize() if DBIx::Class::_ENV_::OLD_MRO;
19 my $artist = $schema->resultset('Artist')->create( { charfield => 20 } );
21 # this should be using the cursor directly, no inflation/processing of any sort
22 my ($raw_db_charfield) = $schema->resultset('Artist')
23 ->search ($artist->ident_condition)
24 ->get_column('charfield')
29 is ($raw_db_charfield, 10, 'INSERT: correctly unfiltered on insertion');
31 for my $reloaded (0, 1) {
32 my $test = $reloaded ? 'reloaded' : 'stored';
33 $artist->discard_changes if $reloaded;
35 is( $artist->charfield , 20, "got $test filtered charfield" );
39 $artist->discard_changes;
40 is( $artist->charfield , 20, "got filtered charfield" );
42 $artist->update ({ charfield => 40 });
43 ($raw_db_charfield) = $schema->resultset('Artist')
44 ->search ($artist->ident_condition)
45 ->get_column('charfield')
49 is ($raw_db_charfield, 20, 'UPDATE: correctly unflitered on update');
51 $artist->discard_changes;
52 $artist->charfield(40);
53 ok( !$artist->is_column_changed('charfield'), 'column is not dirty after setting the same value' );
56 my $cd = $schema->resultset('CD')->create({
57 artist => { charfield => 20 },
58 title => 'fun time city!',
59 year => 'forevertime',
61 ($raw_db_charfield) = $schema->resultset('Artist')
62 ->search ($cd->artist->ident_condition)
63 ->get_column('charfield')
68 is $raw_db_charfield, 10, 'artist charfield gets correctly unfiltered w/ MC';
69 is $cd->artist->charfield, 20, 'artist charfield gets correctly filtered w/ MC';
73 my $expected_from = $from_storage_ran;
74 my $expected_to = $to_storage_ran;
76 # ensure we are creating a fresh obj
77 $artist = $schema->resultset('Artist')->single($artist->ident_condition);
79 is $from_storage_ran, $expected_from, 'from has not run yet';
80 is $to_storage_ran, $expected_to, 'to has not run yet';
84 $artist->get_filtered_column('charfield'),
86 $artist->get_column('charfield'),
87 'filter/unfilter differ'
89 is $from_storage_ran, ++$expected_from, 'from ran once, therefor caches';
90 is $to_storage_ran, $expected_to, 'to did not run';
92 $artist->charfield(6);
93 is $from_storage_ran, $expected_from, 'from did not run';
94 is $to_storage_ran, ++$expected_to, 'to ran once';
96 ok ($artist->is_column_changed ('charfield'), 'Column marked as dirty');
99 is $from_storage_ran, $expected_from, 'from did not run';
100 is $to_storage_ran, $expected_to, 'to did not run';
104 $artist->set_column(charfield => 3);
105 ok (! $artist->is_column_changed ('charfield'), 'Column not marked as dirty on same set_column value');
106 is ($artist->charfield, '6', 'Column set properly (cache blown)');
107 is $from_storage_ran, ++$expected_from, 'from ran once (set_column blew cache)';
108 is $to_storage_ran, $expected_to, 'to did not run';
110 $artist->charfield(6);
111 ok (! $artist->is_column_changed ('charfield'), 'Column not marked as dirty on same accessor-set value');
112 is ($artist->charfield, '6', 'Column set properly');
113 is $from_storage_ran, $expected_from, 'from did not run';
114 is $to_storage_ran, ++$expected_to, 'to did run once (call in to set_column)';
116 $artist->store_column(charfield => 4);
117 ok (! $artist->is_column_changed ('charfield'), 'Column not marked as dirty on differing store_column value');
118 is ($artist->charfield, '8', 'Cache properly blown');
119 is $from_storage_ran, ++$expected_from, 'from did not run';
120 is $to_storage_ran, $expected_to, 'to did not run';
122 $artist->update({ charfield => undef });
123 is $from_storage_ran, $expected_from, 'from did not run';
124 is $to_storage_ran, ++$expected_to, 'to did run';
126 $artist->discard_changes;
127 is ( $artist->get_column('charfield'), undef, 'Got back null' );
128 is ( $artist->charfield, undef, 'Got back null through filter' );
130 is $from_storage_ran, ++$expected_from, 'from did run';
131 is $to_storage_ran, $expected_to, 'to did not run';
133 ok ! $artist->is_changed, 'object clean';
135 { $artist->get_dirty_columns },
137 'dirty columns as expected',
140 is $from_storage_ran, $expected_from, 'from did not run';
141 is $to_storage_ran, $expected_to, 'to did not run';
143 $artist->charfield(42);
145 is $from_storage_ran, $expected_from, 'from did not run';
146 is $to_storage_ran, ++$expected_to, 'to ran once, determining dirtyness';
148 is $artist->charfield, 42, 'setting once works';
149 ok $artist->is_column_changed('charfield'), 'column changed';
150 ok $artist->is_changed, 'object changed';
152 { $artist->get_dirty_columns },
154 'dirty columns as expected',
157 is $from_storage_ran, $expected_from, 'from did not run';
158 is $to_storage_ran, $expected_to, 'to did not run';
160 $artist->charfield(66);
161 is $artist->charfield, 66, 'setting twice works';
162 ok $artist->is_column_changed('charfield'), 'column changed';
163 ok $artist->is_changed, 'object changed';
165 is $from_storage_ran, $expected_from, 'from did not run';
166 is $to_storage_ran, $expected_to, 'to did not run a second time on dirty column';
169 { $artist->get_dirty_columns },
171 'dirty columns as expected',
173 is $from_storage_ran, $expected_from, 'from did not run';
174 is $to_storage_ran, ++$expected_to, 'to did run producing a new dirty_columns set';
177 { $artist->get_dirty_columns },
179 'dirty columns still as expected',
181 is $from_storage_ran, $expected_from, 'from did not run';
182 is $to_storage_ran, $expected_to, 'to did not run on re-invoked get_dirty_columns';
185 is $artist->charfield, 66, 'value still there';
187 is $from_storage_ran, $expected_from, 'from did not run';
188 is $to_storage_ran, $expected_to, 'to did not run ';
190 $artist->discard_changes;
192 is $from_storage_ran, $expected_from, 'from did not run after discard_changes';
193 is $to_storage_ran, $expected_to, 'to did not run after discard_changes';
195 is $artist->charfield, 66, 'value still there post reload';
197 is $from_storage_ran, ++$expected_from, 'from did run';
198 is $to_storage_ran, $expected_to, 'to did not run';
201 # test in-memory operations
202 for my $artist_maker (
203 sub { $schema->resultset('Artist')->new({ charfield => 42 }) },
204 sub { my $art = $schema->resultset('Artist')->new({}); $art->charfield(42); $art },
206 $schema->resultset('Artist')->delete;
208 my $expected_from = $from_storage_ran;
209 my $expected_to = $to_storage_ran;
211 my $artist = $artist_maker->();
213 is $from_storage_ran, $expected_from, 'from has not run yet';
214 is $to_storage_ran, $expected_to, 'to has not run yet';
216 ok( ! $artist->has_column_loaded('artistid'), 'pk not loaded' );
217 ok( $artist->has_column_loaded('charfield'), 'Filtered column marked as loaded under new' );
218 is( $artist->charfield, 42, 'Proper unfiltered value' );
219 is( $artist->get_column('charfield'), 21, 'Proper filtered value' );
222 ($raw_db_charfield) = $schema->resultset('Artist')
223 ->search ($artist->ident_condition)
224 ->get_column('charfield')
227 is $raw_db_charfield, 21, 'Proper value in database';
231 for my $v ( \ '16', \[ '?', '16' ] ) {
232 my $rs = $schema->resultset('Artist');
235 my $art = $rs->new({ charfield => 10 });
238 is_deeply( $art->charfield, $v);
239 is_deeply( $art->get_filtered_column("charfield"), $v);
240 is_deeply( $art->get_column("charfield"), $v);
243 $art->discard_changes;
245 is ($art->get_column("charfield"), 16, "Literal inserted into database properly");
246 is ($art->charfield, 32, "filtering still works");
248 $art->update({ charfield => $v });
250 is_deeply( $art->charfield, $v);
251 is_deeply( $art->get_filtered_column("charfield"), $v);
252 is_deeply( $art->get_column("charfield"), $v);
254 $art->discard_changes;
256 is ($art->get_column("charfield"), 16, "Literal inserted into database properly");
257 is ($art->charfield, 32, "filtering still works");
262 DBICTest::Schema::Artist->inflate_column(charfield =>
263 { inflate => sub {}, deflate => sub {} }
265 } qr/InflateColumn can not be used on a column with a declared FilterColumn filter/, q(Can't inflate column after filter column);
267 DBICTest::Schema::Artist->inflate_column(name =>
268 { inflate => sub {}, deflate => sub {} }
272 DBICTest::Schema::Artist->filter_column(name => {
273 filter_to_storage => sub {},
274 filter_from_storage => sub {}
276 } qr/FilterColumn can not be used on a column with a declared InflateColumn inflator/, q(Can't filter column after inflate column);
279 # test when we do not set both filter_from_storage/filter_to_storage
280 DBICTest::Schema::Artist->filter_column(charfield => {
281 filter_to_storage => sub { $to_storage_ran++; $_[1] },
283 Class::C3->reinitialize() if DBIx::Class::_ENV_::OLD_MRO;
285 ASYMMETRIC_TO_TEST: {
287 $artist->charfield(20);
290 my $expected_from = $from_storage_ran;
291 my $expected_to = $to_storage_ran;
293 $artist->charfield(10);
294 ok ($artist->is_column_changed ('charfield'), 'Column marked as dirty on accessor-set value');
295 is ($artist->charfield, '10', 'Column set properly');
296 is $from_storage_ran, $expected_from, 'from did not run';
297 is $to_storage_ran, ++$expected_to, 'to did run';
299 $artist->discard_changes;
301 is ($artist->charfield, '20', 'Column set properly');
302 is $from_storage_ran, $expected_from, 'from did not run';
303 is $to_storage_ran, $expected_to, 'to did not run';
306 DBICTest::Schema::Artist->filter_column(charfield => {
307 filter_from_storage => sub { $from_storage_ran++; $_[1] },
309 Class::C3->reinitialize() if DBIx::Class::_ENV_::OLD_MRO;
311 ASYMMETRIC_FROM_TEST: {
313 $artist->charfield(23);
316 my $expected_from = $from_storage_ran;
317 my $expected_to = $to_storage_ran;
319 $artist->charfield(13);
320 ok ($artist->is_column_changed ('charfield'), 'Column marked as dirty on accessor-set value');
321 is ($artist->charfield, '13', 'Column set properly');
322 is $from_storage_ran, $expected_from, 'from did not run';
323 is $to_storage_ran, $expected_to, 'to did not run';
325 $artist->discard_changes;
327 is ($artist->charfield, '23', 'Column set properly');
328 is $from_storage_ran, ++$expected_from, 'from did run';
329 is $to_storage_ran, $expected_to, 'to did not run';
332 throws_ok { DBICTest::Schema::Artist->filter_column( charfield => {} ) }
333 qr/\QAn invocation of filter_column() must specify either a filter_from_storage or filter_to_storage/,
334 'Correctly throws exception for empty attributes'
338 # there are cases in the wild that autovivify stuff deep in the
339 # colinfo guts. While this is insane, there is no alternative
340 # so at leats make sure it keeps working...
342 $schema->source('Artist')->column_info('artistid')->{_filter_info} ||= {};
344 for my $key ('', 'primary') {
346 $schema->resultset('Artist')->find_or_create({ artistid => 42 }, { $key ? ( key => $key ) : () });
351 DBICTest::Schema::Artist->filter_column(artistid => {
352 filter_to_storage => sub { $_[1] * 100 },
353 filter_from_storage => sub { $_[1] - 100 },
356 for my $key ('', 'primary') {
358 $schema->resultset('Artist')->find_or_create({ artistid => 42 }, { $key ? ( key => $key ) : () });
359 } qr/\QUnable to satisfy requested constraint 'primary', FilterColumn values not usable for column(s): 'artistid'/;