Bug 26635: Move expand syntax to x-koha-embed
[koha.git] / t / Koha / REST / Plugin / Query.t
1 #!/usr/bin/perl
2
3 # This file is part of Koha.
4 #
5 # Koha is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # Koha is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18 use Modern::Perl;
19
20 # Dummy app for testing the plugin
21 use Mojolicious::Lite;
22 use Try::Tiny;
23
24 use Koha::Cities;
25 use Koha::Holds;
26 use Koha::Biblios;
27 use Koha::Patron::Relationship;
28
29 app->log->level('error');
30
31 plugin 'Koha::REST::Plugin::Query';
32
33 get '/empty' => sub {
34     my $c = shift;
35     $c->render( json => undef, status => 200 );
36 };
37
38 get '/query' => sub {
39     my $c     = shift;
40     my ( $filtered_params, $reserved_params ) = $c->extract_reserved_params($c->req->params->to_hash);
41     $c->render(
42         json => {
43             filtered_params => $filtered_params,
44             reserved_params => $reserved_params
45         },
46         status => 200
47     );
48 };
49
50 get '/query_full/:id/:subid' => sub {
51     my $c     = shift;
52     my $params = $c->req->params->to_hash;
53     $params->{id} = $c->stash->{id};
54     $params->{subid} = $c->stash->{subid};
55     my ( $filtered_params, $reserved_params, $path_params ) = $c->extract_reserved_params($params);
56     $c->render(
57         json => {
58             filtered_params => $filtered_params,
59             reserved_params => $reserved_params,
60             path_params => $path_params
61         },
62         status => 200
63     );
64 };
65
66 get '/dbic_merge_sorting' => sub {
67     my $c = shift;
68     my $attributes = { a => 'a', b => 'b' };
69     $attributes = $c->dbic_merge_sorting(
70         {
71             attributes => $attributes,
72             params     => { _match => 'exact', _order_by => [ 'uno', '-dos', '+tres', ' cuatro' ] }
73         }
74     );
75     $c->render( json => $attributes, status => 200 );
76 };
77
78 get '/dbic_merge_sorting_single' => sub {
79     my $c = shift;
80     my $attributes = { a => 'a', b => 'b' };
81     $attributes = $c->dbic_merge_sorting(
82         {
83             attributes => $attributes,
84             params     => { _match => 'exact', _order_by => '-uno' }
85         }
86     );
87     $c->render( json => $attributes, status => 200 );
88 };
89
90 get '/dbic_merge_sorting_result_set' => sub {
91     my $c = shift;
92     my $attributes = { a => 'a', b => 'b' };
93     my $result_set = Koha::Cities->new;
94     $attributes = $c->dbic_merge_sorting(
95         {
96             attributes => $attributes,
97             params     => { _match => 'exact', _order_by => [ 'name', '-postal_code', '+country', ' state' ] },
98             result_set => $result_set
99         }
100     );
101     $c->render( json => $attributes, status => 200 );
102 };
103
104 get '/dbic_merge_sorting_date' => sub {
105     my $c = shift;
106     my $attributes = { a => 'a', b => 'b' };
107     my $result_set = Koha::Holds->new;
108     $attributes = $c->dbic_merge_sorting(
109         {
110             attributes => $attributes,
111             params     => { _match => 'exact', _order_by => [ '-hold_date' ] },
112             result_set => $result_set
113         }
114     );
115     $c->render( json => $attributes, status => 200 );
116 };
117
118 get '/dbic_merge_prefetch' => sub {
119     my $c = shift;
120     my $attributes = {};
121     my $result_set = Koha::Holds->new;
122     $c->stash('koha.embed', {
123             "item" => {},
124             "biblio" => {
125                 children => {
126                     "orders" => {}
127                 }
128             }
129         });
130
131     $c->dbic_merge_prefetch({
132         attributes => $attributes,
133         result_set => $result_set
134     });
135
136     $c->render( json => $attributes, status => 200 );
137 };
138
139 get '/dbic_merge_prefetch_recursive' => sub {
140     my $c = shift;
141     my $attributes = {};
142     my $result_set = Koha::Patron::Relationship->new;
143     $c->stash('koha.embed', {
144       "guarantee" => {
145         "children" => {
146           "article_requests" => {},
147           "housebound_profile" => {
148             "children" => {
149               "housebound_visits" => {}
150             }
151           },
152           "housebound_role" => {}
153         }
154       }
155     });
156
157     $c->dbic_merge_prefetch({
158         attributes => $attributes,
159         result_set => $result_set
160     });
161
162     $c->render( json => $attributes, status => 200 );
163 };
164
165 get '/dbic_merge_prefetch_count' => sub {
166     my $c = shift;
167     my $attributes = {};
168     my $result_set = Koha::Patron::Relationship->new;
169     $c->stash('koha.embed', {
170             "guarantee_count" => {
171               "is_count" => 1
172             }
173         });
174
175     $c->dbic_merge_prefetch({
176         attributes => $attributes,
177         result_set => $result_set
178     });
179
180     $c->render( json => $attributes, status => 200 );
181 };
182
183 get '/merge_q_params' => sub {
184   my $c = shift;
185   my $filtered_params = {'biblio_id' => 1};
186   my $result_set = Koha::Biblios->new;
187   $filtered_params = $c->merge_q_params($filtered_params, $c->req->json->{q}, $result_set);
188
189   $c->render( json => $filtered_params, status => 200 );
190 };
191
192 get '/build_query' => sub {
193     my $c = shift;
194     my ( $filtered_params, $reserved_params ) =
195       $c->extract_reserved_params( $c->req->params->to_hash );
196     my $query;
197     try {
198         $query = $c->build_query_params( $filtered_params, $reserved_params );
199         $c->render( json => { query => $query }, status => 200 );
200     }
201     catch {
202         $c->render(
203             json => { exception_msg => $_->message, exception_type => ref($_) },
204             status => 400
205         );
206     };
207 };
208
209 get '/stash_embed' => sub {
210     my $c = shift;
211
212     $c->stash_embed();
213     my $embed     = $c->stash('koha.embed');
214     my $av_expand = $c->stash('koha.av_expand');
215
216     $c->render(
217         status => 200,
218         json   => {
219             av_expand => $av_expand,
220             embed     => $embed,
221         }
222     );
223 };
224
225 get '/stash_overrides' => sub {
226     my $c = shift;
227
228     $c->stash_overrides();
229     my $overrides = $c->stash('koha.overrides');
230
231     $c->render(
232         status => 200,
233         json   => $overrides
234     );
235 };
236
237 sub to_model {
238     my ($args) = @_;
239     $args->{three} = delete $args->{tres}
240         if exists $args->{tres};
241     return $args;
242 }
243
244 # The tests
245
246 use Test::More tests => 7;
247 use Test::Mojo;
248
249 subtest 'extract_reserved_params() tests' => sub {
250
251     plan tests => 9;
252
253     my $t = Test::Mojo->new;
254
255     $t->get_ok('/query?_page=2&_per_page=3&firstname=Manuel&surname=Cohen%20Arazi')->status_is(200)
256       ->json_is( '/filtered_params' =>
257           { firstname => 'Manuel', surname => 'Cohen Arazi' } )
258       ->json_is( '/reserved_params' => { _page => 2, _per_page => 3 } );
259
260     $t->get_ok('/query_full/with/path?_match=exact&_order_by=blah&_page=2&_per_page=3&firstname=Manuel&surname=Cohen%20Arazi')->status_is(200)
261       ->json_is(
262         '/filtered_params' => {
263             firstname => 'Manuel',
264             surname   => 'Cohen Arazi'
265         } )
266       ->json_is(
267         '/reserved_params' => {
268             _page     => 2,
269             _per_page => 3,
270             _match    => 'exact',
271             _order_by => 'blah'
272         } )
273       ->json_is(
274         '/path_params' => {
275             id => 'with',
276             subid => 'path'
277         } );
278
279 };
280
281 subtest 'dbic_merge_sorting() tests' => sub {
282
283     plan tests => 20;
284
285     my $t = Test::Mojo->new;
286
287     $t->get_ok('/dbic_merge_sorting')->status_is(200)
288       ->json_is( '/a' => 'a', 'Existing values are kept (a)' )
289       ->json_is( '/b' => 'b', 'Existing values are kept (b)' )->json_is(
290         '/order_by' => [
291             'uno',
292             { -desc => 'dos' },
293             { -asc  => 'tres' },
294             { -asc  => 'cuatro' }
295         ]
296       );
297
298     $t->get_ok('/dbic_merge_sorting_result_set')->status_is(200)
299       ->json_is( '/a' => 'a', 'Existing values are kept (a)' )
300       ->json_is( '/b' => 'b', 'Existing values are kept (b)' )->json_is(
301         '/order_by' => [
302             'city_name',
303             { -desc => 'city_zipcode' },
304             { -asc  => 'city_country' },
305             { -asc  => 'city_state' }
306         ]
307       );
308
309     $t->get_ok('/dbic_merge_sorting_date')->status_is(200)
310       ->json_is( '/a' => 'a', 'Existing values are kept (a)' )
311       ->json_is( '/b' => 'b', 'Existing values are kept (b)' )->json_is(
312         '/order_by' => [
313             { -desc => 'reservedate' }
314         ]
315       );
316
317     $t->get_ok('/dbic_merge_sorting_single')->status_is(200)
318       ->json_is( '/a' => 'a', 'Existing values are kept (a)' )
319       ->json_is( '/b' => 'b', 'Existing values are kept (b)' )->json_is(
320         '/order_by' => [
321             { '-desc' => 'uno' }
322         ]
323       );
324 };
325
326 subtest '/dbic_merge_prefetch' => sub {
327     plan tests => 10;
328
329     my $t = Test::Mojo->new;
330
331     $t->get_ok('/dbic_merge_prefetch')->status_is(200)
332       ->json_is( '/prefetch/0' => { 'biblio' => 'orders' } )
333       ->json_is( '/prefetch/1' => 'item' );
334
335     $t->get_ok('/dbic_merge_prefetch_recursive')->status_is(200)
336       ->json_is('/prefetch/0' => {
337         guarantee => [
338           'article_requests',
339           {housebound_profile => 'housebound_visits'},
340           'housebound_role'
341         ]
342       });
343
344     $t->get_ok('/dbic_merge_prefetch_count')->status_is(200)
345       ->json_is('/prefetch/0' => 'guarantee');
346 };
347
348 subtest '/merge_q_params' => sub {
349   plan tests => 3;
350   my $t = Test::Mojo->new;
351
352   $t->get_ok('/merge_q_params' => json => {
353     q => {
354       "-not_bool" => "suggestions.suggester.patron_card_lost",
355       "-or" => [
356         {
357           "creation_date" => {
358             "!=" => ["fff", "zzz", "xxx"]
359           }
360         },
361         { "suggestions.suggester.housebound_profile.frequency" => "123" },
362         {
363           "suggestions.suggester.library_id" => {"like" => "%CPL%"}
364         }
365       ]
366     }
367   })->status_is(200)
368     ->json_is( '/-and' => [
369         {
370           "-not_bool" => "suggester.lost",
371           "-or" => [
372             {
373               "datecreated" => {
374                 "!=" => [
375                   "fff",
376                   "zzz",
377                   "xxx"
378                 ]
379               }
380             },
381             {
382               "housebound_profile.frequency" => 123
383             },
384             {
385               "suggester.branchcode" => {
386                 "like" => "\%CPL\%"
387               }
388             }
389           ]
390         },
391         {
392           "biblio_id" => 1
393         }
394       ]);
395 };
396
397 subtest '_build_query_params_from_api' => sub {
398
399     plan tests => 16;
400
401     my $t = Test::Mojo->new;
402
403     # _match => contains
404     $t->get_ok('/build_query?_match=contains&title=Ender&author=Orson')
405       ->status_is(200)
406       ->json_is( '/query' =>
407           { author => { like => '%Orson%' }, title => { like => '%Ender%' } } );
408
409     # _match => starts_with
410     $t->get_ok('/build_query?_match=starts_with&title=Ender&author=Orson')
411       ->status_is(200)
412       ->json_is( '/query' =>
413           { author => { like => 'Orson%' }, title => { like => 'Ender%' } } );
414
415     # _match => ends_with
416     $t->get_ok('/build_query?_match=ends_with&title=Ender&author=Orson')
417       ->status_is(200)
418       ->json_is( '/query' =>
419           { author => { like => '%Orson' }, title => { like => '%Ender' } } );
420
421     # _match => exact
422     $t->get_ok('/build_query?_match=exact&title=Ender&author=Orson')
423       ->status_is(200)
424       ->json_is( '/query' => { author => 'Orson', title => 'Ender' } );
425
426     # _match => blah
427     $t->get_ok('/build_query?_match=blah&title=Ender&author=Orson')
428       ->status_is(400)
429       ->json_is( '/exception_msg'  => 'Invalid value for _match param (blah)' )
430       ->json_is( '/exception_type' => 'Koha::Exceptions::WrongParameter' );
431
432 };
433
434 subtest 'stash_embed() tests' => sub {
435
436     plan tests => 14;
437
438     my $t = Test::Mojo->new;
439
440     $t->get_ok( '/stash_embed' => { 'x-koha-embed' => 'checkouts,checkouts.item' } )
441       ->json_is( '/embed' => { checkouts => { children => { item => { } } } } );
442
443     $t->get_ok( '/stash_embed' => { 'x-koha-embed' => 'checkouts,checkouts.item,library' } )
444       ->json_is( '/embed' => { checkouts => { children => { item => {} } }, library => {} } );
445
446     $t->get_ok( '/stash_embed' => { 'x-koha-embed' => 'holds+count' } )
447       ->json_is( '/embed' => { holds_count => { is_count => 1 } } );
448
449     $t->get_ok( '/stash_embed' => { 'x-koha-embed' => 'checkouts,checkouts.item,patron' } )
450       ->json_is( '/embed' => {
451             checkouts => { children => { item => {} } },
452             patron    => {}
453         });
454
455     $t->get_ok( '/stash_embed' => { 'x-koha-embed' => 'checkouts,checkouts.item+av_expand,patron+av_expand' } )
456       ->json_is( '/embed' => {
457             checkouts => { children => { item => { av_expand => 1 } } },
458             patron    => { av_expand => 1 }
459         })
460       ->json_is( '/av_expand' => undef );
461
462     $t->get_ok( '/stash_embed' => { 'x-koha-embed' => 'checkouts+av_expand,checkouts.item,patron,+av_expand' } )
463       ->json_is( '/embed' => {
464             checkouts => { children => { item => { } }, av_expand => 1 },
465             patron    => { }
466         })
467       ->json_is( '/av_expand' => 1 );
468 };
469
470 subtest 'stash_overrides() tests' => sub {
471
472     plan tests => 6;
473
474     my $t = Test::Mojo->new;
475
476     $t->get_ok( '/stash_overrides' => { 'x-koha-override' => 'any,none,some_other,any,' } )
477       ->json_is( { 'any' => 1, 'none' => 1, 'some_other' => 1 } ); # empty string and duplicates are skipped
478
479     $t->get_ok( '/stash_overrides' => { 'x-koha-override' => '' } )
480       ->json_is( {} ); # empty string is skipped
481
482     $t->get_ok( '/stash_overrides' => { } )
483       ->json_is( {} ); # x-koha-ovverride not passed is skipped
484
485 };