Changeset 2538
- Timestamp:
- 02/23/10 09:40:38 (5 months ago)
- Location:
- Search-Query/trunk
- Files:
-
- 2 added
- 2 edited
-
lib/Search/Query/Dialect/KSx.pm (modified) (2 diffs)
-
lib/Search/Query/Field/KSx.pm (added)
-
lib/Search/Query/Field/SWISH.pm (modified) (1 diff)
-
t/06-ks.t (added)
Legend:
- Unmodified
- Added
- Removed
-
Search-Query/trunk/lib/Search/Query/Dialect/KSx.pm
r2537 r2538 5 5 use Carp; 6 6 use Data::Dump qw( dump ); 7 use Search::Query::Field::KSx; 7 8 8 9 our $VERSION = '0.08'; 10 11 __PACKAGE__->mk_accessors( 12 qw( 13 wildcard 14 fuzzify 15 ) 16 ); 9 17 10 18 =head1 NAME … … 23 31 =head1 METHODS 24 32 25 This class is a subclass of Search::Query::Dialect::Native. 26 Only new or overridden methods are documented here. 27 28 =cut 33 This class is a subclass of Search::Query::Dialect. Only new or overridden 34 methods are documented here. 35 36 =cut 37 38 =head2 init 39 40 Overrides base method and sets SWISH-appropriate defaults. 41 Can take the following params, also available as standard attribute 42 methods. 43 44 =over 45 46 =item wildcard 47 48 Default is '*'. 49 50 =item fuzzify 51 52 If true, a wildcard is automatically appended to each query term. 53 54 =back 55 56 =cut 57 58 sub init { 59 my $self = shift; 60 61 $self->SUPER::init(@_); 62 63 #carp dump $self; 64 $self->{wildcard} = '*'; 65 if ( $self->parser->fields ) { 66 $self->{default_field} ||= $self->parser->default_field 67 || [ sort keys %{ $self->parser->fields } ]; 68 } 69 else { 70 $self->{default_field} ||= $self->parser->default_field 71 || 'swishdefault'; 72 } 73 if ( $self->{default_field} and !ref( $self->{default_field} ) ) { 74 $self->{default_field} = [ $self->{default_field} ]; 75 } 76 77 return $self; 78 } 79 80 =head2 stringify 81 82 Returns the Query object as a normalized string. 83 84 =cut 85 86 my %op_map = ( 87 '+' => 'AND', 88 '' => 'OR', 89 '-' => 'NOT', 90 ); 91 92 sub stringify { 93 my $self = shift; 94 my $tree = shift || $self; 95 96 my @q; 97 foreach my $prefix ( '+', '', '-' ) { 98 my @clauses; 99 my $joiner = $op_map{$prefix}; 100 next unless exists $tree->{$prefix}; 101 for my $clause ( @{ $tree->{$prefix} } ) { 102 push( @clauses, $self->stringify_clause( $clause, $prefix ) ); 103 } 104 next if !@clauses; 105 106 push @q, join( " $joiner ", grep { defined and length } @clauses ); 107 } 108 109 return join " AND ", @q; 110 } 111 112 sub _doctor_value { 113 my ( $self, $clause ) = @_; 114 115 my $value = $clause->{value}; 116 117 if ( $self->fuzzify ) { 118 $value .= '*' unless $value =~ m/[\*\%]/; 119 } 120 121 # normalize wildcard 122 my $wildcard = $self->wildcard; 123 $value =~ s/[\*\%]/$wildcard/g; 124 125 return $value; 126 } 127 128 =head2 stringify_clause( I<leaf>, I<prefix> ) 129 130 Called by stringify() to handle each Clause in the Query tree. 131 132 =cut 133 134 sub stringify_clause { 135 my $self = shift; 136 my $clause = shift; 137 my $prefix = shift; 138 139 #warn dump $clause; 140 #warn "prefix = '$prefix'"; 141 142 if ( $clause->{op} eq '()' ) { 143 if ( $clause->has_children and $clause->has_children == 1 ) { 144 return $self->stringify( $clause->{value} ); 145 } 146 else { 147 return 148 ( $prefix eq '-' ? 'NOT ' : '' ) . "(" 149 . $self->stringify( $clause->{value} ) . ")"; 150 } 151 } 152 153 # make sure we have a field 154 my @fields 155 = $clause->{field} 156 ? ( $clause->{field} ) 157 : ( @{ $self->_get_default_field } ); 158 159 # what value 160 my $value 161 = ref $clause->{value} 162 ? $clause->{value} 163 : $self->_doctor_value($clause); 164 165 my $wildcard = $self->wildcard; 166 167 # normalize operator 168 my $op = $clause->{op} || ":"; 169 if ( $op eq '=' ) { 170 $op = ':'; 171 } 172 if ( $prefix eq '-' ) { 173 $op = '!' . $op; 174 } 175 if ( $value =~ m/\%/ ) { 176 $op = $prefix eq '-' ? '!~' : '~'; 177 } 178 179 my $quote = $clause->quote || ''; 180 181 my @buf; 182 NAME: for my $name (@fields) { 183 my $field = $self->_get_field($name); 184 185 if ( defined $field->callback ) { 186 push( @buf, $field->callback->( $field, $op, $value ) ); 187 next NAME; 188 } 189 190 #warn dump [ $name, $op, $quote, $value ]; 191 192 # invert fuzzy 193 if ( $op eq '!~' ) { 194 $value .= $wildcard unless $value =~ m/\Q$wildcard/; 195 push( @buf, 196 join( '', 'NOT ', $name, '=', qq/$quote$value$quote/ ) ); 197 } 198 199 # fuzzy 200 elsif ( $op eq '~' ) { 201 $value .= $wildcard unless $value =~ m/\Q$wildcard/; 202 push( @buf, join( '', $name, '=', qq/$quote$value$quote/ ) ); 203 } 204 205 # invert 206 elsif ( $op eq '!:' ) { 207 push( @buf, 208 join( '', 'NOT ', $name, ':', qq/$quote$value$quote/ ) ); 209 } 210 211 # range 212 elsif ( $op eq '..' ) { 213 if ( ref $value ne 'ARRAY' or @$value != 2 ) { 214 croak "range of values must be a 2-element ARRAY"; 215 } 216 217 # we support only numbers at this point 218 for my $v (@$value) { 219 if ( $v =~ m/\D/ ) { 220 croak "non-numeric range values are not supported: $v"; 221 } 222 } 223 224 my @range = ( $value->[0] .. $value->[1] ); 225 push( @buf, 226 join( '', $name, ':', '(', join( ' OR ', @range ), ')' ) ); 227 228 } 229 230 # invert range 231 elsif ( $op eq '!..' ) { 232 if ( ref $value ne 'ARRAY' or @$value != 2 ) { 233 croak "range of values must be a 2-element ARRAY"; 234 } 235 236 # we support only numbers at this point 237 for my $v (@$value) { 238 if ( $v =~ m/\D/ ) { 239 croak "non-numeric range values are not supported: $v"; 240 } 241 } 242 243 my @range = ( $value->[0] .. $value->[1] ); 244 push( @buf, 245 join( '', '-', $name, ':', '( ', join( ' ', @range ), ' )' ) 246 ); 247 } 248 249 # standard 250 else { 251 push( @buf, join( '', $name, ':', qq/$quote$value$quote/ ) ); 252 } 253 } 254 my $joiner = $prefix eq '-' ? ' AND ' : ' OR '; 255 return 256 ( scalar(@buf) > 1 ? '(' : '' ) 257 . join( $joiner, @buf ) 258 . ( scalar(@buf) > 1 ? ')' : '' ); 259 } 260 261 =head2 field_class 262 263 Returns "Search::Query::Field::KSx". 264 265 =cut 266 267 sub field_class {'Search::Query::Field::KSx'} 29 268 30 269 1; -
Search-Query/trunk/lib/Search/Query/Field/SWISH.pm
r2536 r2538 66 66 67 67 1; 68 69 __END__ 70 71 =head1 AUTHOR 72 73 Peter Karman, C<< <karman at cpan.org> >> 74 75 =head1 BUGS 76 77 Please report any bugs or feature requests to C<bug-search-query at rt.cpan.org>, or through 78 the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Search-Query>. I will be notified, and then you'll 79 automatically be notified of progress on your bug as I make changes. 80 81 =head1 SUPPORT 82 83 You can find documentation for this module with the perldoc command. 84 85 perldoc Search::Query 86 87 88 You can also look for information at: 89 90 =over 4 91 92 =item * RT: CPAN's request tracker 93 94 L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Search-Query> 95 96 =item * AnnoCPAN: Annotated CPAN documentation 97 98 L<http://annocpan.org/dist/Search-Query> 99 100 =item * CPAN Ratings 101 102 L<http://cpanratings.perl.org/d/Search-Query> 103 104 =item * Search CPAN 105 106 L<http://search.cpan.org/dist/Search-Query/> 107 108 =back 109 110 111 =head1 ACKNOWLEDGEMENTS 112 113 This module started as a fork of Search::QueryParser by 114 Laurent Dami. 115 116 =head1 COPYRIGHT & LICENSE 117 118 Copyright 2010 Peter Karman. 119 120 This program is free software; you can redistribute it and/or modify it 121 under the terms of either: the GNU General Public License as published 122 by the Free Software Foundation; or the Artistic License. 123 124 See http://dev.perl.org/licenses/ for more information. 125 126 =cut
Note: See TracChangeset
for help on using the changeset viewer.