jupyter-duckdb 1.4.107__py3-none-any.whl → 1.4.109__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/parser/RAParser.py +2 -3
- duckdb_kernel/parser/elements/LogicElement.py +0 -2
- duckdb_kernel/parser/elements/RARelationReference.py +86 -0
- duckdb_kernel/parser/elements/RAUnaryOperator.py +6 -0
- duckdb_kernel/parser/elements/__init__.py +1 -0
- duckdb_kernel/parser/elements/unary/AttributeRename.py +39 -0
- duckdb_kernel/parser/elements/unary/Projection.py +1 -1
- duckdb_kernel/parser/elements/unary/Rename.py +68 -14
- duckdb_kernel/parser/elements/unary/__init__.py +2 -0
- duckdb_kernel/tests/test_ra.py +326 -40
- duckdb_kernel/util/ResultSetComparator.py +1 -1
- {jupyter_duckdb-1.4.107.dist-info → jupyter_duckdb-1.4.109.dist-info}/METADATA +1 -1
- {jupyter_duckdb-1.4.107.dist-info → jupyter_duckdb-1.4.109.dist-info}/RECORD +15 -13
- {jupyter_duckdb-1.4.107.dist-info → jupyter_duckdb-1.4.109.dist-info}/WHEEL +0 -0
- {jupyter_duckdb-1.4.107.dist-info → jupyter_duckdb-1.4.109.dist-info}/top_level.txt +0 -0
duckdb_kernel/parser/RAParser.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
from .LogicParser import LogicParser
|
|
2
1
|
from .ParserError import RAParserError
|
|
3
2
|
from .elements import *
|
|
4
3
|
from .tokenizer import *
|
|
@@ -55,7 +54,7 @@ class RAParser:
|
|
|
55
54
|
if target is None:
|
|
56
55
|
op = operator(
|
|
57
56
|
RAParser.parse_tokens(tokens[-1], depth=depth + 1),
|
|
58
|
-
|
|
57
|
+
operator.parse_args(*tokens[-i + 1:-1], depth=depth + 1)
|
|
59
58
|
)
|
|
60
59
|
|
|
61
60
|
# Otherwise the handed target is this operator's
|
|
@@ -63,7 +62,7 @@ class RAParser:
|
|
|
63
62
|
else:
|
|
64
63
|
op = operator(
|
|
65
64
|
target,
|
|
66
|
-
|
|
65
|
+
operator.parse_args(*tokens[-i + 1:], depth=depth + 1)
|
|
67
66
|
)
|
|
68
67
|
|
|
69
68
|
# If there are any more tokens the operator is
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
from . import RAUnaryOperator
|
|
4
|
+
from .LogicElement import LogicElement
|
|
5
|
+
from ..ParserError import RAParserError
|
|
6
|
+
from ..tokenizer import Token
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class RARelationReference(LogicElement):
|
|
10
|
+
@staticmethod
|
|
11
|
+
def parse_tokens(operator: type[RAUnaryOperator], *tokens: Token, depth: int = 0) -> 'RARelationReference':
|
|
12
|
+
try:
|
|
13
|
+
# If we get one single token, it should be like
|
|
14
|
+
# R -> "R"
|
|
15
|
+
# [ R ] -> "R"
|
|
16
|
+
# [ R(A, B, C) ] -> "R(A, B, C)"
|
|
17
|
+
# (A, B, C) -> "(A, B, C")
|
|
18
|
+
# [ (A, B, C) ] -> "(A, B, C)"
|
|
19
|
+
if len(tokens) == 1:
|
|
20
|
+
return RARelationReference._parse_one_token(*tokens)
|
|
21
|
+
|
|
22
|
+
# If we get two tokens, it should be like
|
|
23
|
+
# R(A, B, C) -> "R", "A, B, C"
|
|
24
|
+
# R A -> "R", "A"
|
|
25
|
+
# (The latter equals R(A), but we should think about rejecting this type.)
|
|
26
|
+
elif len(tokens) == 2:
|
|
27
|
+
return RARelationReference._parse_two_tokens(*tokens)
|
|
28
|
+
|
|
29
|
+
# Otherwise, the input is malformed.
|
|
30
|
+
else:
|
|
31
|
+
raise AssertionError()
|
|
32
|
+
|
|
33
|
+
except AssertionError:
|
|
34
|
+
raise RAParserError(f'malformed input for operator {operator.symbols()[0]} {tokens=}', depth=depth)
|
|
35
|
+
|
|
36
|
+
@staticmethod
|
|
37
|
+
def _parse_one_token(token: Token) -> 'RARelationReference':
|
|
38
|
+
match = re.fullmatch(r'^\s*([A-Za-z0-9]+)?\s*(\(?((\s*[A-Za-z0-9]+\s*,\s*)*(\s*[A-Za-z0-9]+\s*,?\s*))\)?)?\s*$', token)
|
|
39
|
+
if match is None:
|
|
40
|
+
raise AssertionError()
|
|
41
|
+
|
|
42
|
+
if match.group(1) is not None:
|
|
43
|
+
relation = match.group(1).strip()
|
|
44
|
+
else:
|
|
45
|
+
relation = None
|
|
46
|
+
|
|
47
|
+
if match.group(3) is not None:
|
|
48
|
+
attributes = [b for b in (a.strip() for a in match.group(3).split(',')) if b != '']
|
|
49
|
+
else:
|
|
50
|
+
attributes = None
|
|
51
|
+
|
|
52
|
+
if relation is None and attributes is None:
|
|
53
|
+
raise AssertionError()
|
|
54
|
+
|
|
55
|
+
return RARelationReference(relation, attributes)
|
|
56
|
+
|
|
57
|
+
@staticmethod
|
|
58
|
+
def _parse_two_tokens(token1: Token, token2: Token) -> 'RARelationReference':
|
|
59
|
+
# We expect the first token to be a relation name and the second one
|
|
60
|
+
# to be a list of column names separated by commas.
|
|
61
|
+
relation = token1.strip()
|
|
62
|
+
attributes = [b for b in (a.strip() for a in token2.split(',')) if b != '']
|
|
63
|
+
|
|
64
|
+
return RARelationReference(relation, attributes)
|
|
65
|
+
|
|
66
|
+
def __init__(self, relation: str | None, attributes: list[str] | None):
|
|
67
|
+
# check duplicated attributes
|
|
68
|
+
if attributes is not None:
|
|
69
|
+
for i in range(len(attributes)):
|
|
70
|
+
for k in range(i + 1, len(attributes)):
|
|
71
|
+
if attributes[i] == attributes[k]:
|
|
72
|
+
raise RAParserError(f'duplicate attribute {attributes[i]}', 0)
|
|
73
|
+
if attributes[i].lower() == attributes[k].lower():
|
|
74
|
+
raise RAParserError(f'duplicate attribute {attributes[i]}={attributes[k]}', 0)
|
|
75
|
+
|
|
76
|
+
# store
|
|
77
|
+
self.relation: str | None = relation
|
|
78
|
+
self.attributes: list[str] | None = attributes
|
|
79
|
+
|
|
80
|
+
def __str__(self) -> str:
|
|
81
|
+
if self.relation is not None and self.attributes is None:
|
|
82
|
+
return self.relation
|
|
83
|
+
elif self.relation is None and self.attributes is not None:
|
|
84
|
+
return f'({", ".join(self.attributes)})'
|
|
85
|
+
else:
|
|
86
|
+
return f'{self.relation}({", ".join(self.attributes)})'
|
|
@@ -3,9 +3,15 @@ from typing import Iterator
|
|
|
3
3
|
from .LogicElement import LogicElement
|
|
4
4
|
from .RAElement import RAElement
|
|
5
5
|
from .RAOperator import RAOperator
|
|
6
|
+
from ..tokenizer import Token
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
class RAUnaryOperator(RAOperator):
|
|
10
|
+
@classmethod
|
|
11
|
+
def parse_args(cls: type['RAUnaryOperator'], *tokens: Token, depth: int):
|
|
12
|
+
from .. import LogicParser
|
|
13
|
+
return LogicParser.parse_tokens(*tokens, depth=depth)
|
|
14
|
+
|
|
9
15
|
def __init__(self, target: RAElement):
|
|
10
16
|
self.target: RAElement = target
|
|
11
17
|
|
|
@@ -11,6 +11,7 @@ from .RAUnaryOperator import RAUnaryOperator
|
|
|
11
11
|
from .RAOperand import RAOperand
|
|
12
12
|
from .binary import RA_BINARY_OPERATORS, RA_BINARY_SYMBOLS
|
|
13
13
|
from .unary import RA_UNARY_OPERATORS
|
|
14
|
+
from .RARelationReference import RARelationReference
|
|
14
15
|
|
|
15
16
|
from .DCOperand import DCOperand
|
|
16
17
|
from .binary import DC_SET
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from typing import Dict, Tuple
|
|
2
|
+
|
|
3
|
+
from ..LogicElement import LogicElement
|
|
4
|
+
from ..RAElement import RAElement
|
|
5
|
+
from ..RAUnaryOperator import RAUnaryOperator
|
|
6
|
+
from ..binary import ArrowLeft
|
|
7
|
+
from ...util.RenamableColumnList import RenamableColumnList
|
|
8
|
+
from ....db import Table
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AttributeRename(RAUnaryOperator):
|
|
12
|
+
@staticmethod
|
|
13
|
+
def symbols() -> Tuple[str, ...]:
|
|
14
|
+
return 'β', 'beta'
|
|
15
|
+
|
|
16
|
+
def __init__(self, target: RAElement, arg: LogicElement):
|
|
17
|
+
if not isinstance(arg, ArrowLeft):
|
|
18
|
+
raise AssertionError('only arrow statements allowed as parameter')
|
|
19
|
+
|
|
20
|
+
super().__init__(target)
|
|
21
|
+
self.arrow: ArrowLeft = arg
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def arg(self) -> LogicElement:
|
|
25
|
+
return self.arrow
|
|
26
|
+
|
|
27
|
+
def to_sql(self, tables: Dict[str, Table]) -> Tuple[str, RenamableColumnList]:
|
|
28
|
+
# execute subquery
|
|
29
|
+
subquery, subcols = self.target.to_sql(tables)
|
|
30
|
+
|
|
31
|
+
# find and rename column
|
|
32
|
+
subcols.rename(str(self.arrow.right), str(self.arrow.left))
|
|
33
|
+
|
|
34
|
+
# return sql statement
|
|
35
|
+
return subquery, subcols
|
|
36
|
+
|
|
37
|
+
# We replace the "real" attribute name later anyway,
|
|
38
|
+
# so we do not need to change the sql statement here.
|
|
39
|
+
# return f'SELECT DISTINCT {subcols.list} FROM ({subquery}) {self._name()}', subcols
|
|
@@ -13,7 +13,7 @@ class Projection(RAUnaryOperator):
|
|
|
13
13
|
def symbols() -> Tuple[str, ...]:
|
|
14
14
|
return 'Π', 'π', 'pi'
|
|
15
15
|
|
|
16
|
-
def __init__(self, target: RAElement, arg:
|
|
16
|
+
def __init__(self, target: RAElement, arg: LogicElement):
|
|
17
17
|
if not isinstance(arg, LogicOperand):
|
|
18
18
|
raise AssertionError('only argument lists allowed as parameter')
|
|
19
19
|
|
|
@@ -1,39 +1,93 @@
|
|
|
1
1
|
from typing import Tuple, Dict
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from .. import RARelationReference
|
|
4
4
|
from ..LogicElement import LogicElement
|
|
5
5
|
from ..RAElement import RAElement
|
|
6
6
|
from ..RAUnaryOperator import RAUnaryOperator
|
|
7
|
-
from
|
|
7
|
+
from ...ParserError import RAParserError
|
|
8
|
+
from ...tokenizer import Token
|
|
8
9
|
from ...util.RenamableColumnList import RenamableColumnList
|
|
10
|
+
from ....db import Table
|
|
9
11
|
|
|
10
12
|
|
|
11
13
|
class Rename(RAUnaryOperator):
|
|
12
14
|
@staticmethod
|
|
13
15
|
def symbols() -> Tuple[str, ...]:
|
|
14
|
-
return '
|
|
16
|
+
return 'ρ', 'ϱ', 'rho'
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
@classmethod
|
|
19
|
+
def parse_args(cls: type[RAUnaryOperator], *tokens: Token, depth: int):
|
|
20
|
+
from .. import RARelationReference
|
|
21
|
+
return RARelationReference.parse_tokens(cls, *tokens, depth=depth)
|
|
19
22
|
|
|
23
|
+
def __init__(self, target: RAElement, arg: RARelationReference):
|
|
20
24
|
super().__init__(target)
|
|
21
|
-
self.
|
|
25
|
+
self.reference: RARelationReference = arg
|
|
22
26
|
|
|
23
27
|
@property
|
|
24
28
|
def arg(self) -> LogicElement:
|
|
25
|
-
return self.
|
|
29
|
+
return self.reference
|
|
26
30
|
|
|
27
31
|
def to_sql(self, tables: Dict[str, Table]) -> Tuple[str, RenamableColumnList]:
|
|
28
32
|
# execute subquery
|
|
29
33
|
subquery, subcols = self.target.to_sql(tables)
|
|
30
34
|
|
|
31
|
-
#
|
|
32
|
-
|
|
35
|
+
# rename attributes
|
|
36
|
+
if self.reference.relation is None and self.reference.attributes is not None:
|
|
37
|
+
return self._to_sql_with_renamed_attributes(tables, subquery, subcols)
|
|
33
38
|
|
|
34
|
-
#
|
|
39
|
+
# rename relation
|
|
40
|
+
elif self.reference.relation is not None and self.reference.attributes is None:
|
|
41
|
+
return self._to_sql_with_renamed_relation(tables, subquery, subcols)
|
|
42
|
+
|
|
43
|
+
# rename relation and attributes
|
|
44
|
+
else:
|
|
45
|
+
return self._to_sql_with_renamed_relation_and_attributes(tables, subquery, subcols)
|
|
46
|
+
|
|
47
|
+
def _to_sql_with_renamed_relation(self,
|
|
48
|
+
tables: Dict[str, Table],
|
|
49
|
+
subquery: str,
|
|
50
|
+
subcols: RenamableColumnList) -> Tuple[str, RenamableColumnList]:
|
|
51
|
+
# check if there are two columns with the same name
|
|
52
|
+
for i in range(len(subcols)):
|
|
53
|
+
for k in range(i + 1, len(subcols)):
|
|
54
|
+
if subcols[i].name == subcols[k].name:
|
|
55
|
+
raise RAParserError(
|
|
56
|
+
f'attribute {subcols[i].name} is present in both {subcols[i].table.name} and {subcols[k].table.name}',
|
|
57
|
+
depth=0
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
# add new table
|
|
61
|
+
table = Table(self.reference.relation)
|
|
62
|
+
# tables[self.reference.relation] = table
|
|
63
|
+
|
|
64
|
+
# set table for all attributes
|
|
65
|
+
for col in subcols:
|
|
66
|
+
col.table = table
|
|
67
|
+
|
|
68
|
+
# return
|
|
35
69
|
return subquery, subcols
|
|
36
70
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
71
|
+
def _to_sql_with_renamed_attributes(self,
|
|
72
|
+
tables: Dict[str, Table],
|
|
73
|
+
subquery: str,
|
|
74
|
+
subcols: RenamableColumnList) -> Tuple[str, RenamableColumnList]:
|
|
75
|
+
# check if there are more names than subcols
|
|
76
|
+
if len(self.reference.attributes) > len(subcols):
|
|
77
|
+
raise RAParserError('more names than attributes', 0)
|
|
78
|
+
|
|
79
|
+
# rename columns
|
|
80
|
+
for col, new_name in zip(subcols, self.reference.attributes):
|
|
81
|
+
col.name = new_name
|
|
82
|
+
|
|
83
|
+
# return
|
|
84
|
+
return subquery, subcols
|
|
85
|
+
|
|
86
|
+
def _to_sql_with_renamed_relation_and_attributes(self,
|
|
87
|
+
tables: Dict[str, Table],
|
|
88
|
+
subquery: str,
|
|
89
|
+
subcols: RenamableColumnList) -> Tuple[str, RenamableColumnList]:
|
|
90
|
+
subquery, subcols = self._to_sql_with_renamed_attributes(tables, subquery, subcols)
|
|
91
|
+
subquery, subcols = self._to_sql_with_renamed_relation(tables, subquery, subcols)
|
|
92
|
+
|
|
93
|
+
return subquery, subcols
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from .AttributeRename import AttributeRename
|
|
1
2
|
from .Not import Not
|
|
2
3
|
from .Projection import Projection
|
|
3
4
|
from .Rename import Rename
|
|
@@ -10,6 +11,7 @@ LOGIC_UNARY_OPERATORS = [
|
|
|
10
11
|
]
|
|
11
12
|
|
|
12
13
|
RA_UNARY_OPERATORS = [
|
|
14
|
+
AttributeRename,
|
|
13
15
|
Projection,
|
|
14
16
|
Rename,
|
|
15
17
|
Selection
|
duckdb_kernel/tests/test_ra.py
CHANGED
|
@@ -3,7 +3,7 @@ import pytest
|
|
|
3
3
|
import duckdb_kernel.parser.elements.binary as BinaryOperators
|
|
4
4
|
import duckdb_kernel.parser.elements.unary as UnaryOperators
|
|
5
5
|
from duckdb_kernel.parser import RAParser, RAParserError
|
|
6
|
-
from duckdb_kernel.parser.elements import RAOperand, LogicElement
|
|
6
|
+
from duckdb_kernel.parser.elements import RAOperand, LogicElement, RARelationReference
|
|
7
7
|
from . import Connection
|
|
8
8
|
|
|
9
9
|
|
|
@@ -102,8 +102,8 @@ def test_comments():
|
|
|
102
102
|
assert isinstance(root.right, RAOperand) and root.right.name == 'Seasons'
|
|
103
103
|
|
|
104
104
|
for query in (
|
|
105
|
-
|
|
106
|
-
|
|
105
|
+
'-- comment',
|
|
106
|
+
'/* comment */'
|
|
107
107
|
):
|
|
108
108
|
root = RAParser.parse_query(query)
|
|
109
109
|
assert root is None
|
|
@@ -500,7 +500,7 @@ def test_unary_operator_projection():
|
|
|
500
500
|
]
|
|
501
501
|
|
|
502
502
|
|
|
503
|
-
def
|
|
503
|
+
def test_unary_operator_attributerename():
|
|
504
504
|
with Connection() as con:
|
|
505
505
|
for query in (
|
|
506
506
|
r'β Id2 ← Id Users',
|
|
@@ -518,7 +518,7 @@ def test_unary_operator_rename():
|
|
|
518
518
|
):
|
|
519
519
|
root = RAParser.parse_query(query)
|
|
520
520
|
|
|
521
|
-
assert isinstance(root, UnaryOperators.
|
|
521
|
+
assert isinstance(root, UnaryOperators.AttributeRename)
|
|
522
522
|
assert isinstance(root.arg, LogicElement)
|
|
523
523
|
assert isinstance(root.target, RAOperand) and root.target.name == 'Users'
|
|
524
524
|
|
|
@@ -547,9 +547,9 @@ def test_unary_operator_rename():
|
|
|
547
547
|
):
|
|
548
548
|
root = RAParser.parse_query(query)
|
|
549
549
|
|
|
550
|
-
assert isinstance(root, UnaryOperators.
|
|
550
|
+
assert isinstance(root, UnaryOperators.AttributeRename)
|
|
551
551
|
assert isinstance(root.arg, LogicElement)
|
|
552
|
-
assert isinstance(root.target, UnaryOperators.
|
|
552
|
+
assert isinstance(root.target, UnaryOperators.AttributeRename)
|
|
553
553
|
assert isinstance(root.target.arg, LogicElement)
|
|
554
554
|
assert isinstance(root.target.target, RAOperand) and root.target.target.name == 'Users'
|
|
555
555
|
|
|
@@ -566,6 +566,162 @@ def test_unary_operator_rename():
|
|
|
566
566
|
]
|
|
567
567
|
|
|
568
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
|
+
|
|
569
725
|
def test_unary_operator_selection():
|
|
570
726
|
with Connection() as con:
|
|
571
727
|
for query in (
|
|
@@ -637,13 +793,21 @@ def test_unary_inner_to_outer_evaluation_order():
|
|
|
637
793
|
assert root.target.condition.left == ('Id',) and root.target.condition.right == ('1',)
|
|
638
794
|
|
|
639
795
|
root = RAParser.parse_query(r'β [ Id3 ← Id2 ] β [ Id2 ← Id ] (Users)')
|
|
640
|
-
assert isinstance(root, UnaryOperators.
|
|
796
|
+
assert isinstance(root, UnaryOperators.AttributeRename)
|
|
641
797
|
assert isinstance(root.arrow, BinaryOperators.ArrowLeft)
|
|
642
798
|
assert root.arrow.left == ('Id3',) and root.arrow.right == ('Id2',)
|
|
643
|
-
assert isinstance(root.target, UnaryOperators.
|
|
799
|
+
assert isinstance(root.target, UnaryOperators.AttributeRename)
|
|
644
800
|
assert isinstance(root.target.arrow, BinaryOperators.ArrowLeft)
|
|
645
801
|
assert root.target.arrow.left == ('Id2',) and root.target.arrow.right == ('Id',)
|
|
646
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
|
+
|
|
647
811
|
|
|
648
812
|
def test_binary_left_to_right_evaluation_order():
|
|
649
813
|
# difference
|
|
@@ -956,30 +1120,58 @@ def test_binary_left_to_right_evaluation_order():
|
|
|
956
1120
|
|
|
957
1121
|
|
|
958
1122
|
def test_unary_evaluation_order():
|
|
959
|
-
|
|
1123
|
+
# π
|
|
1124
|
+
root = RAParser.parse_query(r'π [ Id ] σ [ Id > 1 ] (Users)')
|
|
960
1125
|
assert isinstance(root, UnaryOperators.Projection)
|
|
961
|
-
assert isinstance(root.target, UnaryOperators.
|
|
1126
|
+
assert isinstance(root.target, UnaryOperators.Selection)
|
|
962
1127
|
|
|
963
|
-
root = RAParser.parse_query(r'
|
|
964
|
-
assert isinstance(root, UnaryOperators.
|
|
965
|
-
assert isinstance(root.target, UnaryOperators.
|
|
1128
|
+
root = RAParser.parse_query(r'π [ Id2 ] β [ Id2 ← Id ] (Users)')
|
|
1129
|
+
assert isinstance(root, UnaryOperators.Projection)
|
|
1130
|
+
assert isinstance(root.target, UnaryOperators.AttributeRename)
|
|
966
1131
|
|
|
967
|
-
root = RAParser.parse_query(r'π [
|
|
1132
|
+
root = RAParser.parse_query(r'π [ Id2 ] ρ [ R(Id2, Username2) ] (Users)')
|
|
968
1133
|
assert isinstance(root, UnaryOperators.Projection)
|
|
969
|
-
assert isinstance(root.target, UnaryOperators.
|
|
1134
|
+
assert isinstance(root.target, UnaryOperators.Rename)
|
|
970
1135
|
|
|
1136
|
+
# σ
|
|
971
1137
|
root = RAParser.parse_query(r'σ [ Id > 1 ] π [ Id ] (Users)')
|
|
972
1138
|
assert isinstance(root, UnaryOperators.Selection)
|
|
973
1139
|
assert isinstance(root.target, UnaryOperators.Projection)
|
|
974
1140
|
|
|
975
1141
|
root = RAParser.parse_query(r'σ [ Id2 > 1 ] β [ Id2 ← Id ] (Users)')
|
|
976
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)
|
|
977
1147
|
assert isinstance(root.target, UnaryOperators.Rename)
|
|
978
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
|
+
|
|
979
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)')
|
|
980
1168
|
assert isinstance(root, UnaryOperators.Rename)
|
|
981
1169
|
assert isinstance(root.target, UnaryOperators.Selection)
|
|
982
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
|
+
|
|
983
1175
|
|
|
984
1176
|
def test_binary_evaluation_order():
|
|
985
1177
|
# difference <-> union
|
|
@@ -1369,13 +1561,22 @@ def test_mixed_evaluation_order():
|
|
|
1369
1561
|
assert isinstance(root, BinaryOperators.Difference)
|
|
1370
1562
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Projection)
|
|
1371
1563
|
|
|
1372
|
-
# difference <-> rename
|
|
1564
|
+
# difference <-> attribute rename
|
|
1373
1565
|
root = RAParser.parse_query(r'a \ β [ Id2 ← Id ] b')
|
|
1374
1566
|
assert isinstance(root, BinaryOperators.Difference)
|
|
1375
|
-
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.
|
|
1567
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
|
|
1376
1568
|
|
|
1377
1569
|
root = RAParser.parse_query(r'β [ Id2 ← Id ] a \ b')
|
|
1378
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)
|
|
1379
1580
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
|
|
1380
1581
|
|
|
1381
1582
|
# difference <-> selection
|
|
@@ -1396,13 +1597,22 @@ def test_mixed_evaluation_order():
|
|
|
1396
1597
|
assert isinstance(root, BinaryOperators.Union)
|
|
1397
1598
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Projection)
|
|
1398
1599
|
|
|
1399
|
-
# union <-> rename
|
|
1600
|
+
# union <-> attribute rename
|
|
1400
1601
|
root = RAParser.parse_query(r'a ∪ β [ Id2 ← Id ] b')
|
|
1401
1602
|
assert isinstance(root, BinaryOperators.Union)
|
|
1402
|
-
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.
|
|
1603
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
|
|
1403
1604
|
|
|
1404
1605
|
root = RAParser.parse_query(r'β [ Id2 ← Id ] a ∪ b')
|
|
1405
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)
|
|
1406
1616
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
|
|
1407
1617
|
|
|
1408
1618
|
# union <-> selection
|
|
@@ -1423,13 +1633,22 @@ def test_mixed_evaluation_order():
|
|
|
1423
1633
|
assert isinstance(root, BinaryOperators.Intersection)
|
|
1424
1634
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Projection)
|
|
1425
1635
|
|
|
1426
|
-
# intersection <-> rename
|
|
1636
|
+
# intersection <-> attribute rename
|
|
1427
1637
|
root = RAParser.parse_query(r'a ∩ β [ Id2 ← Id ] b')
|
|
1428
1638
|
assert isinstance(root, BinaryOperators.Intersection)
|
|
1429
|
-
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.
|
|
1639
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
|
|
1430
1640
|
|
|
1431
1641
|
root = RAParser.parse_query(r'β [ Id2 ← Id ] a ∩ b')
|
|
1432
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)
|
|
1433
1652
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
|
|
1434
1653
|
|
|
1435
1654
|
# intersection <-> selection
|
|
@@ -1490,53 +1709,102 @@ def test_mixed_evaluation_order():
|
|
|
1490
1709
|
assert isinstance(root, BinaryOperators.RightSemiJoin)
|
|
1491
1710
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Projection)
|
|
1492
1711
|
|
|
1493
|
-
# join <-> rename
|
|
1712
|
+
# join <-> attribute rename
|
|
1494
1713
|
root = RAParser.parse_query(r'a ⋈ β [ Id2 ← Id ] b')
|
|
1495
1714
|
assert isinstance(root, BinaryOperators.Join)
|
|
1496
|
-
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.
|
|
1715
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
|
|
1497
1716
|
|
|
1498
1717
|
root = RAParser.parse_query(r'β [ Id2 ← Id ] a ⋈ b')
|
|
1499
1718
|
assert isinstance(root, BinaryOperators.Join)
|
|
1500
|
-
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.
|
|
1719
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.AttributeRename)
|
|
1501
1720
|
|
|
1502
1721
|
root = RAParser.parse_query(r'a ⟕ β [ Id2 ← Id ] b')
|
|
1503
1722
|
assert isinstance(root, BinaryOperators.LeftOuterJoin)
|
|
1504
|
-
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.
|
|
1723
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
|
|
1505
1724
|
|
|
1506
1725
|
root = RAParser.parse_query(r'β [ Id2 ← Id ] a ⟕ b')
|
|
1507
1726
|
assert isinstance(root, BinaryOperators.LeftOuterJoin)
|
|
1508
|
-
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.
|
|
1727
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.AttributeRename)
|
|
1509
1728
|
|
|
1510
1729
|
root = RAParser.parse_query(r'a ⟖ β [ Id2 ← Id ] b')
|
|
1511
1730
|
assert isinstance(root, BinaryOperators.RightOuterJoin)
|
|
1512
|
-
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.
|
|
1731
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
|
|
1513
1732
|
|
|
1514
1733
|
root = RAParser.parse_query(r'β [ Id2 ← Id ] a ⟖ b')
|
|
1515
1734
|
assert isinstance(root, BinaryOperators.RightOuterJoin)
|
|
1516
|
-
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.
|
|
1735
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.AttributeRename)
|
|
1517
1736
|
|
|
1518
1737
|
root = RAParser.parse_query(r'a ⟗ β [ Id2 ← Id ] b')
|
|
1519
1738
|
assert isinstance(root, BinaryOperators.FullOuterJoin)
|
|
1520
|
-
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.
|
|
1739
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
|
|
1521
1740
|
|
|
1522
1741
|
root = RAParser.parse_query(r'β [ Id2 ← Id ] a ⟗ b')
|
|
1523
1742
|
assert isinstance(root, BinaryOperators.FullOuterJoin)
|
|
1524
|
-
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.
|
|
1743
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.AttributeRename)
|
|
1525
1744
|
|
|
1526
1745
|
root = RAParser.parse_query(r'a ⋉ β [ Id2 ← Id ] b')
|
|
1527
1746
|
assert isinstance(root, BinaryOperators.LeftSemiJoin)
|
|
1528
|
-
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.
|
|
1747
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
|
|
1529
1748
|
|
|
1530
1749
|
root = RAParser.parse_query(r'β [ Id2 ← Id ] a ⋉ b')
|
|
1531
1750
|
assert isinstance(root, BinaryOperators.LeftSemiJoin)
|
|
1532
|
-
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.
|
|
1751
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.AttributeRename)
|
|
1533
1752
|
|
|
1534
1753
|
root = RAParser.parse_query(r'a ⋊ β [ Id2 ← Id ] b')
|
|
1535
1754
|
assert isinstance(root, BinaryOperators.RightSemiJoin)
|
|
1536
|
-
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.
|
|
1755
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
|
|
1537
1756
|
|
|
1538
1757
|
root = RAParser.parse_query(r'β [ Id2 ← Id ] a ⋊ b')
|
|
1539
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)
|
|
1540
1808
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
|
|
1541
1809
|
|
|
1542
1810
|
# join <-> selection
|
|
@@ -1597,13 +1865,22 @@ def test_mixed_evaluation_order():
|
|
|
1597
1865
|
assert isinstance(root, BinaryOperators.Cross)
|
|
1598
1866
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Projection)
|
|
1599
1867
|
|
|
1600
|
-
# cross <-> rename
|
|
1868
|
+
# cross <-> attribute rename
|
|
1601
1869
|
root = RAParser.parse_query(r'a x β [ Id2 ← Id ] b')
|
|
1602
1870
|
assert isinstance(root, BinaryOperators.Cross)
|
|
1603
|
-
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.
|
|
1871
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
|
|
1604
1872
|
|
|
1605
1873
|
root = RAParser.parse_query(r'β [ Id2 ← Id ] a x b')
|
|
1606
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)
|
|
1607
1884
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
|
|
1608
1885
|
|
|
1609
1886
|
# cross <-> selection
|
|
@@ -1624,13 +1901,22 @@ def test_mixed_evaluation_order():
|
|
|
1624
1901
|
assert isinstance(root, BinaryOperators.Division)
|
|
1625
1902
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Projection)
|
|
1626
1903
|
|
|
1627
|
-
# division <-> rename
|
|
1904
|
+
# division <-> attribute rename
|
|
1628
1905
|
root = RAParser.parse_query(r'a ÷ β [ Id2 ← Id ] b')
|
|
1629
1906
|
assert isinstance(root, BinaryOperators.Division)
|
|
1630
|
-
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.
|
|
1907
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
|
|
1631
1908
|
|
|
1632
1909
|
root = RAParser.parse_query(r'β [ Id2 ← Id ] a ÷ b')
|
|
1633
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)
|
|
1634
1920
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
|
|
1635
1921
|
|
|
1636
1922
|
# division <-> selection
|
|
@@ -1668,8 +1954,8 @@ def test_special_queries():
|
|
|
1668
1954
|
assert isinstance(root.left, UnaryOperators.Selection)
|
|
1669
1955
|
assert isinstance(root.left.target, UnaryOperators.Projection)
|
|
1670
1956
|
assert isinstance(root.left.target.target, RAOperand) and root.left.target.target.name == 'Users'
|
|
1671
|
-
assert isinstance(root.right, UnaryOperators.
|
|
1672
|
-
assert isinstance(root.right.target, UnaryOperators.
|
|
1957
|
+
assert isinstance(root.right, UnaryOperators.AttributeRename)
|
|
1958
|
+
assert isinstance(root.right.target, UnaryOperators.AttributeRename)
|
|
1673
1959
|
assert isinstance(root.right.target.target, RAOperand) and root.right.target.target.name == 'BannedUsers'
|
|
1674
1960
|
|
|
1675
1961
|
assert con.execute_ra(root) == [
|
|
@@ -82,7 +82,7 @@ class ResultSetComparator:
|
|
|
82
82
|
|
|
83
83
|
for le, re in zip(left, right):
|
|
84
84
|
if isinstance(le, float) or isinstance(re, float):
|
|
85
|
-
if abs(le - re) > 1e-
|
|
85
|
+
if abs(le - re) > 1e-4:
|
|
86
86
|
return False
|
|
87
87
|
elif isinstance(le, date) or isinstance(re, date):
|
|
88
88
|
if str(le) != str(re):
|
|
@@ -27,18 +27,19 @@ duckdb_kernel/magics/__init__.py,sha256=ggxzDzDEsKMZzYsWw9JqYVJhciJPvPVYGV7oNo9Y
|
|
|
27
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=pNTnIRH9TzoawGPlM16JCv0KgYu0KZN2K3XC72-pL-4,3324
|
|
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
|
-
duckdb_kernel/parser/elements/LogicElement.py,sha256=
|
|
33
|
+
duckdb_kernel/parser/elements/LogicElement.py,sha256=uH-0Ax6Etp97b3VLnc24RB3rMLCbbPUrCKi2JBBVCLs,251
|
|
34
34
|
duckdb_kernel/parser/elements/LogicOperand.py,sha256=B9NvriloQE5eP734dNMZBZwrdaaIfsuAmZlG1t2eMhs,1021
|
|
35
35
|
duckdb_kernel/parser/elements/LogicOperator.py,sha256=lkM4TAGkXUhsO4w4PLKVA0bgCRGPQQFpNA1FcWWOW9Q,1028
|
|
36
36
|
duckdb_kernel/parser/elements/RABinaryOperator.py,sha256=XN41stGc1e-a4dZ1AQVtQ3lEgjUGNt3dMfYXp85LEeE,538
|
|
37
37
|
duckdb_kernel/parser/elements/RAElement.py,sha256=3qf-ZLQU5WAH_3TvEnfXUg8Y9lE2Fg01D82XutIfgjg,1661
|
|
38
38
|
duckdb_kernel/parser/elements/RAOperand.py,sha256=pghnTYCrrT6MkvynJRgVFPRoMvxIGNB3FTjaq-uCpDQ,1078
|
|
39
39
|
duckdb_kernel/parser/elements/RAOperator.py,sha256=rtqMFBIBBqT-Bwg7Qm4WQwbDrE28Nb74F_7XMeR3ks4,255
|
|
40
|
-
duckdb_kernel/parser/elements/
|
|
41
|
-
duckdb_kernel/parser/elements/
|
|
40
|
+
duckdb_kernel/parser/elements/RARelationReference.py,sha256=d3GLFnfNbQ22BzrI61jxUGXCP3RwheeZGDGCpA0CEkc,3404
|
|
41
|
+
duckdb_kernel/parser/elements/RAUnaryOperator.py,sha256=TyMh5Vh6cdeL8muNRBTgnU6I1JJe97OCv5MH09cCJk0,877
|
|
42
|
+
duckdb_kernel/parser/elements/__init__.py,sha256=yZj38th1ogacHU80ExPsjDeAf6dqZsw3jrkuKA7b3kg,619
|
|
42
43
|
duckdb_kernel/parser/elements/binary/Add.py,sha256=XGkZMfab01huk9EaI6JUfzkd2STbV1C_-TyC2guKE8I,190
|
|
43
44
|
duckdb_kernel/parser/elements/binary/And.py,sha256=p6TQE49DtHlMlTkH9GqyrQVcYWsVgdIMTTCxNuNORuQ,267
|
|
44
45
|
duckdb_kernel/parser/elements/binary/ArrowLeft.py,sha256=u4fZSoyT9lfvWXBwuhUl4DdjVZAOqyVIKmMVbpElLD4,203
|
|
@@ -65,11 +66,12 @@ duckdb_kernel/parser/elements/binary/RightSemiJoin.py,sha256=B7adyKnIRiwrqZ4wQkz
|
|
|
65
66
|
duckdb_kernel/parser/elements/binary/Unequal.py,sha256=1hnC1RcPMxwKKv65OL5prunGgh9cRVDmzJutmtl7gtY,269
|
|
66
67
|
duckdb_kernel/parser/elements/binary/Union.py,sha256=VYTj4M2PVEhWiDwjnyP8qpVVbGvIBSVshlEt-SZYCBY,739
|
|
67
68
|
duckdb_kernel/parser/elements/binary/__init__.py,sha256=-4ZY6vpsiyT8eDkLwyFGHJFWXIMCNYNz9ejFFcjEG5U,1451
|
|
69
|
+
duckdb_kernel/parser/elements/unary/AttributeRename.py,sha256=iMRjU2idjr22-CIR5FIupCKPtxc4WjsrzSbeTxLEQmY,1275
|
|
68
70
|
duckdb_kernel/parser/elements/unary/Not.py,sha256=kG0a-dp3TNjPodUMPiQ6ihtsBrbvn1iWeIPCvtyAwdo,632
|
|
69
|
-
duckdb_kernel/parser/elements/unary/Projection.py,sha256=
|
|
70
|
-
duckdb_kernel/parser/elements/unary/Rename.py,sha256=
|
|
71
|
+
duckdb_kernel/parser/elements/unary/Projection.py,sha256=CcSSLWdDHk1U5JSLhY_NFTdus0BoVNDojVVdIE4SYVo,1112
|
|
72
|
+
duckdb_kernel/parser/elements/unary/Rename.py,sha256=opHSTvQ8jh2yZKmTfSiS8a7vchDuvBXbv1jC77E1Mx4,3755
|
|
71
73
|
duckdb_kernel/parser/elements/unary/Selection.py,sha256=TKykDMw0QGQcMFp0r7g6ye4CkjshBTNq14c7qtMkqs4,955
|
|
72
|
-
duckdb_kernel/parser/elements/unary/__init__.py,sha256=
|
|
74
|
+
duckdb_kernel/parser/elements/unary/__init__.py,sha256=70Gjzfk--ua1B3YG__y-2h2hpVookLYzvrj07GA0UaA,336
|
|
73
75
|
duckdb_kernel/parser/tokenizer/Token.py,sha256=gsCzgU_zLiA-yD0FWvd2qS9LQUXbivESYH-34Glffqs,2404
|
|
74
76
|
duckdb_kernel/parser/tokenizer/Tokenizer.py,sha256=PWGgS7gYgpULiKGDho842UbaXuqmwEkccixuF10oi5g,5081
|
|
75
77
|
duckdb_kernel/parser/tokenizer/__init__.py,sha256=EOSmfc2RJwtB5cE1Hhj1JAra97tckxxS8-legybPy60,58
|
|
@@ -79,10 +81,10 @@ duckdb_kernel/parser/util/RenamableColumnList.py,sha256=5oEDbtvl4YfHbkxu_Ny2pc0E
|
|
|
79
81
|
duckdb_kernel/parser/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
80
82
|
duckdb_kernel/tests/__init__.py,sha256=-BoPfo1FNQKnvAYt22Ioc21dbuO67QVFaV_SmS1zQw8,2731
|
|
81
83
|
duckdb_kernel/tests/test_dc.py,sha256=E-PppvBU6AuLFpg0M3chFscm-2Kuv2rkz85PL2NCESc,15968
|
|
82
|
-
duckdb_kernel/tests/test_ra.py,sha256
|
|
84
|
+
duckdb_kernel/tests/test_ra.py,sha256=-1SHhD99tZpO_YidW70LNHUHCEwv9-vBQs3-vg7DbRY,83066
|
|
83
85
|
duckdb_kernel/tests/test_result_comparison.py,sha256=TQVLPKKNyV2k3i4jCfasetPfVfCzgYZr92wxQmlzPnA,3859
|
|
84
86
|
duckdb_kernel/tests/test_sql.py,sha256=p7UEokoJs2xc-url7xQ4PmWKxtExrDDYnMeoyR1JD0A,1208
|
|
85
|
-
duckdb_kernel/util/ResultSetComparator.py,sha256=
|
|
87
|
+
duckdb_kernel/util/ResultSetComparator.py,sha256=yNca2DBJu6EaPo11cQSWFrXELdadeFlPw9Q80JgVLYU,2831
|
|
86
88
|
duckdb_kernel/util/SQL.py,sha256=-uRfa0IwEQueZNZ7vkBPczLuvm_87y4_nnMBx3FgqNk,643
|
|
87
89
|
duckdb_kernel/util/TestError.py,sha256=iwlGHr9j6pFDa2cGxqGyvJ-exrFUtPJjVm_OhHi4n3g,97
|
|
88
90
|
duckdb_kernel/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -96,7 +98,7 @@ duckdb_kernel/visualization/lib/__init__.py,sha256=LYi0YPtn5fXOejbLIqbt_3KzP-Xrw
|
|
|
96
98
|
duckdb_kernel/visualization/lib/plotly-3.0.1.min.js,sha256=oy6Be7Eh6eiQFs5M7oXuPxxm9qbJXEtTpfSI93dW16Q,4653932
|
|
97
99
|
duckdb_kernel/visualization/lib/ra.css,sha256=foz1v69EQ117BDduB9QyHH978PbRs2TG1kBS4VGqZbI,57
|
|
98
100
|
duckdb_kernel/visualization/lib/ra.js,sha256=VzMRn55ztcd5Kfu2B6gdRPARpi8n-fvs8oNFnfp55Ec,1845
|
|
99
|
-
jupyter_duckdb-1.4.
|
|
100
|
-
jupyter_duckdb-1.4.
|
|
101
|
-
jupyter_duckdb-1.4.
|
|
102
|
-
jupyter_duckdb-1.4.
|
|
101
|
+
jupyter_duckdb-1.4.109.dist-info/METADATA,sha256=HXebOLrYx4Ry7zsv5295hO1BhWyvM16WedLRff_xjBM,9272
|
|
102
|
+
jupyter_duckdb-1.4.109.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
103
|
+
jupyter_duckdb-1.4.109.dist-info/top_level.txt,sha256=KvRRPMnmkQNuhyBsXoPmwyt26LRDp0O-0HN6u0Dm5jA,14
|
|
104
|
+
jupyter_duckdb-1.4.109.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|