[rt-devel] search updates
ivan
ivan-rt-devel at 420.am
Fri Mar 30 04:36:25 EST 2001
Integrating this is held up because of the Oracle broken-ness with
DISTINCT?
For now, i think we should just hack SearchBuilder.pm to not use DISTINCT
with Oracle only, and eliminate duplicates using a hash of id numbers. As
long as we don't change behavior for mysql and Pg, I don't see any reason
not to do this.
On Wed, Mar 21, 2001 at 06:23:43AM -0800, ivan wrote:
> 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
>
> _______________________________________________
> Rt-devel mailing list
> Rt-devel at lists.fsck.com
> http://lists.fsck.com/mailman/listinfo/rt-devel
--
meow
_ivan
More information about the Rt-devel
mailing list