Do not skip running from_storage filter when a NULL is returned
[dbsrgits/DBIx-Class.git] / t / row / filter_column.t
CommitLineData
956f4141 1use strict;
2use warnings;
3
4use Test::More;
c227b295 5use Test::Exception;
956f4141 6use lib qw(t/lib);
7use DBICTest;
cc2d2ead 8
85439e0c 9my $from_storage_ran = 0;
10my $to_storage_ran = 0;
1bc006cf 11my $schema = DBICTest->init_schema( no_populate => 1 );
c227b295 12DBICTest::Schema::Artist->load_components(qw(FilterColumn InflateColumn));
1bc006cf 13DBICTest::Schema::Artist->filter_column(charfield => {
cfa1ab03 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 },
cc2d2ead 16});
cc8ffd7b 17Class::C3->reinitialize() if DBIx::Class::_ENV_::OLD_MRO;
cc2d2ead 18
1bc006cf 19my $artist = $schema->resultset('Artist')->create( { charfield => 20 } );
cc2d2ead 20
21# this should be using the cursor directly, no inflation/processing of any sort
1bc006cf 22my ($raw_db_charfield) = $schema->resultset('Artist')
cc2d2ead 23 ->search ($artist->ident_condition)
1bc006cf 24 ->get_column('charfield')
cc2d2ead 25 ->_resultset
26 ->cursor
27 ->next;
28
1bc006cf 29is ($raw_db_charfield, 10, 'INSERT: correctly unfiltered on insertion');
cc2d2ead 30
31for my $reloaded (0, 1) {
32 my $test = $reloaded ? 'reloaded' : 'stored';
33 $artist->discard_changes if $reloaded;
34
1bc006cf 35 is( $artist->charfield , 20, "got $test filtered charfield" );
cc2d2ead 36}
37
38$artist->update;
39$artist->discard_changes;
1bc006cf 40is( $artist->charfield , 20, "got filtered charfield" );
cc2d2ead 41
1bc006cf 42$artist->update ({ charfield => 40 });
43($raw_db_charfield) = $schema->resultset('Artist')
cc2d2ead 44 ->search ($artist->ident_condition)
1bc006cf 45 ->get_column('charfield')
cc2d2ead 46 ->_resultset
47 ->cursor
48 ->next;
1bc006cf 49is ($raw_db_charfield, 20, 'UPDATE: correctly unflitered on update');
cc2d2ead 50
51$artist->discard_changes;
1bc006cf 52$artist->charfield(40);
53ok( !$artist->is_column_changed('charfield'), 'column is not dirty after setting the same value' );
cc2d2ead 54
8cfbd51c 55MC: {
56 my $cd = $schema->resultset('CD')->create({
1bc006cf 57 artist => { charfield => 20 },
8cfbd51c 58 title => 'fun time city!',
59 year => 'forevertime',
60 });
1bc006cf 61 ($raw_db_charfield) = $schema->resultset('Artist')
0f914ece 62 ->search ($cd->artist->ident_condition)
1bc006cf 63 ->get_column('charfield')
0f914ece 64 ->_resultset
65 ->cursor
66 ->next;
67
1bc006cf 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';
8cfbd51c 70}
71
c227b295 72CACHE_TEST: {
73 my $expected_from = $from_storage_ran;
74 my $expected_to = $to_storage_ran;
75
76 # ensure we are creating a fresh obj
77 $artist = $schema->resultset('Artist')->single($artist->ident_condition);
78
79 is $from_storage_ran, $expected_from, 'from has not run yet';
80 is $to_storage_ran, $expected_to, 'to has not run yet';
81
1bc006cf 82 $artist->charfield;
c227b295 83 cmp_ok (
1bc006cf 84 $artist->get_filtered_column('charfield'),
c227b295 85 '!=',
1bc006cf 86 $artist->get_column('charfield'),
c227b295 87 'filter/unfilter differ'
88 );
89 is $from_storage_ran, ++$expected_from, 'from ran once, therefor caches';
90 is $to_storage_ran, $expected_to, 'to did not run';
91
1bc006cf 92 $artist->charfield(6);
c227b295 93 is $from_storage_ran, $expected_from, 'from did not run';
94 is $to_storage_ran, ++$expected_to, 'to ran once';
95
1bc006cf 96 ok ($artist->is_column_changed ('charfield'), 'Column marked as dirty');
c227b295 97
1bc006cf 98 $artist->charfield;
c227b295 99 is $from_storage_ran, $expected_from, 'from did not run';
100 is $to_storage_ran, $expected_to, 'to did not run';
101
102 $artist->update;
103
1bc006cf 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)');
c227b295 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';
109
1bc006cf 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');
c227b295 113 is $from_storage_ran, $expected_from, 'from did not run';
dc6dadae 114 is $to_storage_ran, ++$expected_to, 'to did run once (call in to set_column)';
c227b295 115
1bc006cf 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');
491c8ff9 119 is $from_storage_ran, ++$expected_from, 'from did not run';
c227b295 120 is $to_storage_ran, $expected_to, 'to did not run';
cfa1ab03 121
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';
125
126 $artist->discard_changes;
127 is ( $artist->get_column('charfield'), undef, 'Got back null' );
128 is ( $artist->charfield, undef, 'Got back null through filter' );
129
130 is $from_storage_ran, ++$expected_from, 'from did run';
131 is $to_storage_ran, $expected_to, 'to did not run';
132
c227b295 133}
85439e0c 134
dc6dadae 135# test in-memory operations
136for my $artist_maker (
1bc006cf 137 sub { $schema->resultset('Artist')->new({ charfield => 42 }) },
138 sub { my $art = $schema->resultset('Artist')->new({}); $art->charfield(42); $art },
dc6dadae 139) {
140
141 my $expected_from = $from_storage_ran;
142 my $expected_to = $to_storage_ran;
143
144 my $artist = $artist_maker->();
145
146 is $from_storage_ran, $expected_from, 'from has not run yet';
147 is $to_storage_ran, $expected_to, 'to has not run yet';
148
149 ok( ! $artist->has_column_loaded('artistid'), 'pk not loaded' );
1bc006cf 150 ok( $artist->has_column_loaded('charfield'), 'Filtered column marked as loaded under new' );
151 is( $artist->charfield, 42, 'Proper unfiltered value' );
152 is( $artist->get_column('charfield'), 21, 'Proper filtered value' );
dc6dadae 153}
154
a524980e 155# test literals
156for my $v ( \ '16', \[ '?', '16' ] ) {
1bc006cf 157 my $rs = $schema->resultset('Artist');
158 $rs->delete;
a524980e 159
1bc006cf 160 my $art = $rs->new({ charfield => 10 });
161 $art->charfield($v);
162
163 is_deeply( $art->charfield, $v);
164 is_deeply( $art->get_filtered_column("charfield"), $v);
165 is_deeply( $art->get_column("charfield"), $v);
a524980e 166
167 $art->insert;
168 $art->discard_changes;
169
1bc006cf 170 is ($art->get_column("charfield"), 16, "Literal inserted into database properly");
171 is ($art->charfield, 32, "filtering still works");
a524980e 172
1bc006cf 173 $art->update({ charfield => $v });
a524980e 174
1bc006cf 175 is_deeply( $art->charfield, $v);
176 is_deeply( $art->get_filtered_column("charfield"), $v);
177 is_deeply( $art->get_column("charfield"), $v);
a524980e 178
179 $art->discard_changes;
180
1bc006cf 181 is ($art->get_column("charfield"), 16, "Literal inserted into database properly");
182 is ($art->charfield, 32, "filtering still works");
a524980e 183}
184
c227b295 185IC_DIE: {
85aee309 186 throws_ok {
1bc006cf 187 DBICTest::Schema::Artist->inflate_column(charfield =>
c227b295 188 { inflate => sub {}, deflate => sub {} }
189 );
85aee309 190 } qr/InflateColumn can not be used on a column with a declared FilterColumn filter/, q(Can't inflate column after filter column);
c227b295 191
192 DBICTest::Schema::Artist->inflate_column(name =>
193 { inflate => sub {}, deflate => sub {} }
194 );
195
85aee309 196 throws_ok {
c227b295 197 DBICTest::Schema::Artist->filter_column(name => {
198 filter_to_storage => sub {},
199 filter_from_storage => sub {}
200 });
85aee309 201 } qr/FilterColumn can not be used on a column with a declared InflateColumn inflator/, q(Can't filter column after inflate column);
cde96798 202}
85439e0c 203
eec182b6 204# test when we do not set both filter_from_storage/filter_to_storage
1bc006cf 205DBICTest::Schema::Artist->filter_column(charfield => {
eec182b6 206 filter_to_storage => sub { $to_storage_ran++; $_[1] },
207});
cc8ffd7b 208Class::C3->reinitialize() if DBIx::Class::_ENV_::OLD_MRO;
eec182b6 209
210ASYMMETRIC_TO_TEST: {
211 # initialise value
1bc006cf 212 $artist->charfield(20);
eec182b6 213 $artist->update;
214
215 my $expected_from = $from_storage_ran;
216 my $expected_to = $to_storage_ran;
217
1bc006cf 218 $artist->charfield(10);
219 ok ($artist->is_column_changed ('charfield'), 'Column marked as dirty on accessor-set value');
220 is ($artist->charfield, '10', 'Column set properly');
eec182b6 221 is $from_storage_ran, $expected_from, 'from did not run';
222 is $to_storage_ran, ++$expected_to, 'to did run';
223
224 $artist->discard_changes;
225
1bc006cf 226 is ($artist->charfield, '20', 'Column set properly');
eec182b6 227 is $from_storage_ran, $expected_from, 'from did not run';
228 is $to_storage_ran, $expected_to, 'to did not run';
229}
230
1bc006cf 231DBICTest::Schema::Artist->filter_column(charfield => {
eec182b6 232 filter_from_storage => sub { $from_storage_ran++; $_[1] },
233});
cc8ffd7b 234Class::C3->reinitialize() if DBIx::Class::_ENV_::OLD_MRO;
eec182b6 235
236ASYMMETRIC_FROM_TEST: {
237 # initialise value
1bc006cf 238 $artist->charfield(23);
eec182b6 239 $artist->update;
240
241 my $expected_from = $from_storage_ran;
242 my $expected_to = $to_storage_ran;
243
1bc006cf 244 $artist->charfield(13);
245 ok ($artist->is_column_changed ('charfield'), 'Column marked as dirty on accessor-set value');
246 is ($artist->charfield, '13', 'Column set properly');
eec182b6 247 is $from_storage_ran, $expected_from, 'from did not run';
248 is $to_storage_ran, $expected_to, 'to did not run';
249
250 $artist->discard_changes;
251
1bc006cf 252 is ($artist->charfield, '23', 'Column set properly');
eec182b6 253 is $from_storage_ran, ++$expected_from, 'from did run';
254 is $to_storage_ran, $expected_to, 'to did not run';
255}
256
1bc006cf 257throws_ok { DBICTest::Schema::Artist->filter_column( charfield => {} ) }
eec182b6 258 qr/\QAn invocation of filter_column() must specify either a filter_from_storage or filter_to_storage/,
259 'Correctly throws exception for empty attributes'
260;
261
cc2d2ead 262done_testing;