blob: f20d524ac6ef42c67e76522200872841cc241566 [file] [log] [blame]
Copybara854996b2021-09-07 19:36:02 +00001# Copyright 2016 The Chromium Authors. All rights reserved.
2# Use of this source code is governed 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"""Tests for the ast2select module."""
7from __future__ import print_function
8from __future__ import division
9from __future__ import absolute_import
10
11import datetime
12import time
13import unittest
14
15from framework import sql
16from proto import ast_pb2
17from proto import tracker_pb2
18from search import ast2select
19from search import query2ast
20from tracker import tracker_bizobj
21
22
23BUILTIN_ISSUE_FIELDS = query2ast.BUILTIN_ISSUE_FIELDS
24ANY_FIELD = query2ast.BUILTIN_ISSUE_FIELDS['any_field']
25
26
27class AST2SelectTest(unittest.TestCase):
28
29 def setUp(self):
30 self.config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
31
32 def testBuildSQLQuery_EmptyAST(self):
33 ast = ast_pb2.QueryAST(conjunctions=[ast_pb2.Conjunction()]) # No conds
34 left_joins, where, unsupported = ast2select.BuildSQLQuery(ast)
35 self.assertEqual([], left_joins)
36 self.assertEqual([], where)
37 self.assertEqual([], unsupported)
38
39 def testBuildSQLQuery_Normal(self):
40 owner_field = BUILTIN_ISSUE_FIELDS['owner']
41 reporter_id_field = BUILTIN_ISSUE_FIELDS['reporter_id']
42 conds = [
43 ast_pb2.MakeCond(
44 ast_pb2.QueryOp.TEXT_HAS, [owner_field], ['example.com'], []),
45 ast_pb2.MakeCond(
46 ast_pb2.QueryOp.EQ, [reporter_id_field], [], [111])]
47 ast = ast_pb2.QueryAST(conjunctions=[ast_pb2.Conjunction(conds=conds)])
48 left_joins, where, unsupported = ast2select.BuildSQLQuery(ast)
49 self.assertEqual(
50 [('User AS Cond0 ON (Issue.owner_id = Cond0.user_id '
51 'OR Issue.derived_owner_id = Cond0.user_id)', [])],
52 left_joins)
53 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
54 self.assertEqual(
55 [('(LOWER(Cond0.email) LIKE %s)', ['%example.com%']),
56 ('Issue.reporter_id = %s', [111])],
57 where)
58 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
59 self.assertEqual([], unsupported)
60
61 def testBlockingIDCond_SingleValue(self):
62 fd = BUILTIN_ISSUE_FIELDS['blocking_id']
63 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [1])
64
65 left_joins, where, unsupported = ast2select._ProcessBlockingIDCond(
66 cond, 'Cond1', 'Issue1', snapshot_mode=False)
67 self.assertEqual(
68 [('IssueRelation AS Cond1 ON Issue.id = Cond1.dst_issue_id AND '
69 'Cond1.kind = %s AND Cond1.issue_id = %s',
70 ['blockedon', 1])],
71 left_joins)
72 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
73 self.assertEqual(
74 [('Cond1.dst_issue_id IS NOT NULL', [])],
75 where)
76 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
77 self.assertEqual([], unsupported)
78
79 def testBlockingIDCond_NegatedSingleValue(self):
80 fd = BUILTIN_ISSUE_FIELDS['blocking_id']
81 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.NE, [fd], [], [1])
82
83 left_joins, where, unsupported = ast2select._ProcessBlockingIDCond(
84 cond, 'Cond1', 'Issue1', snapshot_mode=False)
85 self.assertEqual(
86 [('IssueRelation AS Cond1 ON Issue.id = Cond1.dst_issue_id AND '
87 'Cond1.kind = %s AND Cond1.issue_id = %s',
88 ['blockedon', 1])],
89 left_joins)
90 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
91 self.assertEqual(
92 [('Cond1.dst_issue_id IS NULL', [])],
93 where)
94 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
95 self.assertEqual([], unsupported)
96
97 def testBlockingIDCond_MultiValue(self):
98 fd = BUILTIN_ISSUE_FIELDS['blocking_id']
99 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [1, 2, 3])
100
101 left_joins, where, unsupported = ast2select._ProcessBlockingIDCond(
102 cond, 'Cond1', 'Issue1', snapshot_mode=False)
103 self.assertEqual(
104 [('IssueRelation AS Cond1 ON Issue.id = Cond1.dst_issue_id AND '
105 'Cond1.kind = %s AND Cond1.issue_id IN (%s,%s,%s)',
106 ['blockedon', 1, 2, 3])],
107 left_joins)
108 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
109 self.assertEqual(
110 [('Cond1.dst_issue_id IS NOT NULL', [])],
111 where)
112 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
113 self.assertEqual([], unsupported)
114
115 def testBlockingIDCond_NegatedMultiValue(self):
116 fd = BUILTIN_ISSUE_FIELDS['blocking_id']
117 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.NE, [fd], [], [1, 2, 3])
118
119 left_joins, where, unsupported = ast2select._ProcessBlockingIDCond(
120 cond, 'Cond1', 'Issue1', snapshot_mode=False)
121 self.assertEqual(
122 [('IssueRelation AS Cond1 ON Issue.id = Cond1.dst_issue_id AND '
123 'Cond1.kind = %s AND Cond1.issue_id IN (%s,%s,%s)',
124 ['blockedon', 1, 2, 3])],
125 left_joins)
126 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
127 self.assertEqual(
128 [('Cond1.dst_issue_id IS NULL', [])],
129 where)
130 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
131 self.assertEqual([], unsupported)
132
133 def testBlockingIDCond_SnapshotMode(self):
134 fd = BUILTIN_ISSUE_FIELDS['blocking_id']
135 txt_cond = ast_pb2.MakeCond(
136 ast_pb2.QueryOp.EQ, [fd], ['b/1'], [])
137
138 left_joins, where, unsupported = ast2select._ProcessBlockingIDCond(
139 txt_cond, 'Cond1', 'Issue1', snapshot_mode=True)
140 self.assertEqual([], left_joins)
141 self.assertEqual([], where)
142 self.assertEqual([txt_cond], unsupported)
143
144 def testBlockingIDCond_ExtIssues(self):
145 fd = BUILTIN_ISSUE_FIELDS['blocking_id']
146 ne_cond = ast_pb2.MakeCond(ast_pb2.QueryOp.NE, [fd], ['b/1', 'b/2'], [])
147 eq_cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], ['b/1', 'b/2'], [])
148
149 for cond, where_str in [(eq_cond, 'DIR.issue_id IS NOT NULL'),
150 (ne_cond, 'DIR.issue_id IS NULL')]:
151 left_joins, where, unsupported = ast2select._ProcessBlockingIDCond(
152 cond, 'DIR', 'Issue1', snapshot_mode=False)
153 self.assertEqual(
154 [('DanglingIssueRelation AS DIR ON Issue.id = DIR.issue_id AND '
155 'DIR.kind = %s AND DIR.ext_issue_identifier IN (%s,%s)',
156 ['blocking', 'b/1', 'b/2'])],
157 left_joins)
158 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
159 self.assertEqual(
160 [(where_str, [])],
161 where)
162 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
163 self.assertEqual([], unsupported)
164
165 def testBlockingIDCond_CombinedIssues(self):
166 fd = BUILTIN_ISSUE_FIELDS['blocking_id']
167 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], ['b/1', 'b/2'], [1, 2])
168
169 left_joins, where, unsupported = ast2select._ProcessBlockingIDCond(
170 cond, 'Cond1', 'Issue1', snapshot_mode=False)
171 self.assertEqual(
172 ('IssueRelation AS Cond1 ON Issue.id = Cond1.dst_issue_id AND '
173 'Cond1.kind = %s AND Cond1.issue_id IN (%s,%s)',
174 ['blockedon', 1, 2]), left_joins[0])
175 self.assertEqual(
176 ('DanglingIssueRelation AS DIR ON Issue.id = DIR.issue_id AND '
177 'DIR.kind = %s AND DIR.ext_issue_identifier IN (%s,%s)',
178 ['blocking', 'b/1', 'b/2']), left_joins[1])
179 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
180 self.assertTrue(sql._IsValidJoin(left_joins[1][0]))
181 self.assertEqual(
182 [('Cond1.dst_issue_id IS NOT NULL', []),
183 ('DIR.issue_id IS NOT NULL', [])],
184 where)
185 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
186 self.assertTrue(sql._IsValidWhereCond(where[1][0]))
187 self.assertEqual([], unsupported)
188
189 def testBlockedOnIDCond_SingleValue(self):
190 fd = BUILTIN_ISSUE_FIELDS['blockedon_id']
191 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [1])
192
193 left_joins, where, unsupported = ast2select._ProcessBlockedOnIDCond(
194 cond, 'Cond1', 'Issue1', snapshot_mode=False)
195 self.assertEqual(
196 [('IssueRelation AS Cond1 ON Issue.id = Cond1.issue_id AND '
197 'Cond1.kind = %s AND Cond1.dst_issue_id = %s',
198 ['blockedon', 1])],
199 left_joins)
200 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
201 self.assertEqual(
202 [('Cond1.issue_id IS NOT NULL', [])],
203 where)
204 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
205 self.assertEqual([], unsupported)
206
207 def testBlockedOnIDCond_NegatedSingleValue(self):
208 fd = BUILTIN_ISSUE_FIELDS['blockedon_id']
209 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.NE, [fd], [], [1])
210
211 left_joins, where, unsupported = ast2select._ProcessBlockedOnIDCond(
212 cond, 'Cond1', 'Issue1', snapshot_mode=False)
213 self.assertEqual(
214 [('IssueRelation AS Cond1 ON Issue.id = Cond1.issue_id AND '
215 'Cond1.kind = %s AND Cond1.dst_issue_id = %s',
216 ['blockedon', 1])],
217 left_joins)
218 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
219 self.assertEqual(
220 [('Cond1.issue_id IS NULL', [])],
221 where)
222 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
223 self.assertEqual([], unsupported)
224
225 def testBlockedOnIDCond_MultiValue(self):
226 fd = BUILTIN_ISSUE_FIELDS['blockedon_id']
227 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [1, 2, 3])
228
229 left_joins, where, unsupported = ast2select._ProcessBlockedOnIDCond(
230 cond, 'Cond1', 'Issue1', snapshot_mode=False)
231 self.assertEqual(
232 [('IssueRelation AS Cond1 ON Issue.id = Cond1.issue_id AND '
233 'Cond1.kind = %s AND Cond1.dst_issue_id IN (%s,%s,%s)',
234 ['blockedon', 1, 2, 3])],
235 left_joins)
236 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
237 self.assertEqual(
238 [('Cond1.issue_id IS NOT NULL', [])],
239 where)
240 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
241 self.assertEqual([], unsupported)
242
243 def testBlockedOnIDCond_NegatedMultiValue(self):
244 fd = BUILTIN_ISSUE_FIELDS['blockedon_id']
245 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.NE, [fd], [], [1, 2, 3])
246
247 left_joins, where, unsupported = ast2select._ProcessBlockedOnIDCond(
248 cond, 'Cond1', 'Issue1', snapshot_mode=False)
249 self.assertEqual(
250 [('IssueRelation AS Cond1 ON Issue.id = Cond1.issue_id AND '
251 'Cond1.kind = %s AND Cond1.dst_issue_id IN (%s,%s,%s)',
252 ['blockedon', 1, 2, 3])],
253 left_joins)
254 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
255 self.assertEqual(
256 [('Cond1.issue_id IS NULL', [])],
257 where)
258 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
259 self.assertEqual([], unsupported)
260
261 def testBlockedOnIDCond_SnapshotMode(self):
262 fd = BUILTIN_ISSUE_FIELDS['blockedon_id']
263 txt_cond = ast_pb2.MakeCond(
264 ast_pb2.QueryOp.EQ, [fd], ['b/1'], [])
265
266 left_joins, where, unsupported = ast2select._ProcessBlockedOnIDCond(
267 txt_cond, 'Cond1', 'Issue1', snapshot_mode=True)
268 self.assertEqual([], left_joins)
269 self.assertEqual([], where)
270 self.assertEqual([txt_cond], unsupported)
271
272 def testBlockedOnIDCond_ExtIssues(self):
273 fd = BUILTIN_ISSUE_FIELDS['blockedon_id']
274 eq_cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], ['b/1', 'b/2'], [])
275 ne_cond = ast_pb2.MakeCond(ast_pb2.QueryOp.NE, [fd], ['b/1', 'b/2'], [])
276
277 for cond, where_str in [(eq_cond, 'DIR.issue_id IS NOT NULL'),
278 (ne_cond, 'DIR.issue_id IS NULL')]:
279 left_joins, where, unsupported = ast2select._ProcessBlockedOnIDCond(
280 cond, 'DIR', 'Issue1', snapshot_mode=False)
281 self.assertEqual(
282 [('DanglingIssueRelation AS DIR ON Issue.id = DIR.issue_id AND '
283 'DIR.kind = %s AND DIR.ext_issue_identifier IN (%s,%s)',
284 ['blockedon', 'b/1', 'b/2'])],
285 left_joins)
286 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
287 self.assertEqual(
288 [(where_str, [])],
289 where)
290 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
291 self.assertEqual([], unsupported)
292
293 def testBlockedOnIDCond_CombinedIssues(self):
294 fd = BUILTIN_ISSUE_FIELDS['blockedon_id']
295 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], ['b/1', 'b/2'], [1, 2])
296
297 left_joins, where, unsupported = ast2select._ProcessBlockedOnIDCond(
298 cond, 'Cond1', 'Issue1', snapshot_mode=False)
299 self.assertEqual(
300 ('IssueRelation AS Cond1 ON Issue.id = Cond1.issue_id AND '
301 'Cond1.kind = %s AND Cond1.dst_issue_id IN (%s,%s)',
302 ['blockedon', 1, 2]), left_joins[0])
303 self.assertEqual(
304 ('DanglingIssueRelation AS DIR ON Issue.id = DIR.issue_id AND '
305 'DIR.kind = %s AND DIR.ext_issue_identifier IN (%s,%s)',
306 ['blockedon', 'b/1', 'b/2']), left_joins[1])
307 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
308 self.assertTrue(sql._IsValidJoin(left_joins[1][0]))
309 self.assertEqual(
310 [('Cond1.issue_id IS NOT NULL', []),
311 ('DIR.issue_id IS NOT NULL', [])],
312 where)
313 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
314 self.assertTrue(sql._IsValidWhereCond(where[1][0]))
315 self.assertEqual([], unsupported)
316
317 def testMergedIntoIDCond_MultiValue(self):
318 fd = BUILTIN_ISSUE_FIELDS['mergedinto_id']
319 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [1, 2, 3])
320
321 left_joins, where, unsupported = ast2select._ProcessMergedIntoIDCond(
322 cond, 'Cond1', 'Issue1', snapshot_mode=False)
323 self.assertEqual(
324 [('IssueRelation AS Cond1 ON Issue.id = Cond1.issue_id AND '
325 'Cond1.kind = %s AND Cond1.dst_issue_id IN (%s,%s,%s)',
326 ['mergedinto', 1, 2, 3])],
327 left_joins)
328 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
329 self.assertEqual(
330 [('Cond1.issue_id IS NOT NULL', [])],
331 where)
332 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
333 self.assertEqual([], unsupported)
334
335 def testMergedIntoIDCond_SnapshotMode(self):
336 fd = BUILTIN_ISSUE_FIELDS['mergedinto_id']
337 txt_cond = ast_pb2.MakeCond(
338 ast_pb2.QueryOp.EQ, [fd], ['b/1', 'b/2', 'b/3'], [])
339
340 left_joins, where, unsupported = ast2select._ProcessMergedIntoIDCond(
341 txt_cond, 'Cond1', 'Issue1', snapshot_mode=True)
342 self.assertEqual([], left_joins)
343 self.assertEqual([], where)
344 self.assertEqual([txt_cond], unsupported)
345
346 def testMergedIntoIDCond_ExtIssues(self):
347 fd = BUILTIN_ISSUE_FIELDS['mergedinto_id']
348 eq_cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], ['b/1', 'b/2'], [])
349 ne_cond = ast_pb2.MakeCond(ast_pb2.QueryOp.NE, [fd], ['b/1', 'b/2'], [])
350
351 for cond, expected in [(eq_cond, ['b/1', 'b/2']),
352 (ne_cond, ['b/1', 'b/2'])]:
353 left_joins, where, unsupported = ast2select._ProcessMergedIntoIDCond(
354 cond, 'Cond1', 'Issue1', snapshot_mode=False)
355 self.assertEqual(
356 [('DanglingIssueRelation AS DIR ON Issue.id = DIR.issue_id AND '
357 'DIR.kind = %s AND DIR.ext_issue_identifier IN (%s,%s)',
358 ['mergedinto'] + expected)],
359 left_joins)
360 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
361 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
362 self.assertEqual([], unsupported)
363
364 def testMergedIntoIDCond_CombinedIssues(self):
365 fd = BUILTIN_ISSUE_FIELDS['mergedinto_id']
366 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], ['b/1', 'b/2'], [1, 2])
367
368 left_joins, where, unsupported = ast2select._ProcessMergedIntoIDCond(
369 cond, 'Cond1', 'Issue1', snapshot_mode=False)
370 self.assertEqual(
371 [('IssueRelation AS Cond1 ON Issue.id = Cond1.issue_id AND '
372 'Cond1.kind = %s AND Cond1.dst_issue_id IN (%s,%s)',
373 ['mergedinto', 1, 2]),
374 ('DanglingIssueRelation AS DIR ON Issue.id = DIR.issue_id AND '
375 'DIR.kind = %s AND DIR.ext_issue_identifier IN (%s,%s)',
376 ['mergedinto', 'b/1', 'b/2'])],
377 left_joins)
378 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
379 self.assertEqual(
380 [('Cond1.issue_id IS NOT NULL', []),
381 ('DIR.issue_id IS NOT NULL', [])],
382 where)
383 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
384 self.assertEqual([], unsupported)
385
386 def testHasBlockedCond(self):
387 for op, expected in ((ast_pb2.QueryOp.IS_DEFINED, 'IS NOT NULL'),
388 (ast_pb2.QueryOp.IS_NOT_DEFINED, 'IS NULL')):
389 fd = BUILTIN_ISSUE_FIELDS['blockedon_id']
390 cond = ast_pb2.MakeCond(op, [fd], [], [])
391
392 left_joins, where, unsupported = ast2select._ProcessBlockedOnIDCond(
393 cond, 'Cond1', None, snapshot_mode=False)
394 self.assertEqual(
395 ('IssueRelation AS Cond1 ON Issue.id = Cond1.issue_id AND '
396 'Cond1.kind = %s', ['blockedon']),
397 left_joins[0])
398 self.assertEqual(
399 ('DanglingIssueRelation AS DIR ON Issue.id = DIR.issue_id AND '
400 'DIR.kind = %s', ['blockedon']),
401 left_joins[1])
402 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
403 self.assertTrue(sql._IsValidJoin(left_joins[1][0]))
404 self.assertEqual([('(Cond1.issue_id %s OR DIR.issue_id %s)'
405 % (expected, expected), [])], where)
406 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
407 self.assertEqual([], unsupported)
408
409 def testHasBlockedCond_SnapshotMode(self):
410 op = ast_pb2.QueryOp.IS_DEFINED
411 fd = BUILTIN_ISSUE_FIELDS['blockedon_id']
412 cond = ast_pb2.MakeCond(op, [fd], [], [])
413
414 left_joins, where, unsupported = ast2select._ProcessBlockingIDCond(
415 cond, 'Cond1', 'Issue1', snapshot_mode=True)
416 self.assertEqual([], left_joins)
417 self.assertEqual([], where)
418 self.assertEqual([cond], unsupported)
419
420 def testHasBlockingCond(self):
421 for op, expected in ((ast_pb2.QueryOp.IS_DEFINED, 'IS NOT NULL'),
422 (ast_pb2.QueryOp.IS_NOT_DEFINED, 'IS NULL')):
423 fd = BUILTIN_ISSUE_FIELDS['blocking_id']
424 cond = ast_pb2.MakeCond(op, [fd], [], [])
425
426 left_joins, where, unsupported = ast2select._ProcessBlockingIDCond(cond,
427 'Cond1', None, snapshot_mode=False)
428 self.assertEqual(
429 ('IssueRelation AS Cond1 ON Issue.id = Cond1.dst_issue_id AND '
430 'Cond1.kind = %s', ['blockedon']),
431 left_joins[0])
432 self.assertEqual(
433 ('DanglingIssueRelation AS DIR ON Issue.id = DIR.issue_id AND '
434 'DIR.kind = %s', ['blocking']),
435 left_joins[1])
436 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
437 self.assertTrue(sql._IsValidJoin(left_joins[1][0]))
438 self.assertEqual([('(Cond1.dst_issue_id %s OR DIR.issue_id %s)'
439 % (expected, expected), [])], where)
440 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
441 self.assertEqual([], unsupported)
442
443 def testHasBlockingCond_SnapshotMode(self):
444 op = ast_pb2.QueryOp.IS_DEFINED
445 fd = BUILTIN_ISSUE_FIELDS['blocking_id']
446 cond = ast_pb2.MakeCond(op, [fd], [], [])
447
448 left_joins, where, unsupported = ast2select._ProcessBlockingIDCond(
449 cond, 'Cond1', 'Issue1', snapshot_mode=True)
450 self.assertEqual([], left_joins)
451 self.assertEqual([], where)
452 self.assertEqual([cond], unsupported)
453
454 def testProcessOwnerCond(self):
455 fd = BUILTIN_ISSUE_FIELDS['owner']
456 cond = ast_pb2.MakeCond(
457 ast_pb2.QueryOp.TEXT_HAS, [fd], ['example.com'], [])
458 left_joins, where, unsupported = ast2select._ProcessOwnerCond(cond, 'Cond1',
459 'Spare1', snapshot_mode=False)
460 self.assertEqual(
461 [('User AS Cond1 ON (Issue.owner_id = Cond1.user_id '
462 'OR Issue.derived_owner_id = Cond1.user_id)', [])],
463 left_joins)
464 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
465 self.assertEqual(
466 [('(LOWER(Cond1.email) LIKE %s)', ['%example.com%'])],
467 where)
468 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
469 self.assertEqual([], unsupported)
470
471 def testProcessOwnerCond_SnapshotMode(self):
472 fd = BUILTIN_ISSUE_FIELDS['owner']
473 cond = ast_pb2.MakeCond(
474 ast_pb2.QueryOp.TEXT_HAS, [fd], ['example.com'], [])
475 left_joins, where, unsupported = ast2select._ProcessOwnerCond(cond, 'Cond1',
476 'Spare1', snapshot_mode=True)
477 self.assertEqual(
478 [('User AS Cond1 ON IssueSnapshot.owner_id = Cond1.user_id', [])],
479 left_joins)
480 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
481 self.assertEqual(
482 [('(LOWER(Cond1.email) LIKE %s)', ['%example.com%'])],
483 where)
484 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
485 self.assertEqual([], unsupported)
486
487 def testProcessOwnerIDCond(self):
488 fd = BUILTIN_ISSUE_FIELDS['owner_id']
489 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [111])
490 left_joins, where, unsupported = ast2select._ProcessOwnerIDCond(cond,
491 'Cond1', 'Spare1', snapshot_mode=False)
492 self.assertEqual([], left_joins)
493 self.assertEqual(
494 [('(Issue.owner_id = %s OR Issue.derived_owner_id = %s)',
495 [111, 111])],
496 where)
497 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
498 self.assertEqual([], unsupported)
499
500 def testProcessOwnerIDCond_SnapshotMode(self):
501 fd = BUILTIN_ISSUE_FIELDS['owner_id']
502 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [111])
503 left_joins, where, unsupported = ast2select._ProcessOwnerIDCond(cond,
504 'Cond1', 'Spare1', snapshot_mode=True)
505 self.assertEqual([], left_joins)
506 self.assertEqual([('IssueSnapshot.owner_id = %s', [111])], where)
507 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
508 self.assertEqual([], unsupported)
509
510 def testProcessOwnerLastVisitCond(self):
511 fd = BUILTIN_ISSUE_FIELDS['ownerlastvisit']
512 NOW = 1234567890
513 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.LT, [fd], [], [NOW])
514 left_joins, where, unsupported = ast2select._ProcessOwnerLastVisitCond(
515 cond, 'Cond1', 'Spare1', snapshot_mode=False)
516 self.assertEqual(
517 [('User AS Cond1 ON (Issue.owner_id = Cond1.user_id OR '
518 'Issue.derived_owner_id = Cond1.user_id)',
519 [])],
520 left_joins)
521 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
522 self.assertEqual(
523 [('Cond1.last_visit_timestamp < %s',
524 [NOW])],
525 where)
526 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
527 self.assertEqual([], unsupported)
528
529 def testProcessOwnerLastVisitCond_SnapshotMode(self):
530 fd = BUILTIN_ISSUE_FIELDS['ownerlastvisit']
531 NOW = 1234567890
532 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.LT, [fd], [], [NOW])
533 left_joins, where, unsupported = ast2select._ProcessOwnerLastVisitCond(
534 cond, 'Cond1', 'Spare1', snapshot_mode=True)
535 self.assertEqual([], left_joins)
536 self.assertEqual([], where)
537 self.assertEqual([cond], unsupported)
538
539 def testProcessIsOwnerBouncing(self):
540 fd = BUILTIN_ISSUE_FIELDS['ownerbouncing']
541 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [])
542 left_joins, where, unsupported = ast2select._ProcessIsOwnerBouncing(
543 cond, 'Cond1', 'Spare1', snapshot_mode=False)
544 self.assertEqual(
545 [('User AS Cond1 ON (Issue.owner_id = Cond1.user_id OR '
546 'Issue.derived_owner_id = Cond1.user_id)',
547 [])],
548 left_joins)
549 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
550 self.assertEqual(
551 [('(Cond1.email_bounce_timestamp IS NOT NULL AND'
552 ' Cond1.email_bounce_timestamp != %s)',
553 [0])],
554 where)
555 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
556 self.assertEqual([], unsupported)
557
558 def testProcessIsOwnerBouncing_SnapshotMode(self):
559 fd = BUILTIN_ISSUE_FIELDS['ownerbouncing']
560 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [])
561 left_joins, where, unsupported = ast2select._ProcessIsOwnerBouncing(
562 cond, 'Cond1', 'Spare1', snapshot_mode=True)
563 self.assertEqual([], left_joins)
564 self.assertEqual([], where)
565 self.assertEqual([cond], unsupported)
566
567 def testProcessReporterCond(self):
568 fd = BUILTIN_ISSUE_FIELDS['reporter']
569 cond = ast_pb2.MakeCond(
570 ast_pb2.QueryOp.TEXT_HAS, [fd], ['example.com'], [])
571 left_joins, where, unsupported = ast2select._ProcessReporterCond(cond,
572 'Cond1', 'Spare1', snapshot_mode=False)
573 self.assertEqual(
574 [('User AS Cond1 ON Issue.reporter_id = Cond1.user_id', [])],
575 left_joins)
576 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
577 self.assertEqual(
578 [('(LOWER(Cond1.email) LIKE %s)', ['%example.com%'])],
579 where)
580 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
581 self.assertEqual([], unsupported)
582
583 def testProcessReporterCond_SnapshotMode(self):
584 fd = BUILTIN_ISSUE_FIELDS['reporter']
585 cond = ast_pb2.MakeCond(
586 ast_pb2.QueryOp.TEXT_HAS, [fd], ['example.com'], [])
587 left_joins, where, unsupported = ast2select._ProcessReporterCond(cond,
588 'Cond1', 'Spare1', snapshot_mode=True)
589 self.assertEqual(
590 [('User AS Cond1 ON IssueSnapshot.reporter_id = Cond1.user_id', [])],
591 left_joins)
592 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
593 self.assertEqual(
594 [('(LOWER(Cond1.email) LIKE %s)', ['%example.com%'])],
595 where)
596 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
597 self.assertEqual([], unsupported)
598
599 def testProcessReporterIDCond(self):
600 fd = BUILTIN_ISSUE_FIELDS['reporter_id']
601 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [111])
602 left_joins, where, unsupported = ast2select._ProcessReporterIDCond(
603 cond, 'Cond1', 'Spare1', snapshot_mode=False)
604 self.assertEqual([], left_joins)
605 self.assertEqual(
606 [('Issue.reporter_id = %s', [111])],
607 where)
608 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
609 self.assertEqual([], unsupported)
610
611 def testProcessReporterIDCond_SnapshotMode(self):
612 fd = BUILTIN_ISSUE_FIELDS['reporter_id']
613 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [111])
614 left_joins, where, unsupported = ast2select._ProcessReporterIDCond(
615 cond, 'Cond1', 'Spare1', snapshot_mode=True)
616 self.assertEqual([], left_joins)
617 self.assertEqual(
618 [('IssueSnapshot.reporter_id = %s', [111])],
619 where)
620 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
621 self.assertEqual([], unsupported)
622
623 def testProcessCcCond_SinglePositive(self):
624 fd = BUILTIN_ISSUE_FIELDS['cc']
625 cond = ast_pb2.MakeCond(
626 ast_pb2.QueryOp.TEXT_HAS, [fd], ['example.com'], [])
627 left_joins, where, unsupported = ast2select._ProcessCcCond(cond, 'Cond1',
628 'Spare1', snapshot_mode=False)
629 self.assertEqual(
630 [('(Issue2Cc AS Cond1 JOIN User AS Spare1 '
631 'ON Cond1.cc_id = Spare1.user_id AND (LOWER(Spare1.email) LIKE %s)) '
632 'ON Issue.id = Cond1.issue_id AND Issue.shard = Cond1.issue_shard',
633 ['%example.com%'])],
634 left_joins)
635 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
636 self.assertEqual(
637 [('Spare1.email IS NOT NULL', [])],
638 where)
639 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
640 self.assertEqual([], unsupported)
641
642 def testProcessCcCond_SinglePositive_SnapshotMode(self):
643 fd = BUILTIN_ISSUE_FIELDS['cc']
644 cond = ast_pb2.MakeCond(
645 ast_pb2.QueryOp.TEXT_HAS, [fd], ['example.com'], [])
646 left_joins, where, unsupported = ast2select._ProcessCcCond(cond, 'Cond1',
647 'Spare1', snapshot_mode=True)
648 self.assertEqual(
649 [('(IssueSnapshot2Cc AS Cond1 JOIN User AS Spare1 '
650 'ON Cond1.cc_id = Spare1.user_id AND (LOWER(Spare1.email) LIKE %s)) '
651 'ON IssueSnapshot.id = Cond1.issuesnapshot_id',
652 ['%example.com%'])],
653 left_joins)
654 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
655 self.assertEqual(
656 [('Spare1.email IS NOT NULL', [])],
657 where)
658 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
659 self.assertEqual([], unsupported)
660
661 def testProcessCcCond_MultiplePositive(self):
662 fd = BUILTIN_ISSUE_FIELDS['cc']
663 cond = ast_pb2.MakeCond(
664 ast_pb2.QueryOp.TEXT_HAS, [fd], ['.com', '.org'], [])
665 left_joins, where, unsupported = ast2select._ProcessCcCond(cond, 'Cond1',
666 'Spare1', snapshot_mode=False)
667 self.assertEqual(
668 [('(Issue2Cc AS Cond1 JOIN User AS Spare1 '
669 'ON Cond1.cc_id = Spare1.user_id AND '
670 '(LOWER(Spare1.email) LIKE %s OR LOWER(Spare1.email) LIKE %s)) '
671 'ON Issue.id = Cond1.issue_id AND Issue.shard = Cond1.issue_shard',
672 ['%.com%', '%.org%'])],
673 left_joins)
674 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
675 self.assertEqual(
676 [('Spare1.email IS NOT NULL', [])],
677 where)
678 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
679 self.assertEqual([], unsupported)
680
681 def testProcessCcCond_MultiplePositive_SnapshotMode(self):
682 fd = BUILTIN_ISSUE_FIELDS['cc']
683 cond = ast_pb2.MakeCond(
684 ast_pb2.QueryOp.TEXT_HAS, [fd], ['.com', '.org'], [])
685 left_joins, where, unsupported = ast2select._ProcessCcCond(cond, 'Cond1',
686 'Spare1', snapshot_mode=True)
687 self.assertEqual(
688 [('(IssueSnapshot2Cc AS Cond1 JOIN User AS Spare1 '
689 'ON Cond1.cc_id = Spare1.user_id AND '
690 '(LOWER(Spare1.email) LIKE %s OR LOWER(Spare1.email) LIKE %s)) '
691 'ON IssueSnapshot.id = Cond1.issuesnapshot_id',
692 ['%.com%', '%.org%'])],
693 left_joins)
694 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
695 self.assertEqual(
696 [('Spare1.email IS NOT NULL', [])],
697 where)
698 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
699 self.assertEqual([], unsupported)
700
701 def testProcessCcCond_SingleNegative(self):
702 fd = BUILTIN_ISSUE_FIELDS['cc']
703 cond = ast_pb2.MakeCond(
704 ast_pb2.QueryOp.NOT_TEXT_HAS, [fd], ['example.com'], [])
705 left_joins, where, unsupported = ast2select._ProcessCcCond(cond, 'Cond1',
706 'Spare1', snapshot_mode=False)
707 self.assertEqual(
708 [('(Issue2Cc AS Cond1 JOIN User AS Spare1 '
709 'ON Cond1.cc_id = Spare1.user_id AND (LOWER(Spare1.email) LIKE %s)) '
710 'ON Issue.id = Cond1.issue_id AND Issue.shard = Cond1.issue_shard',
711 ['%example.com%'])],
712 left_joins)
713 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
714 self.assertEqual(
715 [('Spare1.email IS NULL', [])],
716 where)
717 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
718 self.assertEqual([], unsupported)
719
720 def testProcessCcCond_SingleNegative_SnapshotMode(self):
721 fd = BUILTIN_ISSUE_FIELDS['cc']
722 cond = ast_pb2.MakeCond(
723 ast_pb2.QueryOp.NOT_TEXT_HAS, [fd], ['example.com'], [])
724 left_joins, where, unsupported = ast2select._ProcessCcCond(cond, 'Cond1',
725 'Spare1', snapshot_mode=True)
726 self.assertEqual(
727 [('(IssueSnapshot2Cc AS Cond1 JOIN User AS Spare1 '
728 'ON Cond1.cc_id = Spare1.user_id AND (LOWER(Spare1.email) LIKE %s)) '
729 'ON IssueSnapshot.id = Cond1.issuesnapshot_id',
730 ['%example.com%'])],
731 left_joins)
732 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
733 self.assertEqual(
734 [('Spare1.email IS NULL', [])],
735 where)
736 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
737 self.assertEqual([], unsupported)
738
739 def testProcessCcCond_Multiplenegative(self):
740 fd = BUILTIN_ISSUE_FIELDS['cc']
741 cond = ast_pb2.MakeCond(
742 ast_pb2.QueryOp.NOT_TEXT_HAS, [fd], ['.com', '.org'], [])
743 left_joins, where, unsupported = ast2select._ProcessCcCond(cond, 'Cond1',
744 'Spare1', snapshot_mode=False)
745 self.assertEqual(
746 [('(Issue2Cc AS Cond1 JOIN User AS Spare1 '
747 'ON Cond1.cc_id = Spare1.user_id AND '
748 '(LOWER(Spare1.email) LIKE %s OR LOWER(Spare1.email) LIKE %s)) '
749 'ON Issue.id = Cond1.issue_id AND Issue.shard = Cond1.issue_shard',
750 ['%.com%', '%.org%'])],
751 left_joins)
752 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
753 self.assertEqual(
754 [('Spare1.email IS NULL', [])],
755 where)
756 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
757 self.assertEqual([], unsupported)
758
759 def testProcessCcCond_Multiplenegative_SnapshotMode(self):
760 fd = BUILTIN_ISSUE_FIELDS['cc']
761 cond = ast_pb2.MakeCond(
762 ast_pb2.QueryOp.NOT_TEXT_HAS, [fd], ['.com', '.org'], [])
763 left_joins, where, unsupported = ast2select._ProcessCcCond(cond, 'Cond1',
764 'Spare1', snapshot_mode=True)
765 self.assertEqual(
766 [('(IssueSnapshot2Cc AS Cond1 JOIN User AS Spare1 '
767 'ON Cond1.cc_id = Spare1.user_id AND '
768 '(LOWER(Spare1.email) LIKE %s OR LOWER(Spare1.email) LIKE %s)) '
769 'ON IssueSnapshot.id = Cond1.issuesnapshot_id',
770 ['%.com%', '%.org%'])],
771 left_joins)
772 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
773 self.assertEqual(
774 [('Spare1.email IS NULL', [])],
775 where)
776 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
777 self.assertEqual([], unsupported)
778
779 def testProcessCcIDCond(self):
780 fd = BUILTIN_ISSUE_FIELDS['cc_id']
781 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [111])
782 left_joins, where, unsupported = ast2select._ProcessCcIDCond(cond, 'Cond1',
783 'Spare1', snapshot_mode=False)
784 self.assertEqual(
785 [('Issue2Cc AS Cond1 ON Issue.id = Cond1.issue_id AND '
786 'Issue.shard = Cond1.issue_shard AND '
787 'Cond1.cc_id = %s',
788 [111])],
789 left_joins)
790 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
791 self.assertEqual(
792 [('Cond1.cc_id IS NOT NULL', [])],
793 where)
794 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
795 self.assertEqual([], unsupported)
796
797 def testProcessCcIDCond_SnapshotMode(self):
798 fd = BUILTIN_ISSUE_FIELDS['cc_id']
799 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [111])
800 left_joins, where, unsupported = ast2select._ProcessCcIDCond(cond, 'Cond1',
801 'Spare1', snapshot_mode=True)
802 self.assertEqual(
803 [('IssueSnapshot2Cc AS Cond1 '
804 'ON IssueSnapshot.id = Cond1.issuesnapshot_id '
805 'AND Cond1.cc_id = %s',
806 [111])],
807 left_joins)
808 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
809 self.assertEqual(
810 [('Cond1.cc_id IS NOT NULL', [])],
811 where)
812 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
813 self.assertEqual([], unsupported)
814
815 def testProcessStarredByCond(self):
816 fd = BUILTIN_ISSUE_FIELDS['starredby']
817 cond = ast_pb2.MakeCond(
818 ast_pb2.QueryOp.TEXT_HAS, [fd], ['example.com'], [])
819 left_joins, where, unsupported = ast2select._ProcessStarredByCond(
820 cond, 'Cond1', 'Spare1', snapshot_mode=False)
821 self.assertEqual(
822 [('(IssueStar AS Cond1 JOIN User AS Spare1 '
823 'ON Cond1.user_id = Spare1.user_id AND '
824 '(LOWER(Spare1.email) LIKE %s)) '
825 'ON Issue.id = Cond1.issue_id', ['%example.com%'])],
826 left_joins)
827 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
828 self.assertEqual(
829 [('Spare1.email IS NOT NULL', [])],
830 where)
831 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
832 self.assertEqual([], unsupported)
833
834 def testProcessStarredByCond_SnapshotMode(self):
835 fd = BUILTIN_ISSUE_FIELDS['starredby']
836 cond = ast_pb2.MakeCond(
837 ast_pb2.QueryOp.TEXT_HAS, [fd], ['example.com'], [])
838 left_joins, where, unsupported = ast2select._ProcessStarredByCond(
839 cond, 'Cond1', 'Spare1', snapshot_mode=True)
840 self.assertEqual([], left_joins)
841 self.assertEqual([], where)
842 self.assertEqual([cond], unsupported)
843
844 def testProcessStarredByIDCond(self):
845 fd = BUILTIN_ISSUE_FIELDS['starredby_id']
846 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [111])
847 left_joins, where, unsupported = ast2select._ProcessStarredByIDCond(
848 cond, 'Cond1', 'Spare1', snapshot_mode=False)
849 self.assertEqual(
850 [('IssueStar AS Cond1 ON Issue.id = Cond1.issue_id '
851 'AND Cond1.user_id = %s', [111])],
852 left_joins)
853 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
854 self.assertEqual(
855 [('Cond1.user_id IS NOT NULL', [])],
856 where)
857 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
858 self.assertEqual([], unsupported)
859
860 def testProcessStarredByIDCond_SnapshotMode(self):
861 fd = BUILTIN_ISSUE_FIELDS['starredby_id']
862 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [111])
863 left_joins, where, unsupported = ast2select._ProcessStarredByIDCond(
864 cond, 'Cond1', 'Spare1', snapshot_mode=True)
865 self.assertEqual([], left_joins)
866 self.assertEqual([], where)
867 self.assertEqual([cond], unsupported)
868
869 def testProcessCommentByCond(self):
870 fd = BUILTIN_ISSUE_FIELDS['commentby']
871 cond = ast_pb2.MakeCond(
872 ast_pb2.QueryOp.TEXT_HAS, [fd], ['example.com'], [])
873 left_joins, where, unsupported = ast2select._ProcessCommentByCond(
874 cond, 'Cond1', 'Spare1', snapshot_mode=False)
875 self.assertEqual(
876 [('(Comment AS Cond1 JOIN User AS Spare1 '
877 'ON Cond1.commenter_id = Spare1.user_id '
878 'AND (LOWER(Spare1.email) LIKE %s)) '
879 'ON Issue.id = Cond1.issue_id AND Cond1.deleted_by IS NULL',
880 ['%example.com%'])],
881 left_joins)
882 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
883 self.assertEqual(
884 [('Spare1.email IS NOT NULL', [])],
885 where)
886 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
887 self.assertEqual([], unsupported)
888
889 def testProcessCommentByCond_SnapshotMode(self):
890 fd = BUILTIN_ISSUE_FIELDS['commentby']
891 cond = ast_pb2.MakeCond(
892 ast_pb2.QueryOp.TEXT_HAS, [fd], ['example.com'], [])
893 left_joins, where, unsupported = ast2select._ProcessCommentByCond(
894 cond, 'Cond1', 'Spare1', snapshot_mode=True)
895 self.assertEqual([], left_joins)
896 self.assertEqual([], where)
897 self.assertEqual([cond], unsupported)
898
899 def testProcessCommentByIDCond_EqualsUserID(self):
900 fd = BUILTIN_ISSUE_FIELDS['commentby_id']
901 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [111])
902 left_joins, where, unsupported = ast2select._ProcessCommentByIDCond(
903 cond, 'Cond1', 'Spare1', snapshot_mode=False)
904 self.assertEqual(
905 [('Comment AS Cond1 ON Issue.id = Cond1.issue_id AND '
906 'Cond1.commenter_id = %s AND Cond1.deleted_by IS NULL',
907 [111])],
908 left_joins)
909 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
910 self.assertEqual(
911 [('Cond1.commenter_id IS NOT NULL', [])],
912 where)
913 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
914 self.assertEqual([], unsupported)
915
916 def testProcessCommentByIDCond_EqualsUserID_SnapshotMode(self):
917 fd = BUILTIN_ISSUE_FIELDS['commentby_id']
918 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [111])
919 left_joins, where, unsupported = ast2select._ProcessCommentByIDCond(
920 cond, 'Cond1', 'Spare1', snapshot_mode=True)
921 self.assertEqual([], left_joins)
922 self.assertEqual([], where)
923 self.assertEqual([cond], unsupported)
924
925 def testProcessCommentByIDCond_QuickOr(self):
926 fd = BUILTIN_ISSUE_FIELDS['commentby_id']
927 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [111, 222])
928 left_joins, where, unsupported = ast2select._ProcessCommentByIDCond(
929 cond, 'Cond1', 'Spare1', snapshot_mode=False)
930 self.assertEqual(
931 [('Comment AS Cond1 ON Issue.id = Cond1.issue_id AND '
932 'Cond1.commenter_id IN (%s,%s) '
933 'AND Cond1.deleted_by IS NULL',
934 [111, 222])],
935 left_joins)
936 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
937 self.assertEqual(
938 [('Cond1.commenter_id IS NOT NULL', [])],
939 where)
940 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
941 self.assertEqual([], unsupported)
942
943 def testProcessCommentByIDCond_NotEqualsUserID(self):
944 fd = BUILTIN_ISSUE_FIELDS['commentby_id']
945 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.NE, [fd], [], [111])
946 left_joins, where, unsupported = ast2select._ProcessCommentByIDCond(
947 cond, 'Cond1', 'Spare1', snapshot_mode=False)
948 self.assertEqual(
949 [('Comment AS Cond1 ON Issue.id = Cond1.issue_id AND '
950 'Cond1.commenter_id = %s AND Cond1.deleted_by IS NULL',
951 [111])],
952 left_joins)
953 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
954 self.assertEqual(
955 [('Cond1.commenter_id IS NULL', [])],
956 where)
957 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
958 self.assertEqual([], unsupported)
959
960 def testProcessStatusIDCond(self):
961 fd = BUILTIN_ISSUE_FIELDS['status_id']
962 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [2])
963 left_joins, where, unsupported = ast2select._ProcessStatusIDCond(cond,
964 'Cond1', 'Spare1', snapshot_mode=False)
965 self.assertEqual([], left_joins)
966 self.assertEqual(
967 [('(Issue.status_id = %s OR Issue.derived_status_id = %s)', [2, 2])],
968 where)
969 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
970 self.assertEqual([], unsupported)
971
972 def testProcessStatusIDCond_SnapshotMode(self):
973 fd = BUILTIN_ISSUE_FIELDS['status_id']
974 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [2])
975 left_joins, where, unsupported = ast2select._ProcessStatusIDCond(cond,
976 'Cond1', 'Spare1', snapshot_mode=True)
977 self.assertEqual([], left_joins)
978 self.assertEqual([('IssueSnapshot.status_id = %s', [2])], where)
979 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
980 self.assertEqual([], unsupported)
981
982 def testProcessSummaryCond(self):
983 fd = BUILTIN_ISSUE_FIELDS['summary']
984 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], ['sum'], [])
985 left_joins, where, unsupported = ast2select._ProcessSummaryCond(cond,
986 'Cond1', 'Spare1', snapshot_mode=False)
987 self.assertEqual(
988 [('IssueSummary AS Cond1 ON Issue.id = Cond1.issue_id AND '
989 'Cond1.summary = %s', ['sum'])],
990 left_joins)
991 self.assertEqual(
992 [('Cond1.issue_id IS NOT NULL', [])],
993 where)
994 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
995 self.assertEqual([], unsupported)
996
997 def testProcessSummaryCond_SnapshotMode(self):
998 """Issue summary is not currently included in issue snapshot, so ignore."""
999 fd = BUILTIN_ISSUE_FIELDS['summary']
1000 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], ['sum'], [])
1001 left_joins, where, unsupported = ast2select._ProcessSummaryCond(cond,
1002 'Cond1', 'Spare1', snapshot_mode=True)
1003 self.assertEqual([], left_joins)
1004 self.assertEqual([], where)
1005 self.assertEqual([cond], unsupported)
1006
1007 def testProcessLabelIDCond_NoValue(self):
1008 fd = BUILTIN_ISSUE_FIELDS['label_id']
1009 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [])
1010 with self.assertRaises(ast2select.NoPossibleResults):
1011 ast2select._ProcessLabelIDCond(cond, 'Cond1', 'Spare1',
1012 snapshot_mode=False)
1013
1014 def testProcessLabelIDCond_SingleValue(self):
1015 fd = BUILTIN_ISSUE_FIELDS['label_id']
1016 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [1])
1017 left_joins, where, unsupported = ast2select._ProcessLabelIDCond(cond,
1018 'Cond1', 'Spare1', snapshot_mode=False)
1019 self.assertEqual(
1020 [('Issue2Label AS Cond1 ON Issue.id = Cond1.issue_id AND '
1021 'Issue.shard = Cond1.issue_shard AND '
1022 'Cond1.label_id = %s', [1])],
1023 left_joins)
1024 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
1025 self.assertEqual(
1026 [('Cond1.label_id IS NOT NULL', [])],
1027 where)
1028 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
1029 self.assertEqual([], unsupported)
1030
1031 def testProcessLabelIDCond_SingleValue_SnapshotMode(self):
1032 fd = BUILTIN_ISSUE_FIELDS['label_id']
1033 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [1])
1034 left_joins, where, unsupported = ast2select._ProcessLabelIDCond(cond,
1035 'Cond1', 'Spare1', snapshot_mode=True)
1036 self.assertEqual(
1037 [('IssueSnapshot2Label AS Cond1 '
1038 'ON IssueSnapshot.id = Cond1.issuesnapshot_id AND '
1039 'Cond1.label_id = %s', [1])],
1040 left_joins)
1041 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
1042 self.assertEqual(
1043 [('Cond1.label_id IS NOT NULL', [])],
1044 where)
1045 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
1046 self.assertEqual([], unsupported)
1047
1048 def testProcessLabelIDCond_MultipleValue(self):
1049 fd = BUILTIN_ISSUE_FIELDS['label_id']
1050 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [1, 2])
1051 left_joins, where, unsupported = ast2select._ProcessLabelIDCond(cond,
1052 'Cond1', 'Spare1', snapshot_mode=False)
1053 self.assertEqual(
1054 [('Issue2Label AS Cond1 ON Issue.id = Cond1.issue_id AND '
1055 'Issue.shard = Cond1.issue_shard AND '
1056 'Cond1.label_id IN (%s,%s)', [1, 2])],
1057 left_joins)
1058 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
1059 self.assertEqual(
1060 [('Cond1.label_id IS NOT NULL', [])],
1061 where)
1062 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
1063 self.assertEqual([], unsupported)
1064
1065 def testProcessLabelIDCond_NegatedNoValue(self):
1066 fd = BUILTIN_ISSUE_FIELDS['label_id']
1067 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.NE, [fd], [], [])
1068 left_joins, where, unsupported = ast2select._ProcessLabelIDCond(cond,
1069 'Cond1', 'Spare1', snapshot_mode=False)
1070 self.assertEqual([], left_joins)
1071 self.assertEqual([], where)
1072 self.assertEqual([], unsupported)
1073
1074 def testProcessLabelIDCond_NegatedSingleValue(self):
1075 fd = BUILTIN_ISSUE_FIELDS['label_id']
1076 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.NE, [fd], [], [1])
1077 left_joins, where, unsupported = ast2select._ProcessLabelIDCond(cond,
1078 'Cond1', 'Spare1', snapshot_mode=False)
1079 self.assertEqual(
1080 [('Issue2Label AS Cond1 ON Issue.id = Cond1.issue_id AND '
1081 'Issue.shard = Cond1.issue_shard AND '
1082 'Cond1.label_id = %s', [1])],
1083 left_joins)
1084 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
1085 self.assertEqual(
1086 [('Cond1.label_id IS NULL', [])],
1087 where)
1088 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
1089 self.assertEqual([], unsupported)
1090
1091 def testProcessLabelIDCond_NegatedSingleValue_SnapshotMode(self):
1092 fd = BUILTIN_ISSUE_FIELDS['label_id']
1093 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.NE, [fd], [], [1])
1094 left_joins, where, unsupported = ast2select._ProcessLabelIDCond(cond,
1095 'Cond1', 'Spare1', snapshot_mode=True)
1096 self.assertEqual(
1097 [('IssueSnapshot2Label AS Cond1 '
1098 'ON IssueSnapshot.id = Cond1.issuesnapshot_id AND '
1099 'Cond1.label_id = %s', [1])],
1100 left_joins)
1101 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
1102 self.assertEqual(
1103 [('Cond1.label_id IS NULL', [])],
1104 where)
1105 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
1106 self.assertEqual([], unsupported)
1107
1108 def testProcessLabelIDCond_NegatedMultipleValue(self):
1109 fd = BUILTIN_ISSUE_FIELDS['label_id']
1110 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.NE, [fd], [], [1, 2])
1111 left_joins, where, unsupported = ast2select._ProcessLabelIDCond(cond,
1112 'Cond1', 'Spare1', snapshot_mode=False)
1113 self.assertEqual(
1114 [('Issue2Label AS Cond1 ON Issue.id = Cond1.issue_id AND '
1115 'Issue.shard = Cond1.issue_shard AND '
1116 'Cond1.label_id IN (%s,%s)', [1, 2])],
1117 left_joins)
1118 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
1119 self.assertEqual(
1120 [('Cond1.label_id IS NULL', [])],
1121 where)
1122 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
1123 self.assertEqual([], unsupported)
1124
1125 def testProcessComponentIDCond(self):
1126 fd = BUILTIN_ISSUE_FIELDS['component_id']
1127 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [101])
1128 left_joins, where, unsupported = ast2select._ProcessComponentIDCond(
1129 cond, 'Cond1', 'Spare1', snapshot_mode=False)
1130 self.assertEqual(
1131 [('Issue2Component AS Cond1 ON Issue.id = Cond1.issue_id AND '
1132 'Issue.shard = Cond1.issue_shard AND '
1133 'Cond1.component_id = %s', [101])],
1134 left_joins)
1135 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
1136 self.assertEqual(
1137 [('Cond1.component_id IS NOT NULL', [])],
1138 where)
1139 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
1140 self.assertEqual([], unsupported)
1141
1142 def testProcessComponentIDCond_SnapshotMode(self):
1143 fd = BUILTIN_ISSUE_FIELDS['component_id']
1144 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [101])
1145 left_joins, where, unsupported = ast2select._ProcessComponentIDCond(
1146 cond, 'Cond1', 'Spare1', snapshot_mode=True)
1147 self.assertEqual(
1148 [('IssueSnapshot2Component AS Cond1 '
1149 'ON IssueSnapshot.id = Cond1.issuesnapshot_id AND '
1150 'Cond1.component_id = %s', [101])],
1151 left_joins)
1152 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
1153 self.assertEqual(
1154 [('Cond1.component_id IS NOT NULL', [])],
1155 where)
1156 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
1157 self.assertEqual([], unsupported)
1158
1159 def testProcessApprovalFieldCond_Status(self):
1160 approval_fd = tracker_pb2.FieldDef(
1161 field_id=1, field_name='UXReview',
1162 field_type=tracker_pb2.FieldTypes.APPROVAL_TYPE)
1163 cond = ast_pb2.MakeCond(
1164 ast_pb2.QueryOp.EQ, [approval_fd], ['Approved'], [],
1165 key_suffix=query2ast.STATUS_SUFFIX)
1166 left_joins, where, _unsupported = ast2select._ProcessApprovalFieldCond(
1167 cond, 'Cond1', 'Spare1', False)
1168 self.assertEqual(
1169 [('Issue2ApprovalValue AS Cond1 ON Issue.id = Cond1.issue_id AND '
1170 'Cond1.approval_id = %s AND LOWER(Cond1.status) = %s',
1171 [1, 'approved'])],
1172 left_joins)
1173 self.assertEqual(
1174 [('Cond1.approval_id IS NOT NULL', [])],
1175 where)
1176 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
1177
1178 def testProcessApprovalFieldCond_SetOn(self):
1179 approval_fd = tracker_pb2.FieldDef(
1180 field_id=1, field_name='UXReview',
1181 field_type=tracker_pb2.FieldTypes.APPROVAL_TYPE)
1182 int_time = int(time.mktime(datetime.datetime(2016, 10, 5).timetuple()))
1183 cond = ast_pb2.MakeCond(
1184 ast_pb2.QueryOp.NOT_TEXT_HAS, [approval_fd], [], [int_time],
1185 key_suffix=query2ast.SET_ON_SUFFIX)
1186 left_joins, where, _unsupported = ast2select._ProcessApprovalFieldCond(
1187 cond, 'Cond1', 'Spare1', False)
1188 self.assertEqual(
1189 [('Issue2ApprovalValue AS Cond1 ON Issue.id = Cond1.issue_id AND '
1190 'Cond1.approval_id = %s AND Cond1.set_on = %s',
1191 [1, int_time])],
1192 left_joins)
1193 self.assertEqual(
1194 [('Cond1.approval_id IS NULL', [])],
1195 where)
1196 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
1197
1198 def testProcessApprovalFieldCond_SetBy(self):
1199 approval_fd = tracker_pb2.FieldDef(
1200 field_id=1, field_name='UXReview',
1201 field_type=tracker_pb2.FieldTypes.APPROVAL_TYPE)
1202 cond = ast_pb2.MakeCond(
1203 ast_pb2.QueryOp.EQ, [approval_fd], ['user2@email.com'], [],
1204 key_suffix=query2ast.SET_BY_SUFFIX)
1205 left_joins, where, _unsupported = ast2select._ProcessApprovalFieldCond(
1206 cond, 'Cond1', 'Spare1', False)
1207 self.assertEqual(
1208 [('User AS Spare1 ON LOWER(Spare1.email) = %s', ['user2@email.com']),
1209 ('Issue2ApprovalValue AS Cond1 ON Issue.id = Cond1.issue_id AND '
1210 'Cond1.approval_id = %s AND Cond1.setter_id = Spare1.user_id',
1211 [1])],
1212 left_joins)
1213 self.assertEqual(
1214 [('Cond1.approval_id IS NOT NULL', [])],
1215 where)
1216 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
1217
1218 def testProcessApprovalFieldCond_ApproverID(self):
1219 approval_fd = tracker_pb2.FieldDef(
1220 field_id=1, field_name='UXReview',
1221 field_type=tracker_pb2.FieldTypes.APPROVAL_TYPE)
1222 cond = ast_pb2.MakeCond(
1223 ast_pb2.QueryOp.EQ, [approval_fd], [], [111],
1224 key_suffix=query2ast.APPROVER_SUFFIX)
1225 left_joins, where, _unsupported = ast2select._ProcessApprovalFieldCond(
1226 cond, 'Cond1', 'Spare1', False)
1227 self.assertEqual(
1228 [('IssueApproval2Approver AS Cond1 ON Issue.id = Cond1.issue_id AND '
1229 'Cond1.approval_id = %s AND Cond1.approver_id = %s',
1230 [1, 111])], left_joins)
1231 self.assertEqual(
1232 [('Cond1.approval_id IS NOT NULL', [])],
1233 where)
1234 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
1235
1236
1237 def testProcessApprovalFieldCond_IsDefined(self):
1238 approval_fd = tracker_pb2.FieldDef(
1239 field_id=1, field_name='UXReview',
1240 field_type=tracker_pb2.FieldTypes.APPROVAL_TYPE)
1241 cond = ast_pb2.MakeCond(
1242 ast_pb2.QueryOp.IS_DEFINED, [approval_fd], [], [])
1243 left_joins, where, _unsupported = ast2select._ProcessApprovalFieldCond(
1244 cond, 'Cond1', 'Spare1', False)
1245 self.assertEqual(
1246 [('Issue2ApprovalValue AS Cond1 ON Issue.id = Cond1.issue_id AND '
1247 'Cond1.approval_id = %s',
1248 [1])], left_joins)
1249 self.assertEqual(
1250 [('Cond1.approval_id IS NOT NULL', [])],
1251 where)
1252 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
1253
1254 def testProcessCustomFieldCond_IntType(self):
1255 fd = tracker_pb2.FieldDef(
1256 field_id=1, project_id=789, field_name='EstDays',
1257 field_type=tracker_pb2.FieldTypes.INT_TYPE)
1258 val = 42
1259 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [val])
1260 left_joins, where, unsupported = ast2select._ProcessCustomFieldCond(
1261 cond, 'Cond1', 'Spare1', 'Phase', snapshot_mode=False)
1262 self.assertEqual(
1263 [('Issue2FieldValue AS Cond1 ON Issue.id = Cond1.issue_id AND '
1264 'Issue.shard = Cond1.issue_shard AND '
1265 'Cond1.field_id = %s AND '
1266 'Cond1.int_value = %s', [1, val])],
1267 left_joins)
1268 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
1269 self.assertEqual(
1270 [('Cond1.field_id IS NOT NULL', [])],
1271 where)
1272 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
1273 self.assertEqual([], unsupported)
1274
1275 def testProcessCustomFieldCond_StrType(self):
1276 fd = tracker_pb2.FieldDef(
1277 field_id=1, project_id=789, field_name='Nickname',
1278 field_type=tracker_pb2.FieldTypes.STR_TYPE)
1279 val = 'Fuzzy'
1280 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [val], [])
1281 left_joins, where, unsupported = ast2select._ProcessCustomFieldCond(
1282 cond, 'Cond1', 'Spare1','Phase1', snapshot_mode=False)
1283 self.assertEqual(
1284 [('Issue2FieldValue AS Cond1 ON Issue.id = Cond1.issue_id AND '
1285 'Issue.shard = Cond1.issue_shard AND '
1286 'Cond1.field_id = %s AND '
1287 'Cond1.str_value = %s', [1, val])],
1288 left_joins)
1289 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
1290 self.assertEqual(
1291 [('Cond1.field_id IS NOT NULL', [])],
1292 where)
1293 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
1294 self.assertEqual([], unsupported)
1295
1296 def testProcessCustomFieldCond_StrType_SnapshotMode(self):
1297 fd = tracker_pb2.FieldDef(
1298 field_id=1, project_id=789, field_name='Nickname',
1299 field_type=tracker_pb2.FieldTypes.STR_TYPE)
1300 val = 'Fuzzy'
1301 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [val], [])
1302 left_joins, where, unsupported = ast2select._ProcessCustomFieldCond(
1303 cond, 'Cond1', 'Spare1', 'Phase1', snapshot_mode=True)
1304 self.assertEqual([], left_joins)
1305 self.assertEqual([], where)
1306 self.assertEqual([cond], unsupported)
1307
1308 def testProcessCustomFieldCond_UserType_ByID(self):
1309 fd = tracker_pb2.FieldDef(
1310 field_id=1, project_id=789, field_name='ExecutiveProducer',
1311 field_type=tracker_pb2.FieldTypes.USER_TYPE)
1312 val = 111
1313 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [val])
1314 left_joins, where, unsupported = ast2select._ProcessCustomFieldCond(
1315 cond, 'Cond1', 'Spare1', 'Phase1', snapshot_mode=False)
1316 self.assertEqual(
1317 [('Issue2FieldValue AS Cond1 ON Issue.id = Cond1.issue_id AND '
1318 'Issue.shard = Cond1.issue_shard AND '
1319 'Cond1.field_id = %s AND '
1320 'Cond1.user_id = %s', [1, val])],
1321 left_joins)
1322 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
1323 self.assertEqual(
1324 [('Cond1.field_id IS NOT NULL', [])],
1325 where)
1326 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
1327 self.assertEqual([], unsupported)
1328
1329 def testProcessCustomFieldCond_UserType_ByEmail(self):
1330 fd = tracker_pb2.FieldDef(
1331 field_id=1, project_id=789, field_name='ExecutiveProducer',
1332 field_type=tracker_pb2.FieldTypes.USER_TYPE)
1333 val = 'exec@example.com'
1334 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [val], [])
1335 left_joins, where, unsupported = ast2select._ProcessCustomFieldCond(
1336 cond, 'Cond1', 'Spare1', 'Phase1', snapshot_mode=False)
1337 self.assertEqual(
1338 [('User AS Spare1 ON '
1339 'LOWER(Spare1.email) = %s', [val]),
1340 ('Issue2FieldValue AS Cond1 ON Issue.id = Cond1.issue_id AND '
1341 'Issue.shard = Cond1.issue_shard AND '
1342 'Cond1.field_id = %s AND '
1343 'Cond1.user_id = Spare1.user_id', [1])],
1344 left_joins)
1345 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
1346 self.assertTrue(sql._IsValidJoin(left_joins[1][0]))
1347 self.assertEqual(
1348 [('Cond1.field_id IS NOT NULL', [])],
1349 where)
1350 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
1351 self.assertEqual([], unsupported)
1352
1353 def testProcessCustomFieldCond_DateType(self):
1354 fd = tracker_pb2.FieldDef(
1355 field_id=1, project_id=789, field_name='Deadline',
1356 field_type=tracker_pb2.FieldTypes.DATE_TYPE)
1357 val = int(time.mktime(datetime.datetime(2016, 10, 5).timetuple()))
1358 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [val])
1359 left_joins, where, unsupported = ast2select._ProcessCustomFieldCond(
1360 cond, 'Cond1', 'Spare1', 'Phase1', snapshot_mode=False)
1361 self.assertEqual(
1362 [('Issue2FieldValue AS Cond1 ON Issue.id = Cond1.issue_id AND '
1363 'Issue.shard = Cond1.issue_shard AND '
1364 'Cond1.field_id = %s AND '
1365 'Cond1.date_value = %s', [1, val])],
1366 left_joins)
1367 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
1368 self.assertEqual(
1369 [('Cond1.field_id IS NOT NULL', [])],
1370 where)
1371 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
1372 self.assertEqual([], unsupported)
1373
1374 def testProcessCustomFieldCond_PhaseName(self):
1375 fd = tracker_pb2.FieldDef(
1376 field_id=1, project_id=789, field_name='Milestone',
1377 field_type=tracker_pb2.FieldTypes.INT_TYPE)
1378 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [72],
1379 phase_name='Canary')
1380 left_joins, where, unsupported = ast2select._ProcessCustomFieldCond(
1381 cond, 'Cond1', 'User1', 'Phase1', snapshot_mode=False)
1382 self.assertEqual(
1383 [('IssuePhaseDef AS Phase1 ON LOWER(Phase1.name) = %s', ['Canary']),
1384 ('Issue2FieldValue AS Cond1 ON Issue.id = Cond1.issue_id AND '
1385 'Issue.shard = Cond1.issue_shard AND '
1386 'Cond1.field_id = %s AND Cond1.int_value = %s AND '
1387 'Cond1.phase_id = Phase1.id', [1, 72])],
1388 left_joins)
1389 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
1390 self.assertEqual([], unsupported)
1391
1392 def testProcessAttachmentCond_HasAttachment(self):
1393 fd = BUILTIN_ISSUE_FIELDS['attachment']
1394 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.IS_DEFINED, [fd], [], [])
1395 left_joins, where, unsupported = ast2select._ProcessAttachmentCond(
1396 cond, 'Cond1', 'Spare1', snapshot_mode=False)
1397 self.assertEqual([], left_joins)
1398 self.assertEqual(
1399 [('(Issue.attachment_count IS NOT NULL AND '
1400 'Issue.attachment_count != %s)',
1401 [0])],
1402 where)
1403 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
1404
1405 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.IS_NOT_DEFINED, [fd], [], [])
1406 left_joins, where, unsupported = ast2select._ProcessAttachmentCond(
1407 cond, 'Cond1', 'Spare1', snapshot_mode=False)
1408 self.assertEqual([], left_joins)
1409 self.assertEqual(
1410 [('(Issue.attachment_count IS NULL OR '
1411 'Issue.attachment_count = %s)',
1412 [0])],
1413 where)
1414 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
1415 self.assertEqual([], unsupported)
1416
1417 def testProcessAttachmentCond_HasAttachment_SnapshotMode(self):
1418 fd = BUILTIN_ISSUE_FIELDS['attachment']
1419 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.IS_DEFINED, [fd], [], [])
1420 left_joins, where, unsupported = ast2select._ProcessAttachmentCond(
1421 cond, 'Cond1', 'Spare1', snapshot_mode=True)
1422 self.assertEqual([], left_joins)
1423 self.assertEqual([], where)
1424 self.assertEqual([cond], unsupported)
1425
1426 def testProcessAttachmentCond_TextHas(self):
1427 fd = BUILTIN_ISSUE_FIELDS['attachment']
1428 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.TEXT_HAS, [fd], ['jpg'], [])
1429 left_joins, where, unsupported = ast2select._ProcessAttachmentCond(
1430 cond, 'Cond1', 'Spare1', snapshot_mode=False)
1431 self.assertEqual(
1432 [('Attachment AS Cond1 ON Issue.id = Cond1.issue_id AND '
1433 'Cond1.deleted = %s',
1434 [False])],
1435 left_joins)
1436 self.assertTrue(sql._IsValidJoin(left_joins[0][0]))
1437 self.assertEqual(
1438 [('(Cond1.filename LIKE %s)', ['%jpg%'])],
1439 where)
1440 self.assertTrue(sql._IsValidWhereCond(where[0][0]))
1441 self.assertEqual([], unsupported)
1442
1443 def testProcessHotlistIDCond_MultiValue(self):
1444 fd = BUILTIN_ISSUE_FIELDS['hotlist_id']
1445 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [1, 2])
1446 left_joins, where, unsupported = ast2select._ProcessHotlistIDCond(cond,
1447 'Cond1', 'Spare1', snapshot_mode=False)
1448 self.assertEqual(
1449 [('Hotlist2Issue AS Cond1 ON Issue.id = Cond1.issue_id AND '
1450 'Cond1.hotlist_id IN (%s,%s)', [1, 2])],
1451 left_joins)
1452 self.assertEqual(
1453 [('Cond1.hotlist_id IS NOT NULL', [])],
1454 where)
1455 self.assertEqual([], unsupported)
1456
1457 def testProcessHotlistIDCond_MultiValue_SnapshotMode(self):
1458 fd = BUILTIN_ISSUE_FIELDS['hotlist_id']
1459 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [1, 2])
1460 left_joins, where, unsupported = ast2select._ProcessHotlistIDCond(cond,
1461 'Cond1', 'Spare1', snapshot_mode=True)
1462 self.assertEqual(
1463 [('IssueSnapshot2Hotlist AS Cond1 '
1464 'ON IssueSnapshot.id = Cond1.issuesnapshot_id AND '
1465 'Cond1.hotlist_id IN (%s,%s)', [1, 2])],
1466 left_joins)
1467 self.assertEqual(
1468 [('Cond1.hotlist_id IS NOT NULL', [])],
1469 where)
1470 self.assertEqual([], unsupported)
1471
1472 def testProcessHotlistIDCond_SingleValue(self):
1473 fd = BUILTIN_ISSUE_FIELDS['hotlist_id']
1474 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], [], [1])
1475 left_joins, where, unsupported = ast2select._ProcessHotlistIDCond(cond,
1476 'Cond1', 'Spare1', snapshot_mode=False)
1477 self.assertEqual(
1478 [('Hotlist2Issue AS Cond1 ON Issue.id = Cond1.issue_id AND '
1479 'Cond1.hotlist_id = %s', [1])],
1480 left_joins)
1481 self.assertEqual(
1482 [('Cond1.hotlist_id IS NOT NULL', [])],
1483 where)
1484 self.assertEqual([], unsupported)
1485
1486 def testProcessHotlistIDCond_NegatedMultiValue(self):
1487 fd = BUILTIN_ISSUE_FIELDS['hotlist_id']
1488 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.NE, [fd], [], [1, 2])
1489 left_joins, where, unsupported = ast2select._ProcessHotlistIDCond(cond,
1490 'Cond1', 'Spare1', snapshot_mode=False)
1491 self.assertEqual(
1492 [('Hotlist2Issue AS Cond1 ON Issue.id = Cond1.issue_id AND '
1493 'Cond1.hotlist_id IN (%s,%s)', [1, 2])],
1494 left_joins)
1495 self.assertEqual(
1496 [('Cond1.hotlist_id IS NULL', [])],
1497 where)
1498 self.assertEqual([], unsupported)
1499
1500 def testProcessHotlistIDCond_NegatedMultiValue_SnapshotMode(self):
1501 fd = BUILTIN_ISSUE_FIELDS['hotlist_id']
1502 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.NE, [fd], [], [1, 2])
1503 left_joins, where, unsupported = ast2select._ProcessHotlistIDCond(cond,
1504 'Cond1', 'Spare1', snapshot_mode=True)
1505 self.assertEqual(
1506 [('IssueSnapshot2Hotlist AS Cond1 '
1507 'ON IssueSnapshot.id = Cond1.issuesnapshot_id AND '
1508 'Cond1.hotlist_id IN (%s,%s)', [1, 2])],
1509 left_joins)
1510 self.assertEqual(
1511 [('Cond1.hotlist_id IS NULL', [])],
1512 where)
1513 self.assertEqual([], unsupported)
1514
1515 def testProcessHotlistIDCond_NegatedSingleValue(self):
1516 fd = BUILTIN_ISSUE_FIELDS['hotlist_id']
1517 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.NE, [fd], [], [1])
1518 left_joins, where, unsupported = ast2select._ProcessHotlistIDCond(cond,
1519 'Cond1', 'Spare1', snapshot_mode=False)
1520 self.assertEqual(
1521 [('Hotlist2Issue AS Cond1 ON Issue.id = Cond1.issue_id AND '
1522 'Cond1.hotlist_id = %s', [1])],
1523 left_joins)
1524 self.assertEqual(
1525 [('Cond1.hotlist_id IS NULL', [])],
1526 where)
1527 self.assertEqual([], unsupported)
1528
1529 def testProcessHotlistIDCond_NegatedSingleValue_SnapshotMode(self):
1530 fd = BUILTIN_ISSUE_FIELDS['hotlist_id']
1531 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.NE, [fd], [], [1])
1532 left_joins, where, unsupported = ast2select._ProcessHotlistIDCond(cond,
1533 'Cond1', 'Spare1', snapshot_mode=True)
1534 self.assertEqual(
1535 [('IssueSnapshot2Hotlist AS Cond1 '
1536 'ON IssueSnapshot.id = Cond1.issuesnapshot_id AND '
1537 'Cond1.hotlist_id = %s', [1])],
1538 left_joins)
1539 self.assertEqual(
1540 [('Cond1.hotlist_id IS NULL', [])],
1541 where)
1542 self.assertEqual([], unsupported)
1543
1544 def testProcessHotlistCond_SingleValue(self):
1545 fd = BUILTIN_ISSUE_FIELDS['hotlist']
1546 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], ['invalid:spa'], [])
1547 left_joins, where, unsupported = ast2select._ProcessHotlistCond(cond,
1548 'Cond1', 'Spare1', snapshot_mode=False)
1549 self.assertEqual(
1550 [('(Hotlist2Issue JOIN Hotlist AS Cond1 ON '
1551 'Hotlist2Issue.hotlist_id = Cond1.id AND (LOWER(Cond1.name) LIKE %s))'
1552 ' ON Issue.id = Hotlist2Issue.issue_id', ['%spa%'])],
1553 left_joins)
1554 self.assertEqual([('Cond1.name IS NOT NULL', [])], where)
1555 self.assertEqual([], unsupported)
1556
1557 def testProcessHotlistCond_SingleValue_SnapshotMode(self):
1558 fd = BUILTIN_ISSUE_FIELDS['hotlist']
1559 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd], ['invalid:spa'], [])
1560 left_joins, where, unsupported = ast2select._ProcessHotlistCond(cond,
1561 'Cond1', 'Spare1', snapshot_mode=True)
1562 self.assertEqual(
1563 [('(IssueSnapshot2Hotlist JOIN Hotlist AS Cond1 ON '
1564 'IssueSnapshot2Hotlist.hotlist_id = Cond1.id '
1565 'AND (LOWER(Cond1.name) LIKE %s)) '
1566 'ON IssueSnapshot.id = IssueSnapshot2Hotlist.issuesnapshot_id',
1567 ['%spa%'])],
1568 left_joins)
1569 self.assertEqual([('Cond1.name IS NOT NULL', [])], where)
1570 self.assertEqual([], unsupported)
1571
1572 def testProcessHotlistCond_SingleValue2(self):
1573 fd = BUILTIN_ISSUE_FIELDS['hotlist']
1574 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.EQ, [fd],
1575 ['invalid:spa', 'port', 'invalid2:barc'], [])
1576 left_joins, where, unsupported = ast2select._ProcessHotlistCond(cond,
1577 'Cond1', 'Spare1', snapshot_mode=False)
1578 self.assertEqual(
1579 [('(Hotlist2Issue JOIN Hotlist AS Cond1 ON '
1580 'Hotlist2Issue.hotlist_id = Cond1.id AND (LOWER(Cond1.name) LIKE %s OR '
1581 'LOWER(Cond1.name) LIKE %s OR LOWER(Cond1.name) LIKE %s)) ON '
1582 'Issue.id = Hotlist2Issue.issue_id', ['%spa%', '%port%', '%barc%'])],
1583 left_joins)
1584 self.assertEqual([('Cond1.name IS NOT NULL', [])], where)
1585 self.assertEqual([], unsupported)
1586
1587 def testProcessHotlistCond_SingleValue3(self):
1588 fd = BUILTIN_ISSUE_FIELDS['hotlist']
1589 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.NE, [fd], ['invalid:spa'], [])
1590 left_joins, where, unsupported = ast2select._ProcessHotlistCond(cond,
1591 'Cond1', 'Spare1', snapshot_mode=False)
1592 self.assertEqual(
1593 [('(Hotlist2Issue JOIN Hotlist AS Cond1 ON '
1594 'Hotlist2Issue.hotlist_id = Cond1.id AND (LOWER(Cond1.name) LIKE %s))'
1595 ' ON Issue.id = Hotlist2Issue.issue_id', ['%spa%'])],
1596 left_joins)
1597 self.assertEqual([('Cond1.name IS NULL', [])], where)
1598 self.assertEqual([], unsupported)
1599
1600 def testProcessHotlistCond_SingleValue4(self):
1601 fd = BUILTIN_ISSUE_FIELDS['hotlist']
1602 cond = ast_pb2.MakeCond(ast_pb2.QueryOp.NOT_TEXT_HAS, [fd],
1603 ['invalid:spa', 'port', 'invalid2:barc'], [])
1604 left_joins, where, unsupported = ast2select._ProcessHotlistCond(cond,
1605 'Cond1', 'Spare1', snapshot_mode=False)
1606 self.assertEqual(
1607 [('(Hotlist2Issue JOIN Hotlist AS Cond1 ON '
1608 'Hotlist2Issue.hotlist_id = Cond1.id AND (LOWER(Cond1.name) LIKE %s OR '
1609 'LOWER(Cond1.name) LIKE %s OR LOWER(Cond1.name) LIKE %s)) ON '
1610 'Issue.id = Hotlist2Issue.issue_id', ['%spa%', '%port%', '%barc%'])],
1611 left_joins)
1612 self.assertEqual([('Cond1.name IS NULL', [])], where)
1613 self.assertEqual([], unsupported)
1614
1615 def testProcessPhaseCond_HasGateEQ(self):
1616 fd = BUILTIN_ISSUE_FIELDS['gate']
1617 cond = ast_pb2.MakeCond(
1618 ast_pb2.QueryOp.EQ, [fd], ['canary', 'stable'], [])
1619 left_joins, where, unsupported = ast2select._ProcessPhaseCond(
1620 cond, 'Cond1', 'Phase1', False)
1621 self.assertEqual(
1622 [('(Issue2ApprovalValue AS Cond1 JOIN IssuePhaseDef AS Phase1 '
1623 'ON Cond1.phase_id = Phase1.id AND '
1624 'LOWER(Phase1.name) IN (%s,%s)) '
1625 'ON Issue.id = Cond1.issue_id', ['canary', 'stable'])],
1626 left_joins)
1627 self.assertEqual([('Phase1.name IS NOT NULL', [])], where)
1628 self.assertEqual([], unsupported)
1629
1630 def testProcessPhaseCond_NoGateTEXT(self):
1631 fd = BUILTIN_ISSUE_FIELDS['gate']
1632 cond = ast_pb2.MakeCond(
1633 ast_pb2.QueryOp.NOT_TEXT_HAS, [fd], ['canary', 'stable'], [])
1634 left_joins, where, unsupported = ast2select._ProcessPhaseCond(
1635 cond, 'Cond1', 'Phase1', False)
1636 self.assertEqual(
1637 [('(Issue2ApprovalValue AS Cond1 JOIN IssuePhaseDef AS Phase1 '
1638 'ON Cond1.phase_id = Phase1.id AND '
1639 '(LOWER(Phase1.name) LIKE %s '
1640 'OR LOWER(Phase1.name) LIKE %s)) '
1641 'ON Issue.id = Cond1.issue_id', ['%canary%', '%stable%'])],
1642 left_joins)
1643 self.assertEqual([('Phase1.name IS NULL', [])], where)
1644 self.assertEqual([], unsupported)
1645
1646 def testCompare_IntTypes(self):
1647 val_type = tracker_pb2.FieldTypes.INT_TYPE
1648 cond_str, cond_args = ast2select._Compare(
1649 'Alias', ast_pb2.QueryOp.IS_DEFINED, val_type, 'col', [1, 2])
1650 self.assertEqual('(Alias.col IS NOT NULL AND Alias.col != %s)', cond_str)
1651 self.assertEqual([0], cond_args)
1652
1653 cond_str, cond_args = ast2select._Compare(
1654 'Alias', ast_pb2.QueryOp.EQ, val_type, 'col', [1])
1655 self.assertEqual('Alias.col = %s', cond_str)
1656 self.assertEqual([1], cond_args)
1657
1658 cond_str, cond_args = ast2select._Compare(
1659 'Alias', ast_pb2.QueryOp.EQ, val_type, 'col', [1, 2])
1660 self.assertEqual('Alias.col IN (%s,%s)', cond_str)
1661 self.assertEqual([1, 2], cond_args)
1662
1663 cond_str, cond_args = ast2select._Compare(
1664 'Alias', ast_pb2.QueryOp.NE, val_type, 'col', [])
1665 self.assertEqual('TRUE', cond_str)
1666 self.assertEqual([], cond_args)
1667
1668 cond_str, cond_args = ast2select._Compare(
1669 'Alias', ast_pb2.QueryOp.NE, val_type, 'col', [1])
1670 self.assertEqual('(Alias.col IS NULL OR Alias.col != %s)', cond_str)
1671 self.assertEqual([1], cond_args)
1672
1673 cond_str, cond_args = ast2select._Compare(
1674 'Alias', ast_pb2.QueryOp.NE, val_type, 'col', [1, 2])
1675 self.assertEqual('(Alias.col IS NULL OR Alias.col NOT IN (%s,%s))',
1676 cond_str)
1677 self.assertEqual([1, 2], cond_args)
1678
1679 def testCompare_STRTypes(self):
1680 val_type = tracker_pb2.FieldTypes.STR_TYPE
1681 cond_str, cond_args = ast2select._Compare(
1682 'Alias', ast_pb2.QueryOp.IS_DEFINED, val_type, 'col', ['a', 'b'])
1683 self.assertEqual('(Alias.col IS NOT NULL AND Alias.col != %s)', cond_str)
1684 self.assertEqual([''], cond_args)
1685
1686 cond_str, cond_args = ast2select._Compare(
1687 'Alias', ast_pb2.QueryOp.EQ, val_type, 'col', ['a'])
1688 self.assertEqual('Alias.col = %s', cond_str)
1689 self.assertEqual(['a'], cond_args)
1690
1691 cond_str, cond_args = ast2select._Compare(
1692 'Alias', ast_pb2.QueryOp.EQ, val_type, 'col', ['a', 'b'])
1693 self.assertEqual('Alias.col IN (%s,%s)', cond_str)
1694 self.assertEqual(['a', 'b'], cond_args)
1695
1696 cond_str, cond_args = ast2select._Compare(
1697 'Alias', ast_pb2.QueryOp.NE, val_type, 'col', [])
1698 self.assertEqual('TRUE', cond_str)
1699 self.assertEqual([], cond_args)
1700
1701 cond_str, cond_args = ast2select._Compare(
1702 'Alias', ast_pb2.QueryOp.NE, val_type, 'col', ['a'])
1703 self.assertEqual('(Alias.col IS NULL OR Alias.col != %s)', cond_str)
1704 self.assertEqual(['a'], cond_args)
1705
1706 cond_str, cond_args = ast2select._Compare(
1707 'Alias', ast_pb2.QueryOp.NE, val_type, 'col', ['a', 'b'])
1708 self.assertEqual('(Alias.col IS NULL OR Alias.col NOT IN (%s,%s))',
1709 cond_str)
1710 self.assertEqual(['a', 'b'], cond_args)
1711
1712 cond_str, cond_args = ast2select._Compare(
1713 'Alias', ast_pb2.QueryOp.TEXT_HAS, val_type, 'col', ['a'])
1714 self.assertEqual('(Alias.col LIKE %s)', cond_str)
1715 self.assertEqual(['%a%'], cond_args)
1716
1717 cond_str, cond_args = ast2select._Compare(
1718 'Alias', ast_pb2.QueryOp.NOT_TEXT_HAS, val_type, 'col', ['a'])
1719 self.assertEqual('(Alias.col IS NULL OR Alias.col NOT LIKE %s)', cond_str)
1720 self.assertEqual(['%a%'], cond_args)
1721
1722 def testCompareAlreadyJoined(self):
1723 cond_str, cond_args = ast2select._CompareAlreadyJoined(
1724 'Alias', ast_pb2.QueryOp.EQ, 'col')
1725 self.assertEqual('Alias.col IS NOT NULL', cond_str)
1726 self.assertEqual([], cond_args)
1727
1728 cond_str, cond_args = ast2select._CompareAlreadyJoined(
1729 'Alias', ast_pb2.QueryOp.NE, 'col')
1730 self.assertEqual('Alias.col IS NULL', cond_str)
1731 self.assertEqual([], cond_args)