adjust quoting of phrase searches
authorgmc <gmc@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Fri, 29 Oct 2010 01:25:01 +0000 (01:25 +0000)
committergmc <gmc@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Fri, 29 Oct 2010 01:25:01 +0000 (01:25 +0000)
This has three main effects:

* This formalizes the current behavior where a
  phrase search like

  title:"^Harry Potter"

  acts as a left-anchored search and

  title:"Harry Potter$"

  acts as a right-anchored search.

In particular, this can be useful for constructing
searches of bibliographic call numbers.

* Other regex metacharacters in phrase searches are
  now escaped.

* Phrase searches like "C++" will no longer crash; in fact,
  this makes a phrase search currently the only way to
  accurately retrieve all C++ titles with the usual
  normalization rules

Signed-off-by: Galen Charlton <gmc@esilibrary.com>

git-svn-id: svn://svn.open-ils.org/ILS/trunk@18540 dcc99617-32d9-48b4-a31d-7c20da2025e4

Open-ILS/src/perlmods/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm

index 94db0a4..a27081e 100644 (file)
@@ -17,6 +17,20 @@ sub quote_value {
     return "\$_$$\$$value\$_$$\$";
 }
 
+sub quote_phrase_value {
+    my $self = shift;
+    my $value = shift;
+
+    my $left_anchored  = $value =~ m/^\^/;
+    my $right_anchored = $value =~ m/\$$/;
+    $value =~ s/\^//   if $left_anchored;
+    $value =~ s/\$$//  if $right_anchored;
+    $value =~ quotemeta($value);
+    $value = '^' . $value if $left_anchored;
+    $value = "$value\$"   if $right_anchored;
+    return $self->quote_value($value);
+}
+
 sub init {
     my $class = shift;
 
@@ -619,7 +633,7 @@ sub flatten {
                 }
 
                 $where .= '(' . $talias . ".id IS NOT NULL";
-                $where .= ' AND ' . join(' AND ', map {"${talias}.value ~* ".$self->QueryParser->quote_value($_)} @{$node->phrases}) if (@{$node->phrases});
+                $where .= ' AND ' . join(' AND ', map {"${talias}.value ~* ".$self->QueryParser->quote_phrase_value($_)} @{$node->phrases}) if (@{$node->phrases});
                 $where .= ')';
 
                 push @rank_list, $node_rank;