Index: appengine/monorail/proto/ast_pb2.py |
diff --git a/appengine/monorail/proto/ast_pb2.py b/appengine/monorail/proto/ast_pb2.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..db911270118c85eca4b011cdb155ac7ac3913c5a |
--- /dev/null |
+++ b/appengine/monorail/proto/ast_pb2.py |
@@ -0,0 +1,87 @@ |
+# Copyright 2016 The Chromium Authors. All rights reserved. |
+# Use of this source code is govered by a BSD-style |
+# license that can be found in the LICENSE file or at |
+# https://developers.google.com/open-source/licenses/bsd |
+ |
+"""Protocol buffers for user queries parsed into abstract syntax trees. |
+ |
+A user issue query can look like [Type=Defect owner:jrobbins "memory leak"]. |
+In that simple form, all the individual search conditions are simply ANDed |
+together. In the code, a list of conditions to be ANDed is called a |
+conjunction. |
+ |
+Monorail also supports a quick-or feature: [Type=Defect,Enhancement]. That |
+will match any issue that has labels Type-Defect or Type-Enhancement, or both. |
+ |
+TODO(jrobbins): Monorail should also support a top-level "OR" keyword that can |
+be used to logically OR a series of conjunctions. For example: |
+[Type=Defect stars>10 OR Type=Enhancement stars>50]. Right now, these queries |
+are parsed and represented in the AST, but not fully processed. |
+ |
+There are no parenthesis and no "AND" keyword. So, the AST is always exactly |
+two levels: the overall tree consistes of a list of conjunctions, and each |
+conjunction consists of a list of conditions. |
+ |
+A condition can look like [stars>10] or [summary:memory] or |
+[Type=Defect,Enhancement]. Each condition has a single comparison operator. |
+Most conditions refer to a single field definition, but in the case of |
+cross-project search a single condition can have a list of field definitions |
+from the different projects being searched. Each condition can have a list |
+of constant values to compare against. The values may be all strings or all |
+integers. |
+ |
+Some conditions are procesed by the SQL database and others by the GAE |
+search API. All conditions are passed to each module and it is up to |
+the module to decide which conditions to handle and which to ignore. |
+""" |
+ |
+from protorpc import messages |
+ |
+from proto import tracker_pb2 |
+ |
+ |
+# This is a special field_name for a FieldDef that means to do a fulltext |
+# search for words that occur in any part of the issue. |
+ANY_FIELD = 'any_field' |
+ |
+ |
+class QueryOp(messages.Enum): |
+ """Enumeration of possible query condition operators.""" |
+ EQ = 1 |
+ NE = 2 |
+ LT = 3 |
+ GT = 4 |
+ LE = 5 |
+ GE = 6 |
+ TEXT_HAS = 7 |
+ NOT_TEXT_HAS = 8 |
+ TEXT_MATCHES = 9 |
+ NOT_TEXT_MATCHES = 10 |
+ IS_DEFINED = 11 |
+ IS_NOT_DEFINED = 12 |
+ KEY_HAS = 13 |
+ |
+ |
+class Condition(messages.Message): |
+ """Representation of one query condition. E.g., [Type=Defect,Task].""" |
+ op = messages.EnumField(QueryOp, 1, required=True) |
+ field_defs = messages.MessageField(tracker_pb2.FieldDef, 2, repeated=True) |
+ str_values = messages.StringField(3, repeated=True) |
+ int_values = messages.IntegerField(4, repeated=True) |
+ |
+ |
+class Conjunction(messages.Message): |
+ """A list of conditions that are implicitly ANDed together.""" |
+ conds = messages.MessageField(Condition, 1, repeated=True) |
+ |
+ |
+class QueryAST(messages.Message): |
+ """Abstract syntax tree for the user's query.""" |
+ conjunctions = messages.MessageField(Conjunction, 1, repeated=True) |
+ |
+ |
+def MakeCond(op, field_defs, str_values, int_values): |
+ """Shorthand function to construct a Condition PB.""" |
+ return Condition( |
+ op=op, field_defs=field_defs, str_values=str_values, |
+ int_values=int_values) |