|
Lines 24-29
use Try::Tiny;
Link Here
|
| 24 |
use Koha::Cities; |
24 |
use Koha::Cities; |
| 25 |
use Koha::Holds; |
25 |
use Koha::Holds; |
| 26 |
use Koha::Biblios; |
26 |
use Koha::Biblios; |
|
|
27 |
use Koha::Patrons; |
| 27 |
use Koha::Patron::Relationship; |
28 |
use Koha::Patron::Relationship; |
| 28 |
|
29 |
|
| 29 |
app->log->level('error'); |
30 |
app->log->level('error'); |
|
Lines 180-185
get '/dbic_merge_prefetch_count' => sub {
Link Here
|
| 180 |
$c->render( json => $attributes, status => 200 ); |
181 |
$c->render( json => $attributes, status => 200 ); |
| 181 |
}; |
182 |
}; |
| 182 |
|
183 |
|
|
|
184 |
get '/dbic_merge_prefetch_count_sorted' => sub { |
| 185 |
my $c = shift; |
| 186 |
my $attributes = { order_by => [ { '-desc' => 'me.guarantee_count' } ] }; |
| 187 |
my $result_set = Koha::Patron::Relationship->new; |
| 188 |
$c->stash( 'koha.embed', { "guarantee_count" => { "is_count" => 1 } } ); |
| 189 |
|
| 190 |
$c->dbic_merge_prefetch( |
| 191 |
{ |
| 192 |
attributes => $attributes, |
| 193 |
result_set => $result_set |
| 194 |
} |
| 195 |
); |
| 196 |
|
| 197 |
# Serialize: scalar refs become the string they point to |
| 198 |
my $order_by = $attributes->{order_by}; |
| 199 |
for my $atom (@$order_by) { |
| 200 |
if ( ref($atom) eq 'HASH' ) { |
| 201 |
for my $dir ( keys %$atom ) { |
| 202 |
$atom->{$dir} = ${ $atom->{$dir} } if ref( $atom->{$dir} ) eq 'SCALAR'; |
| 203 |
} |
| 204 |
} |
| 205 |
} |
| 206 |
|
| 207 |
$c->render( json => $attributes, status => 200 ); |
| 208 |
}; |
| 209 |
|
| 210 |
get '/dbic_merge_prefetch_count_unsortable' => sub { |
| 211 |
my $c = shift; |
| 212 |
my $attributes = { order_by => [ { '-desc' => 'me.checkouts_count' } ] }; |
| 213 |
my $result_set = Koha::Patrons->new; |
| 214 |
|
| 215 |
# checkouts is a Koha-only method, not a DBIC relationship |
| 216 |
$c->stash( 'koha.embed', { "checkouts_count" => { "is_count" => 1 } } ); |
| 217 |
|
| 218 |
try { |
| 219 |
$c->dbic_merge_prefetch( |
| 220 |
{ |
| 221 |
attributes => $attributes, |
| 222 |
result_set => $result_set |
| 223 |
} |
| 224 |
); |
| 225 |
$c->render( json => { error => 'no exception thrown' }, status => 500 ); |
| 226 |
} catch { |
| 227 |
if ( ref($_) eq 'Koha::Exceptions::BadParameter' ) { |
| 228 |
$c->render( json => { error => $_->message, error_code => 'bad_parameter' }, status => 400 ); |
| 229 |
} else { |
| 230 |
$c->render( json => { error => "$_" }, status => 500 ); |
| 231 |
} |
| 232 |
}; |
| 233 |
}; |
| 234 |
|
| 235 |
get '/dbic_merge_prefetch_count_unsortable_display' => sub { |
| 236 |
my $c = shift; |
| 237 |
my $attributes = {}; |
| 238 |
my $result_set = Koha::Patrons->new; |
| 239 |
|
| 240 |
# checkouts is a Koha-only method — no order_by, so no error |
| 241 |
$c->stash( 'koha.embed', { "checkouts_count" => { "is_count" => 1 } } ); |
| 242 |
|
| 243 |
$c->dbic_merge_prefetch( |
| 244 |
{ |
| 245 |
attributes => $attributes, |
| 246 |
result_set => $result_set |
| 247 |
} |
| 248 |
); |
| 249 |
|
| 250 |
$c->render( json => $attributes, status => 200 ); |
| 251 |
}; |
| 252 |
|
| 253 |
get '/dbic_merge_prefetch_nested_count' => sub { |
| 254 |
my $c = shift; |
| 255 |
my $attributes = { order_by => [ { '-asc' => 'guarantee.article_requests_count' } ] }; |
| 256 |
my $result_set = Koha::Patron::Relationship->new; |
| 257 |
$c->stash( |
| 258 |
'koha.embed', |
| 259 |
{ "guarantee" => { "children" => { "article_requests_count" => { "is_count" => 1 } } } } |
| 260 |
); |
| 261 |
|
| 262 |
$c->dbic_merge_prefetch( |
| 263 |
{ |
| 264 |
attributes => $attributes, |
| 265 |
result_set => $result_set |
| 266 |
} |
| 267 |
); |
| 268 |
|
| 269 |
# Serialize scalar refs |
| 270 |
my $order_by = $attributes->{order_by}; |
| 271 |
for my $atom (@$order_by) { |
| 272 |
if ( ref($atom) eq 'HASH' ) { |
| 273 |
for my $dir ( keys %$atom ) { |
| 274 |
$atom->{$dir} = ${ $atom->{$dir} } if ref( $atom->{$dir} ) eq 'SCALAR'; |
| 275 |
} |
| 276 |
} |
| 277 |
} |
| 278 |
|
| 279 |
$c->render( json => $attributes, status => 200 ); |
| 280 |
}; |
| 281 |
|
| 282 |
get '/dbic_merge_prefetch_nested_count_unsortable' => sub { |
| 283 |
my $c = shift; |
| 284 |
my $attributes = { order_by => [ { '-desc' => 'guarantee.checkouts_count' } ] }; |
| 285 |
my $result_set = Koha::Patron::Relationship->new; |
| 286 |
|
| 287 |
# checkouts is NOT in Patron's prefetch_whitelist |
| 288 |
$c->stash( |
| 289 |
'koha.embed', |
| 290 |
{ "guarantee" => { "children" => { "checkouts_count" => { "is_count" => 1 } } } } |
| 291 |
); |
| 292 |
|
| 293 |
try { |
| 294 |
$c->dbic_merge_prefetch( |
| 295 |
{ |
| 296 |
attributes => $attributes, |
| 297 |
result_set => $result_set |
| 298 |
} |
| 299 |
); |
| 300 |
$c->render( json => { error => 'no exception thrown' }, status => 500 ); |
| 301 |
} catch { |
| 302 |
if ( ref($_) eq 'Koha::Exceptions::BadParameter' ) { |
| 303 |
$c->render( json => { error => $_->message, error_code => 'bad_parameter' }, status => 400 ); |
| 304 |
} else { |
| 305 |
$c->render( json => { error => "$_" }, status => 500 ); |
| 306 |
} |
| 307 |
}; |
| 308 |
}; |
| 309 |
|
| 183 |
get '/merge_q_params' => sub { |
310 |
get '/merge_q_params' => sub { |
| 184 |
my $c = shift; |
311 |
my $c = shift; |
| 185 |
my $filtered_params = { 'biblio_id' => 1 }; |
312 |
my $filtered_params = { 'biblio_id' => 1 }; |
|
Lines 466-472
subtest 'dbic_merge_sorting() tests' => sub {
Link Here
|
| 466 |
}; |
593 |
}; |
| 467 |
|
594 |
|
| 468 |
subtest '/dbic_merge_prefetch' => sub { |
595 |
subtest '/dbic_merge_prefetch' => sub { |
| 469 |
plan tests => 10; |
596 |
plan tests => 32; |
| 470 |
|
597 |
|
| 471 |
my $t = Test::Mojo->new; |
598 |
my $t = Test::Mojo->new; |
| 472 |
|
599 |
|
|
Lines 485-491
subtest '/dbic_merge_prefetch' => sub {
Link Here
|
| 485 |
} |
612 |
} |
| 486 |
); |
613 |
); |
| 487 |
|
614 |
|
| 488 |
$t->get_ok('/dbic_merge_prefetch_count')->status_is(200)->json_is( '/prefetch/0' => 'guarantee' ); |
615 |
# Top-level +count: produces +select/+as, no prefetch |
|
|
616 |
$t->get_ok('/dbic_merge_prefetch_count') |
| 617 |
->status_is(200) |
| 618 |
->json_is( '/+as/0' => 'guarantee_count' ) |
| 619 |
->json_hasnt('/prefetch'); |
| 620 |
|
| 621 |
# Top-level +count sorted: order_by gets the subquery substituted |
| 622 |
$t->get_ok('/dbic_merge_prefetch_count_sorted') |
| 623 |
->status_is(200) |
| 624 |
->json_like( '/order_by/0/-desc' => qr/SELECT COUNT\(\*\) FROM borrowers/ ) |
| 625 |
->json_is( '/+as/0' => 'guarantee_count' ); |
| 626 |
|
| 627 |
# Top-level unsortable +count with order_by: throws BadParameter (400) |
| 628 |
$t->get_ok('/dbic_merge_prefetch_count_unsortable') |
| 629 |
->status_is(400) |
| 630 |
->json_is( '/error_code' => 'bad_parameter' ) |
| 631 |
->json_like( '/error' => qr/Cannot sort on checkouts_count/ ); |
| 632 |
|
| 633 |
# Top-level unsortable +count without order_by: no error (display-only fallback) |
| 634 |
$t->get_ok('/dbic_merge_prefetch_count_unsortable_display') |
| 635 |
->status_is(200) |
| 636 |
->json_hasnt('/prefetch') |
| 637 |
->json_hasnt('/+select'); |
| 638 |
|
| 639 |
# Nested +count sorted: subquery uses parent alias, dotted +as key |
| 640 |
$t->get_ok('/dbic_merge_prefetch_nested_count') |
| 641 |
->status_is(200) |
| 642 |
->json_like( '/order_by/0/-asc' => qr/SELECT COUNT\(\*\) FROM article_requests/ ) |
| 643 |
->json_like( '/order_by/0/-asc' => qr/guarantee\.borrowernumber/ ) |
| 644 |
->json_is( '/+as/0' => 'guarantee.article_requests_count' ); |
| 645 |
|
| 646 |
# Nested unsortable +count with order_by: throws BadParameter (400) |
| 647 |
$t->get_ok('/dbic_merge_prefetch_nested_count_unsortable') |
| 648 |
->status_is(400) |
| 649 |
->json_is( '/error_code' => 'bad_parameter' ) |
| 650 |
->json_like( '/error' => qr/Cannot sort on guarantee\.checkouts_count/ ); |
| 489 |
}; |
651 |
}; |
| 490 |
|
652 |
|
| 491 |
subtest '/merge_q_params' => sub { |
653 |
subtest '/merge_q_params' => sub { |
| 492 |
- |
|
|