OLD | NEW |
(Empty) | |
| 1 # Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is govered by a BSD-style |
| 3 # license that can be found in the LICENSE file or at |
| 4 # https://developers.google.com/open-source/licenses/bsd |
| 5 |
| 6 """Protocol buffers for user queries parsed into abstract syntax trees. |
| 7 |
| 8 A user issue query can look like [Type=Defect owner:jrobbins "memory leak"]. |
| 9 In that simple form, all the individual search conditions are simply ANDed |
| 10 together. In the code, a list of conditions to be ANDed is called a |
| 11 conjunction. |
| 12 |
| 13 Monorail also supports a quick-or feature: [Type=Defect,Enhancement]. That |
| 14 will match any issue that has labels Type-Defect or Type-Enhancement, or both. |
| 15 |
| 16 TODO(jrobbins): Monorail should also support a top-level "OR" keyword that can |
| 17 be used to logically OR a series of conjunctions. For example: |
| 18 [Type=Defect stars>10 OR Type=Enhancement stars>50]. Right now, these queries |
| 19 are parsed and represented in the AST, but not fully processed. |
| 20 |
| 21 There are no parenthesis and no "AND" keyword. So, the AST is always exactly |
| 22 two levels: the overall tree consistes of a list of conjunctions, and each |
| 23 conjunction consists of a list of conditions. |
| 24 |
| 25 A condition can look like [stars>10] or [summary:memory] or |
| 26 [Type=Defect,Enhancement]. Each condition has a single comparison operator. |
| 27 Most conditions refer to a single field definition, but in the case of |
| 28 cross-project search a single condition can have a list of field definitions |
| 29 from the different projects being searched. Each condition can have a list |
| 30 of constant values to compare against. The values may be all strings or all |
| 31 integers. |
| 32 |
| 33 Some conditions are procesed by the SQL database and others by the GAE |
| 34 search API. All conditions are passed to each module and it is up to |
| 35 the module to decide which conditions to handle and which to ignore. |
| 36 """ |
| 37 |
| 38 from protorpc import messages |
| 39 |
| 40 from proto import tracker_pb2 |
| 41 |
| 42 |
| 43 # This is a special field_name for a FieldDef that means to do a fulltext |
| 44 # search for words that occur in any part of the issue. |
| 45 ANY_FIELD = 'any_field' |
| 46 |
| 47 |
| 48 class QueryOp(messages.Enum): |
| 49 """Enumeration of possible query condition operators.""" |
| 50 EQ = 1 |
| 51 NE = 2 |
| 52 LT = 3 |
| 53 GT = 4 |
| 54 LE = 5 |
| 55 GE = 6 |
| 56 TEXT_HAS = 7 |
| 57 NOT_TEXT_HAS = 8 |
| 58 TEXT_MATCHES = 9 |
| 59 NOT_TEXT_MATCHES = 10 |
| 60 IS_DEFINED = 11 |
| 61 IS_NOT_DEFINED = 12 |
| 62 KEY_HAS = 13 |
| 63 |
| 64 |
| 65 class Condition(messages.Message): |
| 66 """Representation of one query condition. E.g., [Type=Defect,Task].""" |
| 67 op = messages.EnumField(QueryOp, 1, required=True) |
| 68 field_defs = messages.MessageField(tracker_pb2.FieldDef, 2, repeated=True) |
| 69 str_values = messages.StringField(3, repeated=True) |
| 70 int_values = messages.IntegerField(4, repeated=True) |
| 71 |
| 72 |
| 73 class Conjunction(messages.Message): |
| 74 """A list of conditions that are implicitly ANDed together.""" |
| 75 conds = messages.MessageField(Condition, 1, repeated=True) |
| 76 |
| 77 |
| 78 class QueryAST(messages.Message): |
| 79 """Abstract syntax tree for the user's query.""" |
| 80 conjunctions = messages.MessageField(Conjunction, 1, repeated=True) |
| 81 |
| 82 |
| 83 def MakeCond(op, field_defs, str_values, int_values): |
| 84 """Shorthand function to construct a Condition PB.""" |
| 85 return Condition( |
| 86 op=op, field_defs=field_defs, str_values=str_values, |
| 87 int_values=int_values) |
OLD | NEW |