From: Mike Rylander Date: Thu, 31 Oct 2019 19:23:22 +0000 (-0400) Subject: Update acq search operators X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=d6a07466bf96945f70601b3a28df8e1377ff89c5;p=working%2FEvergreen.git Update acq search operators Add __age (interval), __starts, and __ends operators. Update __between to support __castdate modifier, for a more natural comparison of dates entered by humans to timestamps stored in the database. Signed-off-by: Mike Rylander --- diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Search.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Search.pm index c09fd35543..e1ce5e6541 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Search.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Search.pm @@ -52,11 +52,12 @@ sub could_be_range { } sub castdate { - my ($value, $gte, $lte) = @_; + my ($value, $gte, $lte, $between) = @_; my $op = "="; $op = ">=" if $gte; $op = "<=" if $lte; + $op = "between" if $between; # avoid transforming a date if the match value is NULL. return {'=' => undef} if $op eq '=' and not $value; @@ -76,7 +77,7 @@ sub prepare_acqlia_search_and { }; # castdate not supported for acqlia fields: they're all type text - my ($k, $v, $fuzzy, $between, $not) = breakdown_term($unit); + my ($k, $v, $fuzzy, $between, $not, $starts, $ends) = breakdown_term($unit); my $point = $subquery->{"where"}->{"-and"}; my $term_clause; @@ -84,6 +85,10 @@ sub prepare_acqlia_search_and { if ($fuzzy and not ref $v) { push @$point, {"attr_value" => {"ilike" => "%" . $v . "%"}}; + } elsif ($starts and not ref $v) { + push @$point, {"attr_value" => {"ilike" => $v . "%"}}; + } elsif ($ends and not ref $v) { + push @$point, {"attr_value" => {"ilike" => "%" . $v}}; } elsif ($between and could_be_range($v)) { push @$point, {"attr_value" => {"between" => $v}}; } elsif (check_1d_max($v)) { @@ -106,7 +111,7 @@ sub prepare_acqlia_search_or { foreach my $unit (@$acqlia) { # castdate not supported for acqlia fields: they're all type text - my ($k, $v, $fuzzy, $between, $not) = breakdown_term($unit); + my ($k, $v, $fuzzy, $between, $not, $starts, $ends) = breakdown_term($unit); my $term_clause; if ($fuzzy and not ref $v) { $term_clause = { @@ -115,6 +120,20 @@ sub prepare_acqlia_search_or { "attr_value" => {"ilike" => "%" . $v . "%"} } }; + } elsif ($starts and not ref $v) { + $term_clause = { + "-and" => { + "definition" => $k, + "attr_value" => {"ilike" => $v . "%"} + } + }; + } elsif ($ends and not ref $v) { + $term_clause = { + "-and" => { + "definition" => $k, + "attr_value" => {"ilike" => "%" . $v} + } + }; } elsif ($between and could_be_range($v)) { $term_clause = { "-and" => { @@ -143,9 +162,12 @@ sub breakdown_term { $term->{"__fuzzy"} ? 1 : 0, $term->{"__between"} ? 1 : 0, $term->{"__not"} ? 1 : 0, + $term->{"__starts"} ? 1 : 0, + $term->{"__ends"} ? 1 : 0, $term->{"__castdate"} ? 1 : 0, $term->{"__gte"} ? 1 : 0, - $term->{"__lte"} ? 1 : 0 + $term->{"__lte"} ? 1 : 0, + $term->{"__age"} ? 1 : 0, ); } @@ -238,17 +260,39 @@ sub prepare_terms { $outer_clause->{$conj} = [] unless $outer_clause->{$conj}; foreach my $unit (@{$terms->{$class}}) { my $special_clause; - my ($k, $v, $fuzzy, $between, $not, $castdate, $gte, $lte) = + my ($k, $v, $fuzzy, $between, $not, $starts, $ends, $castdate, $gte, $lte, $age) = breakdown_term($unit); my $term_clause; - if ($fuzzy and not ref $v) { + if ($age and not ref $v) { # $v is expected to be parsed as an interval + $v =~ s/^\s*//; + + my $op = $gte ? '>=' : '<='; + $term_clause = {$k = {$op => {transform => 'age', params => ['now'], value => '-' . $v}}}; + + # !!! NOTE: we invert $not because we have to compare to a /negative/ + # interval, due to json_query restiction on function parameter order for + # transformed fields, so we flip the comparison. Alternatively we could + # swap the GTE and LTE operators, but that would make the query harder + # to read and make diagnosing issues much more difficult. + $not = $not ? 0 : 1; + + } elsif ($starts and not ref $v) { + $term_clause = {$k => {"ilike" => $v . "%"}}; + } elsif ($ends and not ref $v) { + $term_clause = {$k => {"ilike" => "%" . $v}}; + } elsif ($fuzzy and not ref $v) { $term_clause = {$k => {"ilike" => "%" . $v . "%"}}; } elsif ($between and could_be_range($v)) { - $term_clause = {$k => {"between" => $v}}; + if ($castdate) { + $v = castdate($v, 0, 0, $between); + $term_clause = {$k => $v}; + } else { + $term_clause = {$k => {between => $v}}; + } } elsif (check_1d_max($v)) { if ($castdate) { - $v = castdate($v, $gte, $lte) if $castdate; + $v = castdate($v, $gte, $lte); } elsif ($gte or $lte) { my $op = $gte ? '>=' : '<='; $v = {$op => $v};