Edgewall Software

Ticket #4775: multiple_keywords_ticket_query_redone.diff

File multiple_keywords_ticket_query_redone.diff, 4.0 kB (added by wijister@…, 20 months ago)

Added support for multiple-keywords filtering

  • trac/ticket/tests/query.py

     
    312312        self.assertEqual([], args) 
    313313        tickets = query.execute(Mock(href=self.env.href)) 
    314314 
     315    def test_constrained_allof_keywords(self): 
     316        query = Query.from_string(self.env, None, 
     317                                  'keywords~=foo bar', 
     318                                  order='id') 
     319        sql, args = query.get_sql() 
     320        self.assertEqual(sql, 
     321"""SELECT t.id AS id,t.summary AS summary,t.keywords AS keywords,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.time AS time,t.changetime AS changetime,priority.value AS priority_value 
     322FROM ticket AS t 
     323  LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) 
     324WHERE (COALESCE(t.keywords,'') LIKE %s ESCAPE '/' AND COALESCE(t.keywords,'') LIKE %s ESCAPE '/') 
     325ORDER BY COALESCE(t.id,0)=0,t.id""") 
     326        self.assertEqual(['%foo%', '%bar%'], args) 
     327        tickets = query.execute(Mock(href=self.env.href)) 
     328 
    315329    def test_csv_escape(self): 
    316330        query = Mock(get_columns=lambda: ['col1'], 
    317331                     execute=lambda r,c: [{'col1': 'value, needs escaped'}]) 
     
    336350                         '<em class="error">[Error: Query filter requires ' 
    337351                         'field and constraints separated by a "="]</em>') 
    338352 
    339  
    340353def suite(): 
    341354    suite = unittest.TestSuite() 
    342355    suite.addTest(unittest.makeSuite(QueryTestCase, 'test')) 
  • trac/ticket/query.py

     
    301301 
    302302            if mode == '': 
    303303                return ("COALESCE(%s,'')%s=%%s" % (name, neg and '!' or ''), 
    304                         value) 
     304                        [value]) 
    305305            if not value: 
    306306                return None 
    307307            db = self.env.get_db_cnx() 
    308308            value = db.like_escape(value) 
     309 
     310            # special case - search for keywords separated by space 
     311            if mode == '~' and name == 't.keywords': 
     312                words = value.split(' ') 
     313                con = '(' 
     314                count = 0 
     315                args = [] 
     316                # iterate the words 
     317                for w in words: 
     318                    # word is empty, let's skip it 
     319                    if w == '': 
     320                        continue 
     321                    if count > 0: 
     322                        # need to append to the AND sequence 
     323                        con = con + ' AND '; 
     324                    con = con + "COALESCE(%s,'') %s" % (name, db.like()) 
     325                    args.append('%' + w + '%') 
     326                    count = count + 1 
     327                if (count == 0): 
     328                    # there are no words to filter by 
     329                    return None 
     330                con = con + ')' 
     331                return (con, args) 
     332 
    309333            if mode == '~': 
    310334                value = '%' + value + '%' 
    311335            elif mode == '^': 
     
    314338                value = '%' + value 
    315339            return ("COALESCE(%s,'') %s%s" % (name, neg and 'NOT ' or '', 
    316340                                              db.like()), 
    317                     value) 
     341                    [value]) 
    318342 
    319343        clauses = [] 
    320344        args = [] 
     
    368392                else: 
    369393                    clauses.append("(" + " OR ".join( 
    370394                        [item[0] for item in constraint_sql]) + ")") 
    371                 args += [item[1] for item in constraint_sql] 
     395                for item in constraint_sql: 
     396                    args.extend(item[1]) 
    372397            elif len(v) == 1: 
    373398                constraint_sql = get_constraint_sql(k, v[0], mode, neg) 
    374399                if constraint_sql: 
    375400                    clauses.append(constraint_sql[0]) 
    376                     args.append(constraint_sql[1]) 
     401                    args.extend(constraint_sql[1]) 
    377402 
    378403        clauses = filter(None, clauses) 
    379404        if clauses: