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