1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
|
use strict;
use warnings;
use Test::More;
use Test::Exception;
use Test::Warn;
use lib qw(t/lib);
use DBICTest ':DiffSQL';
my $schema = DBICTest->init_schema();
$schema->resultset('Artist')->delete;
$schema->resultset('CD')->delete;
my $artist = $schema->resultset("Artist")->create({ artistid => 21, name => 'Michael Jackson', rank => 20 });
my $artist2 = $schema->resultset("Artist")->create({ artistid => 22, name => 'Chico Buarque', rank => 1 }) ;
my $artist3 = $schema->resultset("Artist")->create({ artistid => 23, name => 'Ziraldo', rank => 1 });
my $artist4 = $schema->resultset("Artist")->create({ artistid => 24, name => 'Paulo Caruso', rank => 20 });
my @artworks;
foreach my $year (1975..1985) {
my $cd = $artist->create_related('cds', { year => $year, title => 'Compilation from ' . $year });
push @artworks, $cd->create_related('artwork', {});
}
foreach my $year (1975..1995) {
my $cd = $artist2->create_related('cds', { year => $year, title => 'Compilation from ' . $year });
push @artworks, $cd->create_related('artwork', {});
}
foreach my $artwork (@artworks) {
$artwork->create_related('artwork_to_artist', { artist => $_ }) for ($artist3, $artist4);
}
my $cds_80s_rs = $artist->cds_80s;
is_same_sql_bind(
$cds_80s_rs->as_query,
'(
SELECT me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track
FROM cd me
WHERE ( ( me.artist = ? AND ( me.year < ? AND me.year > ? ) ) )
)',
[
[
{}
=> 21
],
[
{ sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'me.year' }
=> 1990
],
[
{ sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'me.year' }
=> 1979
],
],
);
my @cds_80s = $cds_80s_rs->all;
is(@cds_80s, 6, '6 80s cds found (1980 - 1985)');
map { ok($_->year < 1990 && $_->year > 1979) } @cds_80s;
my $cds_90s_rs = $artist2->cds_90s;
is_same_sql_bind(
$cds_90s_rs->as_query,
'(
SELECT me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track
FROM artist artist__row
JOIN cd me
ON ( me.artist = artist__row.artistid AND ( me.year < ? AND me.year > ? ) )
WHERE ( artist__row.artistid = ? )
)',
[
[
{ sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'me.year' }
=> 2000
],
[
{ sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'me.year' }
=> 1989
],
[ { sqlt_datatype => 'integer', dbic_colname => 'artist__row.artistid' }
=> 22
],
]
);
# re-test with ::-containing moniker name
# (we don't have any currently, so fudge it with lots of local() )
{
local $schema->source('Artist')->{source_name} = 'Ar::Tist';
local $artist2->{related_resultsets};
is_same_sql_bind(
$artist2->cds_90s->as_query,
'(
SELECT me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track
FROM artist ar_tist__row
JOIN cd me
ON ( me.artist = ar_tist__row.artistid AND ( me.year < ? AND me.year > ? ) )
WHERE ( ar_tist__row.artistid = ? )
)',
[
[
{ sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'me.year' }
=> 2000
],
[
{ sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'me.year' }
=> 1989
],
[ { sqlt_datatype => 'integer', dbic_colname => 'ar_tist__row.artistid' }
=> 22
],
]
);
}
my @cds_90s = $cds_90s_rs->all;
is(@cds_90s, 6, '6 90s cds found (1990 - 1995) even with non-optimized search');
map { ok($_->year < 2000 && $_->year > 1989) } @cds_90s;
lives_ok {
my @cds_90s_95 = $artist2->cds_90s->search({ 'me.year' => 1995 });
is(@cds_90s_95, 1, '1 90s (95) cds found even with non-optimized search');
map { ok($_->year == 1995) } @cds_90s_95;
} 'should preserve chain-head "me" alias (API-consistency)';
# search for all artists prefetching published cds in the 80s...
my @all_artists_with_80_cds = $schema->resultset("Artist")->search
({ 'cds_80s.cdid' => { '!=' => undef } }, { join => 'cds_80s', distinct => 1 });
is_deeply(
[ sort ( map { $_->year } map { $_->cds_80s->all } @all_artists_with_80_cds ) ],
[ sort (1980..1989, 1980..1985) ],
'16 correct cds found'
);
lives_ok {
my @all_artists_with_80_cds_pref = $schema->resultset("Artist")->search
({ 'cds_80s.cdid' => { '!=' => undef } }, { prefetch => 'cds_80s' });
is_deeply(
[ sort ( map { $_->year } map { $_->cds_80s->all } @all_artists_with_80_cds_pref ) ],
[ sort (1980..1989, 1980..1985) ],
'16 correct cds found'
);
} 'prefetchy-fetchy-fetch';
# create_related a plain cd via the equoivalent coderef cond, with no extra conditions
lives_ok {
$artist->create_related('cds_cref_cond', { title => 'related creation via coderef cond', year => '2010' } );
} 'created_related with simple condition works';
# try to create_related a 80s cd
throws_ok {
$artist->create_related('cds_80s', { title => 'related creation 1' });
} qr/\QUnable to complete value inferrence - custom relationship 'cds_80s' on source 'Artist' returns conditions instead of values for column(s): 'year'/,
'Create failed - complex cond';
# now supply an explicit arg overwriting the ambiguous cond
my $cd_2020 = $artist->create_related('cds_80s', { title => 'related creation 2', year => '2020' });
my $id_2020 = $cd_2020->id;
is(
$schema->resultset('CD')->find($id_2020)->title,
'related creation 2',
'2020 CD created correctly'
);
# try a default year from a specific rel
my $id_1984 = $artist->create_related('cds_84', { title => 'related creation 3' })->id;
is(
$schema->resultset('CD')->find($id_1984)->title,
'related creation 3',
'1984 CD created correctly'
);
# try a specific everything via a non-simplified rel
throws_ok {
$artist->create_related('cds_90s', { title => 'related_creation 4', year => '2038' });
} qr/\QRelationship 'cds_90s' on source 'Artist' does not resolve to a join-free condition fragment/,
'Create failed - non-simplified rel';
# Do a self-join last-entry search
my @last_tracks;
for my $cd ($schema->resultset('CD')->search ({}, { order_by => 'cdid'})->all) {
push @last_tracks, $cd->tracks
->search ({}, { order_by => { -desc => 'position'} })
->next || ();
}
my $last_tracks_rs = $schema->resultset('Track')->search (
{'next_tracks.trackid' => undef},
{ join => 'next_tracks', order_by => 'me.cd' },
);
is_deeply (
[$last_tracks_rs->get_column ('trackid')->all],
[ map { $_->trackid } @last_tracks ],
'last group-entry via self-join works',
);
is_deeply (
[map { $_->last_track->id } grep { $_->last_track } $schema->resultset('CD')->search ({}, { order_by => 'cdid', prefetch => 'last_track'})->all],
[ map { $_->trackid } @last_tracks ],
'last_track via insane subquery condition works',
);
is_deeply (
[map { $_->last_track->id } grep { $_->last_track } $schema->resultset('CD')->search ({}, { order_by => 'cdid'})->all],
[ map { $_->trackid } @last_tracks ],
'last_track via insane subquery condition works, even without prefetch',
);
my $artwork = $schema->resultset('Artwork')->search({},{ order_by => 'cd_id' })->first;
my @artists = $artwork->artists->all;
is(scalar @artists, 2, 'the two artists are associated');
my @artwork_artists = $artwork->artwork_to_artist->all;
foreach (@artwork_artists) {
lives_ok {
my $artista = $_->artist;
my $artistb = $_->artist_test_m2m;
ok($artista->rank < 10 ? $artistb : 1, 'belongs_to with custom rel works.');
my $artistc = $_->artist_test_m2m_noopt;
ok($artista->rank < 10 ? $artistc : 1, 'belongs_to with custom rel works even in non-simplified.');
} 'belongs_to works with custom rels';
}
@artists = ();
lives_ok {
@artists = $artwork->artists_test_m2m2->all;
} 'manytomany with extended rels in the has many works';
is(scalar @artists, 2, 'two artists');
@artists = ();
lives_ok {
@artists = $artwork->artists_test_m2m->all;
} 'can fetch many to many with optimized version';
is(scalar @artists, 1, 'only one artist is associated');
@artists = ();
lives_ok {
@artists = $artwork->artists_test_m2m_noopt->all;
} 'can fetch many to many with non-optimized version';
is(scalar @artists, 1, 'only one artist is associated');
# Make a single for each last_track
my @singles = map {
$_->create_related('cd_single', {
title => $_->title . ' (the single)',
artist => $artist,
year => 1999,
}) } @last_tracks
;
# See if chaining works
is_deeply (
[ map { $_->title } $last_tracks_rs->search_related('cd_single')->all ],
[ map { $_->title } @singles ],
'Retrieved singles in proper order'
);
# See if prefetch works
is_deeply (
[ map { $_->cd_single->title } $last_tracks_rs->search({}, { prefetch => 'cd_single' })->all ],
[ map { $_->title } @singles ],
'Prefetched singles in proper order'
);
# test set_from_related/find_related with a belongs_to custom condition
my $preexisting_cd = $schema->resultset('CD')->find(1);
my $cd_single_track = $schema->resultset('CD')->create({
artist => $artist,
title => 'one one one',
year => 2001,
tracks => [{ title => 'uno uno uno' }]
});
my $single_track = $cd_single_track->tracks->next;
is(
$single_track->cd_cref_cond->title,
$cd_single_track->title,
'Got back the expected single-track cd title',
);
is_deeply
{ $schema->resultset('Track')->find({ cd_cref_cond => { cdid => $cd_single_track->id } })->get_columns },
{ $single_track->get_columns },
'Proper find with related via coderef cond',
;
warnings_exist {
is_same_sql_bind(
$single_track->deliberately_broken_all_cd_tracks->as_query,
'(
SELECT me.trackid, me.cd, me.position, me.title, me.last_updated_on, me.last_updated_at
FROM track track__row
JOIN track me
ON me.cd = ?
WHERE track__row.trackid = ?
)',
[
[{ dbic_colname => "me.cd", sqlt_datatype => "integer" }
=> "track__row.cd" ],
[{ dbic_colname => "track__row.trackid", sqlt_datatype => "integer" }
=> 19 ],
],
'Expected nonsensical JOIN cond',
),
} qr/\Qrelationship 'deliberately_broken_all_cd_tracks' on source 'Track' specifies equality of column 'cd' and the *VALUE* 'cd' (you did not use the { -ident => ... } operator)/,
'Warning on 99.9999% malformed custom cond'
;
$single_track->set_from_related( cd_cref_cond => undef );
ok $single_track->is_column_changed('cd');
is $single_track->get_column('cd'), undef, 'UNset from related via coderef cond';
is $single_track->cd, undef, 'UNset related object via coderef cond';
$single_track->discard_changes;
$single_track->set_from_related( cd_cref_cond => $preexisting_cd );
ok $single_track->is_column_changed('cd');
is $single_track->get_column('cd'), 1, 'set from related via coderef cond';
is_deeply
{ $single_track->cd->get_columns },
{ $preexisting_cd->get_columns },
'set from related via coderef cond inflates properly',
;
throws_ok {
local $schema->source('Track')->relationship_info('cd_cref_cond')->{cond} = sub { 1,2,3 };
$schema->resultset('Track')->find({ cd_cref_cond => {} });
} qr/\QA custom condition coderef can return at most 2 conditions, but relationship 'cd_cref_cond' on source 'Track' returned extra values: 3/;
done_testing;
|