From aa0792986dd9d61e8d059c24d7bc3dd25f34bbed Mon Sep 17 00:00:00 2001 From: Jane Sandberg Date: Fri, 20 May 2022 13:26:57 -0600 Subject: [PATCH] LP1968754: Better handling for blank and wildcard course searches Signed-off-by: Jane Sandberg --- .../perlmods/lib/OpenILS/WWW/EGCatLoader/Course.pm | 27 ++++--- Open-ILS/src/perlmods/t/26-course-opac-search.t | 83 ++++++++++++++++++++++ 2 files changed, 99 insertions(+), 11 deletions(-) create mode 100644 Open-ILS/src/perlmods/t/26-course-opac-search.t diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Course.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Course.pm index f0e8ab0423..866eb7e2c3 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Course.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Course.pm @@ -298,27 +298,32 @@ sub _create_where_clause { for my $query_obj (@{$queries}) { my $type = $query_obj->{'qtype'}; my $query = $query_obj->{'value'}; - $query =~ s/\*//g; + + # Remove punctuation except for the the * wildcard + $query =~ s/\w\s\*//; + + # Do we have a blank query, or just wildcards and/or spaces? + next if $query =~ /^[\s\*]*$/; my $bool = $query_obj->{'bool'}; my $contains = $query_obj->{'contains'}; my $operator = ($contains eq 'nocontains') ? '!~*' : '~*'; my $search_query; if ($type eq 'instructor') { + $query =~ s/\*$/:*/; # postgres prefix matching syntax ends with :* (e.g. string:*, not string*) my $in = ($contains eq 'nocontains') ? "not in" : "in"; $search_query = {'id' => {$in => { - 'from' => 'acmcu', + 'from' => {'acmcu' => 'acmr'}, 'select' => {'acmcu' => ['course']}, - 'where' => {'usr' => {'in' => { - 'from' => 'au', - 'select' => {'au' => ['id']}, - 'where' => { - 'name_kw_tsvector' => { - '@@' => {'value' => [ 'plainto_tsquery', $query ] } - } - } - }}} + 'where' => [ + {"+acmr"=>"is_public"}, + {"usr"=>{"in"=> + {"select"=>{"au"=>["id"]}, + "where"=>{"name_kw_tsvector"=> + {"@@"=>{"value"=>["to_tsquery",$query]}}}, + "from"=>"au"}}}] }}}; } else { + $query =~ s/\*/.*/; $search_query = ($contains eq 'nocontains') ? {'+acmc' => { $type => {$operator => $query}}} : {$type => {$operator => $query}}; diff --git a/Open-ILS/src/perlmods/t/26-course-opac-search.t b/Open-ILS/src/perlmods/t/26-course-opac-search.t new file mode 100644 index 0000000000..9d2da1518d --- /dev/null +++ b/Open-ILS/src/perlmods/t/26-course-opac-search.t @@ -0,0 +1,83 @@ +#!perl +use strict; use warnings; +use Test::More tests => 9; +use OpenILS::WWW::EGCatLoader; + +use_ok('OpenILS::WWW::EGCatLoader'); +can_ok( 'OpenILS::WWW::EGCatLoader', '_create_where_clause' ); + +my $orgs = (1..9); + +my @course_name_query = {'qtype' => 'name','contains' => 'contains','bool' => 'and','value' => 'zebra'}; +my $course_name_expected = {"-and" => [ + {"owning_lib"=> $orgs}, + {"-not"=>{"+acmc"=>"is_archived"}}, + {"name"=>{"~*"=>"zebra"}}]}; +is_query_parsed_correctly ( \@course_name_query, $course_name_expected, 'Create a valid course name search json query' ); + +my @course_name_wildcard_query = {'qtype' => 'name','contains' => 'contains','bool' => 'and','value' => '*ebra'}; +my $course_name_wildcard_expected = {"-and" => [ + {"owning_lib"=> $orgs}, + {"-not"=>{"+acmc"=>"is_archived"}}, + {"name"=>{"~*"=>".*ebra"}}]}; +is_query_parsed_correctly ( \@course_name_wildcard_query, $course_name_wildcard_expected, 'Create a valid course name search json query' ); + +my @empty_number_query = {'qtype' => 'course_number','contains' => 'contains','bool' => 'and','value' => ''}; +my $blank_query_expected = {"-and" => [ + {"owning_lib"=> $orgs}, + {"-not"=>{"+acmc"=>"is_archived"}}]}; +is_query_parsed_correctly ( \@empty_number_query, $blank_query_expected, + 'Create a valid course number search json query for blank search' ); + +my @instructor_wildcard_query = {'qtype' => 'instructor','contains' => 'contains','bool' => 'and','value' => '*'}; +is_query_parsed_correctly( \@instructor_wildcard_query, $blank_query_expected, + 'Create a valid instructor search json query for wildcard search' ); + +my @instructor_blank_query = {'qtype' => 'instructor','contains' => 'contains','bool' => 'and','value' => ''}; +is_query_parsed_correctly( \@instructor_blank_query, $blank_query_expected, + 'Create a valid instructor search json query for blank search' ); + +my @instructor_query = {'qtype' => 'instructor','contains' => 'contains','bool' => 'and','value' => 'leonard'}; +my $instructor_query_expected = {"-and" => [ + {"owning_lib"=> $orgs}, + {"-not"=>{"+acmc"=>"is_archived"}}, + {"id"=>{"in"=>{ + "where"=>[ + {"+acmr"=>"is_public"}, + {"usr"=>{"in"=> + {"select"=>{"au"=>["id"]}, + "where"=>{"name_kw_tsvector"=> + {"@@"=>{"value"=>["to_tsquery","leonard"]}}}, + "from"=>"au"}}}], + "select"=>{"acmcu"=>["course"]}, + "from"=>{"acmcu" => "acmr"}}}}]}; +is_query_parsed_correctly( \@instructor_query, $instructor_query_expected, + 'Create a valid instructor search json query'); + +my @instructor_prefix_wildcard_query = {'qtype' => 'instructor','contains' => 'contains','bool' => 'and','value' => 'd*'}; +my $instructor_prefix_wildcard_query_expected = {"-and" => [ + {"owning_lib"=> $orgs}, + {"-not"=>{"+acmc"=>"is_archived"}}, + {"id"=>{"in"=>{ + "where"=>[ + {"+acmr"=>"is_public"}, + {"usr"=>{"in"=> + {"select"=>{"au"=>["id"]}, + "where"=>{"name_kw_tsvector"=> + {"@@"=>{"value"=>["to_tsquery","d:*"]}}}, + "from"=>"au"}}}], + "select"=>{"acmcu"=>["course"]}, + "from"=>{"acmcu" => "acmr"}}}}]}; +is_query_parsed_correctly( \@instructor_prefix_wildcard_query, $instructor_prefix_wildcard_query_expected, + 'Create a valid instructor prefix tsquery json query'); + + + +sub is_query_parsed_correctly { + my ($query_hash, $expected, $description) = @_; + my $ctx = {'processed_search_query' => '*'}; + my $query = OpenILS::WWW::EGCatLoader::_create_where_clause($ctx, $query_hash, $orgs); + return is_deeply($query, $expected, $description); +} + +1; -- 2.11.0