]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/fts.pm
QueryParser Driver: Much work
[working/Evergreen.git] / Open-ILS / src / perlmods / lib / OpenILS / Application / Storage / Driver / Pg / fts.pm
1 { # Every driver needs to provide a 'compile()' method to OpenILS::Application::Storage::FTS.
2   # If that driver wants to support FTI, that is...
3         #-------------------------------------------------------------------------------
4         package OpenILS::Application::Storage::FTS;
5         use OpenSRF::Utils::Logger qw/:level/;
6         use Unicode::Normalize;
7         my $log = 'OpenSRF::Utils::Logger';
8
9         sub compile {
10                 my $self = shift;
11                 my $class = shift;
12                 my $term = NFD(shift());
13
14                 $log->debug("Raw term: $term",DEBUG);
15                 $log->debug("Search class: $class",DEBUG);
16
17                 $term =~ s/\&//go;
18                 $term =~ s/\|//go;
19
20                 $self = ref($self) || $self;
21                 $self = bless {} => $self;
22                 $self->{class} = $class;
23
24                 $term =~ s/(\pM+)//gos;
25                 $term =~ s/(\b\.\b)//gos;
26
27                 # hack to normalize ratio-like strings
28                 while ($term =~ /\b\d{1}:[, ]?\d+(?:[ ,]\d+[^:])+/o) {
29                         $term = $` . join ('', split(/[, ]/, $&)) . $';
30                 }
31
32                 $self->decompose($term);
33
34                 my $newterm = '';
35                 $newterm = join('&', $self->words) if ($self->words);
36
37                 if (@{$self->nots}) {
38                         $newterm = '('.$newterm.')&' if ($newterm);
39                         $newterm .= '!('. join('|', $self->nots) . ')';
40                 }
41
42                 $log->debug("Compiled term is [$newterm]", DEBUG);
43                 $newterm = OpenILS::Application::Storage::Driver::Pg->quote($newterm);
44                 $log->debug("Quoted term is [$newterm]", DEBUG);
45
46                 $self->{fts_query} = ["to_tsquery('$$self{class}',$newterm)"];
47                 $self->{fts_query_nots} = [];
48                 $self->{fts_op} = '@@';
49                 $self->{text_col} = shift;
50                 $self->{fts_col} = shift;
51
52                 return $self;
53         }
54
55         sub sql_where_clause {
56                 my $self = shift;
57                 my $column = $self->fts_col;
58                 my @output;
59         
60                 my @ranks;
61                 for my $fts ( $self->fts_query ) {
62                         push @output, join(' ', $self->fts_col, $self->{fts_op}, $fts);
63                         push @ranks, "ts_rank($column, $fts)";
64                 }
65                 $self->{fts_rank} = \@ranks;
66         
67                 my $phrase_match = $self->sql_exact_phrase_match();
68                 return join(' AND ', @output) . $phrase_match;
69         }
70
71         sub sql_exact_phrase_match {
72                 my $self = shift;
73                 my $column = $self->text_col;
74                 my $output = '';
75                 for my $phrase ( $self->phrases ) {
76                         $phrase =~ s/\*/\\*/go;
77                         $phrase =~ s/\./\\./go;
78                         $phrase =~ s/'/\\'/go;
79                         $phrase =~ s/\s+/\\s+/go;
80                         $log->debug("Adding phrase [$phrase] to the match list", DEBUG);
81                         $output .= " AND $column ~* \$\$(^|\\W+)$phrase(\\W+|\$)\$\$";
82                 }
83                 $log->debug("Phrase list is [$output]", DEBUG);
84                 return $output;
85         }
86
87 }
88
89 1;