Introduce GOVERNANCE document and empty RESOLUTIONS file.
[dbsrgits/DBIx-Class.git] / t / row / filter_column.t
CommitLineData
c0329273 1BEGIN { do "./t/lib/ANFANG.pm" or die ( $@ || $! ) }
2
956f4141 3use strict;
4use warnings;
5
6use Test::More;
c227b295 7use Test::Exception;
c0329273 8
956f4141 9use DBICTest;
cc2d2ead 10
85439e0c 11my $from_storage_ran = 0;
12my $to_storage_ran = 0;
1bc006cf 13my $schema = DBICTest->init_schema( no_populate => 1 );
c227b295 14DBICTest::Schema::Artist->load_components(qw(FilterColumn InflateColumn));
1bc006cf 15DBICTest::Schema::Artist->filter_column(charfield => {
cfa1ab03 16 filter_from_storage => sub { $from_storage_ran++; defined $_[1] ? $_[1] * 2 : undef },
17 filter_to_storage => sub { $to_storage_ran++; defined $_[1] ? $_[1] / 2 : undef },
cc2d2ead 18});
cc8ffd7b 19Class::C3->reinitialize() if DBIx::Class::_ENV_::OLD_MRO;
cc2d2ead 20
1bc006cf 21my $artist = $schema->resultset('Artist')->create( { charfield => 20 } );
cc2d2ead 22
23# this should be using the cursor directly, no inflation/processing of any sort
1bc006cf 24my ($raw_db_charfield) = $schema->resultset('Artist')
cc2d2ead 25 ->search ($artist->ident_condition)
1bc006cf 26 ->get_column('charfield')
cc2d2ead 27 ->_resultset
28 ->cursor
29 ->next;
30
1bc006cf 31is ($raw_db_charfield, 10, 'INSERT: correctly unfiltered on insertion');
cc2d2ead 32
33for my $reloaded (0, 1) {
34 my $test = $reloaded ? 'reloaded' : 'stored';
35 $artist->discard_changes if $reloaded;
36
1bc006cf 37 is( $artist->charfield , 20, "got $test filtered charfield" );
cc2d2ead 38}
39
40$artist->update;
41$artist->discard_changes;
1bc006cf 42is( $artist->charfield , 20, "got filtered charfield" );
cc2d2ead 43
1bc006cf 44$artist->update ({ charfield => 40 });
45($raw_db_charfield) = $schema->resultset('Artist')
cc2d2ead 46 ->search ($artist->ident_condition)
1bc006cf 47 ->get_column('charfield')
cc2d2ead 48 ->_resultset
49 ->cursor
50 ->next;
1bc006cf 51is ($raw_db_charfield, 20, 'UPDATE: correctly unflitered on update');
cc2d2ead 52
53$artist->discard_changes;
1bc006cf 54$artist->charfield(40);
55ok( !$artist->is_column_changed('charfield'), 'column is not dirty after setting the same value' );
cc2d2ead 56
8cfbd51c 57MC: {
58 my $cd = $schema->resultset('CD')->create({
1bc006cf 59 artist => { charfield => 20 },
8cfbd51c 60 title => 'fun time city!',
61 year => 'forevertime',
62 });
1bc006cf 63 ($raw_db_charfield) = $schema->resultset('Artist')
0f914ece 64 ->search ($cd->artist->ident_condition)
1bc006cf 65 ->get_column('charfield')
0f914ece 66 ->_resultset
67 ->cursor
68 ->next;
69
1bc006cf 70 is $raw_db_charfield, 10, 'artist charfield gets correctly unfiltered w/ MC';
71 is $cd->artist->charfield, 20, 'artist charfield gets correctly filtered w/ MC';
8cfbd51c 72}
73
c227b295 74CACHE_TEST: {
75 my $expected_from = $from_storage_ran;
76 my $expected_to = $to_storage_ran;
77
78 # ensure we are creating a fresh obj
79 $artist = $schema->resultset('Artist')->single($artist->ident_condition);
80
81 is $from_storage_ran, $expected_from, 'from has not run yet';
82 is $to_storage_ran, $expected_to, 'to has not run yet';
83
1bc006cf 84 $artist->charfield;
c227b295 85 cmp_ok (
1bc006cf 86 $artist->get_filtered_column('charfield'),
c227b295 87 '!=',
1bc006cf 88 $artist->get_column('charfield'),
c227b295 89 'filter/unfilter differ'
90 );
91 is $from_storage_ran, ++$expected_from, 'from ran once, therefor caches';
92 is $to_storage_ran, $expected_to, 'to did not run';
93
1bc006cf 94 $artist->charfield(6);
c227b295 95 is $from_storage_ran, $expected_from, 'from did not run';
96 is $to_storage_ran, ++$expected_to, 'to ran once';
97
1bc006cf 98 ok ($artist->is_column_changed ('charfield'), 'Column marked as dirty');
c227b295 99
1bc006cf 100 $artist->charfield;
c227b295 101 is $from_storage_ran, $expected_from, 'from did not run';
102 is $to_storage_ran, $expected_to, 'to did not run';
103
104 $artist->update;
105
1bc006cf 106 $artist->set_column(charfield => 3);
107 ok (! $artist->is_column_changed ('charfield'), 'Column not marked as dirty on same set_column value');
108 is ($artist->charfield, '6', 'Column set properly (cache blown)');
c227b295 109 is $from_storage_ran, ++$expected_from, 'from ran once (set_column blew cache)';
110 is $to_storage_ran, $expected_to, 'to did not run';
111
1bc006cf 112 $artist->charfield(6);
113 ok (! $artist->is_column_changed ('charfield'), 'Column not marked as dirty on same accessor-set value');
114 is ($artist->charfield, '6', 'Column set properly');
c227b295 115 is $from_storage_ran, $expected_from, 'from did not run';
dc6dadae 116 is $to_storage_ran, ++$expected_to, 'to did run once (call in to set_column)';
c227b295 117
1bc006cf 118 $artist->store_column(charfield => 4);
119 ok (! $artist->is_column_changed ('charfield'), 'Column not marked as dirty on differing store_column value');
120 is ($artist->charfield, '8', 'Cache properly blown');
491c8ff9 121 is $from_storage_ran, ++$expected_from, 'from did not run';
c227b295 122 is $to_storage_ran, $expected_to, 'to did not run';
cfa1ab03 123
124 $artist->update({ charfield => undef });
125 is $from_storage_ran, $expected_from, 'from did not run';
126 is $to_storage_ran, ++$expected_to, 'to did run';
127
128 $artist->discard_changes;
129 is ( $artist->get_column('charfield'), undef, 'Got back null' );
130 is ( $artist->charfield, undef, 'Got back null through filter' );
131
132 is $from_storage_ran, ++$expected_from, 'from did run';
133 is $to_storage_ran, $expected_to, 'to did not run';
134
b482a095 135 ok ! $artist->is_changed, 'object clean';
136 is_deeply
137 { $artist->get_dirty_columns },
138 {},
139 'dirty columns as expected',
140 ;
141
142 is $from_storage_ran, $expected_from, 'from did not run';
143 is $to_storage_ran, $expected_to, 'to did not run';
144
145 $artist->charfield(42);
146
147 is $from_storage_ran, $expected_from, 'from did not run';
148 is $to_storage_ran, ++$expected_to, 'to ran once, determining dirtyness';
149
150 is $artist->charfield, 42, 'setting once works';
151 ok $artist->is_column_changed('charfield'), 'column changed';
152 ok $artist->is_changed, 'object changed';
153 is_deeply
154 { $artist->get_dirty_columns },
155 { charfield => 21 },
156 'dirty columns as expected',
157 ;
158
159 is $from_storage_ran, $expected_from, 'from did not run';
160 is $to_storage_ran, $expected_to, 'to did not run';
161
162 $artist->charfield(66);
163 is $artist->charfield, 66, 'setting twice works';
164 ok $artist->is_column_changed('charfield'), 'column changed';
165 ok $artist->is_changed, 'object changed';
166
167 is $from_storage_ran, $expected_from, 'from did not run';
168 is $to_storage_ran, $expected_to, 'to did not run a second time on dirty column';
169
170 is_deeply
171 { $artist->get_dirty_columns },
172 { charfield => 33 },
173 'dirty columns as expected',
174 ;
175 is $from_storage_ran, $expected_from, 'from did not run';
176 is $to_storage_ran, ++$expected_to, 'to did run producing a new dirty_columns set';
177
178 is_deeply
179 { $artist->get_dirty_columns },
180 { charfield => 33 },
181 'dirty columns still as expected',
182 ;
183 is $from_storage_ran, $expected_from, 'from did not run';
184 is $to_storage_ran, $expected_to, 'to did not run on re-invoked get_dirty_columns';
185
186 $artist->update;
187 is $artist->charfield, 66, 'value still there';
188
189 is $from_storage_ran, $expected_from, 'from did not run';
190 is $to_storage_ran, $expected_to, 'to did not run ';
191
192 $artist->discard_changes;
193
194 is $from_storage_ran, $expected_from, 'from did not run after discard_changes';
195 is $to_storage_ran, $expected_to, 'to did not run after discard_changes';
196
197 is $artist->charfield, 66, 'value still there post reload';
198
199 is $from_storage_ran, ++$expected_from, 'from did run';
200 is $to_storage_ran, $expected_to, 'to did not run';
c227b295 201}
85439e0c 202
dc6dadae 203# test in-memory operations
204for my $artist_maker (
1bc006cf 205 sub { $schema->resultset('Artist')->new({ charfield => 42 }) },
206 sub { my $art = $schema->resultset('Artist')->new({}); $art->charfield(42); $art },
dc6dadae 207) {
b482a095 208 $schema->resultset('Artist')->delete;
dc6dadae 209
210 my $expected_from = $from_storage_ran;
211 my $expected_to = $to_storage_ran;
212
213 my $artist = $artist_maker->();
214
215 is $from_storage_ran, $expected_from, 'from has not run yet';
216 is $to_storage_ran, $expected_to, 'to has not run yet';
217
218 ok( ! $artist->has_column_loaded('artistid'), 'pk not loaded' );
1bc006cf 219 ok( $artist->has_column_loaded('charfield'), 'Filtered column marked as loaded under new' );
220 is( $artist->charfield, 42, 'Proper unfiltered value' );
221 is( $artist->get_column('charfield'), 21, 'Proper filtered value' );
b482a095 222
223 $artist->insert;
224 ($raw_db_charfield) = $schema->resultset('Artist')
225 ->search ($artist->ident_condition)
226 ->get_column('charfield')
227 ->next;
228
229 is $raw_db_charfield, 21, 'Proper value in database';
dc6dadae 230}
231
a524980e 232# test literals
233for my $v ( \ '16', \[ '?', '16' ] ) {
1bc006cf 234 my $rs = $schema->resultset('Artist');
235 $rs->delete;
a524980e 236
1bc006cf 237 my $art = $rs->new({ charfield => 10 });
238 $art->charfield($v);
239
240 is_deeply( $art->charfield, $v);
241 is_deeply( $art->get_filtered_column("charfield"), $v);
242 is_deeply( $art->get_column("charfield"), $v);
a524980e 243
244 $art->insert;
245 $art->discard_changes;
246
1bc006cf 247 is ($art->get_column("charfield"), 16, "Literal inserted into database properly");
248 is ($art->charfield, 32, "filtering still works");
a524980e 249
1bc006cf 250 $art->update({ charfield => $v });
a524980e 251
1bc006cf 252 is_deeply( $art->charfield, $v);
253 is_deeply( $art->get_filtered_column("charfield"), $v);
254 is_deeply( $art->get_column("charfield"), $v);
a524980e 255
256 $art->discard_changes;
257
1bc006cf 258 is ($art->get_column("charfield"), 16, "Literal inserted into database properly");
259 is ($art->charfield, 32, "filtering still works");
a524980e 260}
261
c227b295 262IC_DIE: {
85aee309 263 throws_ok {
1bc006cf 264 DBICTest::Schema::Artist->inflate_column(charfield =>
c227b295 265 { inflate => sub {}, deflate => sub {} }
266 );
85aee309 267 } qr/InflateColumn can not be used on a column with a declared FilterColumn filter/, q(Can't inflate column after filter column);
c227b295 268
269 DBICTest::Schema::Artist->inflate_column(name =>
270 { inflate => sub {}, deflate => sub {} }
271 );
272
85aee309 273 throws_ok {
c227b295 274 DBICTest::Schema::Artist->filter_column(name => {
275 filter_to_storage => sub {},
276 filter_from_storage => sub {}
277 });
85aee309 278 } qr/FilterColumn can not be used on a column with a declared InflateColumn inflator/, q(Can't filter column after inflate column);
cde96798 279}
85439e0c 280
eec182b6 281# test when we do not set both filter_from_storage/filter_to_storage
1bc006cf 282DBICTest::Schema::Artist->filter_column(charfield => {
eec182b6 283 filter_to_storage => sub { $to_storage_ran++; $_[1] },
284});
cc8ffd7b 285Class::C3->reinitialize() if DBIx::Class::_ENV_::OLD_MRO;
eec182b6 286
287ASYMMETRIC_TO_TEST: {
288 # initialise value
1bc006cf 289 $artist->charfield(20);
eec182b6 290 $artist->update;
291
292 my $expected_from = $from_storage_ran;
293 my $expected_to = $to_storage_ran;
294
1bc006cf 295 $artist->charfield(10);
296 ok ($artist->is_column_changed ('charfield'), 'Column marked as dirty on accessor-set value');
297 is ($artist->charfield, '10', 'Column set properly');
eec182b6 298 is $from_storage_ran, $expected_from, 'from did not run';
299 is $to_storage_ran, ++$expected_to, 'to did run';
300
301 $artist->discard_changes;
302
1bc006cf 303 is ($artist->charfield, '20', 'Column set properly');
eec182b6 304 is $from_storage_ran, $expected_from, 'from did not run';
305 is $to_storage_ran, $expected_to, 'to did not run';
306}
307
1bc006cf 308DBICTest::Schema::Artist->filter_column(charfield => {
eec182b6 309 filter_from_storage => sub { $from_storage_ran++; $_[1] },
310});
cc8ffd7b 311Class::C3->reinitialize() if DBIx::Class::_ENV_::OLD_MRO;
eec182b6 312
313ASYMMETRIC_FROM_TEST: {
314 # initialise value
1bc006cf 315 $artist->charfield(23);
eec182b6 316 $artist->update;
317
318 my $expected_from = $from_storage_ran;
319 my $expected_to = $to_storage_ran;
320
1bc006cf 321 $artist->charfield(13);
322 ok ($artist->is_column_changed ('charfield'), 'Column marked as dirty on accessor-set value');
323 is ($artist->charfield, '13', 'Column set properly');
eec182b6 324 is $from_storage_ran, $expected_from, 'from did not run';
325 is $to_storage_ran, $expected_to, 'to did not run';
326
327 $artist->discard_changes;
328
1bc006cf 329 is ($artist->charfield, '23', 'Column set properly');
eec182b6 330 is $from_storage_ran, ++$expected_from, 'from did run';
331 is $to_storage_ran, $expected_to, 'to did not run';
332}
333
1bc006cf 334throws_ok { DBICTest::Schema::Artist->filter_column( charfield => {} ) }
eec182b6 335 qr/\QAn invocation of filter_column() must specify either a filter_from_storage or filter_to_storage/,
336 'Correctly throws exception for empty attributes'
337;
338
7ed4b48f 339FC_ON_PK_TEST: {
2a787533 340 # there are cases in the wild that autovivify stuff deep in the
341 # colinfo guts. While this is insane, there is no alternative
342 # so at leats make sure it keeps working...
343
344 $schema->source('Artist')->column_info('artistid')->{_filter_info} ||= {};
345
346 for my $key ('', 'primary') {
347 lives_ok {
348 $schema->resultset('Artist')->find_or_create({ artistid => 42 }, { $key ? ( key => $key ) : () });
349 };
350 }
351
7ed4b48f 352
353 DBICTest::Schema::Artist->filter_column(artistid => {
354 filter_to_storage => sub { $_[1] * 100 },
355 filter_from_storage => sub { $_[1] - 100 },
356 });
357
358 for my $key ('', 'primary') {
359 throws_ok {
360 $schema->resultset('Artist')->find_or_create({ artistid => 42 }, { $key ? ( key => $key ) : () });
361 } qr/\QUnable to satisfy requested constraint 'primary', FilterColumn values not usable for column(s): 'artistid'/;
362 }
363}
364
cc2d2ead 365done_testing;