Use account table in search

Change-Id: Id7dd6342e50d1403cc6c9f3f2a882a2d2125e08d
This commit is contained in:
James E. Blair 2014-07-24 16:36:55 -07:00
parent 9195a05684
commit 9fca5b6ba4
4 changed files with 78 additions and 87 deletions

View File

@ -464,10 +464,11 @@ class DatabaseSession(object):
def getChanges(self, query, unreviewed=False):
self.database.log.debug("Search query: %s" % query)
search_filter = self.search.parse(query)
q = self.session().query(Change).filter(search_filter).order_by(change_table.c.number)
q = self.session().query(Change).filter(self.search.parse(query))
if unreviewed:
q = q.filter(change_table.c.hidden==False, change_table.c.reviewed==False)
q = q.order_by(change_table.c.number)
self.database.log.debug("Search SQL: %s" % q)
try:
return q.all()
except sqlalchemy.orm.exc.NoResultFound:

View File

@ -12,15 +12,22 @@
# License for the specific language governing permissions and limitations
# under the License.
import sqlalchemy.sql.expression
from gertty.search import tokenizer, parser
import gertty.db
class SearchSyntaxError(Exception):
pass
class SearchCompiler(object):
def __init__(self, app):
self.app = app
self.lexer = tokenizer.SearchTokenizer()
self.parser = parser.SearchParser()
def parse(self, data):
self.parser.username = self.app.config.username
return self.parser.parse(data, lexer=self.lexer)

View File

@ -16,7 +16,7 @@ import datetime
import re
import ply.yacc as yacc
from sqlalchemy.sql.expression import and_, or_
from sqlalchemy.sql.expression import and_, or_, not_, exists, select
import gertty.db
import gertty.search
@ -53,7 +53,7 @@ def SearchParser():
def p_negative_expr(p):
'''negative_expr : NOT expression
| NEG expression'''
p[0] = not p[1]
p[0] = not_(p[2])
def p_term(p):
'''term : age_term
@ -120,15 +120,35 @@ def SearchParser():
def p_owner_term(p):
'''owner_term : OP_OWNER string'''
p[0] = gertty.db.change_table.c.owner == p[2]
if p[2] == 'self':
username = p.parser.username
p[0] = gertty.db.account_table.c.username == username
else:
p[0] = or_(gertty.db.account_table.c.username == p[2],
gertty.db.account_table.c.email == p[2],
gertty.db.account_table.c.name == p[2])
def p_reviewer_term(p):
'''reviewer_term : OP_REVIEWER string'''
p[0] = gertty.db.approval_table.c.name == p[2]
filters = []
filters.append(gertty.db.approval_table.c.change_key == gertty.db.change_table.c.key)
if p[2] == 'self':
username = p.parser.username
filters.append(gertty.db.account_table.c.username == username)
else:
filters.append(or_(gertty.db.account_table.c.username == p[2],
gertty.db.account_table.c.email == p[2],
gertty.db.account_table.c.name == p[2]))
s = select([gertty.db.change_table.c.key], correlate=False).where(and_(*filters))
p[0] = gertty.db.change_table.c.key.in_(s)
def p_commit_term(p):
'''commit_term : OP_COMMIT string'''
p[0] = gertty.db.revision_table.c.commit == p[2]
filters = []
filters.append(gertty.db.revision_table.c.change_key == gertty.db.change_table.c.key)
filters.append(gertty.db.revision_table.c.commit == p[2])
s = select([gertty.db.change_table.c.key], correlate=False).where(and_(*filters))
p[0] = gertty.db.change_table.c.key.in_(s)
def p_project_term(p):
'''project_term : OP_PROJECT string'''
@ -167,6 +187,7 @@ def SearchParser():
user = args.group('user')
filters = []
filters.append(gertty.db.approval_table.c.change_key == gertty.db.change_table.c.key)
filters.append(gertty.db.approval_table.c.category == label)
if op == '=':
filters.append(gertty.db.approval_table.c.value == value)
@ -175,31 +196,58 @@ def SearchParser():
elif op == '<=':
filters.append(gertty.db.approval_table.c.value <= value)
if user is not None:
filters.append(gertty.db.approval_table.c.name == user)
p[0] = and_(*filters)
filters.append(
or_(gertty.db.account_table.c.username == user,
gertty.db.account_table.c.email == user,
gertty.db.account_table.c.name == user))
s = select([gertty.db.change_table.c.key], correlate=False).where(and_(*filters))
p[0] = gertty.db.change_table.c.key.in_(s)
def p_message_term(p):
'''message_term : OP_MESSAGE string'''
p[0] = gertty.db.revision_table.c.message.like(p[1])
filters = []
filters.append(gertty.db.revision_table.c.change_key == gertty.db.change_table.c.key)
filters.append(gertty.db.revision_table.c.message == p[2])
s = select([gertty.db.change_table.c.key], correlate=False).where(and_(*filters))
p[0] = gertty.db.change_table.c.key.in_(s)
def p_comment_term(p):
'''comment_term : OP_COMMENT string'''
p[0] = and_(gertty.db.message_table.c.message.like(p[1]),
gertty.db.comment_table.c.message.like(p[1]))
filters = []
filters.append(gertty.db.revision_table.c.change_key == gertty.db.change_table.c.key)
filters.append(gertty.db.revision_table.c.message == p[2])
revision_select = select([gertty.db.change_table.c.key], correlate=False).where(and_(*filters))
filters = []
filters.append(gertty.db.revision_table.c.change_key == gertty.db.change_table.c.key)
filters.append(gertty.db.comment_table.c.revision_key == gertty.db.revision_table.c.key)
filters.append(gertty.db.comment_table.c.message == p[2])
comment_select = select([gertty.db.change_table.c.key], correlate=False).where(and_(*filters))
p[0] = or_(gertty.db.change_table.c.key.in_(comment_select),
gertty.db.change_table.c.key.in_(revision_select))
def p_has_term(p):
'''has_term : OP_HAS string'''
#TODO: implement star
if p[2] == 'draft':
p[0] = gertty.db.message_table.c.pending == True
filters = []
filters.append(gertty.db.revision_table.c.change_key == gertty.db.change_table.c.key)
filters.append(gertty.db.message_table.c.revision_key == gertty.db.revision_table.c.key)
filters.append(gertty.db.message_table.c.pending == True)
s = select([gertty.db.change_table.c.key], correlate=False).where(and_(*filters))
p[0] = gertty.db.change_table.c.key.in_(s)
else:
raise gertty.search.SearchSyntaxError('Syntax error: has:%s is not supported' % p[2])
def p_is_term(p):
'''is_term : OP_IS string'''
#TODO: implement starred, watched, owner, reviewer, draft
username = p.parser.username
if p[2] == 'reviewed':
p[0] = gertty.db.approval_table.c.value != 0
filters = []
filters.append(gertty.db.approval_table.c.change_key == gertty.db.change_table.c.key)
filters.append(gertty.db.approval_table.c.value != 0)
s = select([gertty.db.change_table.c.key], correlate=False).where(and_(*filters))
p[0] = gertty.db.change_table.c.key.in_(s)
elif p[2] == 'open':
p[0] = gertty.db.change_table.c.status.notin_(['MERGED', 'ABANDONED'])
elif p[2] == 'closed':
@ -210,6 +258,14 @@ def SearchParser():
p[0] = gertty.db.change_table.c.status == 'MERGED'
elif p[2] == 'abandoned':
p[0] = gertty.db.change_table.c.status == 'ABANDONED'
elif p[2] == 'owner':
p[0] = gertty.db.account_table.c.username == username
elif p[2] == 'reviewer':
filters = []
filters.append(gertty.db.approval_table.c.change_key == gertty.db.change_table.c.key)
filters.append(gertty.db.account_table.c.username == username)
s = select([gertty.db.change_table.c.key], correlate=False).where(and_(*filters))
p[0] = gertty.db.change_table.c.key.in_(s)
else:
raise gertty.search.SearchSyntaxError('Syntax error: has:%s is not supported' % p[2])

View File

@ -1,73 +0,0 @@
import gertty.search
import re
import sys
label_re = re.compile(r'(?P<label>[a-zA-Z0-9_-]+([a-zA-Z]|((?<![-+])[0-9])))'
r'(?P<operator>[<>]?=?)(?P<value>[-+]?[0-9]+)'
r'($|,user=(?P<user>\S+))')
for a in [
'Code-Review=1',
'Code-Review=+1',
'Code-Review=-1',
'Code-Review>=+1',
'Code-Review<=-1',
'Code-Review+1',
'Code-Review-1',
]:
for b in [
'',
',user=corvus',
]:
data = a+b
print
print data
m = label_re.match(data)
print 'res', m and m.groups()
#sys.exit(0)
parser = gertty.search.SearchCompiler(None)
import tokenizer
lexer = tokenizer.SearchTokenizer()
lexer.input("project:foo/bar")
# Tokenize
while True:
tok = lexer.token()
if not tok: break # No more input
print tok
#TODO: unit test
for a in [
'label:Code-Review=1',
'label:Code-Review=+1',
'label:Code-Review=-1',
'label:Code-Review>=+1',
'label:Code-Review<=-1',
'label:Code-Review+1',
'label:Code-Review-1',
]:
for b in [
'',
',user=corvus',
]:
data = a+b
print
print data
result = parser.parse(data)
print 'res', str(result)
for data in [
'_project_key:18 status:open',
'project:foo/bar status:open',
'project:foo and status:open',
'project:foo or status:open',
'project:foo and (status:merged or status:new)',
'project:foo or project:bar or project:baz',
'project:foo project:bar project:baz',
]:
print
print data
result = parser.parse(data)
print 'res', str(result)