File: custom.t

package info (click to toggle)
libdbix-class-perl 0.082843-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 5,320 kB
  • sloc: perl: 27,215; sql: 322; sh: 29; makefile: 16
file content (344 lines) | stat: -rw-r--r-- 11,264 bytes parent folder | download | duplicates (5)
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;