[rt-devel] search updates
ivan
ivan-rt-devel at 420.am
Wed Mar 21 09:23:43 EST 2001
these changes:
fix bug #46: If we search for Keyword != value, any tickets which don't
have a keyword set for that select aren't found
fix searching for multiple keywords
allow you to search for tickets that don't have a keyword for a given
selection, or tickets that _do_ have a keyword for a given selection.
allow you to search for tickets that do or don't have a particular link
type linked to or from them. i.e. this will allow you to search
for tickets that don't have any sub-tickets, or tickets that aren't
sub-tickets of another ticket, or tickets that depend on other
tickets.
--- SearchBuilder.pm Fri Mar 16 04:41:29 2001
+++ ../../../work/DBIx/DBIx-SearchBuilder/SearchBuilder.pm Wed Mar 21 05:59:41 2001
@@ -78,6 +78,7 @@
$self->{'order'} = "";
$self->{'alias_count'} = 0;
$self->{'first_row'} = 0;
+ $self->{'main_alias'} = 'main';
delete $self->{'items'} if ($self->{'items'});
delete $self->{'subclauses'} if ($self->{'subclauses'});
delete $self->{'restrictions'} if ($self->{'restrictions'});
@@ -101,7 +102,7 @@
my ($QueryString, $Order);
- $QueryString = "SELECT main.* FROM " . $self->_TableAliases;
+ $QueryString = "SELECT DISTINCT main.* FROM " . $self->_TableAliases;
$QueryString .= $self->_WhereClause . " ". $self->{'table_links'}. " "
if ($self->_isLimited > 0);
@@ -410,6 +411,7 @@
TABLE => $self->{'table'},
FIELD => undef,
VALUE => undef,
+ QUOTE => 1,
ALIAS => undef,
ENTRYAGGREGATOR => 'or',
OPERATOR => '=',
@@ -421,9 +423,9 @@
if ($args{'FIELD'}) {
#If it's a like, we supply the %s around the search term
if ($args{'OPERATOR'} =~ /LIKE/) {
- $args{'VALUE'} = "%".$args{'VALUE'} ."%";
- }
- $args{'VALUE'} = $self->_Handle->dbh->quote($args{'VALUE'});
+ $args{'VALUE'} = "%".$args{'VALUE'} ."%";
+ }
+ $args{'VALUE'} = $self->_Handle->dbh->quote($args{'VALUE'}) if $args{QUOTE};
}
$Alias = $self->_GenericRestriction(%args);
@@ -570,8 +572,10 @@
sub _TableAliases {
my $self = shift;
+ my $main_alias =
+ ( exists($self->{'main_alias'}) && $self->{'main_alias'} ) || 'main';
# Set up the first alias. for the _main_ table
- my $compiled_aliases = $self->{'table'}." main";
+ my $compiled_aliases = $self->{'table'}." $main_alias";
# Go through all the other aliases we set up and build the compiled
# aliases string
--- Tickets.pm Wed Mar 21 06:02:40 2001
+++ ../../../../../work/rt/lib/RT/Tickets.pm Wed Mar 21 06:07:47 2001
@@ -53,7 +53,8 @@
ContentType => 'TRANSFIELD',
Watcher => 'WATCHERFIELD',
LinkedTo => 'LINKFIELD',
- Keyword => 'KEYWORDFIELD'
+ Keyword => 'KEYWORDFIELD',
+ IsLinked => 'ISLINKFIELD',
);
# }}}
@@ -607,7 +608,66 @@
);
}
+# }}}
+
+# {{{ LimitNotLinkedTo
+sub LimitNotLinkedTo {
+ my $self = shift;
+ my $type = shift;
+
+ $self->Limit( FIELD => 'IsLinked',
+ LINKFIELD => 'LocalBase',
+ TYPE => $type,
+ OPERATOR => 'IS',
+ VALUE => 'NULL',
+ DESCRIPTION => "Not $type to any ticket",
+ );
+}
+# }}}
+
+# {{{ LimitIsLinkedTo
+sub LimitIsLinkedTo {
+ my $self = shift;
+ my $type = shift;
+
+ $self->Limit( FIELD => 'IsLinked',
+ LINKFIELD => 'LocalBase',
+ TYPE => $type,
+ OPERATOR => 'IS NOT',
+ VALUE => 'NULL',
+ DESCRIPTION => "Is $type another ticket",
+ );
+}
+# }}}
+
+# {{{ LimitNotLinkedFrom
+sub LimitNotLinkedFrom {
+ my $self = shift;
+ my $type = shift;
+ $self->Limit( FIELD => 'IsLinked',
+ LINKFIELD => 'LocalTarget',
+ TYPE => $type,
+ OPERATOR => 'IS',
+ VALUE => 'NULL',
+ DESCRIPTION => "No $type from any ticket",
+ );
+}
+# }}}
+
+# {{{ LimitIsLinkedTo
+sub LimitIsLinkedFrom {
+ my $self = shift;
+ my $type = shift;
+
+ $self->Limit( FIELD => 'IsLinked',
+ LINKFIELD => 'LocalTarget',
+ TYPE => $type,
+ OPERATOR => 'IS NOT',
+ VALUE => 'NULL',
+ DESCRIPTION => "Is $type another ticket",
+ );
+}
# }}}
# }}}
@@ -643,7 +703,6 @@
$args{'DESCRIPTION'} = $args{'FIELD'} . " " .$args{'OPERATOR'}. " ". $args{'VALUE'} . " GMT"
}
- print "Limiting ". join(';', %args) ."\n";
$self->Limit (%args);
}
@@ -704,17 +763,21 @@
OPERATOR => '=',
DESCRIPTION => undef,
FIELD => 'Keyword',
+ QUOTE => 1,
@_
);
use RT::KeywordSelect;
my $KeywordSelect = RT::KeywordSelect->new($self->CurrentUser);
$KeywordSelect->Load($args{KEYWORDSELECT});
- use RT::Keyword;
- my $Keyword = RT::Keyword->new($self->CurrentUser);
- $Keyword->Load($args{KEYWORD});
- $args{'DESCRIPTION'} ||= $KeywordSelect->Name. " $args{OPERATOR} ". $Keyword->Name;
-
+ if ($args{QUOTE}) {
+ use RT::Keyword;
+ my $Keyword = RT::Keyword->new($self->CurrentUser);
+ $Keyword->Load($args{KEYWORD});
+ $args{'DESCRIPTION'} ||= $KeywordSelect->Name. " $args{OPERATOR} ". $Keyword->Name;
+ } else {
+ $args{'DESCRIPTION'} ||= $KeywordSelect->Name ." $args{OPERATOR} $args{KEYWORD}";
+ }
my $index = $self->_NextIndex;
%{$self->{'TicketRestrictions'}{$index}} = %args;
@@ -904,6 +967,8 @@
#Blow away ticket aliases since we'll need to regenerate them for a new search
delete $self->{'TicketAliases'};
+ $self->{'islink_alias_count'} = 0;
+
my $row;
foreach $row (keys %{$self->{'TicketRestrictions'}}) {
my $restriction = $self->{'TicketRestrictions'}{$row};
@@ -1062,6 +1127,36 @@
}
# }}}
+ # {{{ if it's the existance of a relationship that we're hunting for
+ # Takes FIELD: 'IsLinked'
+ # LINKFIELD: 'LocalBase' or 'LocalTarget'
+ # TYPE: 'MemberOf' 'DependsOn' etc.
+ # OPERATOR: 'IS' (or = or != ?)
+ # VALUE: 'NULL' or 'NOT NULL' (or ticket id?)
+ elsif ( $TYPES{$restriction->{'FIELD'}} eq 'ISLINKFIELD' ) {
+ my $linkfield = $restriction->{'LINKFIELD'};
+ my $type = $restriction->{'TYPE'};
+
+ my $alias = 'Links'. '_'. $self->{'islink_alias_count'};
+ $self->{'islink_alias_count'}++;
+
+ $self->{'main_alias'} .=
+ " LEFT OUTER JOIN Links AS $alias".
+ " ON main.id = $alias.$linkfield".
+ " AND $alias.Type = ". $self->_Handle->dbh->quote($type). " ";
+
+ $self->SUPER::Limit(
+ FIELD => $linkfield,
+ VALUE => $restriction->{'VALUE'},
+ QUOTE => 0,
+ ALIAS => $alias,
+ ENTRYAGGREGATOR => 'AND',
+ OPERATOR => $restriction->{'OPERATOR'},
+ );
+
+ }
+
+ # }}}
# {{{ if it's a watcher that we're hunting for
elsif ($TYPES{$restriction->{'FIELD'}} eq 'WATCHERFIELD') {
my $Watch = $self->NewAlias('Watchers');
@@ -1103,31 +1198,27 @@
# }}}
# {{{ keyword
elsif ($TYPES{$restriction->{'FIELD'}} eq 'KEYWORDFIELD') {
- my $ObjKeywordsAlias = $self->NewAlias('ObjectKeywords');
- $self->Join(
- ALIAS1 => 'main',
- FIELD1 => 'id',
- ALIAS2 => $ObjKeywordsAlias,
- FIELD2 => 'ObjectId'
- );
+
+ my $alias;
+ $alias = 'ObjectKeywords_'. $restriction->{'KEYWORDSELECT'};
+ unless ( $self->{'TicketAliases'}{$alias} ) {
+ $self->{'TicketAliases'}{$alias} = $alias;
+ $self->{'main_alias'} .=
+ " LEFT OUTER JOIN ObjectKeywords AS $alias".
+ " ON main.id = $alias.ObjectId".
+ " AND $alias.KeywordSelect = ".
+ $self->_Handle->dbh->quote($restriction->{'KEYWORDSELECT'}).
+ " AND $alias.ObjectType = ".
+ $self->_Handle->dbh->quote('Ticket'). " ";
+ }
+
$self->SUPER::Limit(
- ALIAS => $ObjKeywordsAlias,
+ ALIAS => $alias,
FIELD => 'Keyword',
VALUE => $restriction->{'KEYWORD'},
OPERATOR => $restriction->{'OPERATOR'},
- ENTRYAGGREGATOR => 'AND',
- );
- $self->SUPER::Limit(
- ALIAS => $ObjKeywordsAlias,
- FIELD => 'KeywordSelect',
- VALUE => $restriction->{'KEYWORDSELECT'},
- ENTRYAGGREGATOR => 'AND',
- );
- $self->SUPER::Limit(
- ALIAS => $ObjKeywordsAlias,
- FIELD => 'ObjectType',
- VALUE => 'Ticket',
- ENTRYAGGREGATOR => 'AND',
+ QUOTE => $restriction->{'QUOTE'},
+ ENTRYAGGREGATOR => 'OR',
);
}
# }}}
--- Web.pm Mon Mar 19 22:55:27 2001
+++ ../../../../../../work/rt/lib/RT/Interface/Web.pm Wed Mar 21 05:38:55 2001
@@ -328,16 +379,57 @@
my $oper = $args{ARGS}->{"KeywordSelectOp$KeywordSelectId"};
foreach my $KeywordId ( ref($form) ? @{ $form } : ( $form ) ) {
if ($KeywordId) {
+ my $description = '';
+ my $quote = 1;
+ if ( $KeywordId eq 'NULL' ) {
+ $quote = 0;
+ use RT::KeywordSelect;
+ my $KeywordSelect = RT::KeywordSelect->new($session{'CurrentUser'});
+ $KeywordSelect->Load($KeywordSelectId);
+ if ( $oper eq '=' ) {
+ $oper = 'IS';
+ $description = $KeywordSelect->Name. " has no selection";
+ } elsif ( $oper eq '!=' ) {
+ $oper = 'IS NOT';
+ $description = $KeywordSelect->Name. " has a selection";
+ }
+ }
$session{'tickets'}->LimitKeyword(
KEYWORDSELECT => $KeywordSelectId,
OPERATOR => $oper,
KEYWORD => $KeywordId,
+ QUOTE => $quote,
+ DESCRIPTION => $description,
);
+ if ( $oper eq '!=' ) {
+ $session{'tickets'}->LimitKeyword(
+ KEYWORDSELECT => $KeywordSelectId,
+ OPERATOR => 'IS',
+ KEYWORD => 'NULL',
+ QUOTE => '0',
+ );
+ }
}
}
}
# }}}
+ # {{{ Limit IsLinks
+ if ($args{ARGS}->{'IsLinkType'} ne '') {
+ my @errors;
+ $args{ARGS}->{'IsLinkOp'} =~ /^(Is|Not)$/
+ or push @errors, "Illegal IsLinkOp";
+ my $method = "Limit$1";
+ $args{ARGS}->{'IsLinkType'} =~ /^(\w+)$/
+ or push @errors, "Illegal IsLinkType";
+ my $type = $1;
+ $args{ARGS}->{'IsLinkDirection'} =~ /^(From|To)$/
+ or push @errors, "Illegal IsLinkDirection";
+ $method .= "Linked$1";
+ unless ( @errors ) {
+ $session{'tickets'}->$method($type);
+ } else { die join("\n", @errors); }
+ }
+ # }}}
}
--- PickRestriction Mon Mar 19 22:55:27 2001
+++ ../../../../../work/rt/webrt/Search/PickRestriction Wed Mar 21 06:20:46 2001
@@ -69,6 +69,23 @@
&>
% }
+<li>Ticket
+<& /Elements/SelectBoolean, Name => "IsLinkOp",
+ True => "is",
+ False => "is not",
+ TrueVal => 'Is',
+ FalseVal => 'Not',
+ Default => 'Not',
+&>
+<& /Elements/SelectLinkType, Name => "IsLinkType" &>
+<& /Elements/SelectBoolean, Name => "IsLinkDirection",
+ True => "from other tickets",
+ False => "to other tickets",
+ TrueVal => "From",
+ FalseVal => "To",
+ Default => 'To',
+&>
+
</UL>
<& /Elements/TitleBoxEnd &>
--- SelectKeyword Thu Mar 8 09:59:38 2001
+++ ../../../../../work/rt/webrt/Elements/SelectKeyword Wed Mar 21
03:11:05 2001
@@ -1,5 +1,6 @@
<SELECT NAME=<%$Name%> <%$Size%> <%$Multiple%>>
<OPTION VALUE="">-</OPTION>
+<OPTION VALUE="NULL">(NULL)</OPTION>
% foreach my $kid ( keys %{$Descendents} ) {
<OPTION VALUE="<% $kid %>"
%if ($kid == $Default) {
--- SelectLinkType Fri May 19 05:42:45 2000
+++ ../../../../../work/rt/webrt/Elements/SelectLinkType Thu Mar 8
14:52:53 2001
@@ -1,6 +1,7 @@
%# $Header: /raid/cvsroot/rt/webrt/Elements/Attic/SelectLinkType,v
1.1.2.1 2000/05/19 12:42:45 tobiasb Exp $
<SELECT NAME ="<%$Name%>">
+<OPTION VALUE="">-</OPTION>
% foreach ('MemberOf', 'DependsOn', 'RefersTo') { # TODO: Merging!
<OPTION VALUE="<%$_%>"><%$_%></OPTION>
% }
--
meow
_ivan
More information about the Rt-devel
mailing list