jupyter-duckdb 1.4.105__py3-none-any.whl → 1.4.107__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.
- duckdb_kernel/kernel.py +4 -0
- duckdb_kernel/parser/DCParser.py +7 -0
- duckdb_kernel/parser/RAParser.py +7 -5
- duckdb_kernel/parser/elements/binary/And.py +1 -1
- duckdb_kernel/parser/elements/binary/Cross.py +2 -2
- duckdb_kernel/parser/elements/binary/FullOuterJoin.py +4 -1
- duckdb_kernel/parser/elements/binary/Join.py +4 -1
- duckdb_kernel/parser/elements/binary/LeftOuterJoin.py +4 -1
- duckdb_kernel/parser/elements/binary/LeftSemiJoin.py +27 -0
- duckdb_kernel/parser/elements/binary/RightOuterJoin.py +4 -1
- duckdb_kernel/parser/elements/binary/RightSemiJoin.py +27 -0
- duckdb_kernel/parser/elements/binary/__init__.py +3 -1
- duckdb_kernel/tests/test_dc.py +29 -0
- duckdb_kernel/tests/test_ra.py +417 -10
- duckdb_kernel/util/ResultSetComparator.py +18 -3
- {jupyter_duckdb-1.4.105.dist-info → jupyter_duckdb-1.4.107.dist-info}/METADATA +1 -1
- {jupyter_duckdb-1.4.105.dist-info → jupyter_duckdb-1.4.107.dist-info}/RECORD +19 -17
- {jupyter_duckdb-1.4.105.dist-info → jupyter_duckdb-1.4.107.dist-info}/WHEEL +0 -0
- {jupyter_duckdb-1.4.105.dist-info → jupyter_duckdb-1.4.107.dist-info}/top_level.txt +0 -0
duckdb_kernel/kernel.py
CHANGED
|
@@ -535,6 +535,8 @@ class DuckDBKernel(Kernel):
|
|
|
535
535
|
|
|
536
536
|
# parse ra input
|
|
537
537
|
root_node = RAParser.parse_query(state.code)
|
|
538
|
+
if root_node is None:
|
|
539
|
+
return
|
|
538
540
|
|
|
539
541
|
# create and show visualization
|
|
540
542
|
if analyze:
|
|
@@ -575,6 +577,8 @@ class DuckDBKernel(Kernel):
|
|
|
575
577
|
|
|
576
578
|
# parse dc input
|
|
577
579
|
root_node = DCParser.parse_query(state.code)
|
|
580
|
+
if root_node is None:
|
|
581
|
+
return
|
|
578
582
|
|
|
579
583
|
# generate sql
|
|
580
584
|
sql, cnm = root_node.to_sql_with_renamed_columns(tables)
|
duckdb_kernel/parser/DCParser.py
CHANGED
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
from .ParserError import DCParserError
|
|
2
2
|
from .elements import *
|
|
3
3
|
from .tokenizer import *
|
|
4
|
+
from .util.QuerySplitter import get_last_query
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
class DCParser:
|
|
7
8
|
@staticmethod
|
|
8
9
|
def parse_query(query: str) -> DC_SET:
|
|
10
|
+
# remove comments from query
|
|
11
|
+
query = get_last_query(query, split_at=None, remove_comments=True)
|
|
12
|
+
|
|
9
13
|
# create initial token set
|
|
10
14
|
initial_token = Token(query)
|
|
11
15
|
tokens = tuple(Tokenizer.tokenize(initial_token))
|
|
12
16
|
|
|
17
|
+
if len(tokens) == 0:
|
|
18
|
+
return None
|
|
19
|
+
|
|
13
20
|
# split at |
|
|
14
21
|
for i, token in enumerate(tokens):
|
|
15
22
|
if token in DC_SET.symbols():
|
duckdb_kernel/parser/RAParser.py
CHANGED
|
@@ -10,7 +10,7 @@ from .util.QuerySplitter import get_last_query
|
|
|
10
10
|
|
|
11
11
|
class RAParser:
|
|
12
12
|
@staticmethod
|
|
13
|
-
def parse_query(query: str) -> RAElement:
|
|
13
|
+
def parse_query(query: str) -> RAElement | None:
|
|
14
14
|
# remove comments from query
|
|
15
15
|
query = get_last_query(query, split_at=None, remove_comments=True)
|
|
16
16
|
|
|
@@ -19,7 +19,7 @@ class RAParser:
|
|
|
19
19
|
return RAParser.parse_tokens(initial_token, depth=0)
|
|
20
20
|
|
|
21
21
|
@staticmethod
|
|
22
|
-
def parse_tokens(*tokens: Token, target: RAOperator | RAOperand = None, depth: int = 0) -> RAElement:
|
|
22
|
+
def parse_tokens(*tokens: Token, target: RAOperator | RAOperand = None, depth: int = 0) -> RAElement | None:
|
|
23
23
|
if len(tokens) == 1:
|
|
24
24
|
tokens = tuple(Tokenizer.tokenize(tokens[0]))
|
|
25
25
|
|
|
@@ -76,7 +76,9 @@ class RAParser:
|
|
|
76
76
|
return op
|
|
77
77
|
|
|
78
78
|
# return as name
|
|
79
|
-
if len(tokens)
|
|
79
|
+
if len(tokens) == 0:
|
|
80
|
+
return None
|
|
81
|
+
elif len(tokens) == 1:
|
|
82
|
+
return RAOperand(tokens[0])
|
|
83
|
+
else:
|
|
80
84
|
raise RAParserError(f'{tokens=}', depth)
|
|
81
|
-
|
|
82
|
-
return RAOperand(tokens[0])
|
|
@@ -8,7 +8,7 @@ from ...util.RenamableColumnList import RenamableColumnList
|
|
|
8
8
|
class Cross(RABinaryOperator):
|
|
9
9
|
@staticmethod
|
|
10
10
|
def symbols() -> Tuple[str, ...]:
|
|
11
|
-
return chr(215), 'x'
|
|
11
|
+
return chr(215), 'x', 'times'
|
|
12
12
|
|
|
13
13
|
def to_sql(self, tables: Dict[str, Table]) -> Tuple[str, RenamableColumnList]:
|
|
14
14
|
# execute subqueries
|
|
@@ -19,4 +19,4 @@ class Cross(RABinaryOperator):
|
|
|
19
19
|
cols = lcols.merge(rcols)
|
|
20
20
|
|
|
21
21
|
# create statement
|
|
22
|
-
return f'SELECT {cols.list} FROM ({lq}) {self._name()} CROSS JOIN ({rq}) {self._name()}', cols
|
|
22
|
+
return f'SELECT DISTINCT {cols.list} FROM ({lq}) {self._name()} CROSS JOIN ({rq}) {self._name()}', cols
|
|
@@ -3,6 +3,7 @@ from typing import Tuple, Dict
|
|
|
3
3
|
|
|
4
4
|
from duckdb_kernel.db import Table
|
|
5
5
|
from ..RABinaryOperator import RABinaryOperator
|
|
6
|
+
from ...ParserError import RAParserError
|
|
6
7
|
from ...util.RenamableColumn import RenamableColumn
|
|
7
8
|
from ...util.RenamableColumnList import RenamableColumnList
|
|
8
9
|
|
|
@@ -26,6 +27,8 @@ class FullOuterJoin(RABinaryOperator):
|
|
|
26
27
|
|
|
27
28
|
# find matching columns
|
|
28
29
|
join_cols, all_cols = lcols.intersect(rcols)
|
|
30
|
+
if len(join_cols) == 0:
|
|
31
|
+
raise RAParserError('no common attributes found for full outer join', 0)
|
|
29
32
|
|
|
30
33
|
replacements = {c1: c2 for c1, c2 in join_cols}
|
|
31
34
|
select_cols = [self._coalesce(c, replacements.get(c)) for c in all_cols]
|
|
@@ -34,4 +37,4 @@ class FullOuterJoin(RABinaryOperator):
|
|
|
34
37
|
on_clause = ' AND '.join(f'{l.current_name} = {r.current_name}' for l, r in join_cols)
|
|
35
38
|
|
|
36
39
|
# create sql
|
|
37
|
-
return f'SELECT {select_clause} FROM ({lq}) {self._name()} FULL OUTER JOIN ({rq}) {self._name()} ON {on_clause}', all_cols
|
|
40
|
+
return f'SELECT DISTINCT {select_clause} FROM ({lq}) {self._name()} FULL OUTER JOIN ({rq}) {self._name()} ON {on_clause}', all_cols
|
|
@@ -2,6 +2,7 @@ from typing import Tuple, Dict
|
|
|
2
2
|
|
|
3
3
|
from duckdb_kernel.db import Table
|
|
4
4
|
from ..RABinaryOperator import RABinaryOperator
|
|
5
|
+
from ...ParserError import RAParserError
|
|
5
6
|
from ...util.RenamableColumnList import RenamableColumnList
|
|
6
7
|
|
|
7
8
|
|
|
@@ -17,8 +18,10 @@ class Join(RABinaryOperator):
|
|
|
17
18
|
|
|
18
19
|
# find matching columns
|
|
19
20
|
join_cols, all_cols = lcols.intersect(rcols)
|
|
21
|
+
if len(join_cols) == 0:
|
|
22
|
+
raise RAParserError('no common attributes found for join', 0)
|
|
20
23
|
|
|
21
24
|
on_clause = ' AND '.join(f'{l.current_name} = {r.current_name}' for l, r in join_cols)
|
|
22
25
|
|
|
23
26
|
# create sql
|
|
24
|
-
return f'SELECT {all_cols.list} FROM ({lq}) {self._name()} JOIN ({rq}) {self._name()} ON {on_clause}', all_cols
|
|
27
|
+
return f'SELECT DISTINCT {all_cols.list} FROM ({lq}) {self._name()} JOIN ({rq}) {self._name()} ON {on_clause}', all_cols
|
|
@@ -2,6 +2,7 @@ from typing import Tuple, Dict
|
|
|
2
2
|
|
|
3
3
|
from duckdb_kernel.db import Table
|
|
4
4
|
from ..RABinaryOperator import RABinaryOperator
|
|
5
|
+
from ...ParserError import RAParserError
|
|
5
6
|
from ...util.RenamableColumnList import RenamableColumnList
|
|
6
7
|
|
|
7
8
|
|
|
@@ -17,8 +18,10 @@ class LeftOuterJoin(RABinaryOperator):
|
|
|
17
18
|
|
|
18
19
|
# find matching columns
|
|
19
20
|
join_cols, all_cols = lcols.intersect(rcols)
|
|
21
|
+
if len(join_cols) == 0:
|
|
22
|
+
raise RAParserError('no common attributes found for left outer join', 0)
|
|
20
23
|
|
|
21
24
|
on_clause = ' AND '.join(f'{l.current_name} = {r.current_name}' for l, r in join_cols)
|
|
22
25
|
|
|
23
26
|
# create sql
|
|
24
|
-
return f'SELECT {all_cols.list} FROM ({lq}) {self._name()} LEFT OUTER JOIN ({rq}) {self._name()} ON {on_clause}', all_cols
|
|
27
|
+
return f'SELECT DISTINCT {all_cols.list} FROM ({lq}) {self._name()} LEFT OUTER JOIN ({rq}) {self._name()} ON {on_clause}', all_cols
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from typing import Tuple, Dict
|
|
2
|
+
|
|
3
|
+
from duckdb_kernel.db import Table
|
|
4
|
+
from ..RABinaryOperator import RABinaryOperator
|
|
5
|
+
from ...ParserError import RAParserError
|
|
6
|
+
from ...util.RenamableColumnList import RenamableColumnList
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class LeftSemiJoin(RABinaryOperator):
|
|
10
|
+
@staticmethod
|
|
11
|
+
def symbols() -> Tuple[str, ...]:
|
|
12
|
+
return chr(8905), 'lsjoin'
|
|
13
|
+
|
|
14
|
+
def to_sql(self, tables: Dict[str, Table]) -> Tuple[str, RenamableColumnList]:
|
|
15
|
+
# execute subqueries
|
|
16
|
+
lq, lcols = self.left.to_sql(tables)
|
|
17
|
+
rq, rcols = self.right.to_sql(tables)
|
|
18
|
+
|
|
19
|
+
# find matching columns
|
|
20
|
+
join_cols, all_cols = lcols.intersect(rcols)
|
|
21
|
+
if len(join_cols) == 0:
|
|
22
|
+
raise RAParserError('no common attributes found for left semi join', 0)
|
|
23
|
+
|
|
24
|
+
on_clause = ' AND '.join(f'{l.current_name} = {r.current_name}' for l, r in join_cols)
|
|
25
|
+
|
|
26
|
+
# create sql
|
|
27
|
+
return f'SELECT DISTINCT {lcols.list} FROM ({lq}) {self._name()} JOIN ({rq}) {self._name()} ON {on_clause}', lcols
|
|
@@ -2,6 +2,7 @@ from typing import Tuple, Dict
|
|
|
2
2
|
|
|
3
3
|
from duckdb_kernel.db import Table
|
|
4
4
|
from ..RABinaryOperator import RABinaryOperator
|
|
5
|
+
from ...ParserError import RAParserError
|
|
5
6
|
from ...util.RenamableColumnList import RenamableColumnList
|
|
6
7
|
|
|
7
8
|
|
|
@@ -17,8 +18,10 @@ class RightOuterJoin(RABinaryOperator):
|
|
|
17
18
|
|
|
18
19
|
# find matching columns
|
|
19
20
|
join_cols, all_cols = lcols.intersect(rcols, prefer_right=True)
|
|
21
|
+
if len(join_cols) == 0:
|
|
22
|
+
raise RAParserError('no common attributes found for right outer join', 0)
|
|
20
23
|
|
|
21
24
|
on_clause = ' AND '.join(f'{l.current_name} = {r.current_name}' for l, r in join_cols)
|
|
22
25
|
|
|
23
26
|
# create sql
|
|
24
|
-
return f'SELECT {all_cols.list} FROM ({lq}) {self._name()} RIGHT OUTER JOIN ({rq}) {self._name()} ON {on_clause}', all_cols
|
|
27
|
+
return f'SELECT DISTINCT {all_cols.list} FROM ({lq}) {self._name()} RIGHT OUTER JOIN ({rq}) {self._name()} ON {on_clause}', all_cols
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from typing import Tuple, Dict
|
|
2
|
+
|
|
3
|
+
from duckdb_kernel.db import Table
|
|
4
|
+
from ..RABinaryOperator import RABinaryOperator
|
|
5
|
+
from ...ParserError import RAParserError
|
|
6
|
+
from ...util.RenamableColumnList import RenamableColumnList
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class RightSemiJoin(RABinaryOperator):
|
|
10
|
+
@staticmethod
|
|
11
|
+
def symbols() -> Tuple[str, ...]:
|
|
12
|
+
return chr(8906), 'rsjoin'
|
|
13
|
+
|
|
14
|
+
def to_sql(self, tables: Dict[str, Table]) -> Tuple[str, RenamableColumnList]:
|
|
15
|
+
# execute subqueries
|
|
16
|
+
lq, lcols = self.left.to_sql(tables)
|
|
17
|
+
rq, rcols = self.right.to_sql(tables)
|
|
18
|
+
|
|
19
|
+
# find matching columns
|
|
20
|
+
join_cols, all_cols = lcols.intersect(rcols, prefer_right=True)
|
|
21
|
+
if len(join_cols) == 0:
|
|
22
|
+
raise RAParserError('no common attributes found for right semi join', 0)
|
|
23
|
+
|
|
24
|
+
on_clause = ' AND '.join(f'{l.current_name} = {r.current_name}' for l, r in join_cols)
|
|
25
|
+
|
|
26
|
+
# create sql
|
|
27
|
+
return f'SELECT DISTINCT {rcols.list} FROM ({lq}) {self._name()} JOIN ({rq}) {self._name()} ON {on_clause}', rcols
|
|
@@ -3,7 +3,9 @@ from .Difference import Difference
|
|
|
3
3
|
from .Intersection import Intersection
|
|
4
4
|
from .Join import Join
|
|
5
5
|
from .LeftOuterJoin import LeftOuterJoin
|
|
6
|
+
from .LeftSemiJoin import LeftSemiJoin
|
|
6
7
|
from .RightOuterJoin import RightOuterJoin
|
|
8
|
+
from .RightSemiJoin import RightSemiJoin
|
|
7
9
|
from .FullOuterJoin import FullOuterJoin
|
|
8
10
|
from .Union import Union
|
|
9
11
|
|
|
@@ -37,7 +39,7 @@ RA_BINARY_OPERATORS = [
|
|
|
37
39
|
[Union],
|
|
38
40
|
[Intersection],
|
|
39
41
|
[Join],
|
|
40
|
-
[LeftOuterJoin, RightOuterJoin, FullOuterJoin],
|
|
42
|
+
[LeftOuterJoin, RightOuterJoin, FullOuterJoin, LeftSemiJoin, RightSemiJoin],
|
|
41
43
|
[Cross],
|
|
42
44
|
[Division]
|
|
43
45
|
]
|
duckdb_kernel/tests/test_dc.py
CHANGED
|
@@ -46,6 +46,35 @@ def test_case_insensitivity():
|
|
|
46
46
|
]
|
|
47
47
|
|
|
48
48
|
|
|
49
|
+
def test_comments():
|
|
50
|
+
for query in (
|
|
51
|
+
'{ username | users(id, username) } -- cmmnt',
|
|
52
|
+
'{ username | users(id, username) } /* cmmnt */',
|
|
53
|
+
'{ username | /* cmmnt */ users(id, username) }',
|
|
54
|
+
):
|
|
55
|
+
root = DCParser.parse_query(query)
|
|
56
|
+
|
|
57
|
+
# execute to test case insensitivity
|
|
58
|
+
with Connection() as con:
|
|
59
|
+
cols, rows = con.execute_dc_return_cols(root)
|
|
60
|
+
|
|
61
|
+
assert [c.lower() for c in cols] == [
|
|
62
|
+
'username'
|
|
63
|
+
]
|
|
64
|
+
assert rows == [
|
|
65
|
+
('Alice',),
|
|
66
|
+
('Bob',),
|
|
67
|
+
('Charlie',)
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
for query in (
|
|
71
|
+
'-- comment',
|
|
72
|
+
'/* comment */'
|
|
73
|
+
):
|
|
74
|
+
root = DCParser.parse_query(query)
|
|
75
|
+
assert root is None
|
|
76
|
+
|
|
77
|
+
|
|
49
78
|
def test_simple_queries():
|
|
50
79
|
with Connection() as con:
|
|
51
80
|
for query in [
|
duckdb_kernel/tests/test_ra.py
CHANGED
|
@@ -101,10 +101,18 @@ def test_comments():
|
|
|
101
101
|
assert isinstance(root.left, RAOperand) and root.left.name == 'Shows'
|
|
102
102
|
assert isinstance(root.right, RAOperand) and root.right.name == 'Seasons'
|
|
103
103
|
|
|
104
|
+
for query in (
|
|
105
|
+
'-- comment',
|
|
106
|
+
'/* comment */'
|
|
107
|
+
):
|
|
108
|
+
root = RAParser.parse_query(query)
|
|
109
|
+
assert root is None
|
|
110
|
+
|
|
104
111
|
|
|
105
112
|
def test_binary_operator_cross():
|
|
106
113
|
for query in (
|
|
107
114
|
r'Shows x Seasons',
|
|
115
|
+
r'Shows times Seasons',
|
|
108
116
|
):
|
|
109
117
|
root = RAParser.parse_query(query)
|
|
110
118
|
|
|
@@ -235,6 +243,14 @@ def test_binary_operator_join():
|
|
|
235
243
|
(2, 'Show 2', 2, 'Show 2 / Season 2')
|
|
236
244
|
]
|
|
237
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
|
+
|
|
238
254
|
|
|
239
255
|
def test_binary_operator_ljoin():
|
|
240
256
|
for query in (
|
|
@@ -261,6 +277,14 @@ def test_binary_operator_ljoin():
|
|
|
261
277
|
(3, 'Charlie', None),
|
|
262
278
|
]
|
|
263
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
|
+
|
|
264
288
|
|
|
265
289
|
def test_binary_operator_rjoin():
|
|
266
290
|
for query in (
|
|
@@ -286,6 +310,14 @@ def test_binary_operator_rjoin():
|
|
|
286
310
|
(4, None, 'David')
|
|
287
311
|
]
|
|
288
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
|
+
|
|
289
321
|
|
|
290
322
|
def test_binary_operator_fjoin():
|
|
291
323
|
for query in (
|
|
@@ -314,6 +346,76 @@ def test_binary_operator_fjoin():
|
|
|
314
346
|
(4, None, 'David')
|
|
315
347
|
]
|
|
316
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
|
+
|
|
317
419
|
|
|
318
420
|
def test_binary_operator_union():
|
|
319
421
|
for query in (
|
|
@@ -589,7 +691,7 @@ def test_binary_left_to_right_evaluation_order():
|
|
|
589
691
|
assert root.right.name == 'c'
|
|
590
692
|
|
|
591
693
|
# outer join
|
|
592
|
-
root = RAParser.parse_query(r'a ⟕ b ⟕ c')
|
|
694
|
+
root = RAParser.parse_query(r'a ⟕ b ⟕ c') # left outer, left outer
|
|
593
695
|
assert isinstance(root, BinaryOperators.LeftOuterJoin)
|
|
594
696
|
assert isinstance(root.left, BinaryOperators.LeftOuterJoin)
|
|
595
697
|
assert isinstance(root.left.left, RAOperand)
|
|
@@ -599,7 +701,7 @@ def test_binary_left_to_right_evaluation_order():
|
|
|
599
701
|
assert isinstance(root.right, RAOperand)
|
|
600
702
|
assert root.right.name == 'c'
|
|
601
703
|
|
|
602
|
-
root = RAParser.parse_query(r'a ⟖ b ⟖ c')
|
|
704
|
+
root = RAParser.parse_query(r'a ⟖ b ⟖ c') # right outer, right outer
|
|
603
705
|
assert isinstance(root, BinaryOperators.RightOuterJoin)
|
|
604
706
|
assert isinstance(root.left, BinaryOperators.RightOuterJoin)
|
|
605
707
|
assert isinstance(root.left.left, RAOperand)
|
|
@@ -609,7 +711,7 @@ def test_binary_left_to_right_evaluation_order():
|
|
|
609
711
|
assert isinstance(root.right, RAOperand)
|
|
610
712
|
assert root.right.name == 'c'
|
|
611
713
|
|
|
612
|
-
root = RAParser.parse_query(r'a ⟗ b ⟗ c')
|
|
714
|
+
root = RAParser.parse_query(r'a ⟗ b ⟗ c') # full outer, full outer
|
|
613
715
|
assert isinstance(root, BinaryOperators.FullOuterJoin)
|
|
614
716
|
assert isinstance(root.left, BinaryOperators.FullOuterJoin)
|
|
615
717
|
assert isinstance(root.left.left, RAOperand)
|
|
@@ -619,8 +721,29 @@ def test_binary_left_to_right_evaluation_order():
|
|
|
619
721
|
assert isinstance(root.right, RAOperand)
|
|
620
722
|
assert root.right.name == 'c'
|
|
621
723
|
|
|
622
|
-
#
|
|
623
|
-
root = RAParser.parse_query(r'a
|
|
724
|
+
# semi join
|
|
725
|
+
root = RAParser.parse_query(r'a ⋉ b ⋉ c') # left semi, left semi
|
|
726
|
+
assert isinstance(root, BinaryOperators.LeftSemiJoin)
|
|
727
|
+
assert isinstance(root.left, BinaryOperators.LeftSemiJoin)
|
|
728
|
+
assert isinstance(root.left.left, RAOperand)
|
|
729
|
+
assert root.left.left.name == 'a'
|
|
730
|
+
assert isinstance(root.left.right, RAOperand)
|
|
731
|
+
assert root.left.right.name == 'b'
|
|
732
|
+
assert isinstance(root.right, RAOperand)
|
|
733
|
+
assert root.right.name == 'c'
|
|
734
|
+
|
|
735
|
+
root = RAParser.parse_query(r'a ⋊ b ⋊ c') # right semi, right semi
|
|
736
|
+
assert isinstance(root, BinaryOperators.RightSemiJoin)
|
|
737
|
+
assert isinstance(root.left, BinaryOperators.RightSemiJoin)
|
|
738
|
+
assert isinstance(root.left.left, RAOperand)
|
|
739
|
+
assert root.left.left.name == 'a'
|
|
740
|
+
assert isinstance(root.left.right, RAOperand)
|
|
741
|
+
assert root.left.right.name == 'b'
|
|
742
|
+
assert isinstance(root.right, RAOperand)
|
|
743
|
+
assert root.right.name == 'c'
|
|
744
|
+
|
|
745
|
+
# mixed outer and semi joins
|
|
746
|
+
root = RAParser.parse_query(r'a ⟕ b ⟖ c') # left outer, right outer
|
|
624
747
|
assert isinstance(root, BinaryOperators.RightOuterJoin)
|
|
625
748
|
assert isinstance(root.left, BinaryOperators.LeftOuterJoin)
|
|
626
749
|
assert isinstance(root.left.left, RAOperand)
|
|
@@ -630,7 +753,7 @@ def test_binary_left_to_right_evaluation_order():
|
|
|
630
753
|
assert isinstance(root.right, RAOperand)
|
|
631
754
|
assert root.right.name == 'c'
|
|
632
755
|
|
|
633
|
-
root = RAParser.parse_query(r'a ⟕ b ⟗ c')
|
|
756
|
+
root = RAParser.parse_query(r'a ⟕ b ⟗ c') # left outer, full outer
|
|
634
757
|
assert isinstance(root, BinaryOperators.FullOuterJoin)
|
|
635
758
|
assert isinstance(root.left, BinaryOperators.LeftOuterJoin)
|
|
636
759
|
assert isinstance(root.left.left, RAOperand)
|
|
@@ -640,7 +763,27 @@ def test_binary_left_to_right_evaluation_order():
|
|
|
640
763
|
assert isinstance(root.right, RAOperand)
|
|
641
764
|
assert root.right.name == 'c'
|
|
642
765
|
|
|
643
|
-
root = RAParser.parse_query(r'a
|
|
766
|
+
root = RAParser.parse_query(r'a ⟕ b ⋉ c') # left outer, left semi
|
|
767
|
+
assert isinstance(root, BinaryOperators.LeftSemiJoin)
|
|
768
|
+
assert isinstance(root.left, BinaryOperators.LeftOuterJoin)
|
|
769
|
+
assert isinstance(root.left.left, RAOperand)
|
|
770
|
+
assert root.left.left.name == 'a'
|
|
771
|
+
assert isinstance(root.left.right, RAOperand)
|
|
772
|
+
assert root.left.right.name == 'b'
|
|
773
|
+
assert isinstance(root.right, RAOperand)
|
|
774
|
+
assert root.right.name == 'c'
|
|
775
|
+
|
|
776
|
+
root = RAParser.parse_query(r'a ⟕ b ⋊ c') # left outer, right semi
|
|
777
|
+
assert isinstance(root, BinaryOperators.RightSemiJoin)
|
|
778
|
+
assert isinstance(root.left, BinaryOperators.LeftOuterJoin)
|
|
779
|
+
assert isinstance(root.left.left, RAOperand)
|
|
780
|
+
assert root.left.left.name == 'a'
|
|
781
|
+
assert isinstance(root.left.right, RAOperand)
|
|
782
|
+
assert root.left.right.name == 'b'
|
|
783
|
+
assert isinstance(root.right, RAOperand)
|
|
784
|
+
assert root.right.name == 'c'
|
|
785
|
+
|
|
786
|
+
root = RAParser.parse_query(r'a ⟖ b ⟕ c') # right outer, left outer
|
|
644
787
|
assert isinstance(root, BinaryOperators.LeftOuterJoin)
|
|
645
788
|
assert isinstance(root.left, BinaryOperators.RightOuterJoin)
|
|
646
789
|
assert isinstance(root.left.left, RAOperand)
|
|
@@ -650,7 +793,7 @@ def test_binary_left_to_right_evaluation_order():
|
|
|
650
793
|
assert isinstance(root.right, RAOperand)
|
|
651
794
|
assert root.right.name == 'c'
|
|
652
795
|
|
|
653
|
-
root = RAParser.parse_query(r'a ⟖ b ⟗ c')
|
|
796
|
+
root = RAParser.parse_query(r'a ⟖ b ⟗ c') # right outer, full outer
|
|
654
797
|
assert isinstance(root, BinaryOperators.FullOuterJoin)
|
|
655
798
|
assert isinstance(root.left, BinaryOperators.RightOuterJoin)
|
|
656
799
|
assert isinstance(root.left.left, RAOperand)
|
|
@@ -660,7 +803,27 @@ def test_binary_left_to_right_evaluation_order():
|
|
|
660
803
|
assert isinstance(root.right, RAOperand)
|
|
661
804
|
assert root.right.name == 'c'
|
|
662
805
|
|
|
663
|
-
root = RAParser.parse_query(r'a
|
|
806
|
+
root = RAParser.parse_query(r'a ⟖ b ⋉ c') # right outer, left semi
|
|
807
|
+
assert isinstance(root, BinaryOperators.LeftSemiJoin)
|
|
808
|
+
assert isinstance(root.left, BinaryOperators.RightOuterJoin)
|
|
809
|
+
assert isinstance(root.left.left, RAOperand)
|
|
810
|
+
assert root.left.left.name == 'a'
|
|
811
|
+
assert isinstance(root.left.right, RAOperand)
|
|
812
|
+
assert root.left.right.name == 'b'
|
|
813
|
+
assert isinstance(root.right, RAOperand)
|
|
814
|
+
assert root.right.name == 'c'
|
|
815
|
+
|
|
816
|
+
root = RAParser.parse_query(r'a ⟖ b ⋊ c') # right outer, right semi
|
|
817
|
+
assert isinstance(root, BinaryOperators.RightSemiJoin)
|
|
818
|
+
assert isinstance(root.left, BinaryOperators.RightOuterJoin)
|
|
819
|
+
assert isinstance(root.left.left, RAOperand)
|
|
820
|
+
assert root.left.left.name == 'a'
|
|
821
|
+
assert isinstance(root.left.right, RAOperand)
|
|
822
|
+
assert root.left.right.name == 'b'
|
|
823
|
+
assert isinstance(root.right, RAOperand)
|
|
824
|
+
assert root.right.name == 'c'
|
|
825
|
+
|
|
826
|
+
root = RAParser.parse_query(r'a ⟗ b ⟕ c') # full outer, left outer
|
|
664
827
|
assert isinstance(root, BinaryOperators.LeftOuterJoin)
|
|
665
828
|
assert isinstance(root.left, BinaryOperators.FullOuterJoin)
|
|
666
829
|
assert isinstance(root.left.left, RAOperand)
|
|
@@ -670,7 +833,7 @@ def test_binary_left_to_right_evaluation_order():
|
|
|
670
833
|
assert isinstance(root.right, RAOperand)
|
|
671
834
|
assert root.right.name == 'c'
|
|
672
835
|
|
|
673
|
-
root = RAParser.parse_query(r'a ⟗ b ⟖ c')
|
|
836
|
+
root = RAParser.parse_query(r'a ⟗ b ⟖ c') # full outer, right outer
|
|
674
837
|
assert isinstance(root, BinaryOperators.RightOuterJoin)
|
|
675
838
|
assert isinstance(root.left, BinaryOperators.FullOuterJoin)
|
|
676
839
|
assert isinstance(root.left.left, RAOperand)
|
|
@@ -680,6 +843,106 @@ def test_binary_left_to_right_evaluation_order():
|
|
|
680
843
|
assert isinstance(root.right, RAOperand)
|
|
681
844
|
assert root.right.name == 'c'
|
|
682
845
|
|
|
846
|
+
root = RAParser.parse_query(r'a ⟗ b ⋉ c') # full outer, left semi
|
|
847
|
+
assert isinstance(root, BinaryOperators.LeftSemiJoin)
|
|
848
|
+
assert isinstance(root.left, BinaryOperators.FullOuterJoin)
|
|
849
|
+
assert isinstance(root.left.left, RAOperand)
|
|
850
|
+
assert root.left.left.name == 'a'
|
|
851
|
+
assert isinstance(root.left.right, RAOperand)
|
|
852
|
+
assert root.left.right.name == 'b'
|
|
853
|
+
assert isinstance(root.right, RAOperand)
|
|
854
|
+
assert root.right.name == 'c'
|
|
855
|
+
|
|
856
|
+
root = RAParser.parse_query(r'a ⟗ b ⋊ c') # full outer, right semi
|
|
857
|
+
assert isinstance(root, BinaryOperators.RightSemiJoin)
|
|
858
|
+
assert isinstance(root.left, BinaryOperators.FullOuterJoin)
|
|
859
|
+
assert isinstance(root.left.left, RAOperand)
|
|
860
|
+
assert root.left.left.name == 'a'
|
|
861
|
+
assert isinstance(root.left.right, RAOperand)
|
|
862
|
+
assert root.left.right.name == 'b'
|
|
863
|
+
assert isinstance(root.right, RAOperand)
|
|
864
|
+
assert root.right.name == 'c'
|
|
865
|
+
|
|
866
|
+
root = RAParser.parse_query(r'a ⋉ b ⟕ c') # left semi, left outer
|
|
867
|
+
assert isinstance(root, BinaryOperators.LeftOuterJoin)
|
|
868
|
+
assert isinstance(root.left, BinaryOperators.LeftSemiJoin)
|
|
869
|
+
assert isinstance(root.left.left, RAOperand)
|
|
870
|
+
assert root.left.left.name == 'a'
|
|
871
|
+
assert isinstance(root.left.right, RAOperand)
|
|
872
|
+
assert root.left.right.name == 'b'
|
|
873
|
+
assert isinstance(root.right, RAOperand)
|
|
874
|
+
assert root.right.name == 'c'
|
|
875
|
+
|
|
876
|
+
root = RAParser.parse_query(r'a ⋉ b ⟖ c') # left semi, right outer
|
|
877
|
+
assert isinstance(root, BinaryOperators.RightOuterJoin)
|
|
878
|
+
assert isinstance(root.left, BinaryOperators.LeftSemiJoin)
|
|
879
|
+
assert isinstance(root.left.left, RAOperand)
|
|
880
|
+
assert root.left.left.name == 'a'
|
|
881
|
+
assert isinstance(root.left.right, RAOperand)
|
|
882
|
+
assert root.left.right.name == 'b'
|
|
883
|
+
assert isinstance(root.right, RAOperand)
|
|
884
|
+
assert root.right.name == 'c'
|
|
885
|
+
|
|
886
|
+
root = RAParser.parse_query(r'a ⋉ b ⟗ c') # left semi, full outer
|
|
887
|
+
assert isinstance(root, BinaryOperators.FullOuterJoin)
|
|
888
|
+
assert isinstance(root.left, BinaryOperators.LeftSemiJoin)
|
|
889
|
+
assert isinstance(root.left.left, RAOperand)
|
|
890
|
+
assert root.left.left.name == 'a'
|
|
891
|
+
assert isinstance(root.left.right, RAOperand)
|
|
892
|
+
assert root.left.right.name == 'b'
|
|
893
|
+
assert isinstance(root.right, RAOperand)
|
|
894
|
+
assert root.right.name == 'c'
|
|
895
|
+
|
|
896
|
+
root = RAParser.parse_query(r'a ⋉ b ⋊ c') # left semi, right semi
|
|
897
|
+
assert isinstance(root, BinaryOperators.RightSemiJoin)
|
|
898
|
+
assert isinstance(root.left, BinaryOperators.LeftSemiJoin)
|
|
899
|
+
assert isinstance(root.left.left, RAOperand)
|
|
900
|
+
assert root.left.left.name == 'a'
|
|
901
|
+
assert isinstance(root.left.right, RAOperand)
|
|
902
|
+
assert root.left.right.name == 'b'
|
|
903
|
+
assert isinstance(root.right, RAOperand)
|
|
904
|
+
assert root.right.name == 'c'
|
|
905
|
+
|
|
906
|
+
root = RAParser.parse_query(r'a ⋊ b ⟕ c') # right semi, left outer
|
|
907
|
+
assert isinstance(root, BinaryOperators.LeftOuterJoin)
|
|
908
|
+
assert isinstance(root.left, BinaryOperators.RightSemiJoin)
|
|
909
|
+
assert isinstance(root.left.left, RAOperand)
|
|
910
|
+
assert root.left.left.name == 'a'
|
|
911
|
+
assert isinstance(root.left.right, RAOperand)
|
|
912
|
+
assert root.left.right.name == 'b'
|
|
913
|
+
assert isinstance(root.right, RAOperand)
|
|
914
|
+
assert root.right.name == 'c'
|
|
915
|
+
|
|
916
|
+
root = RAParser.parse_query(r'a ⋊ b ⟖ c') # right semi, right outer
|
|
917
|
+
assert isinstance(root, BinaryOperators.RightOuterJoin)
|
|
918
|
+
assert isinstance(root.left, BinaryOperators.RightSemiJoin)
|
|
919
|
+
assert isinstance(root.left.left, RAOperand)
|
|
920
|
+
assert root.left.left.name == 'a'
|
|
921
|
+
assert isinstance(root.left.right, RAOperand)
|
|
922
|
+
assert root.left.right.name == 'b'
|
|
923
|
+
assert isinstance(root.right, RAOperand)
|
|
924
|
+
assert root.right.name == 'c'
|
|
925
|
+
|
|
926
|
+
root = RAParser.parse_query(r'a ⋊ b ⟗ c') # right semi, full outer
|
|
927
|
+
assert isinstance(root, BinaryOperators.FullOuterJoin)
|
|
928
|
+
assert isinstance(root.left, BinaryOperators.RightSemiJoin)
|
|
929
|
+
assert isinstance(root.left.left, RAOperand)
|
|
930
|
+
assert root.left.left.name == 'a'
|
|
931
|
+
assert isinstance(root.left.right, RAOperand)
|
|
932
|
+
assert root.left.right.name == 'b'
|
|
933
|
+
assert isinstance(root.right, RAOperand)
|
|
934
|
+
assert root.right.name == 'c'
|
|
935
|
+
|
|
936
|
+
root = RAParser.parse_query(r'a ⋊ b ⋉ c') # right semi, left semi
|
|
937
|
+
assert isinstance(root, BinaryOperators.LeftSemiJoin)
|
|
938
|
+
assert isinstance(root.left, BinaryOperators.RightSemiJoin)
|
|
939
|
+
assert isinstance(root.left.left, RAOperand)
|
|
940
|
+
assert root.left.left.name == 'a'
|
|
941
|
+
assert isinstance(root.left.right, RAOperand)
|
|
942
|
+
assert root.left.right.name == 'b'
|
|
943
|
+
assert isinstance(root.right, RAOperand)
|
|
944
|
+
assert root.right.name == 'c'
|
|
945
|
+
|
|
683
946
|
# cross join
|
|
684
947
|
root = RAParser.parse_query(r'a x b x c')
|
|
685
948
|
assert isinstance(root, BinaryOperators.Cross)
|
|
@@ -770,6 +1033,22 @@ def test_binary_evaluation_order():
|
|
|
770
1033
|
assert isinstance(root, BinaryOperators.Difference)
|
|
771
1034
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.FullOuterJoin)
|
|
772
1035
|
|
|
1036
|
+
root = RAParser.parse_query(r'a \ b ⋉ c')
|
|
1037
|
+
assert isinstance(root, BinaryOperators.Difference)
|
|
1038
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.LeftSemiJoin)
|
|
1039
|
+
|
|
1040
|
+
root = RAParser.parse_query(r'a ⋉ b \ c')
|
|
1041
|
+
assert isinstance(root, BinaryOperators.Difference)
|
|
1042
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.LeftSemiJoin)
|
|
1043
|
+
|
|
1044
|
+
root = RAParser.parse_query(r'a \ b ⋊ c')
|
|
1045
|
+
assert isinstance(root, BinaryOperators.Difference)
|
|
1046
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.RightSemiJoin)
|
|
1047
|
+
|
|
1048
|
+
root = RAParser.parse_query(r'a ⋊ b \ c')
|
|
1049
|
+
assert isinstance(root, BinaryOperators.Difference)
|
|
1050
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.RightSemiJoin)
|
|
1051
|
+
|
|
773
1052
|
# difference <-> cross
|
|
774
1053
|
root = RAParser.parse_query(r'a \ b x c')
|
|
775
1054
|
assert isinstance(root, BinaryOperators.Difference)
|
|
@@ -830,6 +1109,22 @@ def test_binary_evaluation_order():
|
|
|
830
1109
|
assert isinstance(root, BinaryOperators.Union)
|
|
831
1110
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.FullOuterJoin)
|
|
832
1111
|
|
|
1112
|
+
root = RAParser.parse_query(r'a ∪ b ⋉ c')
|
|
1113
|
+
assert isinstance(root, BinaryOperators.Union)
|
|
1114
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.LeftSemiJoin)
|
|
1115
|
+
|
|
1116
|
+
root = RAParser.parse_query(r'a ⋉ b ∪ c')
|
|
1117
|
+
assert isinstance(root, BinaryOperators.Union)
|
|
1118
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.LeftSemiJoin)
|
|
1119
|
+
|
|
1120
|
+
root = RAParser.parse_query(r'a ∪ b ⋊ c')
|
|
1121
|
+
assert isinstance(root, BinaryOperators.Union)
|
|
1122
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.RightSemiJoin)
|
|
1123
|
+
|
|
1124
|
+
root = RAParser.parse_query(r'a ⋊ b ∪ c')
|
|
1125
|
+
assert isinstance(root, BinaryOperators.Union)
|
|
1126
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.RightSemiJoin)
|
|
1127
|
+
|
|
833
1128
|
# union <-> cross
|
|
834
1129
|
root = RAParser.parse_query(r'a ∪ b x c')
|
|
835
1130
|
assert isinstance(root, BinaryOperators.Union)
|
|
@@ -881,6 +1176,22 @@ def test_binary_evaluation_order():
|
|
|
881
1176
|
assert isinstance(root, BinaryOperators.Intersection)
|
|
882
1177
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.FullOuterJoin)
|
|
883
1178
|
|
|
1179
|
+
root = RAParser.parse_query(r'a ∩ b ⋉ c')
|
|
1180
|
+
assert isinstance(root, BinaryOperators.Intersection)
|
|
1181
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.LeftSemiJoin)
|
|
1182
|
+
|
|
1183
|
+
root = RAParser.parse_query(r'a ⋉ b ∩ c')
|
|
1184
|
+
assert isinstance(root, BinaryOperators.Intersection)
|
|
1185
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.LeftSemiJoin)
|
|
1186
|
+
|
|
1187
|
+
root = RAParser.parse_query(r'a ∩ b ⋊ c')
|
|
1188
|
+
assert isinstance(root, BinaryOperators.Intersection)
|
|
1189
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.RightSemiJoin)
|
|
1190
|
+
|
|
1191
|
+
root = RAParser.parse_query(r'a ⋊ b ∩ c')
|
|
1192
|
+
assert isinstance(root, BinaryOperators.Intersection)
|
|
1193
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.RightSemiJoin)
|
|
1194
|
+
|
|
884
1195
|
# intersection <-> cross
|
|
885
1196
|
root = RAParser.parse_query(r'a ∩ b x c')
|
|
886
1197
|
assert isinstance(root, BinaryOperators.Intersection)
|
|
@@ -932,6 +1243,22 @@ def test_binary_evaluation_order():
|
|
|
932
1243
|
assert isinstance(root, BinaryOperators.FullOuterJoin)
|
|
933
1244
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Cross)
|
|
934
1245
|
|
|
1246
|
+
root = RAParser.parse_query(r'a ⋉ b x c')
|
|
1247
|
+
assert isinstance(root, BinaryOperators.LeftSemiJoin)
|
|
1248
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Cross)
|
|
1249
|
+
|
|
1250
|
+
root = RAParser.parse_query(r'a x b ⋉ c')
|
|
1251
|
+
assert isinstance(root, BinaryOperators.LeftSemiJoin)
|
|
1252
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Cross)
|
|
1253
|
+
|
|
1254
|
+
root = RAParser.parse_query(r'a ⋊ b x c')
|
|
1255
|
+
assert isinstance(root, BinaryOperators.RightSemiJoin)
|
|
1256
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Cross)
|
|
1257
|
+
|
|
1258
|
+
root = RAParser.parse_query(r'a x b ⋊ c')
|
|
1259
|
+
assert isinstance(root, BinaryOperators.RightSemiJoin)
|
|
1260
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Cross)
|
|
1261
|
+
|
|
935
1262
|
# join <-> division
|
|
936
1263
|
root = RAParser.parse_query(r'a ⋈ b ÷ c')
|
|
937
1264
|
assert isinstance(root, BinaryOperators.Join)
|
|
@@ -965,6 +1292,22 @@ def test_binary_evaluation_order():
|
|
|
965
1292
|
assert isinstance(root, BinaryOperators.FullOuterJoin)
|
|
966
1293
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Division)
|
|
967
1294
|
|
|
1295
|
+
root = RAParser.parse_query(r'a ⋉ b ÷ c')
|
|
1296
|
+
assert isinstance(root, BinaryOperators.LeftSemiJoin)
|
|
1297
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Division)
|
|
1298
|
+
|
|
1299
|
+
root = RAParser.parse_query(r'a ÷ b ⋉ c')
|
|
1300
|
+
assert isinstance(root, BinaryOperators.LeftSemiJoin)
|
|
1301
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Division)
|
|
1302
|
+
|
|
1303
|
+
root = RAParser.parse_query(r'a ⋊ b ÷ c')
|
|
1304
|
+
assert isinstance(root, BinaryOperators.RightSemiJoin)
|
|
1305
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Division)
|
|
1306
|
+
|
|
1307
|
+
root = RAParser.parse_query(r'a ÷ b ⋊ c')
|
|
1308
|
+
assert isinstance(root, BinaryOperators.RightSemiJoin)
|
|
1309
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Division)
|
|
1310
|
+
|
|
968
1311
|
# natural join <-> outer join
|
|
969
1312
|
root = RAParser.parse_query(r'a ⋈ b ⟕ c')
|
|
970
1313
|
assert isinstance(root, BinaryOperators.Join)
|
|
@@ -990,6 +1333,22 @@ def test_binary_evaluation_order():
|
|
|
990
1333
|
assert isinstance(root, BinaryOperators.Join)
|
|
991
1334
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.FullOuterJoin)
|
|
992
1335
|
|
|
1336
|
+
root = RAParser.parse_query(r'a ⋈ b ⋉ c')
|
|
1337
|
+
assert isinstance(root, BinaryOperators.Join)
|
|
1338
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.LeftSemiJoin)
|
|
1339
|
+
|
|
1340
|
+
root = RAParser.parse_query(r'a ⋉ b ⋈ c')
|
|
1341
|
+
assert isinstance(root, BinaryOperators.Join)
|
|
1342
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.LeftSemiJoin)
|
|
1343
|
+
|
|
1344
|
+
root = RAParser.parse_query(r'a ⋈ b ⋊ c')
|
|
1345
|
+
assert isinstance(root, BinaryOperators.Join)
|
|
1346
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.RightSemiJoin)
|
|
1347
|
+
|
|
1348
|
+
root = RAParser.parse_query(r'a ⋊ b ⋈ c')
|
|
1349
|
+
assert isinstance(root, BinaryOperators.Join)
|
|
1350
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.RightSemiJoin)
|
|
1351
|
+
|
|
993
1352
|
# cross <-> division
|
|
994
1353
|
root = RAParser.parse_query(r'a x b ÷ c')
|
|
995
1354
|
assert isinstance(root, BinaryOperators.Cross)
|
|
@@ -1115,6 +1474,22 @@ def test_mixed_evaluation_order():
|
|
|
1115
1474
|
assert isinstance(root, BinaryOperators.FullOuterJoin)
|
|
1116
1475
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Projection)
|
|
1117
1476
|
|
|
1477
|
+
root = RAParser.parse_query(r'a ⋉ π [ Id ] b')
|
|
1478
|
+
assert isinstance(root, BinaryOperators.LeftSemiJoin)
|
|
1479
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Projection)
|
|
1480
|
+
|
|
1481
|
+
root = RAParser.parse_query(r'π [ Id ] a ⋉ b')
|
|
1482
|
+
assert isinstance(root, BinaryOperators.LeftSemiJoin)
|
|
1483
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Projection)
|
|
1484
|
+
|
|
1485
|
+
root = RAParser.parse_query(r'a ⋊ π [ Id ] b')
|
|
1486
|
+
assert isinstance(root, BinaryOperators.RightSemiJoin)
|
|
1487
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Projection)
|
|
1488
|
+
|
|
1489
|
+
root = RAParser.parse_query(r'π [ Id ] a ⋊ b')
|
|
1490
|
+
assert isinstance(root, BinaryOperators.RightSemiJoin)
|
|
1491
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Projection)
|
|
1492
|
+
|
|
1118
1493
|
# join <-> rename
|
|
1119
1494
|
root = RAParser.parse_query(r'a ⋈ β [ Id2 ← Id ] b')
|
|
1120
1495
|
assert isinstance(root, BinaryOperators.Join)
|
|
@@ -1148,6 +1523,22 @@ def test_mixed_evaluation_order():
|
|
|
1148
1523
|
assert isinstance(root, BinaryOperators.FullOuterJoin)
|
|
1149
1524
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
|
|
1150
1525
|
|
|
1526
|
+
root = RAParser.parse_query(r'a ⋉ β [ Id2 ← Id ] b')
|
|
1527
|
+
assert isinstance(root, BinaryOperators.LeftSemiJoin)
|
|
1528
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Rename)
|
|
1529
|
+
|
|
1530
|
+
root = RAParser.parse_query(r'β [ Id2 ← Id ] a ⋉ b')
|
|
1531
|
+
assert isinstance(root, BinaryOperators.LeftSemiJoin)
|
|
1532
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
|
|
1533
|
+
|
|
1534
|
+
root = RAParser.parse_query(r'a ⋊ β [ Id2 ← Id ] b')
|
|
1535
|
+
assert isinstance(root, BinaryOperators.RightSemiJoin)
|
|
1536
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Rename)
|
|
1537
|
+
|
|
1538
|
+
root = RAParser.parse_query(r'β [ Id2 ← Id ] a ⋊ b')
|
|
1539
|
+
assert isinstance(root, BinaryOperators.RightSemiJoin)
|
|
1540
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
|
|
1541
|
+
|
|
1151
1542
|
# join <-> selection
|
|
1152
1543
|
root = RAParser.parse_query(r'a ⋈ σ [ Id > 1 ] b')
|
|
1153
1544
|
assert isinstance(root, BinaryOperators.Join)
|
|
@@ -1181,6 +1572,22 @@ def test_mixed_evaluation_order():
|
|
|
1181
1572
|
assert isinstance(root, BinaryOperators.FullOuterJoin)
|
|
1182
1573
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Selection)
|
|
1183
1574
|
|
|
1575
|
+
root = RAParser.parse_query(r'a ⋉ σ [ Id > 1 ] b')
|
|
1576
|
+
assert isinstance(root, BinaryOperators.LeftSemiJoin)
|
|
1577
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Selection)
|
|
1578
|
+
|
|
1579
|
+
root = RAParser.parse_query(r'σ [ Id > 1 ] a ⋉ b')
|
|
1580
|
+
assert isinstance(root, BinaryOperators.LeftSemiJoin)
|
|
1581
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Selection)
|
|
1582
|
+
|
|
1583
|
+
root = RAParser.parse_query(r'a ⋊ σ [ Id > 1 ] b')
|
|
1584
|
+
assert isinstance(root, BinaryOperators.RightSemiJoin)
|
|
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.RightSemiJoin)
|
|
1589
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Selection)
|
|
1590
|
+
|
|
1184
1591
|
# cross <-> projection
|
|
1185
1592
|
root = RAParser.parse_query(r'a x π [ Id ] b')
|
|
1186
1593
|
assert isinstance(root, BinaryOperators.Cross)
|
|
@@ -1,11 +1,26 @@
|
|
|
1
|
+
import datetime
|
|
1
2
|
from datetime import date
|
|
2
|
-
from typing import Tuple, List, Optional
|
|
3
|
+
from typing import Tuple, List, Optional, Any
|
|
3
4
|
|
|
4
5
|
|
|
5
6
|
class ResultSetComparator:
|
|
6
7
|
def __init__(self, left: List[Tuple | List], right: List[Tuple | List]):
|
|
7
|
-
self._left: List[Tuple] = [tuple(t) for t in left]
|
|
8
|
-
self._right: List[Tuple] = [tuple(t) for t in right]
|
|
8
|
+
self._left: List[Tuple] = [tuple(self.format_value(t)) for t in left]
|
|
9
|
+
self._right: List[Tuple] = [tuple(self.format_value(t)) for t in right]
|
|
10
|
+
|
|
11
|
+
@staticmethod
|
|
12
|
+
def format_value(value: Any) -> Any:
|
|
13
|
+
if isinstance(value, tuple) or isinstance(value, list):
|
|
14
|
+
return tuple(ResultSetComparator.format_value(t) for t in value)
|
|
15
|
+
|
|
16
|
+
if isinstance(value, datetime.datetime):
|
|
17
|
+
return value.strftime("%Y-%m-%d %H:%M:%S")
|
|
18
|
+
if isinstance(value, datetime.date):
|
|
19
|
+
return value.strftime("%Y-%m-%d")
|
|
20
|
+
if isinstance(value, datetime.time):
|
|
21
|
+
return value.strftime("%H:%M:%S")
|
|
22
|
+
|
|
23
|
+
return value
|
|
9
24
|
|
|
10
25
|
@property
|
|
11
26
|
def left_only(self) -> List[Tuple]:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
duckdb_kernel/__init__.py,sha256=6auU6zeJrsA4fxPSr2PYamS8fG-SMXTn5YQFXF2cseo,33
|
|
2
2
|
duckdb_kernel/__main__.py,sha256=Z3GwHEBWoQjNm2Y84ijnbA0Lk66L7nsFREuqhZ_ptk0,165
|
|
3
3
|
duckdb_kernel/kernel.json,sha256=_7E8Ci2FSdCvnzCjsOaue8QE8AvpS5JLQuxORO5IGtA,127
|
|
4
|
-
duckdb_kernel/kernel.py,sha256=
|
|
4
|
+
duckdb_kernel/kernel.py,sha256=VOQQXr0Cn3BhFvOr_Oh1f2_OFUOUgvkyz4c55mRwdgs,28484
|
|
5
5
|
duckdb_kernel/db/Column.py,sha256=GM5P6sFdlYK92hiKln5-6038gIDOTxh1AYbR4kiga_w,559
|
|
6
6
|
duckdb_kernel/db/Connection.py,sha256=tBXQBYt9c52RLbpl9sakNuAm0Z84--fhZ4efo8ACz-U,670
|
|
7
7
|
duckdb_kernel/db/Constraint.py,sha256=1YgUHk7s8mHCVedbcuJKyXDykj7_ybbwT3Dk9p2VMis,287
|
|
@@ -24,10 +24,10 @@ duckdb_kernel/magics/MagicCommandException.py,sha256=MwuWkpA6NoCqz437urdI0RVXhbS
|
|
|
24
24
|
duckdb_kernel/magics/MagicCommandHandler.py,sha256=hKNHRfa0BSPei4QXdVlLlbpvZIhJJ91aaT_HTMiK28E,4700
|
|
25
25
|
duckdb_kernel/magics/MagicState.py,sha256=Vt_KwUwQP3446c1snSxS68Skl5AZQzrJd2Q1ETpKuKI,344
|
|
26
26
|
duckdb_kernel/magics/__init__.py,sha256=ggxzDzDEsKMZzYsWw9JqYVJhciJPvPVYGV7oNo9Yp-E,239
|
|
27
|
-
duckdb_kernel/parser/DCParser.py,sha256=
|
|
27
|
+
duckdb_kernel/parser/DCParser.py,sha256=Hjlck8k17WhlHZ_zeEoQBP1xbf94bFD7YMEELTC7BnM,2507
|
|
28
28
|
duckdb_kernel/parser/LogicParser.py,sha256=_vZwE5OPRUEN8aEC_fSZAYKR_dpexqNthXog9OFHYRY,1233
|
|
29
29
|
duckdb_kernel/parser/ParserError.py,sha256=qJQVloFtID1HgVDQ1Io247bODT1ic3oO9Z1ZrWR-2Mk,321
|
|
30
|
-
duckdb_kernel/parser/RAParser.py,sha256=
|
|
30
|
+
duckdb_kernel/parser/RAParser.py,sha256=raQN-H_LmDaIekr-49alMegcnKVF2HA98EqBZo_-2Xc,3371
|
|
31
31
|
duckdb_kernel/parser/__init__.py,sha256=nTmDm1ADvNPDHhVJQLxKYmArNJk6967EUXqn5AkT8FM,126
|
|
32
32
|
duckdb_kernel/parser/elements/DCOperand.py,sha256=qEg_6Us4WV1eK4Bq6oUsmFt_L_x5pJPGce_wSapzIYA,1149
|
|
33
33
|
duckdb_kernel/parser/elements/LogicElement.py,sha256=YasKHxWLDDP8UdyLIKbXzqIRA8-XaakjmvTj-1Iuzyc,280
|
|
@@ -40,29 +40,31 @@ duckdb_kernel/parser/elements/RAOperator.py,sha256=rtqMFBIBBqT-Bwg7Qm4WQwbDrE28N
|
|
|
40
40
|
duckdb_kernel/parser/elements/RAUnaryOperator.py,sha256=XC1nphkSm88JaEu5V_HKnb_8JNoeBfE3EvNL4o0qh2c,654
|
|
41
41
|
duckdb_kernel/parser/elements/__init__.py,sha256=t5H6SVOm3z8r6UWRYOI7HmMIuB4Yh6TLNu4_N3jg2t0,566
|
|
42
42
|
duckdb_kernel/parser/elements/binary/Add.py,sha256=XGkZMfab01huk9EaI6JUfzkd2STbV1C_-TyC2guKE8I,190
|
|
43
|
-
duckdb_kernel/parser/elements/binary/And.py,sha256=
|
|
43
|
+
duckdb_kernel/parser/elements/binary/And.py,sha256=p6TQE49DtHlMlTkH9GqyrQVcYWsVgdIMTTCxNuNORuQ,267
|
|
44
44
|
duckdb_kernel/parser/elements/binary/ArrowLeft.py,sha256=u4fZSoyT9lfvWXBwuhUl4DdjVZAOqyVIKmMVbpElLD4,203
|
|
45
45
|
duckdb_kernel/parser/elements/binary/ConditionalSet.py,sha256=yzUPWO4KL8BEIQ-SiV00bdLulwHoxgoJRxebyhsRSPU,17884
|
|
46
|
-
duckdb_kernel/parser/elements/binary/Cross.py,sha256=
|
|
46
|
+
duckdb_kernel/parser/elements/binary/Cross.py,sha256=9AFfnpkMApJQulqp81hMOn7yRDZXZJCP1UUaf_-HSrg,705
|
|
47
47
|
duckdb_kernel/parser/elements/binary/Difference.py,sha256=4nyHhjo09UmYjtGNC3xGQxV5ROzCGOpPkyerUN-AlF4,746
|
|
48
48
|
duckdb_kernel/parser/elements/binary/Divide.py,sha256=ubekU4C1wkCTidUSMLEj5neheRx0QjhWSrsPGuXTa1g,265
|
|
49
49
|
duckdb_kernel/parser/elements/binary/Division.py,sha256=FOYxmeNGljRETwygtVn102POCUmt71t9DXdAnLFCXZM,1535
|
|
50
50
|
duckdb_kernel/parser/elements/binary/Equal.py,sha256=xd5eMwVwM7thXqmoBg-JSux4y6osxxznNzaChmgrnGI,192
|
|
51
|
-
duckdb_kernel/parser/elements/binary/FullOuterJoin.py,sha256=
|
|
51
|
+
duckdb_kernel/parser/elements/binary/FullOuterJoin.py,sha256=fXyz-eTVO4uzLSG4wky-SKh93u0Rzuxjlp_w-MVHS-M,1550
|
|
52
52
|
duckdb_kernel/parser/elements/binary/GreaterThan.py,sha256=lW7EPYjwwZ1VLZOE4ai6MBW7Zq5itsUTi_v6FxoAuU0,204
|
|
53
53
|
duckdb_kernel/parser/elements/binary/GreaterThanEqual.py,sha256=gO1I3J5CZwrpqZb5Oc-WJ_fCnGylpj4YKl4s-ZAr_-4,286
|
|
54
54
|
duckdb_kernel/parser/elements/binary/Intersection.py,sha256=K6NrwcLTJ1BUccifVQ2R2YHR5B71LhjuLhOalxZcM0g,757
|
|
55
|
-
duckdb_kernel/parser/elements/binary/Join.py,sha256=
|
|
56
|
-
duckdb_kernel/parser/elements/binary/LeftOuterJoin.py,sha256=
|
|
55
|
+
duckdb_kernel/parser/elements/binary/Join.py,sha256=t_PPV7rGXob34ls27IiNkSzgB5yg-XYhuKO9xDkLqQY,992
|
|
56
|
+
duckdb_kernel/parser/elements/binary/LeftOuterJoin.py,sha256=HKQIQaV7Er6WYVqpdGgeVbe_DNEUwBoxL9CC0k9ZYBQ,1013
|
|
57
|
+
duckdb_kernel/parser/elements/binary/LeftSemiJoin.py,sha256=sWzG5f3H8nGxmXbJUQFVpEZHjJOAcYo5unm3VvGrTIg,994
|
|
57
58
|
duckdb_kernel/parser/elements/binary/LessThan.py,sha256=gNlyAvew0VyvU8x3ol88zbdh_t9GU51Kd2P_PmHUrAc,201
|
|
58
59
|
duckdb_kernel/parser/elements/binary/LessThanEqual.py,sha256=BKKXBZ4TZQ4EBxBDSNzIpFl4Oz1IGI0tI0Oj7KZUoDo,283
|
|
59
60
|
duckdb_kernel/parser/elements/binary/Minus.py,sha256=1XUTXCA0GcAcCnv9nq4B9ewT0XHJ91LlZGEW1y60POA,192
|
|
60
61
|
duckdb_kernel/parser/elements/binary/Multiply.py,sha256=OctlfN71izFYxIpMo09Qwq-3BmQmSh6-PNKBljMsBrg,195
|
|
61
62
|
duckdb_kernel/parser/elements/binary/Or.py,sha256=e1H_BuY7TQD7XHKGqJYLOebYQvrh1euWOUsXF0FT5dY,264
|
|
62
|
-
duckdb_kernel/parser/elements/binary/RightOuterJoin.py,sha256=
|
|
63
|
+
duckdb_kernel/parser/elements/binary/RightOuterJoin.py,sha256=cakJNIor_AQRe7LBrQVu2ZN_eksVAZqSVBy1EBFahLA,1035
|
|
64
|
+
duckdb_kernel/parser/elements/binary/RightSemiJoin.py,sha256=B7adyKnIRiwrqZ4wQkz81O_1e6xFkHFajTtSZz-jpS0,1015
|
|
63
65
|
duckdb_kernel/parser/elements/binary/Unequal.py,sha256=1hnC1RcPMxwKKv65OL5prunGgh9cRVDmzJutmtl7gtY,269
|
|
64
66
|
duckdb_kernel/parser/elements/binary/Union.py,sha256=VYTj4M2PVEhWiDwjnyP8qpVVbGvIBSVshlEt-SZYCBY,739
|
|
65
|
-
duckdb_kernel/parser/elements/binary/__init__.py,sha256
|
|
67
|
+
duckdb_kernel/parser/elements/binary/__init__.py,sha256=-4ZY6vpsiyT8eDkLwyFGHJFWXIMCNYNz9ejFFcjEG5U,1451
|
|
66
68
|
duckdb_kernel/parser/elements/unary/Not.py,sha256=kG0a-dp3TNjPodUMPiQ6ihtsBrbvn1iWeIPCvtyAwdo,632
|
|
67
69
|
duckdb_kernel/parser/elements/unary/Projection.py,sha256=CJ-MIf1-__1ewTjNZVy5hOz3Z18CWnCDNJBxUdpWXVQ,1112
|
|
68
70
|
duckdb_kernel/parser/elements/unary/Rename.py,sha256=Zr2n9EJ3nA476lND0Djz2b6493nnsbSpJ9kkEgk5B_Y,1273
|
|
@@ -76,11 +78,11 @@ duckdb_kernel/parser/util/RenamableColumn.py,sha256=LxJhFDMUv_OxYYDLwKn63QGpBRfs
|
|
|
76
78
|
duckdb_kernel/parser/util/RenamableColumnList.py,sha256=5oEDbtvl4YfHbkxu_Ny2pc0EYnhCZsf7EeoNQvftbrU,3281
|
|
77
79
|
duckdb_kernel/parser/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
78
80
|
duckdb_kernel/tests/__init__.py,sha256=-BoPfo1FNQKnvAYt22Ioc21dbuO67QVFaV_SmS1zQw8,2731
|
|
79
|
-
duckdb_kernel/tests/test_dc.py,sha256=
|
|
80
|
-
duckdb_kernel/tests/test_ra.py,sha256=
|
|
81
|
+
duckdb_kernel/tests/test_dc.py,sha256=E-PppvBU6AuLFpg0M3chFscm-2Kuv2rkz85PL2NCESc,15968
|
|
82
|
+
duckdb_kernel/tests/test_ra.py,sha256=qvI5Sxkl8Sr3_E7qgMh5B1wJbMEekAXlXp1sm16uZTk,71194
|
|
81
83
|
duckdb_kernel/tests/test_result_comparison.py,sha256=TQVLPKKNyV2k3i4jCfasetPfVfCzgYZr92wxQmlzPnA,3859
|
|
82
84
|
duckdb_kernel/tests/test_sql.py,sha256=p7UEokoJs2xc-url7xQ4PmWKxtExrDDYnMeoyR1JD0A,1208
|
|
83
|
-
duckdb_kernel/util/ResultSetComparator.py,sha256=
|
|
85
|
+
duckdb_kernel/util/ResultSetComparator.py,sha256=5Pj1Vpi6laJJOK9HYiFwjrz0zj7Ogj8hYnTKIdN07wo,2831
|
|
84
86
|
duckdb_kernel/util/SQL.py,sha256=-uRfa0IwEQueZNZ7vkBPczLuvm_87y4_nnMBx3FgqNk,643
|
|
85
87
|
duckdb_kernel/util/TestError.py,sha256=iwlGHr9j6pFDa2cGxqGyvJ-exrFUtPJjVm_OhHi4n3g,97
|
|
86
88
|
duckdb_kernel/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -94,7 +96,7 @@ duckdb_kernel/visualization/lib/__init__.py,sha256=LYi0YPtn5fXOejbLIqbt_3KzP-Xrw
|
|
|
94
96
|
duckdb_kernel/visualization/lib/plotly-3.0.1.min.js,sha256=oy6Be7Eh6eiQFs5M7oXuPxxm9qbJXEtTpfSI93dW16Q,4653932
|
|
95
97
|
duckdb_kernel/visualization/lib/ra.css,sha256=foz1v69EQ117BDduB9QyHH978PbRs2TG1kBS4VGqZbI,57
|
|
96
98
|
duckdb_kernel/visualization/lib/ra.js,sha256=VzMRn55ztcd5Kfu2B6gdRPARpi8n-fvs8oNFnfp55Ec,1845
|
|
97
|
-
jupyter_duckdb-1.4.
|
|
98
|
-
jupyter_duckdb-1.4.
|
|
99
|
-
jupyter_duckdb-1.4.
|
|
100
|
-
jupyter_duckdb-1.4.
|
|
99
|
+
jupyter_duckdb-1.4.107.dist-info/METADATA,sha256=jx9R59sGi_iPrSVoOZj4WLrG6FPzReXq1UTybnh_Vyo,9272
|
|
100
|
+
jupyter_duckdb-1.4.107.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
101
|
+
jupyter_duckdb-1.4.107.dist-info/top_level.txt,sha256=KvRRPMnmkQNuhyBsXoPmwyt26LRDp0O-0HN6u0Dm5jA,14
|
|
102
|
+
jupyter_duckdb-1.4.107.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|