jupyter-duckdb 1.4.107__py3-none-any.whl → 1.4.108__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 +319 -38
- {jupyter_duckdb-1.4.107.dist-info → jupyter_duckdb-1.4.108.dist-info}/METADATA +1 -1
- {jupyter_duckdb-1.4.107.dist-info → jupyter_duckdb-1.4.108.dist-info}/RECORD +14 -12
- {jupyter_duckdb-1.4.107.dist-info → jupyter_duckdb-1.4.108.dist-info}/WHEEL +0 -0
- {jupyter_duckdb-1.4.107.dist-info → jupyter_duckdb-1.4.108.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
|
|
|
@@ -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,157 @@ 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
|
+
root = RAParser.parse_query(query)
|
|
718
|
+
|
|
719
|
+
|
|
569
720
|
def test_unary_operator_selection():
|
|
570
721
|
with Connection() as con:
|
|
571
722
|
for query in (
|
|
@@ -637,13 +788,21 @@ def test_unary_inner_to_outer_evaluation_order():
|
|
|
637
788
|
assert root.target.condition.left == ('Id',) and root.target.condition.right == ('1',)
|
|
638
789
|
|
|
639
790
|
root = RAParser.parse_query(r'β [ Id3 ← Id2 ] β [ Id2 ← Id ] (Users)')
|
|
640
|
-
assert isinstance(root, UnaryOperators.
|
|
791
|
+
assert isinstance(root, UnaryOperators.AttributeRename)
|
|
641
792
|
assert isinstance(root.arrow, BinaryOperators.ArrowLeft)
|
|
642
793
|
assert root.arrow.left == ('Id3',) and root.arrow.right == ('Id2',)
|
|
643
|
-
assert isinstance(root.target, UnaryOperators.
|
|
794
|
+
assert isinstance(root.target, UnaryOperators.AttributeRename)
|
|
644
795
|
assert isinstance(root.target.arrow, BinaryOperators.ArrowLeft)
|
|
645
796
|
assert root.target.arrow.left == ('Id2',) and root.target.arrow.right == ('Id',)
|
|
646
797
|
|
|
798
|
+
root = RAParser.parse_query(r'ρ [ S(X, Y) ] ρ [ R(A, B) ] (Users)')
|
|
799
|
+
assert isinstance(root, UnaryOperators.Rename)
|
|
800
|
+
assert isinstance(root.arg, RARelationReference)
|
|
801
|
+
assert root.arg.relation == 'S' and root.arg.attributes == ['X', 'Y']
|
|
802
|
+
assert isinstance(root.target, UnaryOperators.Rename)
|
|
803
|
+
assert isinstance(root.target.arg, RARelationReference)
|
|
804
|
+
assert root.target.arg.relation == 'R' and root.target.arg.attributes == ['A', 'B']
|
|
805
|
+
|
|
647
806
|
|
|
648
807
|
def test_binary_left_to_right_evaluation_order():
|
|
649
808
|
# difference
|
|
@@ -956,30 +1115,58 @@ def test_binary_left_to_right_evaluation_order():
|
|
|
956
1115
|
|
|
957
1116
|
|
|
958
1117
|
def test_unary_evaluation_order():
|
|
959
|
-
|
|
1118
|
+
# π
|
|
1119
|
+
root = RAParser.parse_query(r'π [ Id ] σ [ Id > 1 ] (Users)')
|
|
960
1120
|
assert isinstance(root, UnaryOperators.Projection)
|
|
961
|
-
assert isinstance(root.target, UnaryOperators.
|
|
1121
|
+
assert isinstance(root.target, UnaryOperators.Selection)
|
|
962
1122
|
|
|
963
|
-
root = RAParser.parse_query(r'
|
|
964
|
-
assert isinstance(root, UnaryOperators.
|
|
965
|
-
assert isinstance(root.target, UnaryOperators.
|
|
1123
|
+
root = RAParser.parse_query(r'π [ Id2 ] β [ Id2 ← Id ] (Users)')
|
|
1124
|
+
assert isinstance(root, UnaryOperators.Projection)
|
|
1125
|
+
assert isinstance(root.target, UnaryOperators.AttributeRename)
|
|
966
1126
|
|
|
967
|
-
root = RAParser.parse_query(r'π [
|
|
1127
|
+
root = RAParser.parse_query(r'π [ Id2 ] ρ [ R(Id2, Username2) ] (Users)')
|
|
968
1128
|
assert isinstance(root, UnaryOperators.Projection)
|
|
969
|
-
assert isinstance(root.target, UnaryOperators.
|
|
1129
|
+
assert isinstance(root.target, UnaryOperators.Rename)
|
|
970
1130
|
|
|
1131
|
+
# σ
|
|
971
1132
|
root = RAParser.parse_query(r'σ [ Id > 1 ] π [ Id ] (Users)')
|
|
972
1133
|
assert isinstance(root, UnaryOperators.Selection)
|
|
973
1134
|
assert isinstance(root.target, UnaryOperators.Projection)
|
|
974
1135
|
|
|
975
1136
|
root = RAParser.parse_query(r'σ [ Id2 > 1 ] β [ Id2 ← Id ] (Users)')
|
|
976
1137
|
assert isinstance(root, UnaryOperators.Selection)
|
|
1138
|
+
assert isinstance(root.target, UnaryOperators.AttributeRename)
|
|
1139
|
+
|
|
1140
|
+
root = RAParser.parse_query(r'σ [ Id2 > 1 ] ρ [ R(Id2, Username2) ] (Users)')
|
|
1141
|
+
assert isinstance(root, UnaryOperators.Selection)
|
|
977
1142
|
assert isinstance(root.target, UnaryOperators.Rename)
|
|
978
1143
|
|
|
1144
|
+
# β
|
|
1145
|
+
root = RAParser.parse_query(r'β [ Id2 ← Id ] π [ Id ] (Users)')
|
|
1146
|
+
assert isinstance(root, UnaryOperators.AttributeRename)
|
|
1147
|
+
assert isinstance(root.target, UnaryOperators.Projection)
|
|
1148
|
+
|
|
979
1149
|
root = RAParser.parse_query(r'β [ Id2 ← Id ] σ [ Id > 1 ] (Users)')
|
|
1150
|
+
assert isinstance(root, UnaryOperators.AttributeRename)
|
|
1151
|
+
assert isinstance(root.target, UnaryOperators.Selection)
|
|
1152
|
+
|
|
1153
|
+
root = RAParser.parse_query(r'β [ Id3 ← Id2 ] ρ [ R(Id2, Username2) ] (Users)')
|
|
1154
|
+
assert isinstance(root, UnaryOperators.AttributeRename)
|
|
1155
|
+
assert isinstance(root.target, UnaryOperators.Rename)
|
|
1156
|
+
|
|
1157
|
+
# ρ
|
|
1158
|
+
root = RAParser.parse_query(r'ρ [ R(Id2,) ] π [ Id ] (Users)')
|
|
1159
|
+
assert isinstance(root, UnaryOperators.Rename)
|
|
1160
|
+
assert isinstance(root.target, UnaryOperators.Projection)
|
|
1161
|
+
|
|
1162
|
+
root = RAParser.parse_query(r'ρ [ R(Id2, Username2) ] σ [ Id > 1 ] (Users)')
|
|
980
1163
|
assert isinstance(root, UnaryOperators.Rename)
|
|
981
1164
|
assert isinstance(root.target, UnaryOperators.Selection)
|
|
982
1165
|
|
|
1166
|
+
root = RAParser.parse_query(r'ρ [ R(Id3, Username2) ] β [ Id2 ← Id ] (Users)')
|
|
1167
|
+
assert isinstance(root, UnaryOperators.Rename)
|
|
1168
|
+
assert isinstance(root.target, UnaryOperators.AttributeRename)
|
|
1169
|
+
|
|
983
1170
|
|
|
984
1171
|
def test_binary_evaluation_order():
|
|
985
1172
|
# difference <-> union
|
|
@@ -1369,13 +1556,22 @@ def test_mixed_evaluation_order():
|
|
|
1369
1556
|
assert isinstance(root, BinaryOperators.Difference)
|
|
1370
1557
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Projection)
|
|
1371
1558
|
|
|
1372
|
-
# difference <-> rename
|
|
1559
|
+
# difference <-> attribute rename
|
|
1373
1560
|
root = RAParser.parse_query(r'a \ β [ Id2 ← Id ] b')
|
|
1374
1561
|
assert isinstance(root, BinaryOperators.Difference)
|
|
1375
|
-
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.
|
|
1562
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
|
|
1376
1563
|
|
|
1377
1564
|
root = RAParser.parse_query(r'β [ Id2 ← Id ] a \ b')
|
|
1378
1565
|
assert isinstance(root, BinaryOperators.Difference)
|
|
1566
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.AttributeRename)
|
|
1567
|
+
|
|
1568
|
+
# difference <-> rename
|
|
1569
|
+
root = RAParser.parse_query(r'a \ ρ [ R(Id2) ] b')
|
|
1570
|
+
assert isinstance(root, BinaryOperators.Difference)
|
|
1571
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Rename)
|
|
1572
|
+
|
|
1573
|
+
root = RAParser.parse_query(r'ρ [ R(Id2) ] a \ b')
|
|
1574
|
+
assert isinstance(root, BinaryOperators.Difference)
|
|
1379
1575
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
|
|
1380
1576
|
|
|
1381
1577
|
# difference <-> selection
|
|
@@ -1396,13 +1592,22 @@ def test_mixed_evaluation_order():
|
|
|
1396
1592
|
assert isinstance(root, BinaryOperators.Union)
|
|
1397
1593
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Projection)
|
|
1398
1594
|
|
|
1399
|
-
# union <-> rename
|
|
1595
|
+
# union <-> attribute rename
|
|
1400
1596
|
root = RAParser.parse_query(r'a ∪ β [ Id2 ← Id ] b')
|
|
1401
1597
|
assert isinstance(root, BinaryOperators.Union)
|
|
1402
|
-
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.
|
|
1598
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
|
|
1403
1599
|
|
|
1404
1600
|
root = RAParser.parse_query(r'β [ Id2 ← Id ] a ∪ b')
|
|
1405
1601
|
assert isinstance(root, BinaryOperators.Union)
|
|
1602
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.AttributeRename)
|
|
1603
|
+
|
|
1604
|
+
# union <-> rename
|
|
1605
|
+
root = RAParser.parse_query(r'a ∪ ρ [ R(Id2) ] b')
|
|
1606
|
+
assert isinstance(root, BinaryOperators.Union)
|
|
1607
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Rename)
|
|
1608
|
+
|
|
1609
|
+
root = RAParser.parse_query(r'ρ [ R(Id2) ] a ∪ b')
|
|
1610
|
+
assert isinstance(root, BinaryOperators.Union)
|
|
1406
1611
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
|
|
1407
1612
|
|
|
1408
1613
|
# union <-> selection
|
|
@@ -1423,13 +1628,22 @@ def test_mixed_evaluation_order():
|
|
|
1423
1628
|
assert isinstance(root, BinaryOperators.Intersection)
|
|
1424
1629
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Projection)
|
|
1425
1630
|
|
|
1426
|
-
# intersection <-> rename
|
|
1631
|
+
# intersection <-> attribute rename
|
|
1427
1632
|
root = RAParser.parse_query(r'a ∩ β [ Id2 ← Id ] b')
|
|
1428
1633
|
assert isinstance(root, BinaryOperators.Intersection)
|
|
1429
|
-
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.
|
|
1634
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
|
|
1430
1635
|
|
|
1431
1636
|
root = RAParser.parse_query(r'β [ Id2 ← Id ] a ∩ b')
|
|
1432
1637
|
assert isinstance(root, BinaryOperators.Intersection)
|
|
1638
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.AttributeRename)
|
|
1639
|
+
|
|
1640
|
+
# intersection <-> rename
|
|
1641
|
+
root = RAParser.parse_query(r'a ∩ ρ [ R(Id2) ] b')
|
|
1642
|
+
assert isinstance(root, BinaryOperators.Intersection)
|
|
1643
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Rename)
|
|
1644
|
+
|
|
1645
|
+
root = RAParser.parse_query(r'ρ [ R(Id2) ] a ∩ b')
|
|
1646
|
+
assert isinstance(root, BinaryOperators.Intersection)
|
|
1433
1647
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
|
|
1434
1648
|
|
|
1435
1649
|
# intersection <-> selection
|
|
@@ -1490,53 +1704,102 @@ def test_mixed_evaluation_order():
|
|
|
1490
1704
|
assert isinstance(root, BinaryOperators.RightSemiJoin)
|
|
1491
1705
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Projection)
|
|
1492
1706
|
|
|
1493
|
-
# join <-> rename
|
|
1707
|
+
# join <-> attribute rename
|
|
1494
1708
|
root = RAParser.parse_query(r'a ⋈ β [ Id2 ← Id ] b')
|
|
1495
1709
|
assert isinstance(root, BinaryOperators.Join)
|
|
1496
|
-
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.
|
|
1710
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
|
|
1497
1711
|
|
|
1498
1712
|
root = RAParser.parse_query(r'β [ Id2 ← Id ] a ⋈ b')
|
|
1499
1713
|
assert isinstance(root, BinaryOperators.Join)
|
|
1500
|
-
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.
|
|
1714
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.AttributeRename)
|
|
1501
1715
|
|
|
1502
1716
|
root = RAParser.parse_query(r'a ⟕ β [ Id2 ← Id ] b')
|
|
1503
1717
|
assert isinstance(root, BinaryOperators.LeftOuterJoin)
|
|
1504
|
-
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.
|
|
1718
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
|
|
1505
1719
|
|
|
1506
1720
|
root = RAParser.parse_query(r'β [ Id2 ← Id ] a ⟕ b')
|
|
1507
1721
|
assert isinstance(root, BinaryOperators.LeftOuterJoin)
|
|
1508
|
-
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.
|
|
1722
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.AttributeRename)
|
|
1509
1723
|
|
|
1510
1724
|
root = RAParser.parse_query(r'a ⟖ β [ Id2 ← Id ] b')
|
|
1511
1725
|
assert isinstance(root, BinaryOperators.RightOuterJoin)
|
|
1512
|
-
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.
|
|
1726
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
|
|
1513
1727
|
|
|
1514
1728
|
root = RAParser.parse_query(r'β [ Id2 ← Id ] a ⟖ b')
|
|
1515
1729
|
assert isinstance(root, BinaryOperators.RightOuterJoin)
|
|
1516
|
-
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.
|
|
1730
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.AttributeRename)
|
|
1517
1731
|
|
|
1518
1732
|
root = RAParser.parse_query(r'a ⟗ β [ Id2 ← Id ] b')
|
|
1519
1733
|
assert isinstance(root, BinaryOperators.FullOuterJoin)
|
|
1520
|
-
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.
|
|
1734
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
|
|
1521
1735
|
|
|
1522
1736
|
root = RAParser.parse_query(r'β [ Id2 ← Id ] a ⟗ b')
|
|
1523
1737
|
assert isinstance(root, BinaryOperators.FullOuterJoin)
|
|
1524
|
-
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.
|
|
1738
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.AttributeRename)
|
|
1525
1739
|
|
|
1526
1740
|
root = RAParser.parse_query(r'a ⋉ β [ Id2 ← Id ] b')
|
|
1527
1741
|
assert isinstance(root, BinaryOperators.LeftSemiJoin)
|
|
1528
|
-
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.
|
|
1742
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
|
|
1529
1743
|
|
|
1530
1744
|
root = RAParser.parse_query(r'β [ Id2 ← Id ] a ⋉ b')
|
|
1531
1745
|
assert isinstance(root, BinaryOperators.LeftSemiJoin)
|
|
1532
|
-
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.
|
|
1746
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.AttributeRename)
|
|
1533
1747
|
|
|
1534
1748
|
root = RAParser.parse_query(r'a ⋊ β [ Id2 ← Id ] b')
|
|
1535
1749
|
assert isinstance(root, BinaryOperators.RightSemiJoin)
|
|
1536
|
-
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.
|
|
1750
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
|
|
1537
1751
|
|
|
1538
1752
|
root = RAParser.parse_query(r'β [ Id2 ← Id ] a ⋊ b')
|
|
1539
1753
|
assert isinstance(root, BinaryOperators.RightSemiJoin)
|
|
1754
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.AttributeRename)
|
|
1755
|
+
|
|
1756
|
+
# join <-> rename
|
|
1757
|
+
root = RAParser.parse_query(r'a ⋈ ρ [ R(Id2) ] b')
|
|
1758
|
+
assert isinstance(root, BinaryOperators.Join)
|
|
1759
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Rename)
|
|
1760
|
+
|
|
1761
|
+
root = RAParser.parse_query(r'ρ [ R(Id2) ] a ⋈ b')
|
|
1762
|
+
assert isinstance(root, BinaryOperators.Join)
|
|
1763
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
|
|
1764
|
+
|
|
1765
|
+
root = RAParser.parse_query(r'a ⟕ ρ [ R(Id2) ] b')
|
|
1766
|
+
assert isinstance(root, BinaryOperators.LeftOuterJoin)
|
|
1767
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Rename)
|
|
1768
|
+
|
|
1769
|
+
root = RAParser.parse_query(r'ρ [ R(Id2) ] a ⟕ b')
|
|
1770
|
+
assert isinstance(root, BinaryOperators.LeftOuterJoin)
|
|
1771
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
|
|
1772
|
+
|
|
1773
|
+
root = RAParser.parse_query(r'a ⟖ ρ [ R(Id2) ] b')
|
|
1774
|
+
assert isinstance(root, BinaryOperators.RightOuterJoin)
|
|
1775
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Rename)
|
|
1776
|
+
|
|
1777
|
+
root = RAParser.parse_query(r'ρ [ R(Id2) ] a ⟖ b')
|
|
1778
|
+
assert isinstance(root, BinaryOperators.RightOuterJoin)
|
|
1779
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
|
|
1780
|
+
|
|
1781
|
+
root = RAParser.parse_query(r'a ⟗ ρ [ R(Id2) ] b')
|
|
1782
|
+
assert isinstance(root, BinaryOperators.FullOuterJoin)
|
|
1783
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Rename)
|
|
1784
|
+
|
|
1785
|
+
root = RAParser.parse_query(r'ρ [ R(Id2) ] a ⟗ b')
|
|
1786
|
+
assert isinstance(root, BinaryOperators.FullOuterJoin)
|
|
1787
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
|
|
1788
|
+
|
|
1789
|
+
root = RAParser.parse_query(r'a ⋉ ρ [ R(Id2) ] b')
|
|
1790
|
+
assert isinstance(root, BinaryOperators.LeftSemiJoin)
|
|
1791
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Rename)
|
|
1792
|
+
|
|
1793
|
+
root = RAParser.parse_query(r'ρ [ R(Id2) ] a ⋉ b')
|
|
1794
|
+
assert isinstance(root, BinaryOperators.LeftSemiJoin)
|
|
1795
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
|
|
1796
|
+
|
|
1797
|
+
root = RAParser.parse_query(r'a ⋊ ρ [ R(Id2) ] b')
|
|
1798
|
+
assert isinstance(root, BinaryOperators.RightSemiJoin)
|
|
1799
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Rename)
|
|
1800
|
+
|
|
1801
|
+
root = RAParser.parse_query(r'ρ [ R(Id2) ] a ⋊ b')
|
|
1802
|
+
assert isinstance(root, BinaryOperators.RightSemiJoin)
|
|
1540
1803
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
|
|
1541
1804
|
|
|
1542
1805
|
# join <-> selection
|
|
@@ -1597,13 +1860,22 @@ def test_mixed_evaluation_order():
|
|
|
1597
1860
|
assert isinstance(root, BinaryOperators.Cross)
|
|
1598
1861
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Projection)
|
|
1599
1862
|
|
|
1600
|
-
# cross <-> rename
|
|
1863
|
+
# cross <-> attribute rename
|
|
1601
1864
|
root = RAParser.parse_query(r'a x β [ Id2 ← Id ] b')
|
|
1602
1865
|
assert isinstance(root, BinaryOperators.Cross)
|
|
1603
|
-
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.
|
|
1866
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
|
|
1604
1867
|
|
|
1605
1868
|
root = RAParser.parse_query(r'β [ Id2 ← Id ] a x b')
|
|
1606
1869
|
assert isinstance(root, BinaryOperators.Cross)
|
|
1870
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.AttributeRename)
|
|
1871
|
+
|
|
1872
|
+
# cross <-> rename
|
|
1873
|
+
root = RAParser.parse_query(r'a x ρ [ R(Id2) ] b')
|
|
1874
|
+
assert isinstance(root, BinaryOperators.Cross)
|
|
1875
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Rename)
|
|
1876
|
+
|
|
1877
|
+
root = RAParser.parse_query(r'ρ [ R(Id2) ] a x b')
|
|
1878
|
+
assert isinstance(root, BinaryOperators.Cross)
|
|
1607
1879
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
|
|
1608
1880
|
|
|
1609
1881
|
# cross <-> selection
|
|
@@ -1624,13 +1896,22 @@ def test_mixed_evaluation_order():
|
|
|
1624
1896
|
assert isinstance(root, BinaryOperators.Division)
|
|
1625
1897
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Projection)
|
|
1626
1898
|
|
|
1627
|
-
# division <-> rename
|
|
1899
|
+
# division <-> attribute rename
|
|
1628
1900
|
root = RAParser.parse_query(r'a ÷ β [ Id2 ← Id ] b')
|
|
1629
1901
|
assert isinstance(root, BinaryOperators.Division)
|
|
1630
|
-
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.
|
|
1902
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.AttributeRename)
|
|
1631
1903
|
|
|
1632
1904
|
root = RAParser.parse_query(r'β [ Id2 ← Id ] a ÷ b')
|
|
1633
1905
|
assert isinstance(root, BinaryOperators.Division)
|
|
1906
|
+
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.AttributeRename)
|
|
1907
|
+
|
|
1908
|
+
# division <-> rename
|
|
1909
|
+
root = RAParser.parse_query(r'a ÷ ρ [ R(Id2) ] b')
|
|
1910
|
+
assert isinstance(root, BinaryOperators.Division)
|
|
1911
|
+
assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Rename)
|
|
1912
|
+
|
|
1913
|
+
root = RAParser.parse_query(r'ρ [ R(Id2) ] a ÷ b')
|
|
1914
|
+
assert isinstance(root, BinaryOperators.Division)
|
|
1634
1915
|
assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
|
|
1635
1916
|
|
|
1636
1917
|
# division <-> selection
|
|
@@ -1668,8 +1949,8 @@ def test_special_queries():
|
|
|
1668
1949
|
assert isinstance(root.left, UnaryOperators.Selection)
|
|
1669
1950
|
assert isinstance(root.left.target, UnaryOperators.Projection)
|
|
1670
1951
|
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.
|
|
1952
|
+
assert isinstance(root.right, UnaryOperators.AttributeRename)
|
|
1953
|
+
assert isinstance(root.right.target, UnaryOperators.AttributeRename)
|
|
1673
1954
|
assert isinstance(root.right.target.target, RAOperand) and root.right.target.target.name == 'BannedUsers'
|
|
1674
1955
|
|
|
1675
1956
|
assert con.execute_ra(root) == [
|
|
@@ -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=hvzpt4KWYtN273TXdXyHdfnqvzzS6ZYLwRfPzqnnDU0,3753
|
|
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,7 +81,7 @@ 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=PV_xLkC_zKxvDTCRtX5Y8nVzUsp3KAcvRfXaBf5VVkY,82843
|
|
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
87
|
duckdb_kernel/util/ResultSetComparator.py,sha256=5Pj1Vpi6laJJOK9HYiFwjrz0zj7Ogj8hYnTKIdN07wo,2831
|
|
@@ -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.108.dist-info/METADATA,sha256=Mf7R00FIYrxDEyg024KF5uabih3qpPsgtPioauTWFHI,9272
|
|
102
|
+
jupyter_duckdb-1.4.108.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
103
|
+
jupyter_duckdb-1.4.108.dist-info/top_level.txt,sha256=KvRRPMnmkQNuhyBsXoPmwyt26LRDp0O-0HN6u0Dm5jA,14
|
|
104
|
+
jupyter_duckdb-1.4.108.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|