[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