3 # This file is part of Koha.
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.
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.
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>.
24 use t::lib::TestBuilder;
25 use Test::More tests => 7;
27 use List::Util qw( all );
30 use Koha::SearchEngine::Elasticsearch::QueryBuilder;
32 my $schema = Koha::Database->new->schema;
33 $schema->storage->txn_begin;
35 my $se = Test::MockModule->new( 'Koha::SearchEngine::Elasticsearch' );
36 $se->mock( 'get_elasticsearch_mappings', sub {
53 'subject-heading-thesaurus' => {
63 sortablenumber__sort => {
81 'match-heading-see-from' => {
86 $all_mappings{$self->index} = $mappings;
97 $self->sort_fields($sort_fields->{$self->index});
99 return $all_mappings{$self->index};
102 subtest 'build_authorities_query_compat() tests' => sub {
109 $qb = Koha::SearchEngine::Elasticsearch::QueryBuilder->new({ 'index' => 'authorities' }),
110 'Creating new query builder object for authorities'
113 my $koha_to_index_name = $Koha::SearchEngine::Elasticsearch::QueryBuilder::koha_to_index_name;
114 my $search_term = 'a';
115 foreach my $koha_name ( keys %{ $koha_to_index_name } ) {
116 my $query = $qb->build_authorities_query_compat( [ $koha_name ], undef, undef, ['contains'], [$search_term], 'AUTH_TYPE', 'asc' );
117 if ( $koha_name eq 'all' || $koha_name eq 'any' ) {
118 is( $query->{query}->{bool}->{must}[0]->{query_string}->{query},
121 is( $query->{query}->{bool}->{must}[0]->{query_string}->{query},
124 is( $query->{query}->{bool}->{must}[0]->{query_string}->{analyze_wildcard}, JSON::true, 'Set analyze_wildcard true' );
125 is( $query->{query}->{bool}->{must}[0]->{query_string}->{lenient}, JSON::true, 'Set lenient true' );
128 $search_term = 'Donald Duck';
129 foreach my $koha_name ( keys %{ $koha_to_index_name } ) {
130 my $query = $qb->build_authorities_query_compat( [ $koha_name ], undef, undef, ['contains'], [$search_term], 'AUTH_TYPE', 'asc' );
131 is( $query->{query}->{bool}->{must}[0]->{query_string}->{query}, "(Donald*) AND (Duck*)" );
132 if ( $koha_name eq 'all' || $koha_name eq 'any' ) {
133 isa_ok( $query->{query}->{bool}->{must}[0]->{query_string}->{fields}, 'ARRAY')
135 is( $query->{query}->{bool}->{must}[0]->{query_string}->{default_field}, $koha_to_index_name->{$koha_name} );
139 foreach my $koha_name ( keys %{ $koha_to_index_name } ) {
140 my $query = $qb->build_authorities_query_compat( [ $koha_name ], undef, undef, ['is'], [$search_term], 'AUTH_TYPE', 'asc' );
141 if ( $koha_name eq 'all' || $koha_name eq 'any' ) {
143 $query->{query}->{bool}->{must}[0]->{multi_match}->{query},
146 my $all_matches = all { /\.ci_raw$/ }
147 @{$query->{query}->{bool}->{must}[0]->{multi_match}->{fields}};
148 ok( $all_matches, 'Correct fields parameter for "is" query in "any" or "all"' );
151 $query->{query}->{bool}->{must}[0]->{term}->{$koha_to_index_name->{$koha_name} . ".ci_raw"},
157 foreach my $koha_name ( keys %{ $koha_to_index_name } ) {
158 my $query = $qb->build_authorities_query_compat( [ $koha_name ], undef, undef, ['start'], [$search_term], 'AUTH_TYPE', 'asc' );
159 if ( $koha_name eq 'all' || $koha_name eq 'any' ) {
160 my $all_matches = all { (%{$_->{prefix}})[0] =~ /\.ci_raw$/ && (%{$_->{prefix}})[1] eq "Donald Duck" }
161 @{$query->{query}->{bool}->{must}[0]->{bool}->{should}};
162 ok( $all_matches, "Correct multiple prefix query" );
164 is( $query->{query}->{bool}->{must}[0]->{prefix}->{$koha_to_index_name->{$koha_name} . ".ci_raw"}, "Donald Duck" );
169 my $query = $qb->build_authorities_query_compat( [ 'mainentry' ], undef, undef, ['start'], [$search_term], 'AUTH_TYPE', 'HeadingAsc' );
174 'heading__sort' => 'asc'
177 "ascending sort parameter properly formed"
179 $query = $qb->build_authorities_query_compat( [ 'mainentry' ], undef, undef, ['start'], [$search_term], 'AUTH_TYPE', 'HeadingDsc' );
184 'heading__sort' => 'desc'
187 "descending sort parameter properly formed"
191 $query = $qb->build_authorities_query_compat( [ 'mainentry' ], undef, undef, ['contains'], [$search_term], 'AUTH_TYPE', 'asc' );
193 $query->{query}->{bool}->{filter},
194 { term => { 'authtype.raw' => 'AUTH_TYPE' } },
195 "authorities type code is used as filter"
198 # Authorities marclist check
200 $query = $qb->build_authorities_query_compat( [ 'tomas','mainentry' ], undef, undef, ['contains'], [$search_term,$search_term], 'AUTH_TYPE', 'asc' )
202 qr/Unknown search field tomas/,
203 "Warning for unknown field in marclist";
205 $query->{query}->{bool}->{must}[0]->{query_string}->{default_field},
207 "If no mapping for marclist the index is passed through as defined"
210 $query->{query}->{bool}->{must}[1]->{query_string}{default_field},
212 "If mapping found for marclist the index is passed through converted"
217 subtest 'build_query tests' => sub {
223 $qb = Koha::SearchEngine::Elasticsearch::QueryBuilder->new({ 'index' => 'biblios' }),
224 'Creating new query builder object for biblios'
227 my @sort_by = 'title_asc';
228 my @sort_params = $qb->_convert_sort_fields(@sort_by);
230 $options{sort} = \@sort_params;
231 my $query = $qb->build_query('test', %options);
242 "sort parameter properly formed"
245 t::lib::Mocks::mock_preference('FacetMaxCount','37');
246 t::lib::Mocks::mock_preference('DisplayLibraryFacets','both');
247 $query = $qb->build_query('test', %options);
248 ok( defined $query->{aggregations}{ccode}{terms}{size},'we need to ask for a size or we get only 5 facet' );
249 is( $query->{aggregations}{ccode}{terms}{size}, 37,'we ask for the size as defined by the syspref FacetMaxCount');
250 is( $query->{aggregations}{homebranch}{terms}{size}, 37,'we ask for the size as defined by the syspref FacetMaxCount for homebranch');
251 is( $query->{aggregations}{holdingbranch}{terms}{size}, 37,'we ask for the size as defined by the syspref FacetMaxCount for holdingbranch');
253 t::lib::Mocks::mock_preference('DisplayLibraryFacets','both');
254 $query = $qb->build_query();
255 ok( defined $query->{aggregations}{homebranch},
256 'homebranch added to facets if DisplayLibraryFacets=both' );
257 ok( defined $query->{aggregations}{holdingbranch},
258 'holdingbranch added to facets if DisplayLibraryFacets=both' );
259 t::lib::Mocks::mock_preference('DisplayLibraryFacets','holding');
260 $query = $qb->build_query();
261 ok( !defined $query->{aggregations}{homebranch},
262 'homebranch not added to facets if DisplayLibraryFacets=holding' );
263 ok( defined $query->{aggregations}{holdingbranch},
264 'holdingbranch added to facets if DisplayLibraryFacets=holding' );
265 t::lib::Mocks::mock_preference('DisplayLibraryFacets','home');
266 $query = $qb->build_query();
267 ok( defined $query->{aggregations}{homebranch},
268 'homebranch added to facets if DisplayLibraryFacets=home' );
269 ok( !defined $query->{aggregations}{holdingbranch},
270 'holdingbranch not added to facets if DisplayLibraryFacets=home' );
272 t::lib::Mocks::mock_preference( 'QueryAutoTruncate', '' );
274 ( undef, $query ) = $qb->build_query_compat( undef, ['donald duck'] );
276 $query->{query}{query_string}{query},
278 "query not altered if QueryAutoTruncate disabled"
281 ( undef, $query ) = $qb->build_query_compat( undef, ['donald duck'], ['kw,phr'] );
283 $query->{query}{query_string}{query},
285 "keyword as phrase correctly quotes search term and strips index"
288 ( undef, $query ) = $qb->build_query_compat( undef, ['donald duck'], ['title'] );
290 $query->{query}{query_string}{query},
291 '(title:(donald duck))',
292 'multiple words in a query term are enclosed in parenthesis'
295 ( undef, $query ) = $qb->build_query_compat( ['AND'], ['donald duck', 'disney'], ['title', 'author'] );
297 $query->{query}{query_string}{query},
298 '(title:(donald duck)) AND (author:disney)',
299 'multiple query terms are enclosed in parenthesis while a single one is not'
302 my ($simple_query, $query_cgi, $query_desc);
303 ( undef, $query, $simple_query, $query_cgi, $query_desc ) = $qb->build_query_compat( undef, ['"donald duck"', 'walt disney'], ['ti', 'au'] );
304 is($query_cgi, 'idx=ti&q=%22donald%20duck%22&idx=au&q=walt%20disney', 'query cgi ok for multiterm query');
305 is($query_desc, '(title:("donald duck")) (author:(walt disney))', 'query desc ok for multiterm query');
307 ( undef, $query ) = $qb->build_query_compat( undef, ['2019'], ['yr,st-year'] );
309 $query->{query}{query_string}{query},
310 '(date-of-publication:2019)',
311 'Year in an st-year search is handled properly'
314 ( undef, $query ) = $qb->build_query_compat( undef, ['2018-2019'], ['yr,st-year'] );
316 $query->{query}{query_string}{query},
317 '(date-of-publication:[2018 TO 2019])',
318 'Year range in an st-year search is handled properly'
321 ( undef, $query ) = $qb->build_query_compat( undef, ['-2019'], ['yr,st-year'] );
323 $query->{query}{query_string}{query},
324 '(date-of-publication:[* TO 2019])',
325 'Open start year in year range of an st-year search is handled properly'
328 ( undef, $query ) = $qb->build_query_compat( undef, ['2019-'], ['yr,st-year'] );
330 $query->{query}{query_string}{query},
331 '(date-of-publication:[2019 TO *])',
332 'Open end year in year range of an st-year search is handled properly'
335 ( undef, $query ) = $qb->build_query_compat( undef, ['2019-'], ['yr,st-year'], ['yr,st-numeric=-2019'] );
337 $query->{query}{query_string}{query},
338 '(date-of-publication:[2019 TO *]) AND date-of-publication:[* TO 2019]',
339 'Open end year in year range of an st-year search is handled properly'
342 # Enable auto-truncation
343 t::lib::Mocks::mock_preference( 'QueryAutoTruncate', '1' );
345 ( undef, $query ) = $qb->build_query_compat( undef, ['donald duck'] );
347 $query->{query}{query_string}{query},
349 "simple query is auto truncated when QueryAutoTruncate enabled"
352 # Ensure reserved words are not truncated
353 ( undef, $query ) = $qb->build_query_compat( undef,
354 ['donald or duck and mickey not mouse'] );
356 $query->{query}{query_string}{query},
357 "(donald* or duck* and mickey* not mouse*)",
358 "reserved words are not affected by QueryAutoTruncate"
361 ( undef, $query ) = $qb->build_query_compat( undef, ['donald* duck*'] );
363 $query->{query}{query_string}{query},
365 "query with '*' is unaltered when QueryAutoTruncate is enabled"
368 ( undef, $query ) = $qb->build_query_compat( undef, ['donald duck and the mouse'] );
370 $query->{query}{query_string}{query},
371 "(donald* duck* and the* mouse*)",
372 "individual words are all truncated and stopwords ignored"
375 ( undef, $query ) = $qb->build_query_compat( undef, ['*'] );
377 $query->{query}{query_string}{query},
379 "query of just '*' is unaltered when QueryAutoTruncate is enabled"
382 ( undef, $query ) = $qb->build_query_compat( undef, ['"donald duck"'], undef, ['available'] );
384 $query->{query}{query_string}{query},
385 '("donald duck") AND onloan:false',
386 "query with quotes is unaltered when QueryAutoTruncate is enabled"
390 ( undef, $query ) = $qb->build_query_compat( undef, ['"donald duck" and "the mouse"'] );
392 $query->{query}{query_string}{query},
393 '("donald duck" and "the mouse")',
394 "all quoted strings are unaltered if more than one in query"
397 ( undef, $query ) = $qb->build_query_compat( undef, ['barcode:123456'] );
399 $query->{query}{query_string}{query},
401 "query of specific field is truncated"
404 ( undef, $query ) = $qb->build_query_compat( undef, ['Local-number:"123456"'] );
406 $query->{query}{query_string}{query},
407 '(local-number:"123456")',
408 "query of specific field including hyphen and quoted is not truncated, field name is converted to lower case"
411 ( undef, $query ) = $qb->build_query_compat( undef, ['Local-number:123456'] );
413 $query->{query}{query_string}{query},
414 '(local-number:123456*)',
415 "query of specific field including hyphen and not quoted is truncated, field name is converted to lower case"
418 ( undef, $query ) = $qb->build_query_compat( undef, ['Local-number.raw:123456'] );
420 $query->{query}{query_string}{query},
421 '(local-number.raw:123456*)',
422 "query of specific field including period and not quoted is truncated, field name is converted to lower case"
425 ( undef, $query ) = $qb->build_query_compat( undef, ['Local-number.raw:"123456"'] );
427 $query->{query}{query_string}{query},
428 '(local-number.raw:"123456")',
429 "query of specific field including period and quoted is not truncated, field name is converted to lower case"
432 ( undef, $query ) = $qb->build_query_compat( undef, ['J.R.R'] );
434 $query->{query}{query_string}{query},
436 "query including period is truncated but not split at periods"
439 ( undef, $query ) = $qb->build_query_compat( undef, ['title:"donald duck"'] );
441 $query->{query}{query_string}{query},
442 '(title:"donald duck")',
443 "query of specific field is not truncated when surrounded by quotes"
446 ( undef, $query ) = $qb->build_query_compat( undef, ['donald duck'], ['title'] );
448 $query->{query}{query_string}{query},
449 '(title:(donald* duck*))',
450 'words of a multi-word term are properly truncated'
453 ( undef, $query ) = $qb->build_query_compat( ['AND'], ['donald duck', 'disney'], ['title', 'author'] );
455 $query->{query}{query_string}{query},
456 '(title:(donald* duck*)) AND (author:disney*)',
457 'words of a multi-word term and single-word term are properly truncated'
460 ( undef, $query ) = $qb->build_query_compat( undef, ['title:"donald duck"'], undef, undef, undef, undef, undef, { suppress => 1 } );
462 $query->{query}{query_string}{query},
463 '(title:"donald duck") AND suppress:false',
464 "query of specific field is added AND suppress:false"
467 ( undef, $query, $simple_query, $query_cgi, $query_desc ) = $qb->build_query_compat( undef, ['title:"donald duck"'], undef, undef, undef, undef, undef, { suppress => 0 } );
469 $query->{query}{query_string}{query},
470 '(title:"donald duck")',
471 "query of specific field is not added AND suppress:0"
474 ( undef, $query ) = $qb->build_query_compat( ['AND'], ['title:"donald duck"'], undef, ['author:Dillinger Escaplan'] );
476 $query->{query}{query_string}{query},
477 '(title:"donald duck") AND author:("Dillinger Escaplan")',
478 "Simple query with limit term quoted in parentheses"
481 ( undef, $query ) = $qb->build_query_compat( ['AND'], ['title:"donald duck"'], undef, ['author:Dillinger Escaplan', 'itype:BOOK'] );
483 $query->{query}{query_string}{query},
484 '(title:"donald duck") AND (author:("Dillinger Escaplan")) AND (itype:("BOOK"))',
485 "Simple query with each limit's term quoted in parentheses"
487 is($query_cgi, 'idx=&q=title%3A%22donald%20duck%22', 'query cgi');
488 is($query_desc, 'title:"donald duck"', 'query desc ok');
490 ( undef, $query ) = $qb->build_query_compat( ['AND'], ['title:"donald duck"'], undef, ['author:Dillinger Escaplan', 'mc-itype,phr:BOOK', 'mc-itype,phr:CD'] );
492 $query->{query}{query_string}{query},
493 '(title:"donald duck") AND (author:("Dillinger Escaplan")) AND itype:(("BOOK") OR ("CD"))',
494 "Limits quoted correctly when passed as phrase"
498 ( undef, $query, $simple_query, $query_cgi, $query_desc ) = $qb->build_query_compat( undef, ['new'], ['au'], undef, undef, 1 );
500 $query->{query}{query_string}{query},
502 "scan query is properly formed"
505 $query->{aggregations}{'author'}{'terms'},
507 field => 'author__facet',
508 order => { '_key' => 'asc' },
509 include => '[nN][eE][wW].*'
511 "scan aggregation request is properly formed"
513 is($query_cgi, 'idx=au&q=new&scan=1', 'query cgi');
514 is($query_desc, 'new', 'query desc ok');
516 ( undef, $query, $simple_query, $query_cgi, $query_desc ) = $qb->build_query_compat( undef, ['new'], [], undef, undef, 1 );
518 $query->{query}{query_string}{query},
520 "scan query is properly formed"
523 $query->{aggregations}{'subject'}{'terms'},
525 field => 'subject__facet',
526 order => { '_key' => 'asc' },
527 include => '[nN][eE][wW].*'
529 "scan aggregation request is properly formed"
531 is($query_cgi, 'idx=&q=new&scan=1', 'query cgi');
532 is($query_desc, 'new', 'query desc ok');
534 my( $limit, $limit_cgi, $limit_desc );
535 ( undef, $query, $simple_query, $query_cgi, $query_desc, $limit, $limit_cgi, $limit_desc ) = $qb->build_query_compat( ['AND'], ['kw:""'], undef, ['author:Dillinger Escaplan', 'mc-itype,phr:BOOK', 'mc-itype,phr:CD'] );
536 is( $limit, '(author:("Dillinger Escaplan")) AND itype:(("BOOK") OR ("CD"))', "Limit formed correctly when no search terms");
537 is( $limit_cgi,'&limit=author%3ADillinger%20Escaplan&limit=mc-itype%2Cphr%3ABOOK&limit=mc-itype%2Cphr%3ACD', "Limit CGI formed correctly when no search terms");
538 is( $limit_desc,'(author:("Dillinger Escaplan")) AND itype:(("BOOK") OR ("CD"))',"Limit desc formed correctly when no search terms");
542 subtest 'build query from form subtests' => sub {
545 my $qb = Koha::SearchEngine::Elasticsearch::QueryBuilder->new({ 'index' => 'authorities' }),
546 #when searching for authorities from a record the form returns marclist with blanks for unentered terms
547 my @marclist = ('mainmainentry','mainentry','match', 'all');
548 my @values = ( undef, 'Hamilton', undef, undef);
549 my @operator = ( 'contains', 'contains', 'contains', 'contains');
551 my $query = $qb->build_authorities_query_compat( \@marclist, undef,
552 undef, \@operator , \@values, 'AUTH_TYPE', 'asc' );
553 is($query->{query}->{bool}->{must}[0]->{query_string}->{query}, "Hamilton*","Expected search is populated");
554 is( scalar @{ $query->{query}->{bool}->{must} }, 1,"Only defined search is populated");
556 @values[2] = 'Jefferson';
557 $query = $qb->build_authorities_query_compat( \@marclist, undef,
558 undef, \@operator , \@values, 'AUTH_TYPE', 'asc' );
559 is($query->{query}->{bool}->{must}[0]->{query_string}->{query}, "Hamilton*","First index searched as expected");
560 is($query->{query}->{bool}->{must}[1]->{query_string}->{query}, "Jefferson*","Second index searched when populated");
561 is( scalar @{ $query->{query}->{bool}->{must} }, 2,"Only defined searches are populated");
566 subtest 'build_query with weighted fields tests' => sub {
569 $se->mock( '_load_elasticsearch_mappings', sub {
579 marc_type => 'marc21',
583 label => 'headingmain',
589 marc_type => 'marc21',
601 marc_type => 'marc21',
610 marc_field => '952d',
611 marc_type => 'marc21',
614 marc_field => '9955',
615 marc_type => 'marc21',
626 marc_type => 'marc21'
635 marc_field => '600a',
636 marc_type => 'marc21'
643 my $qb = Koha::SearchEngine::Elasticsearch::QueryBuilder->new( { index => 'biblios' } );
644 Koha::SearchFields->search({})->delete;
645 Koha::SearchEngine::Elasticsearch->reset_elasticsearch_mappings();
648 $search_field = Koha::SearchFields->find({ name => 'title' });
649 $search_field->update({ weight => 25.0 });
650 $search_field = Koha::SearchFields->find({ name => 'subject' });
651 $search_field->update({ weight => 15.5 });
652 Koha::SearchEngine::Elasticsearch->clear_search_fields_cache();
654 my ( undef, $query ) = $qb->build_query_compat( undef, ['title:"donald duck"'], undef, undef,
655 undef, undef, undef, { weighted_fields => 1 });
657 my $fields = $query->{query}{query_string}{fields};
659 is(@{$fields}, 2, 'Search field with no searchable mappings has been excluded');
661 my @found = grep { $_ eq 'title^25.00' } @{$fields};
662 is(@found, 1, 'Search field title has correct weight');
664 @found = grep { $_ eq 'subject^15.50' } @{$fields};
665 is(@found, 1, 'Search field subject has correct weight');
667 ( undef, $query ) = $qb->build_query_compat( undef, ['title:"donald duck"'], undef, undef,
668 undef, undef, undef, { weighted_fields => 1, is_opac => 1 });
670 $fields = $query->{query}{query_string}{fields};
675 'Only OPAC search fields are used when opac search is performed'
678 $qb = Koha::SearchEngine::Elasticsearch::QueryBuilder->new( { index => 'authorities' } );
679 ( undef, $query ) = $qb->build_query_compat( undef, ['title:"donald duck"'], undef, undef,
680 undef, undef, undef, { weighted_fields => 1 });
681 $fields = $query->{query}{query_string}{fields};
682 is_deeply( [sort @$fields], ['heading','headingmain'],'Authorities fields retrieve for authorities index');
684 ( undef, $query ) = $qb->build_query_compat( undef, ['title:"donald duck"'], undef, undef,
685 undef, undef, undef, { weighted_fields => 1, is_opac => 1 });
686 $fields = $query->{query}{query_string}{fields};
687 is_deeply($fields,['headingmain'],'Only opac authorities fields retrieved for authorities index is is_opac');
691 subtest 'build_query_compat() SearchLimitLibrary tests' => sub {
695 $schema->storage->txn_begin;
697 my $builder = t::lib::TestBuilder->new;
699 my $branch_1 = $builder->build_object({ class => 'Koha::Libraries' });
700 my $branch_2 = $builder->build_object({ class => 'Koha::Libraries' });
701 my $group = $builder->build_object({ class => 'Koha::Library::Groups', value => {
702 ft_search_groups_opac => 1,
703 ft_search_groups_staff => 1,
708 my $group_1 = $builder->build_object({ class => 'Koha::Library::Groups', value => {
709 parent_id => $group->id,
710 branchcode => $branch_1->id
713 my $group_2 = $builder->build_object({ class => 'Koha::Library::Groups', value => {
714 parent_id => $group->id,
715 branchcode => $branch_2->id
718 my $groupid = $group->id;
719 my @branchcodes = sort { $a cmp $b } ( $branch_1->id, $branch_2->id );
722 my $query_builder = Koha::SearchEngine::Elasticsearch::QueryBuilder->new({index => $Koha::SearchEngine::BIBLIOS_INDEX});
723 t::lib::Mocks::mock_preference('SearchLimitLibrary', 'both');
724 my ( undef, undef, undef, undef, undef, $limit, $limit_cgi, $limit_desc, undef ) =
725 $query_builder->build_query_compat( undef, undef, undef, [ "branch:CPL" ], undef, undef, undef, undef );
726 is( $limit, '(homebranch: "CPL" OR holdingbranch: "CPL")', "Branch limit expanded to home/holding branch");
727 is( $limit_desc, '(homebranch: "CPL" OR holdingbranch: "CPL")', "Limit description correctly expanded");
728 is( $limit_cgi, '&limit=branch%3ACPL', "Limit cgi does not get expanded");
729 ( undef, undef, undef, undef, undef, $limit, $limit_cgi, $limit_desc, undef ) =
730 $query_builder->build_query_compat( undef, undef, undef, [ "multibranchlimit:$groupid" ], undef, undef, undef, undef );
731 is( $limit, "(homebranch: \"$branchcodes[0]\" OR homebranch: \"$branchcodes[1]\" OR holdingbranch: \"$branchcodes[0]\" OR holdingbranch: \"$branchcodes[1]\")", "Multibranch limit expanded to home/holding branches");
732 is( $limit_desc, "(homebranch: \"$branchcodes[0]\" OR homebranch: \"$branchcodes[1]\" OR holdingbranch: \"$branchcodes[0]\" OR holdingbranch: \"$branchcodes[1]\")", "Multibranch limit description correctly expanded");
733 is( $limit_cgi, "&limit=multibranchlimit%3A$groupid", "Multibranch limit cgi does not get expanded");
735 t::lib::Mocks::mock_preference('SearchLimitLibrary', 'homebranch');
736 ( undef, undef, undef, undef, undef, $limit, $limit_cgi, $limit_desc, undef ) =
737 $query_builder->build_query_compat( undef, undef, undef, [ "branch:CPL" ], undef, undef, undef, undef );
738 is( $limit, "(homebranch: \"CPL\")", "branch limit expanded to home branch");
739 is( $limit_desc, "(homebranch: \"CPL\")", "limit description correctly expanded");
740 is( $limit_cgi, "&limit=branch%3ACPL", "limit cgi does not get expanded");
741 ( undef, undef, undef, undef, undef, $limit, $limit_cgi, $limit_desc, undef ) =
742 $query_builder->build_query_compat( undef, undef, undef, [ "multibranchlimit:$groupid" ], undef, undef, undef, undef );
743 is( $limit, "(homebranch: \"$branchcodes[0]\" OR homebranch: \"$branchcodes[1]\")", "branch limit expanded to home branch");
744 is( $limit_desc, "(homebranch: \"$branchcodes[0]\" OR homebranch: \"$branchcodes[1]\")", "limit description correctly expanded");
745 is( $limit_cgi, "&limit=multibranchlimit%3A$groupid", "Limit cgi does not get expanded");
747 t::lib::Mocks::mock_preference('SearchLimitLibrary', 'holdingbranch');
748 ( undef, undef, undef, undef, undef, $limit, $limit_cgi, $limit_desc, undef ) =
749 $query_builder->build_query_compat( undef, undef, undef, [ "branch:CPL" ], undef, undef, undef, undef );
750 is( $limit, "(holdingbranch: \"CPL\")", "branch limit expanded to holding branch");
751 is( $limit_desc, "(holdingbranch: \"CPL\")", "Limit description correctly expanded");
752 is( $limit_cgi, "&limit=branch%3ACPL", "Limit cgi does not get expanded");
753 ( undef, undef, undef, undef, undef, $limit, $limit_cgi, $limit_desc, undef ) =
754 $query_builder->build_query_compat( undef, undef, undef, [ "multibranchlimit:$groupid" ], undef, undef, undef, undef );
755 is( $limit, "(holdingbranch: \"$branchcodes[0]\" OR holdingbranch: \"$branchcodes[1]\")", "branch limit expanded to holding branch");
756 is( $limit_desc, "(holdingbranch: \"$branchcodes[0]\" OR holdingbranch: \"$branchcodes[1]\")", "Limit description correctly expanded");
757 is( $limit_cgi, "&limit=multibranchlimit%3A$groupid", "Limit cgi does not get expanded");
761 subtest "_convert_sort_fields() tests" => sub {
767 $qb = Koha::SearchEngine::Elasticsearch::QueryBuilder->new({ 'index' => 'biblios' }),
768 'Creating new query builder object for biblios'
771 my @sort_by = $qb->_convert_sort_fields(qw( call_number_asc author_dsc ));
775 { field => 'cn-sort', direction => 'asc' },
776 { field => 'author', direction => 'desc' }
778 'sort fields should have been split correctly'
781 # We could expect this to pass, but direction is undef instead of 'desc'
782 @sort_by = $qb->_convert_sort_fields(qw( call_number_asc author_desc ));
786 { field => 'cn-sort', direction => 'asc' },
787 { field => 'author', direction => 'desc' }
789 'sort fields should have been split correctly'
793 subtest "_sort_field() tests" => sub {
799 $qb = Koha::SearchEngine::Elasticsearch::QueryBuilder->new({ 'index' => 'biblios' }),
800 'Creating new query builder object for biblios'
803 my $f = $qb->_sort_field('title');
807 'title sort mapped correctly'
810 $f = $qb->_sort_field('subject');
814 'subject sort mapped correctly'
817 $f = $qb->_sort_field('itemnumber');
821 'itemnumber sort mapped correctly'
824 $f = $qb->_sort_field('sortablenumber');
827 'sortablenumber__sort',
828 'sortablenumber sort mapped correctly'
832 $schema->storage->txn_rollback;