jupyter-duckdb 1.2.0.1__py3-none-any.whl → 1.4.111__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. duckdb_kernel/db/Connection.py +3 -0
  2. duckdb_kernel/db/Table.py +8 -0
  3. duckdb_kernel/db/implementation/duckdb/Connection.py +27 -13
  4. duckdb_kernel/db/implementation/postgres/Connection.py +27 -12
  5. duckdb_kernel/db/implementation/sqlite/Connection.py +9 -3
  6. duckdb_kernel/kernel.py +407 -200
  7. duckdb_kernel/magics/MagicCommand.py +34 -10
  8. duckdb_kernel/magics/MagicCommandCallback.py +11 -7
  9. duckdb_kernel/magics/MagicCommandHandler.py +58 -9
  10. duckdb_kernel/magics/MagicState.py +11 -0
  11. duckdb_kernel/magics/__init__.py +1 -0
  12. duckdb_kernel/parser/DCParser.py +17 -7
  13. duckdb_kernel/parser/LogicParser.py +6 -6
  14. duckdb_kernel/parser/ParserError.py +18 -0
  15. duckdb_kernel/parser/RAParser.py +29 -21
  16. duckdb_kernel/parser/__init__.py +1 -0
  17. duckdb_kernel/parser/elements/DCOperand.py +7 -4
  18. duckdb_kernel/parser/elements/LogicElement.py +0 -2
  19. duckdb_kernel/parser/elements/RAElement.py +4 -1
  20. duckdb_kernel/parser/elements/RARelationReference.py +86 -0
  21. duckdb_kernel/parser/elements/RAUnaryOperator.py +6 -0
  22. duckdb_kernel/parser/elements/__init__.py +2 -1
  23. duckdb_kernel/parser/elements/binary/And.py +1 -1
  24. duckdb_kernel/parser/elements/binary/ConditionalSet.py +37 -10
  25. duckdb_kernel/parser/elements/binary/Cross.py +2 -2
  26. duckdb_kernel/parser/elements/binary/Difference.py +1 -1
  27. duckdb_kernel/parser/elements/binary/Divide.py +1 -1
  28. duckdb_kernel/parser/elements/binary/Division.py +0 -4
  29. duckdb_kernel/parser/elements/binary/FullOuterJoin.py +40 -0
  30. duckdb_kernel/parser/elements/binary/Join.py +4 -1
  31. duckdb_kernel/parser/elements/binary/LeftOuterJoin.py +27 -0
  32. duckdb_kernel/parser/elements/binary/LeftSemiJoin.py +27 -0
  33. duckdb_kernel/parser/elements/binary/RightOuterJoin.py +27 -0
  34. duckdb_kernel/parser/elements/binary/RightSemiJoin.py +27 -0
  35. duckdb_kernel/parser/elements/binary/__init__.py +21 -6
  36. duckdb_kernel/parser/elements/unary/AttributeRename.py +39 -0
  37. duckdb_kernel/parser/elements/unary/Projection.py +1 -1
  38. duckdb_kernel/parser/elements/unary/Rename.py +68 -14
  39. duckdb_kernel/parser/elements/unary/__init__.py +2 -0
  40. duckdb_kernel/parser/tokenizer/Token.py +24 -3
  41. duckdb_kernel/parser/util/QuerySplitter.py +87 -0
  42. duckdb_kernel/parser/util/RenamableColumnList.py +10 -2
  43. duckdb_kernel/tests/__init__.py +76 -0
  44. duckdb_kernel/tests/test_dc.py +483 -0
  45. duckdb_kernel/tests/test_ra.py +1966 -0
  46. duckdb_kernel/tests/test_result_comparison.py +173 -0
  47. duckdb_kernel/tests/test_sql.py +48 -0
  48. duckdb_kernel/util/ResultSetComparator.py +22 -4
  49. duckdb_kernel/util/SQL.py +6 -0
  50. duckdb_kernel/util/TestError.py +4 -0
  51. duckdb_kernel/visualization/Plotly.py +144 -0
  52. duckdb_kernel/visualization/RATreeDrawer.py +34 -2
  53. duckdb_kernel/visualization/__init__.py +1 -0
  54. duckdb_kernel/visualization/lib/__init__.py +53 -0
  55. duckdb_kernel/visualization/lib/plotly-3.0.1.min.js +3879 -0
  56. duckdb_kernel/visualization/lib/ra.css +3 -0
  57. duckdb_kernel/visualization/lib/ra.js +55 -0
  58. {jupyter_duckdb-1.2.0.1.dist-info → jupyter_duckdb-1.4.111.dist-info}/METADATA +53 -19
  59. jupyter_duckdb-1.4.111.dist-info/RECORD +104 -0
  60. {jupyter_duckdb-1.2.0.1.dist-info → jupyter_duckdb-1.4.111.dist-info}/WHEEL +1 -1
  61. jupyter_duckdb-1.2.0.1.dist-info/RECORD +0 -82
  62. {jupyter_duckdb-1.2.0.1.dist-info → jupyter_duckdb-1.4.111.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,1966 @@
1
+ import pytest
2
+
3
+ import duckdb_kernel.parser.elements.binary as BinaryOperators
4
+ import duckdb_kernel.parser.elements.unary as UnaryOperators
5
+ from duckdb_kernel.parser import RAParser, RAParserError
6
+ from duckdb_kernel.parser.elements import RAOperand, LogicElement, RARelationReference
7
+ from . import Connection
8
+
9
+
10
+ def test_case_insensitivity():
11
+ for query in (
12
+ 'Users',
13
+ 'users',
14
+ 'USERS',
15
+ 'userS'
16
+ ):
17
+ root = RAParser.parse_query(query)
18
+
19
+ # root is an RAOperand
20
+ assert isinstance(root, RAOperand)
21
+
22
+ # Root's name is the relation name in whatever case
23
+ # it has been written.
24
+ assert root.name == query
25
+
26
+ # execute to test case insensitivity
27
+ with Connection() as con:
28
+ cols, rows = con.execute_ra_return_cols(root)
29
+
30
+ assert [c.lower() for c in cols] == [
31
+ 'id',
32
+ 'username'
33
+ ]
34
+ assert rows == [
35
+ (1, 'Alice'),
36
+ (2, 'Bob'),
37
+ (3, 'Charlie')
38
+ ]
39
+
40
+ for query in (
41
+ 'π [ Username ] ( Users )',
42
+ 'π [ username ] ( Users )',
43
+ 'π [ userName ] ( Users )'
44
+ ):
45
+ root = RAParser.parse_query(query)
46
+
47
+ # execute to test case insensitivity
48
+ with (Connection() as con):
49
+ cols, rows = con.execute_ra_return_cols(root)
50
+
51
+ assert [c.lower() for c in cols] == [
52
+ 'username'
53
+ ]
54
+ assert rows == [
55
+ ('Alice',),
56
+ ('Bob',),
57
+ ('Charlie',)
58
+ ]
59
+
60
+ for query in (
61
+ 'π [ Id, Username ] ( Users )',
62
+ 'π [ id, username ] ( Users )',
63
+ 'π [ iD, userName ] ( Users )'
64
+ ):
65
+ root = RAParser.parse_query(query)
66
+
67
+ # execute to test case insensitivity
68
+ with Connection() as con:
69
+ cols, rows = con.execute_ra_return_cols(root)
70
+
71
+ assert [c.lower() for c in cols] == [
72
+ 'id',
73
+ 'username'
74
+ ]
75
+ assert rows == [
76
+ (1, 'Alice'),
77
+ (2, 'Bob'),
78
+ (3, 'Charlie')
79
+ ]
80
+
81
+
82
+ def test_comments():
83
+ for query in (
84
+ # single line
85
+ 'Shows -- x Users\n x Seasons',
86
+ 'Shows x Seasons -- x Users',
87
+ 'Shows x Seasons--',
88
+ 'Shows x Seasons--\n',
89
+ # multi line
90
+ 'Shows /* x Users */ x Seasons',
91
+ 'Shows /* x Users */\n x Seasons',
92
+ 'Shows /* x Users\n */ x Seasons',
93
+ 'Shows x Seasons/**/',
94
+ 'Shows x Seasons/*\n*/',
95
+ 'Shows x Seasons\n/**/',
96
+ 'Shows x Seasons/* x Users'
97
+ ):
98
+ root = RAParser.parse_query(query)
99
+
100
+ assert isinstance(root, BinaryOperators.Cross)
101
+ assert isinstance(root.left, RAOperand) and root.left.name == 'Shows'
102
+ assert isinstance(root.right, RAOperand) and root.right.name == 'Seasons'
103
+
104
+ for query in (
105
+ '-- comment',
106
+ '/* comment */'
107
+ ):
108
+ root = RAParser.parse_query(query)
109
+ assert root is None
110
+
111
+
112
+ def test_binary_operator_cross():
113
+ for query in (
114
+ r'Shows x Seasons',
115
+ r'Shows times Seasons',
116
+ ):
117
+ root = RAParser.parse_query(query)
118
+
119
+ assert isinstance(root, BinaryOperators.Cross)
120
+ assert isinstance(root.left, RAOperand) and root.left.name == 'Shows'
121
+ assert isinstance(root.right, RAOperand) and root.right.name == 'Seasons'
122
+
123
+ with Connection() as con:
124
+ cols, rows = con.execute_ra_return_cols(root)
125
+
126
+ assert [c.lower() for c in cols] == [
127
+ 'shows.showid',
128
+ 'shows.showname',
129
+ 'seasons.seasonnumber',
130
+ 'seasons.showid',
131
+ 'seasons.seasonname'
132
+ ]
133
+ assert rows == [
134
+ (1, 'Show 1', 1, 1, 'Show 1 / Season 1'),
135
+ (1, 'Show 1', 1, 2, 'Show 2 / Season 1'),
136
+ (1, 'Show 1', 2, 1, 'Show 1 / Season 2'),
137
+ (1, 'Show 1', 2, 2, 'Show 2 / Season 2'),
138
+ (2, 'Show 2', 1, 1, 'Show 1 / Season 1'),
139
+ (2, 'Show 2', 1, 2, 'Show 2 / Season 1'),
140
+ (2, 'Show 2', 2, 1, 'Show 1 / Season 2'),
141
+ (2, 'Show 2', 2, 2, 'Show 2 / Season 2')
142
+ ]
143
+
144
+
145
+ def test_binary_operator_difference():
146
+ for query in (
147
+ r'Users - BannedUsers',
148
+ r'Users \ BannedUsers',
149
+ ):
150
+ root = RAParser.parse_query(query)
151
+
152
+ assert isinstance(root, BinaryOperators.Difference)
153
+ assert isinstance(root.left, RAOperand) and root.left.name == 'Users'
154
+ assert isinstance(root.right, RAOperand) and root.right.name == 'BannedUsers'
155
+
156
+ with Connection() as con:
157
+ cols, rows = con.execute_ra_return_cols(root)
158
+
159
+ assert [c.lower() for c in cols] == [
160
+ 'id',
161
+ 'username'
162
+ ]
163
+ assert rows == [
164
+ (1, 'Alice'),
165
+ (3, 'Charlie')
166
+ ]
167
+
168
+
169
+ def test_binary_operator_division():
170
+ for query in (
171
+ r'π [ShowId, SeasonNumber, EpisodeNumber] (Episodes) ÷ π [ EpisodeNumber ] (σ [ ShowId = 1 AND SeasonNumber = 1 ] (Episodes))',
172
+ r'π [ShowId, SeasonNumber, EpisodeNumber] (Episodes) : π [ EpisodeNumber ] (σ [ ShowId = 1 AND SeasonNumber = 1 ] (Episodes))',
173
+ ):
174
+ root = RAParser.parse_query(query)
175
+
176
+ assert isinstance(root, BinaryOperators.Division)
177
+ assert isinstance(root.left, UnaryOperators.Projection)
178
+ assert isinstance(root.left.target, RAOperand) and root.left.target.name == 'Episodes'
179
+ assert isinstance(root.right, UnaryOperators.Projection)
180
+ assert isinstance(root.right.target, UnaryOperators.Selection)
181
+ assert isinstance(root.right.target.target, RAOperand) and root.right.target.target.name == 'Episodes'
182
+
183
+ with Connection() as con:
184
+ cols, rows = con.execute_ra_return_cols(root)
185
+
186
+ assert [c.lower() for c in cols] == [
187
+ 'showid',
188
+ 'seasonnumber'
189
+ ]
190
+ assert rows == [
191
+ (1, 1),
192
+ (1, 2)
193
+ ]
194
+
195
+
196
+ def test_binary_operator_intersection():
197
+ for query in (
198
+ r'Users ∩ BannedUsers',
199
+ r'Users cap BannedUsers'
200
+ ):
201
+ root = RAParser.parse_query(query)
202
+
203
+ assert isinstance(root, BinaryOperators.Intersection)
204
+ assert isinstance(root.left, RAOperand) and root.left.name == 'Users'
205
+ assert isinstance(root.right, RAOperand) and root.right.name == 'BannedUsers'
206
+
207
+ with Connection() as con:
208
+ cols, rows = con.execute_ra_return_cols(root)
209
+
210
+ assert [c.lower() for c in cols] == [
211
+ 'id',
212
+ 'username'
213
+ ]
214
+ assert rows == [
215
+ (2, 'Bob')
216
+ ]
217
+
218
+
219
+ def test_binary_operator_join():
220
+ for query in (
221
+ r'Shows ⋈ Seasons',
222
+ r'Shows join Seasons'
223
+ ):
224
+ root = RAParser.parse_query(query)
225
+
226
+ assert isinstance(root, BinaryOperators.Join)
227
+ assert isinstance(root.left, RAOperand) and root.left.name == 'Shows'
228
+ assert isinstance(root.right, RAOperand) and root.right.name == 'Seasons'
229
+
230
+ with Connection() as con:
231
+ cols, rows = con.execute_ra_return_cols(root)
232
+
233
+ assert [c.lower() for c in cols] == [
234
+ 'shows.showid',
235
+ 'shows.showname',
236
+ 'seasons.seasonnumber',
237
+ 'seasons.seasonname'
238
+ ]
239
+ assert rows == [
240
+ (1, 'Show 1', 1, 'Show 1 / Season 1'),
241
+ (1, 'Show 1', 2, 'Show 1 / Season 2'),
242
+ (2, 'Show 2', 1, 'Show 2 / Season 1'),
243
+ (2, 'Show 2', 2, 'Show 2 / Season 2')
244
+ ]
245
+
246
+ for query in (
247
+ r'Shows ⋈ Users',
248
+ ):
249
+ with pytest.raises(RAParserError):
250
+ with Connection() as con:
251
+ root = RAParser.parse_query(query)
252
+ con.execute_ra_return_cols(root)
253
+
254
+
255
+ def test_binary_operator_ljoin():
256
+ for query in (
257
+ r'Users ⟕ BannedUsers',
258
+ r'Users ljoin BannedUsers'
259
+ ):
260
+ root = RAParser.parse_query(query)
261
+
262
+ assert isinstance(root, BinaryOperators.LeftOuterJoin)
263
+ assert isinstance(root.left, RAOperand) and root.left.name == 'Users'
264
+ assert isinstance(root.right, RAOperand) and root.right.name == 'BannedUsers'
265
+
266
+ with Connection() as con:
267
+ cols, rows = con.execute_ra_return_cols(root)
268
+
269
+ assert [c.lower() for c in cols] == [
270
+ 'users.id',
271
+ 'users.username',
272
+ 'bannedusers.bannedusername'
273
+ ]
274
+ assert rows == [
275
+ (1, 'Alice', None),
276
+ (2, 'Bob', 'Bob'),
277
+ (3, 'Charlie', None),
278
+ ]
279
+
280
+ for query in (
281
+ r'Shows ⟕ Users',
282
+ ):
283
+ with pytest.raises(RAParserError):
284
+ with Connection() as con:
285
+ root = RAParser.parse_query(query)
286
+ con.execute_ra_return_cols(root)
287
+
288
+
289
+ def test_binary_operator_rjoin():
290
+ for query in (
291
+ r'Users ⟖ BannedUsers',
292
+ r'Users rjoin BannedUsers'
293
+ ):
294
+ root = RAParser.parse_query(query)
295
+
296
+ assert isinstance(root, BinaryOperators.RightOuterJoin)
297
+ assert isinstance(root.left, RAOperand) and root.left.name == 'Users'
298
+ assert isinstance(root.right, RAOperand) and root.right.name == 'BannedUsers'
299
+
300
+ with Connection() as con:
301
+ cols, rows = con.execute_ra_return_cols(root)
302
+
303
+ assert [c.lower() for c in cols] == [
304
+ 'bannedusers.id',
305
+ 'users.username',
306
+ 'bannedusers.bannedusername'
307
+ ]
308
+ assert rows == [
309
+ (2, 'Bob', 'Bob'),
310
+ (4, None, 'David')
311
+ ]
312
+
313
+ for query in (
314
+ r'Shows ⟖ Users',
315
+ ):
316
+ with pytest.raises(RAParserError):
317
+ with Connection() as con:
318
+ root = RAParser.parse_query(query)
319
+ con.execute_ra_return_cols(root)
320
+
321
+
322
+ def test_binary_operator_fjoin():
323
+ for query in (
324
+ r'Users ⟗ BannedUsers',
325
+ r'Users fjoin BannedUsers',
326
+ r'Users ojoin BannedUsers'
327
+ ):
328
+ root = RAParser.parse_query(query)
329
+
330
+ assert isinstance(root, BinaryOperators.FullOuterJoin)
331
+ assert isinstance(root.left, RAOperand) and root.left.name == 'Users'
332
+ assert isinstance(root.right, RAOperand) and root.right.name == 'BannedUsers'
333
+
334
+ with Connection() as con:
335
+ cols, rows = con.execute_ra_return_cols(root)
336
+
337
+ assert [c.lower() for c in cols] == [
338
+ 'users.id',
339
+ 'users.username',
340
+ 'bannedusers.bannedusername'
341
+ ]
342
+ assert rows == [
343
+ (1, 'Alice', None),
344
+ (2, 'Bob', 'Bob'),
345
+ (3, 'Charlie', None),
346
+ (4, None, 'David')
347
+ ]
348
+
349
+ for query in (
350
+ r'Shows ⟗ Users',
351
+ ):
352
+ with pytest.raises(RAParserError):
353
+ with Connection() as con:
354
+ root = RAParser.parse_query(query)
355
+ con.execute_ra_return_cols(root)
356
+
357
+
358
+ def test_binary_operator_lsjoin():
359
+ for query in (
360
+ r'Users ⋉ BannedUsers',
361
+ r'Users lsjoin BannedUsers'
362
+ ):
363
+ root = RAParser.parse_query(query)
364
+
365
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
366
+ assert isinstance(root.left, RAOperand) and root.left.name == 'Users'
367
+ assert isinstance(root.right, RAOperand) and root.right.name == 'BannedUsers'
368
+
369
+ with Connection() as con:
370
+ cols, rows = con.execute_ra_return_cols(root)
371
+
372
+ assert [c.lower() for c in cols] == [
373
+ 'id',
374
+ 'username'
375
+ ]
376
+ assert rows == [
377
+ (2, 'Bob')
378
+ ]
379
+
380
+ for query in (
381
+ r'Shows ⋉ Users',
382
+ ):
383
+ with pytest.raises(RAParserError):
384
+ with Connection() as con:
385
+ root = RAParser.parse_query(query)
386
+ con.execute_ra_return_cols(root)
387
+
388
+
389
+ def test_binary_operator_rsjoin():
390
+ for query in (
391
+ r'Users ⋊ BannedUsers',
392
+ r'Users rsjoin BannedUsers'
393
+ ):
394
+ root = RAParser.parse_query(query)
395
+
396
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
397
+ assert isinstance(root.left, RAOperand) and root.left.name == 'Users'
398
+ assert isinstance(root.right, RAOperand) and root.right.name == 'BannedUsers'
399
+
400
+ with Connection() as con:
401
+ cols, rows = con.execute_ra_return_cols(root)
402
+
403
+ assert [c.lower() for c in cols] == [
404
+ 'id',
405
+ 'bannedusername'
406
+ ]
407
+ assert rows == [
408
+ (2, 'Bob')
409
+ ]
410
+
411
+ for query in (
412
+ r'Shows ⋊ Users',
413
+ ):
414
+ with pytest.raises(RAParserError):
415
+ with Connection() as con:
416
+ root = RAParser.parse_query(query)
417
+ con.execute_ra_return_cols(root)
418
+
419
+
420
+ def test_binary_operator_union():
421
+ for query in (
422
+ r'Users ∪ BannedUsers',
423
+ r'Users cup BannedUsers'
424
+ ):
425
+ root = RAParser.parse_query(query)
426
+
427
+ assert isinstance(root, BinaryOperators.Union)
428
+ assert isinstance(root.left, RAOperand) and root.left.name == 'Users'
429
+ assert isinstance(root.right, RAOperand) and root.right.name == 'BannedUsers'
430
+
431
+ with Connection() as con:
432
+ cols, rows = con.execute_ra_return_cols(root)
433
+
434
+ assert [c.lower() for c in cols] == [
435
+ 'id',
436
+ 'username'
437
+ ]
438
+ assert rows == [
439
+ (1, 'Alice'),
440
+ (2, 'Bob'),
441
+ (3, 'Charlie'),
442
+ (4, 'David')
443
+ ]
444
+
445
+
446
+ def test_unary_operator_projection():
447
+ with Connection() as con:
448
+ for query in (
449
+ r'π Id Users',
450
+ r'π [ Id ] Users',
451
+ r'π [ Id ] ( Users )',
452
+ r'π[Id](Users)',
453
+ r'Pi Id Users',
454
+ r'Pi [ Id ] Users',
455
+ r'Pi [ Id ] ( Users )',
456
+ r'Pi[Id](Users)'
457
+ ):
458
+ root = RAParser.parse_query(query)
459
+
460
+ assert isinstance(root, UnaryOperators.Projection)
461
+ assert isinstance(root.arg, LogicElement)
462
+ assert isinstance(root.target, RAOperand) and root.target.name == 'Users'
463
+
464
+ cols, rows = con.execute_ra_return_cols(root)
465
+
466
+ assert [c.lower() for c in cols] == [
467
+ 'id'
468
+ ]
469
+ assert rows == [
470
+ (1,),
471
+ (2,),
472
+ (3,)
473
+ ]
474
+
475
+ for query in (
476
+ r'π Id π Id, Username Users',
477
+ r'π [ Id ] (π [ Id, Username ] (Users))',
478
+ r'π[Id]π[Id,Username]Users',
479
+ r'Pi Id Pi Id, Username Users',
480
+ r'Pi [ Id ] (Pi [ Id, Username ] (Users))',
481
+ r'Pi[Id]Pi[Id,Username]Users'
482
+ ):
483
+ root = RAParser.parse_query(query)
484
+
485
+ assert isinstance(root, UnaryOperators.Projection)
486
+ assert isinstance(root.arg, LogicElement)
487
+ assert isinstance(root.target, UnaryOperators.Projection)
488
+ assert isinstance(root.target.arg, LogicElement)
489
+ assert isinstance(root.target.target, RAOperand) and root.target.target.name == 'Users'
490
+
491
+ cols, rows = con.execute_ra_return_cols(root)
492
+
493
+ assert [c.lower() for c in cols] == [
494
+ 'id'
495
+ ]
496
+ assert rows == [
497
+ (1,),
498
+ (2,),
499
+ (3,)
500
+ ]
501
+
502
+
503
+ def test_unary_operator_attributerename():
504
+ with Connection() as con:
505
+ for query in (
506
+ r'β Id2 ← Id Users',
507
+ r'β [ Id2 ← Id ] Users',
508
+ r'β [ Id2 ← Id ] ( Users )',
509
+ r'β[Id2←Id](Users)',
510
+ r'Beta Id2 ← Id Users',
511
+ r'Beta [ Id2 ← Id ] Users',
512
+ r'Beta [ Id2 ← Id ] ( Users )',
513
+ r'Beta[Id2←Id](Users)',
514
+ r'Beta Id2 <- Id Users',
515
+ r'Beta [ Id2 <- Id ] Users',
516
+ r'Beta [ Id2 <- Id ] ( Users )',
517
+ r'Beta[Id2<-Id](Users)'
518
+ ):
519
+ root = RAParser.parse_query(query)
520
+
521
+ assert isinstance(root, UnaryOperators.AttributeRename)
522
+ assert isinstance(root.arg, LogicElement)
523
+ assert isinstance(root.target, RAOperand) and root.target.name == 'Users'
524
+
525
+ cols, rows = con.execute_ra_return_cols(root)
526
+
527
+ assert [c.lower() for c in cols] == [
528
+ 'id2',
529
+ 'username'
530
+ ]
531
+ assert rows == [
532
+ (1, 'Alice'),
533
+ (2, 'Bob'),
534
+ (3, 'Charlie')
535
+ ]
536
+
537
+ for query in (
538
+ r'β Id ← Id2 β Id2 ← Id Users',
539
+ r'β [Id ← Id2] (β [Id2 ← Id] (Users))',
540
+ r'βId←Id2βId2←Id Users',
541
+ r'beta Id ← Id2 beta Id2 ← Id Users',
542
+ r'beta [Id ← Id2] (beta [Id2 ← Id] (Users))',
543
+ r'beta Id←Id2 beta Id2←Id Users',
544
+ r'beta Id <- Id2 beta Id2 <- Id Users',
545
+ r'beta [Id <- Id2] (beta [Id2 <- Id] (Users))',
546
+ r'beta Id<-Id2 beta Id2<-Id Users'
547
+ ):
548
+ root = RAParser.parse_query(query)
549
+
550
+ assert isinstance(root, UnaryOperators.AttributeRename)
551
+ assert isinstance(root.arg, LogicElement)
552
+ assert isinstance(root.target, UnaryOperators.AttributeRename)
553
+ assert isinstance(root.target.arg, LogicElement)
554
+ assert isinstance(root.target.target, RAOperand) and root.target.target.name == 'Users'
555
+
556
+ cols, rows = con.execute_ra_return_cols(root)
557
+
558
+ assert [c.lower() for c in cols] == [
559
+ 'id',
560
+ 'username'
561
+ ]
562
+ assert rows == [
563
+ (1, 'Alice'),
564
+ (2, 'Bob'),
565
+ (3, 'Charlie')
566
+ ]
567
+
568
+
569
+ def test_unary_operator_rename():
570
+ with Connection() as con:
571
+ # relation
572
+ for query in (
573
+ # ρ
574
+ r'ρ R Users',
575
+ r'ρ R ( Users )',
576
+ r'ρ [ R ] Users',
577
+ r'ρ [ R ] ( Users )',
578
+ # ϱ
579
+ r'ϱ R Users',
580
+ r'ϱ R ( Users )',
581
+ r'ϱ [ R ] Users',
582
+ r'ϱ [ R ] ( Users )',
583
+ # rho
584
+ r'rho R Users',
585
+ r'rho R ( Users )',
586
+ r'rho [ R ] Users',
587
+ r'rho [ R ] ( Users )',
588
+ ):
589
+ root = RAParser.parse_query(query)
590
+
591
+ assert isinstance(root, UnaryOperators.Rename)
592
+ assert isinstance(root.arg, RARelationReference)
593
+ assert isinstance(root.target, RAOperand) and root.target.name == 'Users'
594
+
595
+ cols, rows = con.execute_ra_return_cols(root)
596
+
597
+ assert root.arg.relation == 'R'
598
+ assert root.arg.attributes is None
599
+
600
+ assert [c.lower() for c in cols] == [
601
+ 'id',
602
+ 'username'
603
+ ]
604
+ assert rows == [
605
+ (1, 'Alice'),
606
+ (2, 'Bob'),
607
+ (3, 'Charlie')
608
+ ]
609
+
610
+ # attributes
611
+ for query in (
612
+ # ρ
613
+ r'ρ (A,) Users',
614
+ r'ρ (A,) ( Users )',
615
+ r'ρ [ (A,) ] Users',
616
+ r'ρ [ (A,) ] ( Users )',
617
+ # ϱ
618
+ r'ϱ (A,) Users',
619
+ r'ϱ (A,) ( Users )',
620
+ r'ϱ [ (A,) ] Users',
621
+ r'ϱ [ (A,) ] ( Users )',
622
+ # rho
623
+ r'rho (A,) Users',
624
+ r'rho (A,) ( Users )',
625
+ r'rho [ (A,) ] Users',
626
+ r'rho [ (A,) ] ( Users )',
627
+ ):
628
+ root = RAParser.parse_query(query)
629
+
630
+ assert isinstance(root, UnaryOperators.Rename)
631
+ assert isinstance(root.arg, RARelationReference)
632
+ assert isinstance(root.target, RAOperand) and root.target.name == 'Users'
633
+
634
+ cols, rows = con.execute_ra_return_cols(root)
635
+
636
+ assert root.arg.relation is None
637
+ assert root.arg.attributes == ['A']
638
+
639
+ assert [c.lower() for c in cols] == [
640
+ 'a',
641
+ 'username'
642
+ ]
643
+ assert rows == [
644
+ (1, 'Alice'),
645
+ (2, 'Bob'),
646
+ (3, 'Charlie')
647
+ ]
648
+
649
+ for query in (
650
+ # ρ
651
+ r'ρ (A,B) Users',
652
+ r'ρ (A, B) Users',
653
+ r'ρ (A,B) ( Users )',
654
+ r'ρ (A, B) ( Users )',
655
+ r'ρ [ (A,B) ] Users',
656
+ r'ρ [ (A, B) ] Users',
657
+ r'ρ [ (A,B) ] ( Users )',
658
+ r'ρ [ (A, B) ] ( Users )',
659
+ # ϱ
660
+ r'ϱ (A,B) Users',
661
+ r'ϱ (A, B) Users',
662
+ r'ϱ (A,B) ( Users )',
663
+ r'ϱ (A, B) ( Users )',
664
+ r'ϱ [ (A,B) ] Users',
665
+ r'ϱ [ (A, B) ] Users',
666
+ r'ϱ [ (A,B) ] ( Users )',
667
+ r'ϱ [ (A, B) ] ( Users )',
668
+ # rho
669
+ r'rho (A,B) Users',
670
+ r'rho (A, B) Users',
671
+ r'rho (A,B) ( Users )',
672
+ r'rho (A, B) ( Users )',
673
+ r'rho [ (A,B) ] Users',
674
+ r'rho [ (A, B) ] Users',
675
+ r'rho [ (A,B) ] ( Users )',
676
+ r'rho [ (A, B) ] ( Users )',
677
+ ):
678
+ root = RAParser.parse_query(query)
679
+
680
+ assert isinstance(root, UnaryOperators.Rename)
681
+ assert isinstance(root.arg, RARelationReference)
682
+ assert isinstance(root.target, RAOperand) and root.target.name == 'Users'
683
+
684
+ cols, rows = con.execute_ra_return_cols(root)
685
+
686
+ assert root.arg.relation is None
687
+ assert root.arg.attributes == ['A', 'B']
688
+
689
+ assert [c.lower() for c in cols] == [
690
+ 'a',
691
+ 'b'
692
+ ]
693
+ assert rows == [
694
+ (1, 'Alice'),
695
+ (2, 'Bob'),
696
+ (3, 'Charlie')
697
+ ]
698
+
699
+ for query in (
700
+ # ρ
701
+ r'ρ (A,A) (Users)',
702
+ r'ρ (A,a) (Users)',
703
+ r'ρ (A, A) (Users)',
704
+ r'ρ (A, a) (Users)',
705
+ # ϱ
706
+ r'ϱ (A,A) (Users)',
707
+ r'ϱ (A,a) (Users)',
708
+ r'ϱ (A, A) (Users)',
709
+ r'ϱ (A, a) (Users)',
710
+ # rho
711
+ r'rho (A,A) (Users)',
712
+ r'rho (A,a) (Users)',
713
+ r'rho (A, A) (Users)',
714
+ r'rho (A, a) (Users)',
715
+ ):
716
+ with pytest.raises(RAParserError):
717
+ RAParser.parse_query(query)
718
+
719
+ # exception when using a renamed relation outside its scope
720
+ with pytest.raises(AssertionError):
721
+ root = RAParser.parse_query('ρ [ R ] (Users) x R')
722
+ con.execute_ra_return_cols(root)
723
+
724
+
725
+ def test_unary_operator_selection():
726
+ with Connection() as con:
727
+ for query in (
728
+ r'σ Id > 1 Users',
729
+ r'σ [ Id > 1 ] Users',
730
+ r'σ [ Id > 1 ] ( Users )',
731
+ r'σ[Id>1](Users)',
732
+ r'Sigma Id > 1 Users',
733
+ r'Sigma [ Id > 1 ] Users',
734
+ r'Sigma [ Id > 1 ] ( Users )',
735
+ r'Sigma[Id>1](Users)'
736
+ ):
737
+ root = RAParser.parse_query(query)
738
+
739
+ assert isinstance(root, UnaryOperators.Selection)
740
+ assert isinstance(root.target, RAOperand) and root.target.name == 'Users'
741
+ assert isinstance(root.arg, LogicElement)
742
+
743
+ cols, rows = con.execute_ra_return_cols(root)
744
+
745
+ assert [c.lower() for c in cols] == [
746
+ 'id',
747
+ 'username'
748
+ ]
749
+ assert rows == [
750
+ (2, 'Bob'),
751
+ (3, 'Charlie')
752
+ ]
753
+
754
+ for query in (
755
+ r'σ Id > 1 σ Id > 0 Users',
756
+ r'σ [ Id > 1 ] (σ [Id > 1] (Users))',
757
+ r'σ[Id>1]σ[Id>1]Users',
758
+ r'Sigma Id > 1 Sigma Id > 0 Users',
759
+ r'Sigma [ Id > 1 ] (Sigma [Id > 1] (Users))',
760
+ r'Sigma[Id>1]Sigma[Id>1]Users'
761
+ ):
762
+ root = RAParser.parse_query(query)
763
+
764
+ assert isinstance(root, UnaryOperators.Selection)
765
+ assert isinstance(root.arg, LogicElement)
766
+ assert isinstance(root.target, UnaryOperators.Selection)
767
+ assert isinstance(root.target.arg, LogicElement)
768
+ assert isinstance(root.target.target, RAOperand) and root.target.target.name == 'Users'
769
+
770
+ cols, rows = con.execute_ra_return_cols(root)
771
+
772
+ assert [c.lower() for c in cols] == [
773
+ 'id',
774
+ 'username'
775
+ ]
776
+ assert rows == [
777
+ (2, 'Bob'),
778
+ (3, 'Charlie')
779
+ ]
780
+
781
+
782
+ def test_unary_inner_to_outer_evaluation_order():
783
+ root = RAParser.parse_query(r'π [ Id ] π [ Id, Username ] (Users)')
784
+ assert isinstance(root, UnaryOperators.Projection) and root.columns == ('Id',)
785
+ assert isinstance(root.target, UnaryOperators.Projection) and root.target.columns == ('Id', 'Username')
786
+
787
+ root = RAParser.parse_query(r'σ [ Id > 2 ] σ [ Id > 1 ] (Users)')
788
+ assert isinstance(root, UnaryOperators.Selection)
789
+ assert isinstance(root.condition, BinaryOperators.GreaterThan)
790
+ assert root.condition.left == ('Id',) and root.condition.right == ('2',)
791
+ assert isinstance(root.target, UnaryOperators.Selection)
792
+ assert isinstance(root.target.condition, BinaryOperators.GreaterThan)
793
+ assert root.target.condition.left == ('Id',) and root.target.condition.right == ('1',)
794
+
795
+ root = RAParser.parse_query(r'β [ Id3 ← Id2 ] β [ Id2 ← Id ] (Users)')
796
+ assert isinstance(root, UnaryOperators.AttributeRename)
797
+ assert isinstance(root.arrow, BinaryOperators.ArrowLeft)
798
+ assert root.arrow.left == ('Id3',) and root.arrow.right == ('Id2',)
799
+ assert isinstance(root.target, UnaryOperators.AttributeRename)
800
+ assert isinstance(root.target.arrow, BinaryOperators.ArrowLeft)
801
+ assert root.target.arrow.left == ('Id2',) and root.target.arrow.right == ('Id',)
802
+
803
+ root = RAParser.parse_query(r'ρ [ S(X, Y) ] ρ [ R(A, B) ] (Users)')
804
+ assert isinstance(root, UnaryOperators.Rename)
805
+ assert isinstance(root.arg, RARelationReference)
806
+ assert root.arg.relation == 'S' and root.arg.attributes == ['X', 'Y']
807
+ assert isinstance(root.target, UnaryOperators.Rename)
808
+ assert isinstance(root.target.arg, RARelationReference)
809
+ assert root.target.arg.relation == 'R' and root.target.arg.attributes == ['A', 'B']
810
+
811
+
812
+ def test_binary_left_to_right_evaluation_order():
813
+ # difference
814
+ root = RAParser.parse_query(r'a \ b \ c')
815
+ assert isinstance(root, BinaryOperators.Difference)
816
+ assert isinstance(root.left, BinaryOperators.Difference)
817
+ assert isinstance(root.left.left, RAOperand)
818
+ assert root.left.left.name == 'a'
819
+ assert isinstance(root.left.right, RAOperand)
820
+ assert root.left.right.name == 'b'
821
+ assert isinstance(root.right, RAOperand)
822
+ assert root.right.name == 'c'
823
+
824
+ # union
825
+ root = RAParser.parse_query(r'a ∪ b ∪ c')
826
+ assert isinstance(root, BinaryOperators.Union)
827
+ assert isinstance(root.left, BinaryOperators.Union)
828
+ assert isinstance(root.left.left, RAOperand)
829
+ assert root.left.left.name == 'a'
830
+ assert isinstance(root.left.right, RAOperand)
831
+ assert root.left.right.name == 'b'
832
+ assert isinstance(root.right, RAOperand)
833
+ assert root.right.name == 'c'
834
+
835
+ # intersection
836
+ root = RAParser.parse_query(r'a ∩ b ∩ c')
837
+ assert isinstance(root, BinaryOperators.Intersection)
838
+ assert isinstance(root.left, BinaryOperators.Intersection)
839
+ assert isinstance(root.left.left, RAOperand)
840
+ assert root.left.left.name == 'a'
841
+ assert isinstance(root.left.right, RAOperand)
842
+ assert root.left.right.name == 'b'
843
+ assert isinstance(root.right, RAOperand)
844
+ assert root.right.name == 'c'
845
+
846
+ # natural join
847
+ root = RAParser.parse_query(r'a ⋈ b ⋈ c')
848
+ assert isinstance(root, BinaryOperators.Join)
849
+ assert isinstance(root.left, BinaryOperators.Join)
850
+ assert isinstance(root.left.left, RAOperand)
851
+ assert root.left.left.name == 'a'
852
+ assert isinstance(root.left.right, RAOperand)
853
+ assert root.left.right.name == 'b'
854
+ assert isinstance(root.right, RAOperand)
855
+ assert root.right.name == 'c'
856
+
857
+ # outer join
858
+ root = RAParser.parse_query(r'a ⟕ b ⟕ c') # left outer, left outer
859
+ assert isinstance(root, BinaryOperators.LeftOuterJoin)
860
+ assert isinstance(root.left, BinaryOperators.LeftOuterJoin)
861
+ assert isinstance(root.left.left, RAOperand)
862
+ assert root.left.left.name == 'a'
863
+ assert isinstance(root.left.right, RAOperand)
864
+ assert root.left.right.name == 'b'
865
+ assert isinstance(root.right, RAOperand)
866
+ assert root.right.name == 'c'
867
+
868
+ root = RAParser.parse_query(r'a ⟖ b ⟖ c') # right outer, right outer
869
+ assert isinstance(root, BinaryOperators.RightOuterJoin)
870
+ assert isinstance(root.left, BinaryOperators.RightOuterJoin)
871
+ assert isinstance(root.left.left, RAOperand)
872
+ assert root.left.left.name == 'a'
873
+ assert isinstance(root.left.right, RAOperand)
874
+ assert root.left.right.name == 'b'
875
+ assert isinstance(root.right, RAOperand)
876
+ assert root.right.name == 'c'
877
+
878
+ root = RAParser.parse_query(r'a ⟗ b ⟗ c') # full outer, full outer
879
+ assert isinstance(root, BinaryOperators.FullOuterJoin)
880
+ assert isinstance(root.left, BinaryOperators.FullOuterJoin)
881
+ assert isinstance(root.left.left, RAOperand)
882
+ assert root.left.left.name == 'a'
883
+ assert isinstance(root.left.right, RAOperand)
884
+ assert root.left.right.name == 'b'
885
+ assert isinstance(root.right, RAOperand)
886
+ assert root.right.name == 'c'
887
+
888
+ # semi join
889
+ root = RAParser.parse_query(r'a ⋉ b ⋉ c') # left semi, left semi
890
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
891
+ assert isinstance(root.left, BinaryOperators.LeftSemiJoin)
892
+ assert isinstance(root.left.left, RAOperand)
893
+ assert root.left.left.name == 'a'
894
+ assert isinstance(root.left.right, RAOperand)
895
+ assert root.left.right.name == 'b'
896
+ assert isinstance(root.right, RAOperand)
897
+ assert root.right.name == 'c'
898
+
899
+ root = RAParser.parse_query(r'a ⋊ b ⋊ c') # right semi, right semi
900
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
901
+ assert isinstance(root.left, BinaryOperators.RightSemiJoin)
902
+ assert isinstance(root.left.left, RAOperand)
903
+ assert root.left.left.name == 'a'
904
+ assert isinstance(root.left.right, RAOperand)
905
+ assert root.left.right.name == 'b'
906
+ assert isinstance(root.right, RAOperand)
907
+ assert root.right.name == 'c'
908
+
909
+ # mixed outer and semi joins
910
+ root = RAParser.parse_query(r'a ⟕ b ⟖ c') # left outer, right outer
911
+ assert isinstance(root, BinaryOperators.RightOuterJoin)
912
+ assert isinstance(root.left, BinaryOperators.LeftOuterJoin)
913
+ assert isinstance(root.left.left, RAOperand)
914
+ assert root.left.left.name == 'a'
915
+ assert isinstance(root.left.right, RAOperand)
916
+ assert root.left.right.name == 'b'
917
+ assert isinstance(root.right, RAOperand)
918
+ assert root.right.name == 'c'
919
+
920
+ root = RAParser.parse_query(r'a ⟕ b ⟗ c') # left outer, full outer
921
+ assert isinstance(root, BinaryOperators.FullOuterJoin)
922
+ assert isinstance(root.left, BinaryOperators.LeftOuterJoin)
923
+ assert isinstance(root.left.left, RAOperand)
924
+ assert root.left.left.name == 'a'
925
+ assert isinstance(root.left.right, RAOperand)
926
+ assert root.left.right.name == 'b'
927
+ assert isinstance(root.right, RAOperand)
928
+ assert root.right.name == 'c'
929
+
930
+ root = RAParser.parse_query(r'a ⟕ b ⋉ c') # left outer, left semi
931
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
932
+ assert isinstance(root.left, BinaryOperators.LeftOuterJoin)
933
+ assert isinstance(root.left.left, RAOperand)
934
+ assert root.left.left.name == 'a'
935
+ assert isinstance(root.left.right, RAOperand)
936
+ assert root.left.right.name == 'b'
937
+ assert isinstance(root.right, RAOperand)
938
+ assert root.right.name == 'c'
939
+
940
+ root = RAParser.parse_query(r'a ⟕ b ⋊ c') # left outer, right semi
941
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
942
+ assert isinstance(root.left, BinaryOperators.LeftOuterJoin)
943
+ assert isinstance(root.left.left, RAOperand)
944
+ assert root.left.left.name == 'a'
945
+ assert isinstance(root.left.right, RAOperand)
946
+ assert root.left.right.name == 'b'
947
+ assert isinstance(root.right, RAOperand)
948
+ assert root.right.name == 'c'
949
+
950
+ root = RAParser.parse_query(r'a ⟖ b ⟕ c') # right outer, left outer
951
+ assert isinstance(root, BinaryOperators.LeftOuterJoin)
952
+ assert isinstance(root.left, BinaryOperators.RightOuterJoin)
953
+ assert isinstance(root.left.left, RAOperand)
954
+ assert root.left.left.name == 'a'
955
+ assert isinstance(root.left.right, RAOperand)
956
+ assert root.left.right.name == 'b'
957
+ assert isinstance(root.right, RAOperand)
958
+ assert root.right.name == 'c'
959
+
960
+ root = RAParser.parse_query(r'a ⟖ b ⟗ c') # right outer, full outer
961
+ assert isinstance(root, BinaryOperators.FullOuterJoin)
962
+ assert isinstance(root.left, BinaryOperators.RightOuterJoin)
963
+ assert isinstance(root.left.left, RAOperand)
964
+ assert root.left.left.name == 'a'
965
+ assert isinstance(root.left.right, RAOperand)
966
+ assert root.left.right.name == 'b'
967
+ assert isinstance(root.right, RAOperand)
968
+ assert root.right.name == 'c'
969
+
970
+ root = RAParser.parse_query(r'a ⟖ b ⋉ c') # right outer, left semi
971
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
972
+ assert isinstance(root.left, BinaryOperators.RightOuterJoin)
973
+ assert isinstance(root.left.left, RAOperand)
974
+ assert root.left.left.name == 'a'
975
+ assert isinstance(root.left.right, RAOperand)
976
+ assert root.left.right.name == 'b'
977
+ assert isinstance(root.right, RAOperand)
978
+ assert root.right.name == 'c'
979
+
980
+ root = RAParser.parse_query(r'a ⟖ b ⋊ c') # right outer, right semi
981
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
982
+ assert isinstance(root.left, BinaryOperators.RightOuterJoin)
983
+ assert isinstance(root.left.left, RAOperand)
984
+ assert root.left.left.name == 'a'
985
+ assert isinstance(root.left.right, RAOperand)
986
+ assert root.left.right.name == 'b'
987
+ assert isinstance(root.right, RAOperand)
988
+ assert root.right.name == 'c'
989
+
990
+ root = RAParser.parse_query(r'a ⟗ b ⟕ c') # full outer, left outer
991
+ assert isinstance(root, BinaryOperators.LeftOuterJoin)
992
+ assert isinstance(root.left, BinaryOperators.FullOuterJoin)
993
+ assert isinstance(root.left.left, RAOperand)
994
+ assert root.left.left.name == 'a'
995
+ assert isinstance(root.left.right, RAOperand)
996
+ assert root.left.right.name == 'b'
997
+ assert isinstance(root.right, RAOperand)
998
+ assert root.right.name == 'c'
999
+
1000
+ root = RAParser.parse_query(r'a ⟗ b ⟖ c') # full outer, right outer
1001
+ assert isinstance(root, BinaryOperators.RightOuterJoin)
1002
+ assert isinstance(root.left, BinaryOperators.FullOuterJoin)
1003
+ assert isinstance(root.left.left, RAOperand)
1004
+ assert root.left.left.name == 'a'
1005
+ assert isinstance(root.left.right, RAOperand)
1006
+ assert root.left.right.name == 'b'
1007
+ assert isinstance(root.right, RAOperand)
1008
+ assert root.right.name == 'c'
1009
+
1010
+ root = RAParser.parse_query(r'a ⟗ b ⋉ c') # full outer, left semi
1011
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
1012
+ assert isinstance(root.left, BinaryOperators.FullOuterJoin)
1013
+ assert isinstance(root.left.left, RAOperand)
1014
+ assert root.left.left.name == 'a'
1015
+ assert isinstance(root.left.right, RAOperand)
1016
+ assert root.left.right.name == 'b'
1017
+ assert isinstance(root.right, RAOperand)
1018
+ assert root.right.name == 'c'
1019
+
1020
+ root = RAParser.parse_query(r'a ⟗ b ⋊ c') # full outer, right semi
1021
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
1022
+ assert isinstance(root.left, BinaryOperators.FullOuterJoin)
1023
+ assert isinstance(root.left.left, RAOperand)
1024
+ assert root.left.left.name == 'a'
1025
+ assert isinstance(root.left.right, RAOperand)
1026
+ assert root.left.right.name == 'b'
1027
+ assert isinstance(root.right, RAOperand)
1028
+ assert root.right.name == 'c'
1029
+
1030
+ root = RAParser.parse_query(r'a ⋉ b ⟕ c') # left semi, left outer
1031
+ assert isinstance(root, BinaryOperators.LeftOuterJoin)
1032
+ assert isinstance(root.left, BinaryOperators.LeftSemiJoin)
1033
+ assert isinstance(root.left.left, RAOperand)
1034
+ assert root.left.left.name == 'a'
1035
+ assert isinstance(root.left.right, RAOperand)
1036
+ assert root.left.right.name == 'b'
1037
+ assert isinstance(root.right, RAOperand)
1038
+ assert root.right.name == 'c'
1039
+
1040
+ root = RAParser.parse_query(r'a ⋉ b ⟖ c') # left semi, right outer
1041
+ assert isinstance(root, BinaryOperators.RightOuterJoin)
1042
+ assert isinstance(root.left, BinaryOperators.LeftSemiJoin)
1043
+ assert isinstance(root.left.left, RAOperand)
1044
+ assert root.left.left.name == 'a'
1045
+ assert isinstance(root.left.right, RAOperand)
1046
+ assert root.left.right.name == 'b'
1047
+ assert isinstance(root.right, RAOperand)
1048
+ assert root.right.name == 'c'
1049
+
1050
+ root = RAParser.parse_query(r'a ⋉ b ⟗ c') # left semi, full outer
1051
+ assert isinstance(root, BinaryOperators.FullOuterJoin)
1052
+ assert isinstance(root.left, BinaryOperators.LeftSemiJoin)
1053
+ assert isinstance(root.left.left, RAOperand)
1054
+ assert root.left.left.name == 'a'
1055
+ assert isinstance(root.left.right, RAOperand)
1056
+ assert root.left.right.name == 'b'
1057
+ assert isinstance(root.right, RAOperand)
1058
+ assert root.right.name == 'c'
1059
+
1060
+ root = RAParser.parse_query(r'a ⋉ b ⋊ c') # left semi, right semi
1061
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
1062
+ assert isinstance(root.left, BinaryOperators.LeftSemiJoin)
1063
+ assert isinstance(root.left.left, RAOperand)
1064
+ assert root.left.left.name == 'a'
1065
+ assert isinstance(root.left.right, RAOperand)
1066
+ assert root.left.right.name == 'b'
1067
+ assert isinstance(root.right, RAOperand)
1068
+ assert root.right.name == 'c'
1069
+
1070
+ root = RAParser.parse_query(r'a ⋊ b ⟕ c') # right semi, left outer
1071
+ assert isinstance(root, BinaryOperators.LeftOuterJoin)
1072
+ assert isinstance(root.left, BinaryOperators.RightSemiJoin)
1073
+ assert isinstance(root.left.left, RAOperand)
1074
+ assert root.left.left.name == 'a'
1075
+ assert isinstance(root.left.right, RAOperand)
1076
+ assert root.left.right.name == 'b'
1077
+ assert isinstance(root.right, RAOperand)
1078
+ assert root.right.name == 'c'
1079
+
1080
+ root = RAParser.parse_query(r'a ⋊ b ⟖ c') # right semi, right outer
1081
+ assert isinstance(root, BinaryOperators.RightOuterJoin)
1082
+ assert isinstance(root.left, BinaryOperators.RightSemiJoin)
1083
+ assert isinstance(root.left.left, RAOperand)
1084
+ assert root.left.left.name == 'a'
1085
+ assert isinstance(root.left.right, RAOperand)
1086
+ assert root.left.right.name == 'b'
1087
+ assert isinstance(root.right, RAOperand)
1088
+ assert root.right.name == 'c'
1089
+
1090
+ root = RAParser.parse_query(r'a ⋊ b ⟗ c') # right semi, full outer
1091
+ assert isinstance(root, BinaryOperators.FullOuterJoin)
1092
+ assert isinstance(root.left, BinaryOperators.RightSemiJoin)
1093
+ assert isinstance(root.left.left, RAOperand)
1094
+ assert root.left.left.name == 'a'
1095
+ assert isinstance(root.left.right, RAOperand)
1096
+ assert root.left.right.name == 'b'
1097
+ assert isinstance(root.right, RAOperand)
1098
+ assert root.right.name == 'c'
1099
+
1100
+ root = RAParser.parse_query(r'a ⋊ b ⋉ c') # right semi, left semi
1101
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
1102
+ assert isinstance(root.left, BinaryOperators.RightSemiJoin)
1103
+ assert isinstance(root.left.left, RAOperand)
1104
+ assert root.left.left.name == 'a'
1105
+ assert isinstance(root.left.right, RAOperand)
1106
+ assert root.left.right.name == 'b'
1107
+ assert isinstance(root.right, RAOperand)
1108
+ assert root.right.name == 'c'
1109
+
1110
+ # cross join
1111
+ root = RAParser.parse_query(r'a x b x c')
1112
+ assert isinstance(root, BinaryOperators.Cross)
1113
+ assert isinstance(root.left, BinaryOperators.Cross)
1114
+ assert isinstance(root.left.left, RAOperand)
1115
+ assert root.left.left.name == 'a'
1116
+ assert isinstance(root.left.right, RAOperand)
1117
+ assert root.left.right.name == 'b'
1118
+ assert isinstance(root.right, RAOperand)
1119
+ assert root.right.name == 'c'
1120
+
1121
+
1122
+ def test_unary_evaluation_order():
1123
+ # π
1124
+ root = RAParser.parse_query(r'π [ Id ] σ [ Id > 1 ] (Users)')
1125
+ assert isinstance(root, UnaryOperators.Projection)
1126
+ assert isinstance(root.target, UnaryOperators.Selection)
1127
+
1128
+ root = RAParser.parse_query(r'π [ Id2 ] β [ Id2 ← Id ] (Users)')
1129
+ assert isinstance(root, UnaryOperators.Projection)
1130
+ assert isinstance(root.target, UnaryOperators.AttributeRename)
1131
+
1132
+ root = RAParser.parse_query(r'π [ Id2 ] ρ [ R(Id2, Username2) ] (Users)')
1133
+ assert isinstance(root, UnaryOperators.Projection)
1134
+ assert isinstance(root.target, UnaryOperators.Rename)
1135
+
1136
+ # σ
1137
+ root = RAParser.parse_query(r'σ [ Id > 1 ] π [ Id ] (Users)')
1138
+ assert isinstance(root, UnaryOperators.Selection)
1139
+ assert isinstance(root.target, UnaryOperators.Projection)
1140
+
1141
+ root = RAParser.parse_query(r'σ [ Id2 > 1 ] β [ Id2 ← Id ] (Users)')
1142
+ assert isinstance(root, UnaryOperators.Selection)
1143
+ assert isinstance(root.target, UnaryOperators.AttributeRename)
1144
+
1145
+ root = RAParser.parse_query(r'σ [ Id2 > 1 ] ρ [ R(Id2, Username2) ] (Users)')
1146
+ assert isinstance(root, UnaryOperators.Selection)
1147
+ assert isinstance(root.target, UnaryOperators.Rename)
1148
+
1149
+ # β
1150
+ root = RAParser.parse_query(r'β [ Id2 ← Id ] π [ Id ] (Users)')
1151
+ assert isinstance(root, UnaryOperators.AttributeRename)
1152
+ assert isinstance(root.target, UnaryOperators.Projection)
1153
+
1154
+ root = RAParser.parse_query(r'β [ Id2 ← Id ] σ [ Id > 1 ] (Users)')
1155
+ assert isinstance(root, UnaryOperators.AttributeRename)
1156
+ assert isinstance(root.target, UnaryOperators.Selection)
1157
+
1158
+ root = RAParser.parse_query(r'β [ Id3 ← Id2 ] ρ [ R(Id2, Username2) ] (Users)')
1159
+ assert isinstance(root, UnaryOperators.AttributeRename)
1160
+ assert isinstance(root.target, UnaryOperators.Rename)
1161
+
1162
+ # ρ
1163
+ root = RAParser.parse_query(r'ρ [ R(Id2,) ] π [ Id ] (Users)')
1164
+ assert isinstance(root, UnaryOperators.Rename)
1165
+ assert isinstance(root.target, UnaryOperators.Projection)
1166
+
1167
+ root = RAParser.parse_query(r'ρ [ R(Id2, Username2) ] σ [ Id > 1 ] (Users)')
1168
+ assert isinstance(root, UnaryOperators.Rename)
1169
+ assert isinstance(root.target, UnaryOperators.Selection)
1170
+
1171
+ root = RAParser.parse_query(r'ρ [ R(Id3, Username2) ] β [ Id2 ← Id ] (Users)')
1172
+ assert isinstance(root, UnaryOperators.Rename)
1173
+ assert isinstance(root.target, UnaryOperators.AttributeRename)
1174
+
1175
+
1176
+ def test_binary_evaluation_order():
1177
+ # difference <-> union
1178
+ root = RAParser.parse_query(r'a \ b ∪ c')
1179
+ assert isinstance(root, BinaryOperators.Difference)
1180
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Union)
1181
+
1182
+ root = RAParser.parse_query(r'a ∪ b \ c')
1183
+ assert isinstance(root, BinaryOperators.Difference)
1184
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Union)
1185
+
1186
+ # difference <-> intersection
1187
+ root = RAParser.parse_query(r'a \ b ∩ c')
1188
+ assert isinstance(root, BinaryOperators.Difference)
1189
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Intersection)
1190
+
1191
+ root = RAParser.parse_query(r'a ∩ b \ c')
1192
+ assert isinstance(root, BinaryOperators.Difference)
1193
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Intersection)
1194
+
1195
+ # difference <-> join
1196
+ root = RAParser.parse_query(r'a \ b ⋈ c')
1197
+ assert isinstance(root, BinaryOperators.Difference)
1198
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Join)
1199
+
1200
+ root = RAParser.parse_query(r'a ⋈ b \ c')
1201
+ assert isinstance(root, BinaryOperators.Difference)
1202
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Join)
1203
+
1204
+ root = RAParser.parse_query(r'a \ b ⟕ c')
1205
+ assert isinstance(root, BinaryOperators.Difference)
1206
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.LeftOuterJoin)
1207
+
1208
+ root = RAParser.parse_query(r'a ⟕ b \ c')
1209
+ assert isinstance(root, BinaryOperators.Difference)
1210
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.LeftOuterJoin)
1211
+
1212
+ root = RAParser.parse_query(r'a \ b ⟖ c')
1213
+ assert isinstance(root, BinaryOperators.Difference)
1214
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.RightOuterJoin)
1215
+
1216
+ root = RAParser.parse_query(r'a ⟖ b \ c')
1217
+ assert isinstance(root, BinaryOperators.Difference)
1218
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.RightOuterJoin)
1219
+
1220
+ root = RAParser.parse_query(r'a \ b ⟗ c')
1221
+ assert isinstance(root, BinaryOperators.Difference)
1222
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.FullOuterJoin)
1223
+
1224
+ root = RAParser.parse_query(r'a ⟗ b \ c')
1225
+ assert isinstance(root, BinaryOperators.Difference)
1226
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.FullOuterJoin)
1227
+
1228
+ root = RAParser.parse_query(r'a \ b ⋉ c')
1229
+ assert isinstance(root, BinaryOperators.Difference)
1230
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.LeftSemiJoin)
1231
+
1232
+ root = RAParser.parse_query(r'a ⋉ b \ c')
1233
+ assert isinstance(root, BinaryOperators.Difference)
1234
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.LeftSemiJoin)
1235
+
1236
+ root = RAParser.parse_query(r'a \ b ⋊ c')
1237
+ assert isinstance(root, BinaryOperators.Difference)
1238
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.RightSemiJoin)
1239
+
1240
+ root = RAParser.parse_query(r'a ⋊ b \ c')
1241
+ assert isinstance(root, BinaryOperators.Difference)
1242
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.RightSemiJoin)
1243
+
1244
+ # difference <-> cross
1245
+ root = RAParser.parse_query(r'a \ b x c')
1246
+ assert isinstance(root, BinaryOperators.Difference)
1247
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Cross)
1248
+
1249
+ root = RAParser.parse_query(r'a x b \ c')
1250
+ assert isinstance(root, BinaryOperators.Difference)
1251
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Cross)
1252
+
1253
+ # difference <-> division
1254
+ root = RAParser.parse_query(r'a \ b ÷ c')
1255
+ assert isinstance(root, BinaryOperators.Difference)
1256
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Division)
1257
+
1258
+ root = RAParser.parse_query(r'a ÷ b \ c')
1259
+ assert isinstance(root, BinaryOperators.Difference)
1260
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Division)
1261
+
1262
+ # union <-> intersection
1263
+ root = RAParser.parse_query(r'a ∪ b ∩ c')
1264
+ assert isinstance(root, BinaryOperators.Union)
1265
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Intersection)
1266
+
1267
+ root = RAParser.parse_query(r'a ∩ b ∪ c')
1268
+ assert isinstance(root, BinaryOperators.Union)
1269
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Intersection)
1270
+
1271
+ # union <-> join
1272
+ root = RAParser.parse_query(r'a ∪ b ⋈ c')
1273
+ assert isinstance(root, BinaryOperators.Union)
1274
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Join)
1275
+
1276
+ root = RAParser.parse_query(r'a ⋈ b ∪ c')
1277
+ assert isinstance(root, BinaryOperators.Union)
1278
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Join)
1279
+
1280
+ root = RAParser.parse_query(r'a ∪ b ⟕ c')
1281
+ assert isinstance(root, BinaryOperators.Union)
1282
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.LeftOuterJoin)
1283
+
1284
+ root = RAParser.parse_query(r'a ⟕ b ∪ c')
1285
+ assert isinstance(root, BinaryOperators.Union)
1286
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.LeftOuterJoin)
1287
+
1288
+ root = RAParser.parse_query(r'a ∪ b ⟖ c')
1289
+ assert isinstance(root, BinaryOperators.Union)
1290
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.RightOuterJoin)
1291
+
1292
+ root = RAParser.parse_query(r'a ⟖ b ∪ c')
1293
+ assert isinstance(root, BinaryOperators.Union)
1294
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.RightOuterJoin)
1295
+
1296
+ root = RAParser.parse_query(r'a ∪ b ⟗ c')
1297
+ assert isinstance(root, BinaryOperators.Union)
1298
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.FullOuterJoin)
1299
+
1300
+ root = RAParser.parse_query(r'a ⟗ b ∪ c')
1301
+ assert isinstance(root, BinaryOperators.Union)
1302
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.FullOuterJoin)
1303
+
1304
+ root = RAParser.parse_query(r'a ∪ b ⋉ c')
1305
+ assert isinstance(root, BinaryOperators.Union)
1306
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.LeftSemiJoin)
1307
+
1308
+ root = RAParser.parse_query(r'a ⋉ b ∪ c')
1309
+ assert isinstance(root, BinaryOperators.Union)
1310
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.LeftSemiJoin)
1311
+
1312
+ root = RAParser.parse_query(r'a ∪ b ⋊ c')
1313
+ assert isinstance(root, BinaryOperators.Union)
1314
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.RightSemiJoin)
1315
+
1316
+ root = RAParser.parse_query(r'a ⋊ b ∪ c')
1317
+ assert isinstance(root, BinaryOperators.Union)
1318
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.RightSemiJoin)
1319
+
1320
+ # union <-> cross
1321
+ root = RAParser.parse_query(r'a ∪ b x c')
1322
+ assert isinstance(root, BinaryOperators.Union)
1323
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Cross)
1324
+
1325
+ root = RAParser.parse_query(r'a x b ∪ c')
1326
+ assert isinstance(root, BinaryOperators.Union)
1327
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Cross)
1328
+
1329
+ # union <-> division
1330
+ root = RAParser.parse_query(r'a ∪ b ÷ c')
1331
+ assert isinstance(root, BinaryOperators.Union)
1332
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Division)
1333
+
1334
+ root = RAParser.parse_query(r'a ÷ b ∪ c')
1335
+ assert isinstance(root, BinaryOperators.Union)
1336
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Division)
1337
+
1338
+ # intersection <-> join
1339
+ root = RAParser.parse_query(r'a ∩ b ⋈ c')
1340
+ assert isinstance(root, BinaryOperators.Intersection)
1341
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Join)
1342
+
1343
+ root = RAParser.parse_query(r'a ⋈ b ∩ c')
1344
+ assert isinstance(root, BinaryOperators.Intersection)
1345
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Join)
1346
+
1347
+ root = RAParser.parse_query(r'a ∩ b ⟕ c')
1348
+ assert isinstance(root, BinaryOperators.Intersection)
1349
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.LeftOuterJoin)
1350
+
1351
+ root = RAParser.parse_query(r'a ⟕ b ∩ c')
1352
+ assert isinstance(root, BinaryOperators.Intersection)
1353
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.LeftOuterJoin)
1354
+
1355
+ root = RAParser.parse_query(r'a ∩ b ⟖ c')
1356
+ assert isinstance(root, BinaryOperators.Intersection)
1357
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.RightOuterJoin)
1358
+
1359
+ root = RAParser.parse_query(r'a ⟖ b ∩ c')
1360
+ assert isinstance(root, BinaryOperators.Intersection)
1361
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.RightOuterJoin)
1362
+
1363
+ root = RAParser.parse_query(r'a ∩ b ⟗ c')
1364
+ assert isinstance(root, BinaryOperators.Intersection)
1365
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.FullOuterJoin)
1366
+
1367
+ root = RAParser.parse_query(r'a ⟗ b ∩ c')
1368
+ assert isinstance(root, BinaryOperators.Intersection)
1369
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.FullOuterJoin)
1370
+
1371
+ root = RAParser.parse_query(r'a ∩ b ⋉ c')
1372
+ assert isinstance(root, BinaryOperators.Intersection)
1373
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.LeftSemiJoin)
1374
+
1375
+ root = RAParser.parse_query(r'a ⋉ b ∩ c')
1376
+ assert isinstance(root, BinaryOperators.Intersection)
1377
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.LeftSemiJoin)
1378
+
1379
+ root = RAParser.parse_query(r'a ∩ b ⋊ c')
1380
+ assert isinstance(root, BinaryOperators.Intersection)
1381
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.RightSemiJoin)
1382
+
1383
+ root = RAParser.parse_query(r'a ⋊ b ∩ c')
1384
+ assert isinstance(root, BinaryOperators.Intersection)
1385
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.RightSemiJoin)
1386
+
1387
+ # intersection <-> cross
1388
+ root = RAParser.parse_query(r'a ∩ b x c')
1389
+ assert isinstance(root, BinaryOperators.Intersection)
1390
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Cross)
1391
+
1392
+ root = RAParser.parse_query(r'a x b ∩ c')
1393
+ assert isinstance(root, BinaryOperators.Intersection)
1394
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Cross)
1395
+
1396
+ # intersection <-> division
1397
+ root = RAParser.parse_query(r'a ∩ b ÷ c')
1398
+ assert isinstance(root, BinaryOperators.Intersection)
1399
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Division)
1400
+
1401
+ root = RAParser.parse_query(r'a ÷ b ∩ c')
1402
+ assert isinstance(root, BinaryOperators.Intersection)
1403
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Division)
1404
+
1405
+ # join <-> cross
1406
+ root = RAParser.parse_query(r'a ⋈ b x c')
1407
+ assert isinstance(root, BinaryOperators.Join)
1408
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Cross)
1409
+
1410
+ root = RAParser.parse_query(r'a x b ⋈ c')
1411
+ assert isinstance(root, BinaryOperators.Join)
1412
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Cross)
1413
+
1414
+ root = RAParser.parse_query(r'a ⟕ b x c')
1415
+ assert isinstance(root, BinaryOperators.LeftOuterJoin)
1416
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Cross)
1417
+
1418
+ root = RAParser.parse_query(r'a x b ⟕ c')
1419
+ assert isinstance(root, BinaryOperators.LeftOuterJoin)
1420
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Cross)
1421
+
1422
+ root = RAParser.parse_query(r'a ⟖ b x c')
1423
+ assert isinstance(root, BinaryOperators.RightOuterJoin)
1424
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Cross)
1425
+
1426
+ root = RAParser.parse_query(r'a x b ⟖ c')
1427
+ assert isinstance(root, BinaryOperators.RightOuterJoin)
1428
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Cross)
1429
+
1430
+ root = RAParser.parse_query(r'a ⟗ b x c')
1431
+ assert isinstance(root, BinaryOperators.FullOuterJoin)
1432
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Cross)
1433
+
1434
+ root = RAParser.parse_query(r'a x b ⟗ c')
1435
+ assert isinstance(root, BinaryOperators.FullOuterJoin)
1436
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Cross)
1437
+
1438
+ root = RAParser.parse_query(r'a ⋉ b x c')
1439
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
1440
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Cross)
1441
+
1442
+ root = RAParser.parse_query(r'a x b ⋉ c')
1443
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
1444
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Cross)
1445
+
1446
+ root = RAParser.parse_query(r'a ⋊ b x c')
1447
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
1448
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Cross)
1449
+
1450
+ root = RAParser.parse_query(r'a x b ⋊ c')
1451
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
1452
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Cross)
1453
+
1454
+ # join <-> division
1455
+ root = RAParser.parse_query(r'a ⋈ b ÷ c')
1456
+ assert isinstance(root, BinaryOperators.Join)
1457
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Division)
1458
+
1459
+ root = RAParser.parse_query(r'a ÷ b ⋈ c')
1460
+ assert isinstance(root, BinaryOperators.Join)
1461
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Division)
1462
+
1463
+ root = RAParser.parse_query(r'a ⟕ b ÷ c')
1464
+ assert isinstance(root, BinaryOperators.LeftOuterJoin)
1465
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Division)
1466
+
1467
+ root = RAParser.parse_query(r'a ÷ b ⟕ c')
1468
+ assert isinstance(root, BinaryOperators.LeftOuterJoin)
1469
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Division)
1470
+
1471
+ root = RAParser.parse_query(r'a ⟖ b ÷ c')
1472
+ assert isinstance(root, BinaryOperators.RightOuterJoin)
1473
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Division)
1474
+
1475
+ root = RAParser.parse_query(r'a ÷ b ⟖ c')
1476
+ assert isinstance(root, BinaryOperators.RightOuterJoin)
1477
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Division)
1478
+
1479
+ root = RAParser.parse_query(r'a ⟗ b ÷ c')
1480
+ assert isinstance(root, BinaryOperators.FullOuterJoin)
1481
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Division)
1482
+
1483
+ root = RAParser.parse_query(r'a ÷ b ⟗ c')
1484
+ assert isinstance(root, BinaryOperators.FullOuterJoin)
1485
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Division)
1486
+
1487
+ root = RAParser.parse_query(r'a ⋉ b ÷ c')
1488
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
1489
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Division)
1490
+
1491
+ root = RAParser.parse_query(r'a ÷ b ⋉ c')
1492
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
1493
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Division)
1494
+
1495
+ root = RAParser.parse_query(r'a ⋊ b ÷ c')
1496
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
1497
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Division)
1498
+
1499
+ root = RAParser.parse_query(r'a ÷ b ⋊ c')
1500
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
1501
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Division)
1502
+
1503
+ # natural join <-> outer join
1504
+ root = RAParser.parse_query(r'a ⋈ b ⟕ c')
1505
+ assert isinstance(root, BinaryOperators.Join)
1506
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.LeftOuterJoin)
1507
+
1508
+ root = RAParser.parse_query(r'a ⟕ b ⋈ c')
1509
+ assert isinstance(root, BinaryOperators.Join)
1510
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.LeftOuterJoin)
1511
+
1512
+ root = RAParser.parse_query(r'a ⋈ b ⟖ c')
1513
+ assert isinstance(root, BinaryOperators.Join)
1514
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.RightOuterJoin)
1515
+
1516
+ root = RAParser.parse_query(r'a ⟖ b ⋈ c')
1517
+ assert isinstance(root, BinaryOperators.Join)
1518
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.RightOuterJoin)
1519
+
1520
+ root = RAParser.parse_query(r'a ⋈ b ⟗ c')
1521
+ assert isinstance(root, BinaryOperators.Join)
1522
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.FullOuterJoin)
1523
+
1524
+ root = RAParser.parse_query(r'a ⟗ b ⋈ c')
1525
+ assert isinstance(root, BinaryOperators.Join)
1526
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.FullOuterJoin)
1527
+
1528
+ root = RAParser.parse_query(r'a ⋈ b ⋉ c')
1529
+ assert isinstance(root, BinaryOperators.Join)
1530
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.LeftSemiJoin)
1531
+
1532
+ root = RAParser.parse_query(r'a ⋉ b ⋈ c')
1533
+ assert isinstance(root, BinaryOperators.Join)
1534
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.LeftSemiJoin)
1535
+
1536
+ root = RAParser.parse_query(r'a ⋈ b ⋊ c')
1537
+ assert isinstance(root, BinaryOperators.Join)
1538
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.RightSemiJoin)
1539
+
1540
+ root = RAParser.parse_query(r'a ⋊ b ⋈ c')
1541
+ assert isinstance(root, BinaryOperators.Join)
1542
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.RightSemiJoin)
1543
+
1544
+ # cross <-> division
1545
+ root = RAParser.parse_query(r'a x b ÷ c')
1546
+ assert isinstance(root, BinaryOperators.Cross)
1547
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Division)
1548
+
1549
+ root = RAParser.parse_query(r'a ÷ b x c')
1550
+ assert isinstance(root, BinaryOperators.Cross)
1551
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Division)
1552
+
1553
+
1554
+ def test_mixed_evaluation_order():
1555
+ # difference <-> projection
1556
+ root = RAParser.parse_query(r'a \ π [ Id ] b')
1557
+ assert isinstance(root, BinaryOperators.Difference)
1558
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Projection)
1559
+
1560
+ root = RAParser.parse_query(r'π [ Id ] a \ b')
1561
+ assert isinstance(root, BinaryOperators.Difference)
1562
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Projection)
1563
+
1564
+ # difference <-> attribute rename
1565
+ root = RAParser.parse_query(r'a \ β [ Id2 ← Id ] b')
1566
+ assert isinstance(root, BinaryOperators.Difference)
1567
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
1568
+
1569
+ root = RAParser.parse_query(r'β [ Id2 ← Id ] a \ b')
1570
+ assert isinstance(root, BinaryOperators.Difference)
1571
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.AttributeRename)
1572
+
1573
+ # difference <-> rename
1574
+ root = RAParser.parse_query(r'a \ ρ [ R(Id2) ] b')
1575
+ assert isinstance(root, BinaryOperators.Difference)
1576
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Rename)
1577
+
1578
+ root = RAParser.parse_query(r'ρ [ R(Id2) ] a \ b')
1579
+ assert isinstance(root, BinaryOperators.Difference)
1580
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
1581
+
1582
+ # difference <-> selection
1583
+ root = RAParser.parse_query(r'a \ σ [ Id > 1 ] b')
1584
+ assert isinstance(root, BinaryOperators.Difference)
1585
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Selection)
1586
+
1587
+ root = RAParser.parse_query(r'σ [ Id > 1 ] a \ b')
1588
+ assert isinstance(root, BinaryOperators.Difference)
1589
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Selection)
1590
+
1591
+ # union <-> projection
1592
+ root = RAParser.parse_query(r'a ∪ π [ Id ] b')
1593
+ assert isinstance(root, BinaryOperators.Union)
1594
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Projection)
1595
+
1596
+ root = RAParser.parse_query(r'π [ Id ] a ∪ b')
1597
+ assert isinstance(root, BinaryOperators.Union)
1598
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Projection)
1599
+
1600
+ # union <-> attribute rename
1601
+ root = RAParser.parse_query(r'a ∪ β [ Id2 ← Id ] b')
1602
+ assert isinstance(root, BinaryOperators.Union)
1603
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
1604
+
1605
+ root = RAParser.parse_query(r'β [ Id2 ← Id ] a ∪ b')
1606
+ assert isinstance(root, BinaryOperators.Union)
1607
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.AttributeRename)
1608
+
1609
+ # union <-> rename
1610
+ root = RAParser.parse_query(r'a ∪ ρ [ R(Id2) ] b')
1611
+ assert isinstance(root, BinaryOperators.Union)
1612
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Rename)
1613
+
1614
+ root = RAParser.parse_query(r'ρ [ R(Id2) ] a ∪ b')
1615
+ assert isinstance(root, BinaryOperators.Union)
1616
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
1617
+
1618
+ # union <-> selection
1619
+ root = RAParser.parse_query(r'a ∪ σ [ Id > 1 ] b')
1620
+ assert isinstance(root, BinaryOperators.Union)
1621
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Selection)
1622
+
1623
+ root = RAParser.parse_query(r'σ [ Id > 1 ] a ∪ b')
1624
+ assert isinstance(root, BinaryOperators.Union)
1625
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Selection)
1626
+
1627
+ # intersection <-> projection
1628
+ root = RAParser.parse_query(r'a ∩ π [ Id ] b')
1629
+ assert isinstance(root, BinaryOperators.Intersection)
1630
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Projection)
1631
+
1632
+ root = RAParser.parse_query(r'π [ Id ] a ∩ b')
1633
+ assert isinstance(root, BinaryOperators.Intersection)
1634
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Projection)
1635
+
1636
+ # intersection <-> attribute rename
1637
+ root = RAParser.parse_query(r'a ∩ β [ Id2 ← Id ] b')
1638
+ assert isinstance(root, BinaryOperators.Intersection)
1639
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
1640
+
1641
+ root = RAParser.parse_query(r'β [ Id2 ← Id ] a ∩ b')
1642
+ assert isinstance(root, BinaryOperators.Intersection)
1643
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.AttributeRename)
1644
+
1645
+ # intersection <-> rename
1646
+ root = RAParser.parse_query(r'a ∩ ρ [ R(Id2) ] b')
1647
+ assert isinstance(root, BinaryOperators.Intersection)
1648
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Rename)
1649
+
1650
+ root = RAParser.parse_query(r'ρ [ R(Id2) ] a ∩ b')
1651
+ assert isinstance(root, BinaryOperators.Intersection)
1652
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
1653
+
1654
+ # intersection <-> selection
1655
+ root = RAParser.parse_query(r'a ∩ σ [ Id > 1 ] b')
1656
+ assert isinstance(root, BinaryOperators.Intersection)
1657
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Selection)
1658
+
1659
+ root = RAParser.parse_query(r'σ [ Id > 1 ] a ∩ b')
1660
+ assert isinstance(root, BinaryOperators.Intersection)
1661
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Selection)
1662
+
1663
+ # join <-> projection
1664
+ root = RAParser.parse_query(r'a ⋈ π [ Id ] b')
1665
+ assert isinstance(root, BinaryOperators.Join)
1666
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Projection)
1667
+
1668
+ root = RAParser.parse_query(r'π [ Id ] a ⋈ b')
1669
+ assert isinstance(root, BinaryOperators.Join)
1670
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Projection)
1671
+
1672
+ root = RAParser.parse_query(r'a ⟕ π [ Id ] b')
1673
+ assert isinstance(root, BinaryOperators.LeftOuterJoin)
1674
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Projection)
1675
+
1676
+ root = RAParser.parse_query(r'π [ Id ] a ⟕ b')
1677
+ assert isinstance(root, BinaryOperators.LeftOuterJoin)
1678
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Projection)
1679
+
1680
+ root = RAParser.parse_query(r'a ⟖ π [ Id ] b')
1681
+ assert isinstance(root, BinaryOperators.RightOuterJoin)
1682
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Projection)
1683
+
1684
+ root = RAParser.parse_query(r'π [ Id ] a ⟖ b')
1685
+ assert isinstance(root, BinaryOperators.RightOuterJoin)
1686
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Projection)
1687
+
1688
+ root = RAParser.parse_query(r'a ⟗ π [ Id ] b')
1689
+ assert isinstance(root, BinaryOperators.FullOuterJoin)
1690
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Projection)
1691
+
1692
+ root = RAParser.parse_query(r'π [ Id ] a ⟗ b')
1693
+ assert isinstance(root, BinaryOperators.FullOuterJoin)
1694
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Projection)
1695
+
1696
+ root = RAParser.parse_query(r'a ⋉ π [ Id ] b')
1697
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
1698
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Projection)
1699
+
1700
+ root = RAParser.parse_query(r'π [ Id ] a ⋉ b')
1701
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
1702
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Projection)
1703
+
1704
+ root = RAParser.parse_query(r'a ⋊ π [ Id ] b')
1705
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
1706
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Projection)
1707
+
1708
+ root = RAParser.parse_query(r'π [ Id ] a ⋊ b')
1709
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
1710
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Projection)
1711
+
1712
+ # join <-> attribute rename
1713
+ root = RAParser.parse_query(r'a ⋈ β [ Id2 ← Id ] b')
1714
+ assert isinstance(root, BinaryOperators.Join)
1715
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
1716
+
1717
+ root = RAParser.parse_query(r'β [ Id2 ← Id ] a ⋈ b')
1718
+ assert isinstance(root, BinaryOperators.Join)
1719
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.AttributeRename)
1720
+
1721
+ root = RAParser.parse_query(r'a ⟕ β [ Id2 ← Id ] b')
1722
+ assert isinstance(root, BinaryOperators.LeftOuterJoin)
1723
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
1724
+
1725
+ root = RAParser.parse_query(r'β [ Id2 ← Id ] a ⟕ b')
1726
+ assert isinstance(root, BinaryOperators.LeftOuterJoin)
1727
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.AttributeRename)
1728
+
1729
+ root = RAParser.parse_query(r'a ⟖ β [ Id2 ← Id ] b')
1730
+ assert isinstance(root, BinaryOperators.RightOuterJoin)
1731
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
1732
+
1733
+ root = RAParser.parse_query(r'β [ Id2 ← Id ] a ⟖ b')
1734
+ assert isinstance(root, BinaryOperators.RightOuterJoin)
1735
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.AttributeRename)
1736
+
1737
+ root = RAParser.parse_query(r'a ⟗ β [ Id2 ← Id ] b')
1738
+ assert isinstance(root, BinaryOperators.FullOuterJoin)
1739
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
1740
+
1741
+ root = RAParser.parse_query(r'β [ Id2 ← Id ] a ⟗ b')
1742
+ assert isinstance(root, BinaryOperators.FullOuterJoin)
1743
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.AttributeRename)
1744
+
1745
+ root = RAParser.parse_query(r'a ⋉ β [ Id2 ← Id ] b')
1746
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
1747
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
1748
+
1749
+ root = RAParser.parse_query(r'β [ Id2 ← Id ] a ⋉ b')
1750
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
1751
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.AttributeRename)
1752
+
1753
+ root = RAParser.parse_query(r'a ⋊ β [ Id2 ← Id ] b')
1754
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
1755
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
1756
+
1757
+ root = RAParser.parse_query(r'β [ Id2 ← Id ] a ⋊ b')
1758
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
1759
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.AttributeRename)
1760
+
1761
+ # join <-> rename
1762
+ root = RAParser.parse_query(r'a ⋈ ρ [ R(Id2) ] b')
1763
+ assert isinstance(root, BinaryOperators.Join)
1764
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Rename)
1765
+
1766
+ root = RAParser.parse_query(r'ρ [ R(Id2) ] a ⋈ b')
1767
+ assert isinstance(root, BinaryOperators.Join)
1768
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
1769
+
1770
+ root = RAParser.parse_query(r'a ⟕ ρ [ R(Id2) ] b')
1771
+ assert isinstance(root, BinaryOperators.LeftOuterJoin)
1772
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Rename)
1773
+
1774
+ root = RAParser.parse_query(r'ρ [ R(Id2) ] a ⟕ b')
1775
+ assert isinstance(root, BinaryOperators.LeftOuterJoin)
1776
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
1777
+
1778
+ root = RAParser.parse_query(r'a ⟖ ρ [ R(Id2) ] b')
1779
+ assert isinstance(root, BinaryOperators.RightOuterJoin)
1780
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Rename)
1781
+
1782
+ root = RAParser.parse_query(r'ρ [ R(Id2) ] a ⟖ b')
1783
+ assert isinstance(root, BinaryOperators.RightOuterJoin)
1784
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
1785
+
1786
+ root = RAParser.parse_query(r'a ⟗ ρ [ R(Id2) ] b')
1787
+ assert isinstance(root, BinaryOperators.FullOuterJoin)
1788
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Rename)
1789
+
1790
+ root = RAParser.parse_query(r'ρ [ R(Id2) ] a ⟗ b')
1791
+ assert isinstance(root, BinaryOperators.FullOuterJoin)
1792
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
1793
+
1794
+ root = RAParser.parse_query(r'a ⋉ ρ [ R(Id2) ] b')
1795
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
1796
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Rename)
1797
+
1798
+ root = RAParser.parse_query(r'ρ [ R(Id2) ] a ⋉ b')
1799
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
1800
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
1801
+
1802
+ root = RAParser.parse_query(r'a ⋊ ρ [ R(Id2) ] b')
1803
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
1804
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Rename)
1805
+
1806
+ root = RAParser.parse_query(r'ρ [ R(Id2) ] a ⋊ b')
1807
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
1808
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
1809
+
1810
+ # join <-> selection
1811
+ root = RAParser.parse_query(r'a ⋈ σ [ Id > 1 ] b')
1812
+ assert isinstance(root, BinaryOperators.Join)
1813
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Selection)
1814
+
1815
+ root = RAParser.parse_query(r'σ [ Id > 1 ] a ⋈ b')
1816
+ assert isinstance(root, BinaryOperators.Join)
1817
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Selection)
1818
+
1819
+ root = RAParser.parse_query(r'a ⟕ σ [ Id > 1 ] b')
1820
+ assert isinstance(root, BinaryOperators.LeftOuterJoin)
1821
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Selection)
1822
+
1823
+ root = RAParser.parse_query(r'σ [ Id > 1 ] a ⟕ b')
1824
+ assert isinstance(root, BinaryOperators.LeftOuterJoin)
1825
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Selection)
1826
+
1827
+ root = RAParser.parse_query(r'a ⟖ σ [ Id > 1 ] b')
1828
+ assert isinstance(root, BinaryOperators.RightOuterJoin)
1829
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Selection)
1830
+
1831
+ root = RAParser.parse_query(r'σ [ Id > 1 ] a ⟖ b')
1832
+ assert isinstance(root, BinaryOperators.RightOuterJoin)
1833
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Selection)
1834
+
1835
+ root = RAParser.parse_query(r'a ⟗ σ [ Id > 1 ] b')
1836
+ assert isinstance(root, BinaryOperators.FullOuterJoin)
1837
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Selection)
1838
+
1839
+ root = RAParser.parse_query(r'σ [ Id > 1 ] a ⟗ b')
1840
+ assert isinstance(root, BinaryOperators.FullOuterJoin)
1841
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Selection)
1842
+
1843
+ root = RAParser.parse_query(r'a ⋉ σ [ Id > 1 ] b')
1844
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
1845
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Selection)
1846
+
1847
+ root = RAParser.parse_query(r'σ [ Id > 1 ] a ⋉ b')
1848
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
1849
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Selection)
1850
+
1851
+ root = RAParser.parse_query(r'a ⋊ σ [ Id > 1 ] b')
1852
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
1853
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Selection)
1854
+
1855
+ root = RAParser.parse_query(r'σ [ Id > 1 ] a ⋊ b')
1856
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
1857
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Selection)
1858
+
1859
+ # cross <-> projection
1860
+ root = RAParser.parse_query(r'a x π [ Id ] b')
1861
+ assert isinstance(root, BinaryOperators.Cross)
1862
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Projection)
1863
+
1864
+ root = RAParser.parse_query(r'π [ Id ] a x b')
1865
+ assert isinstance(root, BinaryOperators.Cross)
1866
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Projection)
1867
+
1868
+ # cross <-> attribute rename
1869
+ root = RAParser.parse_query(r'a x β [ Id2 ← Id ] b')
1870
+ assert isinstance(root, BinaryOperators.Cross)
1871
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
1872
+
1873
+ root = RAParser.parse_query(r'β [ Id2 ← Id ] a x b')
1874
+ assert isinstance(root, BinaryOperators.Cross)
1875
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.AttributeRename)
1876
+
1877
+ # cross <-> rename
1878
+ root = RAParser.parse_query(r'a x ρ [ R(Id2) ] b')
1879
+ assert isinstance(root, BinaryOperators.Cross)
1880
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Rename)
1881
+
1882
+ root = RAParser.parse_query(r'ρ [ R(Id2) ] a x b')
1883
+ assert isinstance(root, BinaryOperators.Cross)
1884
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
1885
+
1886
+ # cross <-> selection
1887
+ root = RAParser.parse_query(r'a x σ [ Id > 1 ] b')
1888
+ assert isinstance(root, BinaryOperators.Cross)
1889
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Selection)
1890
+
1891
+ root = RAParser.parse_query(r'σ [ Id > 1 ] a x b')
1892
+ assert isinstance(root, BinaryOperators.Cross)
1893
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Selection)
1894
+
1895
+ # division <-> projection
1896
+ root = RAParser.parse_query(r'a ÷ π [ Id ] b')
1897
+ assert isinstance(root, BinaryOperators.Division)
1898
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Projection)
1899
+
1900
+ root = RAParser.parse_query(r'π [ Id ] a ÷ b')
1901
+ assert isinstance(root, BinaryOperators.Division)
1902
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Projection)
1903
+
1904
+ # division <-> attribute rename
1905
+ root = RAParser.parse_query(r'a ÷ β [ Id2 ← Id ] b')
1906
+ assert isinstance(root, BinaryOperators.Division)
1907
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
1908
+
1909
+ root = RAParser.parse_query(r'β [ Id2 ← Id ] a ÷ b')
1910
+ assert isinstance(root, BinaryOperators.Division)
1911
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.AttributeRename)
1912
+
1913
+ # division <-> rename
1914
+ root = RAParser.parse_query(r'a ÷ ρ [ R(Id2) ] b')
1915
+ assert isinstance(root, BinaryOperators.Division)
1916
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Rename)
1917
+
1918
+ root = RAParser.parse_query(r'ρ [ R(Id2) ] a ÷ b')
1919
+ assert isinstance(root, BinaryOperators.Division)
1920
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
1921
+
1922
+ # division <-> selection
1923
+ root = RAParser.parse_query(r'a ÷ σ [ Id > 1 ] b')
1924
+ assert isinstance(root, BinaryOperators.Division)
1925
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Selection)
1926
+
1927
+ root = RAParser.parse_query(r'σ [ Id > 1 ] a ÷ b')
1928
+ assert isinstance(root, BinaryOperators.Division)
1929
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Selection)
1930
+
1931
+
1932
+ def test_special_queries():
1933
+ with Connection() as con:
1934
+ # Consecutive operators triggered a recursion error in a previous
1935
+ # version, leading to an infinite loop / stack overflow.
1936
+ with pytest.raises(RAParserError, match='right operand missing after x'):
1937
+ RAParser.parse_query(r'''
1938
+ Users x x BannedUsers
1939
+ ''')
1940
+
1941
+ # Enclosing parentheses are removed. In the following case
1942
+ # the parentheses may only be removed from each subquery
1943
+ # independently *after* the cross join is applied. Otherwise,
1944
+ # the result is a parsing error.
1945
+ root = RAParser.parse_query(r'''
1946
+ (
1947
+ Sigma [ Id > 1 ] Pi [ Username, Id ] (Users)
1948
+ ) x (
1949
+ Beta [ Username2 <- BannedUsername ] Beta [ Id2 <- Id ] (BannedUsers)
1950
+ )
1951
+ ''')
1952
+
1953
+ assert isinstance(root, BinaryOperators.Cross)
1954
+ assert isinstance(root.left, UnaryOperators.Selection)
1955
+ assert isinstance(root.left.target, UnaryOperators.Projection)
1956
+ assert isinstance(root.left.target.target, RAOperand) and root.left.target.target.name == 'Users'
1957
+ assert isinstance(root.right, UnaryOperators.AttributeRename)
1958
+ assert isinstance(root.right.target, UnaryOperators.AttributeRename)
1959
+ assert isinstance(root.right.target.target, RAOperand) and root.right.target.target.name == 'BannedUsers'
1960
+
1961
+ assert con.execute_ra(root) == [
1962
+ ('Bob', 2, 2, 'Bob'),
1963
+ ('Bob', 2, 4, 'David'),
1964
+ ('Charlie', 3, 2, 'Bob'),
1965
+ ('Charlie', 3, 4, 'David')
1966
+ ]