Bug 11015: add copyright headers to some files
[koha.git] / Koha / SearchEngine / Solr / QueryBuilder.pm
1 package Koha::SearchEngine::Solr::QueryBuilder;
2
3 # This file is part of Koha.
4 #
5 # Copyright 2012 BibLibre
6 #
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20 use Modern::Perl;
21 use Moose::Role;
22
23 with 'Koha::SearchEngine::QueryBuilderRole';
24
25 sub build_advanced_query {
26     my ($class, $indexes, $operands, $operators) = @_;
27
28     my $q = '';
29     my $i = 0;
30     my $index_name;
31
32     @$operands or return "*:*"; #push @$operands, "[* TO *]";
33
34     # Foreach operands
35     for my $kw (@$operands){
36         $kw =~ s/(\w*\*)/\L$1\E/g; # Lower case on words with right truncation
37         $kw =~ s/(\s*\w*\?+\w*\s*)/\L$1\E/g; # Lower case on words contain wildcard ?
38         $kw =~ s/([^\\]):/$1\\:/g; # escape colons if not already escaped
39         # First element
40         if ($i == 0){
41             if ( (my @x = eval {@$indexes} ) == 0 ){
42                 # There is no index, then query is in first operand
43                 $q = @$operands[0];
44                 last;
45             }
46
47             # Catch index name if it's not 'all_fields'
48             if ( @$indexes[$i] ne 'all_fields' ) {
49                 $index_name = @$indexes[$i];
50             }else{
51                 $index_name = '';
52             }
53
54             # Generate index:operand
55             $q .= BuildTokenString($index_name, $kw);
56             $i = $i + 1;
57
58             next;
59         }
60         # And others
61         $index_name = @$indexes[$i] if @$indexes[$i];
62         my $operator = defined @$operators[$i-1] ? @$operators[$i-1] : 'AND';
63         for ( uc ( $operator ) ) {
64             when ('OR'){
65                 $q .= BuildTokenString($index_name, $kw, 'OR');
66             }
67             when ('NOT'){
68                 $q .= BuildTokenString($index_name, $kw, 'NOT');
69             }
70             default {
71                 $q .= BuildTokenString($index_name, $kw, 'AND');
72             }
73         }
74         $i = $i + 1;
75     }
76
77     return $q;
78
79 }
80
81 sub BuildTokenString {
82     my ($index, $string, $operator) = @_;
83     my $r;
84
85     if ($index ne 'all_fields' && $index ne ''){
86         # Operand can contains an expression in brackets
87         if (
88             $string =~ / /
89                 and not ( $string =~ /^\(.*\)$/ )
90                 and not $string =~ /\[.*TO.*\]/ ) {
91             my @dqs; #double-quoted string
92             while ( $string =~ /"(?:[^"\\]++|\\.)*+"/g ) {
93                 push @dqs, $&;
94                 $string =~ s/\ *\Q$&\E\ *//; # Remove useless space before and after
95             }
96
97             my @words = defined $string ? split ' ', $string : undef;
98             my $join = join qq{ AND } , map {
99                 my $value = $_;
100                 if ( $index =~ /^date_/ ) {
101                     #$value = C4::Search::Engine::Solr::buildDateOperand( $value ); TODO
102                 }
103                 ( $value =~ /^"/ and $value ne '""'
104                         and $index ne "emallfields"
105                         and $index =~ /(txt_|ste_)/ )
106                     ? qq{em$index:$value}
107                     : qq{$index:$value};
108             } (@dqs, @words);
109             $r .= qq{($join)};
110         } else {
111             if ( $index =~ /^date_/ ) {
112                 #$string = C4::Search::Engine::Solr::buildDateOperand( $string ); TODO
113             }
114
115             $r = "$index:$string";
116         }
117     }else{
118         $r = $string;
119     }
120
121     return " $operator $r" if $operator;
122     return $r;
123 }
124
125 sub build_query {
126     my ($class, $query) = @_;
127
128     return "*:*" if not defined $query;
129
130     # Particular *:* query
131     if ($query  eq '*:*'){
132         return $query;
133     }
134
135     $query =~ s/(\w*\*)/\L$1\E/g; # Lower case on words with right truncation
136     $query =~ s/(\s*\w*\?+\w*\s*)/\L$1\E/g; # Lower case on words contain wildcard ?
137
138     my @quotes; # Process colons in quotes
139     while ( $query =~ /'(?:[^'\\]++|\\.)*+'/g ) {
140         push @quotes, $&;
141     }
142
143     for ( @quotes ) {
144         my $replacement = $_;
145         $replacement =~ s/[^\\]\K:/\\:/g;
146         $query =~ s/$_/$replacement/;
147     }
148
149     $query =~ s/ : / \\: /g; # escape colons if " : "
150
151     my $new_query = $query;#C4::Search::Query::splitToken($query); TODO
152
153     $new_query =~ s/all_fields://g;
154
155     # Upper case for operators
156     $new_query =~ s/ or / OR /g;
157     $new_query =~ s/ and / AND /g;
158     $new_query =~ s/ not / NOT /g;
159
160     return $new_query;
161 }
162
163 1;