Changeset 2538


Ignore:
Timestamp:
02/23/10 09:40:38 (5 months ago)
Author:
karpet
Message:

ok. real KS support.

Location:
Search-Query/trunk
Files:
2 added
2 edited

Legend:

Unmodified
Added
Removed
  • Search-Query/trunk/lib/Search/Query/Dialect/KSx.pm

    r2537 r2538  
    55use Carp; 
    66use Data::Dump qw( dump ); 
     7use Search::Query::Field::KSx; 
    78 
    89our $VERSION = '0.08'; 
     10 
     11__PACKAGE__->mk_accessors( 
     12    qw( 
     13        wildcard 
     14        fuzzify 
     15        ) 
     16); 
    917 
    1018=head1 NAME 
     
    2331=head1 METHODS 
    2432 
    25 This class is a subclass of Search::Query::Dialect::Native.  
    26 Only new or overridden methods are documented here. 
    27  
    28 =cut 
     33This class is a subclass of Search::Query::Dialect. Only new or overridden 
     34methods are documented here. 
     35 
     36=cut 
     37 
     38=head2 init 
     39 
     40Overrides base method and sets SWISH-appropriate defaults. 
     41Can take the following params, also available as standard attribute 
     42methods. 
     43 
     44=over 
     45 
     46=item wildcard 
     47 
     48Default is '*'. 
     49 
     50=item fuzzify 
     51 
     52If true, a wildcard is automatically appended to each query term. 
     53 
     54=back 
     55 
     56=cut 
     57 
     58sub 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 
     82Returns the Query object as a normalized string. 
     83 
     84=cut 
     85 
     86my %op_map = ( 
     87    '+' => 'AND', 
     88    ''  => 'OR', 
     89    '-' => 'NOT', 
     90); 
     91 
     92sub 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 
     112sub _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 
     130Called by stringify() to handle each Clause in the Query tree. 
     131 
     132=cut 
     133 
     134sub 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; 
     182NAME: 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 
     263Returns "Search::Query::Field::KSx". 
     264 
     265=cut 
     266 
     267sub field_class {'Search::Query::Field::KSx'} 
    29268 
    302691; 
  • Search-Query/trunk/lib/Search/Query/Field/SWISH.pm

    r2536 r2538  
    6666 
    67671; 
     68 
     69__END__ 
     70 
     71=head1 AUTHOR 
     72 
     73Peter Karman, C<< <karman at cpan.org> >> 
     74 
     75=head1 BUGS 
     76 
     77Please report any bugs or feature requests to C<bug-search-query at rt.cpan.org>, or through 
     78the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Search-Query>.  I will be notified, and then you'll 
     79automatically be notified of progress on your bug as I make changes. 
     80 
     81=head1 SUPPORT 
     82 
     83You can find documentation for this module with the perldoc command. 
     84 
     85    perldoc Search::Query 
     86 
     87 
     88You can also look for information at: 
     89 
     90=over 4 
     91 
     92=item * RT: CPAN's request tracker 
     93 
     94L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Search-Query> 
     95 
     96=item * AnnoCPAN: Annotated CPAN documentation 
     97 
     98L<http://annocpan.org/dist/Search-Query> 
     99 
     100=item * CPAN Ratings 
     101 
     102L<http://cpanratings.perl.org/d/Search-Query> 
     103 
     104=item * Search CPAN 
     105 
     106L<http://search.cpan.org/dist/Search-Query/> 
     107 
     108=back 
     109 
     110 
     111=head1 ACKNOWLEDGEMENTS 
     112 
     113This module started as a fork of Search::QueryParser by 
     114Laurent Dami. 
     115 
     116=head1 COPYRIGHT & LICENSE 
     117 
     118Copyright 2010 Peter Karman. 
     119 
     120This program is free software; you can redistribute it and/or modify it 
     121under the terms of either: the GNU General Public License as published 
     122by the Free Software Foundation; or the Artistic License. 
     123 
     124See http://dev.perl.org/licenses/ for more information. 
     125 
     126=cut 
Note: See TracChangeset for help on using the changeset viewer.