Skip to content

Commit

Permalink
Item9808: corrections from unit testing. One test in Fn_SEARCH fails,…
Browse files Browse the repository at this point in the history
… but Sven comments in the code that the test is wrong.

git-svn-id: http://svn.foswiki.org/trunk/DBIStoreContrib@9544 0b4bb1d4-4e5a-0410-9cc4-b2b747904278
  • Loading branch information
CrawfordCurrie authored and CrawfordCurrie committed Oct 10, 2010
1 parent 5087137 commit 9b87862
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 34 deletions.
2 changes: 1 addition & 1 deletion lib/Foswiki/Contrib/DBIStoreContrib/HoistSQL.pm
Expand Up @@ -127,7 +127,7 @@ sub _hoistB {
my $rhs = _hoistC( $node->{params}[1], "${indent}r", 0 );
if ( $lhs && $rhs ) {
print STDERR "${indent}L&R\n" if MONITOR;
return "($lhs) OR ($rhs)";
return "(($lhs) OR ($rhs))";
}
}
else {
Expand Down
10 changes: 10 additions & 0 deletions lib/Foswiki/Contrib/DBIStoreContrib/Listener.pm
Expand Up @@ -59,6 +59,16 @@ sub _connect {

return 1 if $this->{handle};

if ($Foswiki::inUnitTestMode) {
# Change the DSN to a SQLite test db, which is held in the data
# area; that way it will be ripped down by -clean
$Foswiki::cfg{Extensions}{DBIStoreContrib}{DSN} =
$Foswiki::cfg{Extensions}{DBIStoreContrib}{DSN} =
"dbi:SQLite:dbname=$Foswiki::cfg{DataDir}/TemporarySQLiteCache";
$Foswiki::cfg{Extensions}{DBIStoreContrib}{Username} = '';
$Foswiki::cfg{Extensions}{DBIStoreContrib}{Password} = '';
}

print STDERR "CONNECT $Foswiki::cfg{Extensions}{DBIStoreContrib}{DSN}..."
if MONITOR;
$this->{handle} = DBI->connect(
Expand Down
39 changes: 25 additions & 14 deletions lib/Foswiki/Store/QueryAlgorithms/DBIStoreContrib.pm
Expand Up @@ -3,6 +3,7 @@
=begin TML
---+ package Foswiki::Store::QueryAlgorithms::DBIStoreContrib
Implements Foswiki::Store::Interfaces::QueryAlgorithm
=cut

Expand All @@ -11,9 +12,11 @@ package Foswiki::Store::QueryAlgorithms::DBIStoreContrib;
use strict;
use warnings;

#@ISA = ( 'Foswiki::Query::QueryAlgorithms' ); # interface
#use Foswiki::Store::Interfaces::QueryAlgorithm ();
#@ISA = ( 'Foswiki::Store::Interfaces::QueryAlgorithm' );

use Foswiki::Search::Node ();
use Foswiki::Store::Interfaces::SearchAlgorithm ();
use Foswiki::Meta ();
use Foswiki::Search::InfoCache ();
use Foswiki::Search::ResultSet ();
Expand All @@ -22,7 +25,7 @@ use Foswiki::Query::Node ();
use Foswiki::Contrib::DBIStoreContrib::Listener ();

# Debug prints
use constant MONITOR => 1;
use constant MONITOR => 0;

# See Foswiki::Query::QueryAlgorithms.pm for details
sub query {
Expand All @@ -40,8 +43,8 @@ sub query {
my $webNames = $options->{web} || '';
my $recurse = $options->{'recurse'} || '';
my $searchAllFlag = ( $webNames =~ /(^|[\,\s])(all|on)([\,\s]|$)/i );
my @webs = Foswiki::Search::InfoCache::_getListOfWebs( $webNames, $recurse,
$searchAllFlag );
my @webs = Foswiki::Store::Interfaces::SearchAlgorithm::getListOfWebs(
$webNames, $recurse, $searchAllFlag );

my @interestingWebs;
foreach my $web (@webs) {
Expand Down Expand Up @@ -71,31 +74,34 @@ sub query {
# can use to refine the topic set

require Foswiki::Contrib::DBIStoreContrib::HoistSQL;
my $hoistedSQL = Foswiki::Contrib::DBIStoreContrib::HoistSQL::hoist($query) || 1;
my $hoistedSQL = Foswiki::Contrib::DBIStoreContrib::HoistSQL::hoist(
$query) || 1;

if ($hoistedSQL) {
print STDERR "Hoisted '$hoistedSQL', remaining query: " . $query->stringify . "\n"
if MONITOR;
print STDERR "Hoisted '$hoistedSQL', remaining query: "
. $query->stringify . "\n" if MONITOR;

# Did hoisting eliminate the dynamic query?
if ($query->evaluatesToConstant()) {
print STDERR "\t...eliminated static query\n" if MONITOR;
$query = undef;
}
}

my $sql =
'SELECT tid FROM topic WHERE '
. ( $hoistedSQL ? "$hoistedSQL AND " : '' )
. "topic.web IN ("
. join( ',', map { "'$_'" } @interestingWebs ) . ')';

if ( $interestingTopics && scalar(@$interestingTopics) ) {
if ( $interestingTopics && $interestingTopics->hasNext() ) {
$sql .= " AND topic.name IN ("
. join( ',', map { "'$_'" } @$interestingTopics ) . ')';
. join( ',', map { "'$_'" } $interestingTopics->all() ) . ')';
} # otherwise there is no topic name filter

$sql .= ' ORDER BY web,name';

print STDERR "Generated SQL: $sql\n" if MONITOR;

my $topicSet = Foswiki::Contrib::DBIStoreContrib::Listener::query(
$session, $sql );
my $filter = Foswiki::Search::InfoCache::getOptionFilter($options);
Expand All @@ -119,7 +125,7 @@ sub query {
new Foswiki::Search::InfoCache($Foswiki::Plugins::SESSION);

if ($query) {
print STDERR "Processing " . $meta->getPath() . "\n" if MONITOR;
print STDERR "Evaluating " . $meta->getPath() . "\n" if MONITOR;

# this 'lazy load' will become useful when @$topics becomes
# an infoCache
Expand All @@ -138,9 +144,14 @@ sub query {
}
}

# We have to pre-sort the result sets by web name to mimic the
# behaviour of default search.
my $resultset =
new Foswiki::Search::ResultSet( [values %results], $options->{groupby},
$options->{order}, Foswiki::isTrue( $options->{reverse} ) );
new Foswiki::Search::ResultSet(
[ map { $results{$_} } sort( keys( %results )) ],
$options->{groupby},
$options->{order},
Foswiki::isTrue( $options->{reverse} ) );

#TODO: $options should become redundant
$resultset->sortResults($options);
Expand Down Expand Up @@ -286,7 +297,7 @@ sub getField {
}

# Get a referenced topic
# See Foswiki::Store::QueryAlgorithms.pm for details
# See Foswiki::Store::Interfaces::QueryAlgorithms.pm for details
sub getRefTopic {
my ( $this, $relativeTo, $w, $t ) = @_;
return Foswiki::Meta->load( $relativeTo->session, $w, $t );
Expand Down
60 changes: 41 additions & 19 deletions lib/Foswiki/Store/SearchAlgorithms/DBIStoreContrib.pm
@@ -1,63 +1,85 @@
# See bottom of file for license and copyright information
package Foswiki::Store::SearchAlgorithms::DBIStoreContrib;

=begin TML
---+ package Foswiki::Store::SearchAlgorithms::DBIStoreContrib
Implements Foswiki::Store::Interfaces::SearchAlgorithm
DBI implementation of search.
=cut

use strict;
use Assert;
use Foswiki::Search::InfoCache ();
use Foswiki::Query::Parser ();
use Foswiki::Store::QueryAlgorithms::DBIStoreContrib ();

#@ISA = ( 'Foswiki::Store::Interfaces::SearchAlgorithm' );

# Analyse the requirements of the search, and redirect to the query
# algorithm. This is kinda like the reverse of hoisting regexes :-)
# Implements Foswiki::Store::Interfaces::SearchAlgorithm
sub query {
my ( $query, $inputTopicSet, $session, $options ) = @_;

if (( @{ $query->{tokens} } ) == 0) {
if ( $query->isEmpty() ) {
return new Foswiki::Search::InfoCache($session, '');
}

print STDERR "Search ".$query->stringify()."\n"
if Foswiki::Store::QueryAlgorithms::DBIStoreContrib::MONITOR;

# Convert the search to a query
# AND search - search once for each token, ANDing result together
my @ands;
foreach my $token ( @{ $query->{tokens} } ) {
foreach my $token ( @{ $query->tokens() } ) {

my $tokenCopy = $token;

# flag for AND NOT search
my $invert = ( $tokenCopy =~ s/^\!//o ) ? 'NOT ' : '';
my $invert = ( $tokenCopy =~ s/^\!// ) ? 'NOT ' : '';

# scope can be 'topic' (default), 'text' or "all"
# scope can be 'topic', 'text' or "all"
# scope='topic', e.g. Perl search on topic name:
$options->{scope} = 'text' unless defined $options->{'scope'};
$options->{type} ||= 'literal';
$options->{casesensitive} ||= 0;

$tokenCopy = "\\b$tokenCopy\\b" if $options->{wordboundaries};

my %topicMatches;
my @ors;
if ( $options->{'scope'} =~ /^(topic|all)$/ ) {
if ( $options->{scope} ne 'text' ) { # topic or all
my $expr = $tokenCopy;

$expr = quotemeta($expr) unless ( $options->{'type'} eq 'regex' );
$expr = "(?i:$expr)" unless $options->{'casesensitive'};
$expr = quotemeta($expr) unless ( $options->{type} eq 'regex' );
$expr = "(?i:$expr)" unless $options->{casesensitive};
push(@ors, "${invert}name =~ '$expr'");
}

# scope='text', e.g. grep search on topic text:
if ( $options->{'scope'} =~ /^(text|all)$/ ) {
if ( $options->{scope} ne 'topic' ) { # text or all
my $expr = $tokenCopy;

$expr = quotemeta($expr) unless ( $options->{'type'} eq 'regex' );
$expr = "(?i:$expr)" unless $options->{'casesensitive'};
$expr = quotemeta($expr) unless ( $options->{type} eq 'regex' );
$expr = "(?i:$expr)" unless $options->{casesensitive};

push(@ors, "${invert}raw =~ '$expr'");
}
push(@ands, '(' . join(' OR ', @ors) . ')');
push(@ands, '(' . join($invert ? ' AND ' : ' OR ', @ors) . ')');

}
my $queryParser = Foswiki::Query::Parser->new();
$query = $queryParser->parse(join(' AND ', @ands));

eval "require $Foswiki::cfg{Store}{QueryAlgorithm}";
die $@ if $@;
my $fn = $Foswiki::cfg{Store}{QueryAlgorithm}.'::query';
no strict 'refs';
return &$fn($query, $inputTopicSet, $session, $options);
use strict 'refs';
my $search = join(' AND ', @ands);
print STDERR "Search generated query $search\n"
if Foswiki::Store::QueryAlgorithms::DBIStoreContrib::MONITOR;

$query = $queryParser->parse($search);

return Foswiki::Store::QueryAlgorithms::DBIStoreContrib::query(
$query, $inputTopicSet, $session, $options);
}

1;
Expand Down

0 comments on commit 9b87862

Please sign in to comment.