[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