jupyter-duckdb 1.2.0.6__py3-none-any.whl → 1.2.7__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.
@@ -19,10 +19,14 @@ class RAParser:
19
19
  tokens = tuple(Tokenizer.tokenize(tokens[0]))
20
20
 
21
21
  # binary operators
22
- for operator in RA_BINARY_OPERATORS:
22
+ for operator_symbols in RA_BINARY_SYMBOLS:
23
23
  # iterate tokens and match symbol
24
24
  for i in range(1, len(tokens) + 1):
25
- if tokens[-i].lower() in operator.symbols():
25
+ lower_token = tokens[-i].lower()
26
+
27
+ if lower_token in operator_symbols:
28
+ operator = operator_symbols[lower_token]
29
+
26
30
  # raise error if left or right operand missing
27
31
  if i == 1:
28
32
  raise RAParserError(f'right operand missing after {tokens[-i]}', depth)
@@ -9,7 +9,7 @@ from .RAOperator import RAOperator
9
9
  from .RABinaryOperator import RABinaryOperator
10
10
  from .RAUnaryOperator import RAUnaryOperator
11
11
  from .RAOperand import RAOperand
12
- from .binary import RA_BINARY_OPERATORS
12
+ from .binary import RA_BINARY_OPERATORS, RA_BINARY_SYMBOLS
13
13
  from .unary import RA_UNARY_OPERATORS
14
14
 
15
15
  from .DCOperand import DCOperand
@@ -0,0 +1,30 @@
1
+ from typing import Tuple, Dict
2
+
3
+ from duckdb_kernel.db import Table
4
+ from ..RABinaryOperator import RABinaryOperator
5
+ from ...util.RenamableColumnList import RenamableColumnList
6
+
7
+
8
+ class FullOuterJoin(RABinaryOperator):
9
+ @staticmethod
10
+ def symbols() -> Tuple[str, ...]:
11
+ return chr(10199), 'fjoin', 'ojoin'
12
+
13
+ def to_sql(self, tables: Dict[str, Table]) -> Tuple[str, RenamableColumnList]:
14
+ # execute subqueries
15
+ lq, lcols = self.left.to_sql(tables)
16
+ rq, rcols = self.right.to_sql(tables)
17
+
18
+ # find matching columns
19
+ join_cols, all_cols = lcols.intersect(rcols)
20
+
21
+ replacements = {c1: c2 for c1, c2 in join_cols}
22
+ select_cols = [
23
+ f'COALESCE({c.current_name}, {replacements.get(c).current_name})' if c in replacements else c.current_name
24
+ for c in all_cols]
25
+ select_clause = ', '.join(select_cols)
26
+
27
+ on_clause = ' AND '.join(f'{l.current_name} = {r.current_name}' for l, r in join_cols)
28
+
29
+ # create sql
30
+ return f'SELECT {select_clause} FROM ({lq}) {self._name()} FULL OUTER JOIN ({rq}) {self._name()} ON {on_clause}', all_cols
@@ -0,0 +1,24 @@
1
+ from typing import Tuple, Dict
2
+
3
+ from duckdb_kernel.db import Table
4
+ from ..RABinaryOperator import RABinaryOperator
5
+ from ...util.RenamableColumnList import RenamableColumnList
6
+
7
+
8
+ class LeftOuterJoin(RABinaryOperator):
9
+ @staticmethod
10
+ def symbols() -> Tuple[str, ...]:
11
+ return chr(10197), 'ljoin'
12
+
13
+ def to_sql(self, tables: Dict[str, Table]) -> Tuple[str, RenamableColumnList]:
14
+ # execute subqueries
15
+ lq, lcols = self.left.to_sql(tables)
16
+ rq, rcols = self.right.to_sql(tables)
17
+
18
+ # find matching columns
19
+ join_cols, all_cols = lcols.intersect(rcols)
20
+
21
+ on_clause = ' AND '.join(f'{l.current_name} = {r.current_name}' for l, r in join_cols)
22
+
23
+ # create sql
24
+ return f'SELECT {all_cols.list} FROM ({lq}) {self._name()} LEFT OUTER JOIN ({rq}) {self._name()} ON {on_clause}', all_cols
@@ -0,0 +1,24 @@
1
+ from typing import Tuple, Dict
2
+
3
+ from duckdb_kernel.db import Table
4
+ from ..RABinaryOperator import RABinaryOperator
5
+ from ...util.RenamableColumnList import RenamableColumnList
6
+
7
+
8
+ class RightOuterJoin(RABinaryOperator):
9
+ @staticmethod
10
+ def symbols() -> Tuple[str, ...]:
11
+ return chr(10198), 'rjoin'
12
+
13
+ def to_sql(self, tables: Dict[str, Table]) -> Tuple[str, RenamableColumnList]:
14
+ # execute subqueries
15
+ lq, lcols = self.left.to_sql(tables)
16
+ rq, rcols = self.right.to_sql(tables)
17
+
18
+ # find matching columns
19
+ join_cols, all_cols = lcols.intersect(rcols, prefer_right=True)
20
+
21
+ on_clause = ' AND '.join(f'{l.current_name} = {r.current_name}' for l, r in join_cols)
22
+
23
+ # create sql
24
+ return f'SELECT {all_cols.list} FROM ({lq}) {self._name()} RIGHT OUTER JOIN ({rq}) {self._name()} ON {on_clause}', all_cols
@@ -2,6 +2,9 @@ from .Cross import Cross
2
2
  from .Difference import Difference
3
3
  from .Intersection import Intersection
4
4
  from .Join import Join
5
+ from .LeftOuterJoin import LeftOuterJoin
6
+ from .RightOuterJoin import RightOuterJoin
7
+ from .FullOuterJoin import FullOuterJoin
5
8
  from .Union import Union
6
9
 
7
10
  from .Add import Add
@@ -30,12 +33,22 @@ LOGIC_BINARY_OPERATORS = sorted([
30
33
  ], key=lambda x: x.order, reverse=True)
31
34
 
32
35
  RA_BINARY_OPERATORS = [
33
- Difference,
34
- Union,
35
- Intersection,
36
- Join,
37
- Cross,
38
- Division
36
+ [Difference],
37
+ [Union],
38
+ [Intersection],
39
+ [Join],
40
+ [LeftOuterJoin, RightOuterJoin, FullOuterJoin],
41
+ [Cross],
42
+ [Division]
43
+ ]
44
+
45
+ RA_BINARY_SYMBOLS = [
46
+ {
47
+ symbol: operator
48
+ for operator in level
49
+ for symbol in operator.symbols()
50
+ }
51
+ for level in RA_BINARY_OPERATORS
39
52
  ]
40
53
 
41
54
  DC_SET = ConditionalSet
@@ -73,18 +73,26 @@ class RenamableColumnList(list[RenamableColumn]):
73
73
 
74
74
  return RenamableColumnList(cols.values())
75
75
 
76
- def intersect(self, other: 'RenamableColumnList') \
76
+ def intersect(self, other: 'RenamableColumnList', prefer_right: bool = False) \
77
77
  -> Tuple[List[Tuple[RenamableColumn, RenamableColumn]], 'RenamableColumnList']:
78
78
  self_cols: Dict[str, RenamableColumn] = {col.name: col for col in self}
79
79
  other_cols: Dict[str, RenamableColumn] = {col.name: col for col in other}
80
80
 
81
+ replacements: Dict[RenamableColumn, RenamableColumn] = {}
81
82
  intersection: List[Tuple[RenamableColumn, RenamableColumn]] = []
83
+
82
84
  for name in tuple(self_cols.keys()):
83
85
  if name in other_cols:
86
+ if prefer_right:
87
+ replacements[self_cols[name]] = other_cols[name]
88
+
84
89
  intersection.append((self_cols[name], other_cols[name]))
85
90
  del other_cols[name]
86
91
 
87
92
  # if len(intersection) == 0:
88
93
  # raise AssertionError('no common attributes found for join')
89
94
 
90
- return intersection, RenamableColumnList(self_cols.values(), other_cols.values())
95
+ return intersection, RenamableColumnList(
96
+ (replacements.get(x, x) for x in self_cols.values()),
97
+ other_cols.values()
98
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: jupyter-duckdb
3
- Version: 1.2.0.6
3
+ Version: 1.2.7
4
4
  Summary: a basic wrapper kernel for DuckDB
5
5
  Home-page: https://github.com/erictroebs/jupyter-duckdb
6
6
  Author: Eric Tröbs
@@ -27,7 +27,7 @@ duckdb_kernel/magics/__init__.py,sha256=DA8gnQeRCUt1Scy3_NQ9w5CPmMEY9i8YwB-g392p
27
27
  duckdb_kernel/parser/DCParser.py,sha256=16c1mxa494KP9OreUKQHsSQKoDGZ7NNp2u_gi_D-dkw,2293
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=dL5Q5J8tmlGuKQMfadvJK6cb9KmzfZLkfcUAthqDmXI,2993
30
+ duckdb_kernel/parser/RAParser.py,sha256=vLR2X8zJIJ3cPKdLvU3PKjNakEOvsoFuoK8pr4bA-Fg,3102
31
31
  duckdb_kernel/parser/__init__.py,sha256=nTmDm1ADvNPDHhVJQLxKYmArNJk6967EUXqn5AkT8FM,126
32
32
  duckdb_kernel/parser/elements/DCOperand.py,sha256=qEg_6Us4WV1eK4Bq6oUsmFt_L_x5pJPGce_wSapzIYA,1149
33
33
  duckdb_kernel/parser/elements/LogicElement.py,sha256=YasKHxWLDDP8UdyLIKbXzqIRA8-XaakjmvTj-1Iuzyc,280
@@ -38,7 +38,7 @@ duckdb_kernel/parser/elements/RAElement.py,sha256=d6QWO8KlWcwhA4tXtWsf8K4oT3OMMj
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
40
  duckdb_kernel/parser/elements/RAUnaryOperator.py,sha256=XC1nphkSm88JaEu5V_HKnb_8JNoeBfE3EvNL4o0qh2c,654
41
- duckdb_kernel/parser/elements/__init__.py,sha256=4DA2M43hh9d1fZb5Z6YnTTI-IBkDyhChSF5L9X3EA-s,547
41
+ duckdb_kernel/parser/elements/__init__.py,sha256=t5H6SVOm3z8r6UWRYOI7HmMIuB4Yh6TLNu4_N3jg2t0,566
42
42
  duckdb_kernel/parser/elements/binary/Add.py,sha256=XGkZMfab01huk9EaI6JUfzkd2STbV1C_-TyC2guKE8I,190
43
43
  duckdb_kernel/parser/elements/binary/And.py,sha256=0jgetTG8yo5TJSeK70Kj-PI9ERyek1eyMQXX5HBxa4Y,274
44
44
  duckdb_kernel/parser/elements/binary/ArrowLeft.py,sha256=u4fZSoyT9lfvWXBwuhUl4DdjVZAOqyVIKmMVbpElLD4,203
@@ -48,18 +48,21 @@ duckdb_kernel/parser/elements/binary/Difference.py,sha256=ZVRgJHYVMOFwnc97oPvGtK
48
48
  duckdb_kernel/parser/elements/binary/Divide.py,sha256=d7mzaOeRYSRO1F-2IHsv_C939TuYtLppbf4-5GSRJXs,265
49
49
  duckdb_kernel/parser/elements/binary/Division.py,sha256=Tq98RzGHN7QYF3R2ZVpwIiLhSIMQXzRgIuZ7l0D2fXg,1624
50
50
  duckdb_kernel/parser/elements/binary/Equal.py,sha256=xd5eMwVwM7thXqmoBg-JSux4y6osxxznNzaChmgrnGI,192
51
+ duckdb_kernel/parser/elements/binary/FullOuterJoin.py,sha256=WwV9jVFXr0FkfOOGKNZAiEjFKO_l0ND3RAvJYKEyVzY,1133
51
52
  duckdb_kernel/parser/elements/binary/GreaterThan.py,sha256=lW7EPYjwwZ1VLZOE4ai6MBW7Zq5itsUTi_v6FxoAuU0,204
52
53
  duckdb_kernel/parser/elements/binary/GreaterThanEqual.py,sha256=gO1I3J5CZwrpqZb5Oc-WJ_fCnGylpj4YKl4s-ZAr_-4,286
53
54
  duckdb_kernel/parser/elements/binary/Intersection.py,sha256=K6NrwcLTJ1BUccifVQ2R2YHR5B71LhjuLhOalxZcM0g,757
54
55
  duckdb_kernel/parser/elements/binary/Join.py,sha256=9Z3JinEav3ulLbZZZM9DLbprloHC0oGuSm40Kf1A0mM,836
56
+ duckdb_kernel/parser/elements/binary/LeftOuterJoin.py,sha256=qCyHLMboNjzSDK_FREtYVwZx4UYkfRcy3FMo2pEf93o,846
55
57
  duckdb_kernel/parser/elements/binary/LessThan.py,sha256=gNlyAvew0VyvU8x3ol88zbdh_t9GU51Kd2P_PmHUrAc,201
56
58
  duckdb_kernel/parser/elements/binary/LessThanEqual.py,sha256=BKKXBZ4TZQ4EBxBDSNzIpFl4Oz1IGI0tI0Oj7KZUoDo,283
57
59
  duckdb_kernel/parser/elements/binary/Minus.py,sha256=1XUTXCA0GcAcCnv9nq4B9ewT0XHJ91LlZGEW1y60POA,192
58
60
  duckdb_kernel/parser/elements/binary/Multiply.py,sha256=OctlfN71izFYxIpMo09Qwq-3BmQmSh6-PNKBljMsBrg,195
59
61
  duckdb_kernel/parser/elements/binary/Or.py,sha256=e1H_BuY7TQD7XHKGqJYLOebYQvrh1euWOUsXF0FT5dY,264
62
+ duckdb_kernel/parser/elements/binary/RightOuterJoin.py,sha256=bDxTEQ_dJZ-MUuGbU1YL69kPFR0Hdkc1fow3wxOxfAY,867
60
63
  duckdb_kernel/parser/elements/binary/Unequal.py,sha256=1hnC1RcPMxwKKv65OL5prunGgh9cRVDmzJutmtl7gtY,269
61
64
  duckdb_kernel/parser/elements/binary/Union.py,sha256=VYTj4M2PVEhWiDwjnyP8qpVVbGvIBSVshlEt-SZYCBY,739
62
- duckdb_kernel/parser/elements/binary/__init__.py,sha256=PtZgC0vOQONRx0FnFvzaxK9dYobdCykbQATP20djivA,983
65
+ duckdb_kernel/parser/elements/binary/__init__.py,sha256=BieXw51EBgIwUEK-hn4jBb1b4VKJT6sRzaxwOrSXw2A,1342
63
66
  duckdb_kernel/parser/elements/unary/Not.py,sha256=kG0a-dp3TNjPodUMPiQ6ihtsBrbvn1iWeIPCvtyAwdo,632
64
67
  duckdb_kernel/parser/elements/unary/Projection.py,sha256=CJ-MIf1-__1ewTjNZVy5hOz3Z18CWnCDNJBxUdpWXVQ,1112
65
68
  duckdb_kernel/parser/elements/unary/Rename.py,sha256=Zr2n9EJ3nA476lND0Djz2b6493nnsbSpJ9kkEgk5B_Y,1273
@@ -69,7 +72,7 @@ duckdb_kernel/parser/tokenizer/Token.py,sha256=gsCzgU_zLiA-yD0FWvd2qS9LQUXbivESY
69
72
  duckdb_kernel/parser/tokenizer/Tokenizer.py,sha256=PWGgS7gYgpULiKGDho842UbaXuqmwEkccixuF10oi5g,5081
70
73
  duckdb_kernel/parser/tokenizer/__init__.py,sha256=EOSmfc2RJwtB5cE1Hhj1JAra97tckxxS8-legybPy60,58
71
74
  duckdb_kernel/parser/util/RenamableColumn.py,sha256=LxJhFDMUv_OxYYDLwKn63QGpBRfs08jVvhuJTzRtc9c,704
72
- duckdb_kernel/parser/util/RenamableColumnList.py,sha256=GfhdGv4KYT64Z9YA9TCn-7hhcEcc3Gu3vI2zMZ52w-8,3015
75
+ duckdb_kernel/parser/util/RenamableColumnList.py,sha256=5oEDbtvl4YfHbkxu_Ny2pc0EYnhCZsf7EeoNQvftbrU,3281
73
76
  duckdb_kernel/parser/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
74
77
  duckdb_kernel/util/ResultSetComparator.py,sha256=RZDIfjJyx8-eR-HIqQlEYgZd_V1ympbszpVRF4TlA7o,2262
75
78
  duckdb_kernel/util/SQL.py,sha256=-uRfa0IwEQueZNZ7vkBPczLuvm_87y4_nnMBx3FgqNk,643
@@ -80,7 +83,7 @@ duckdb_kernel/visualization/Drawer.py,sha256=D0LkiGMvuJ2v6cQSg_axLTGaM4VXAJEQJAy
80
83
  duckdb_kernel/visualization/RATreeDrawer.py,sha256=j-Vy1zpYMzwZ3CsphyfPW-J7ou9a9tM6aXXgAlQTgDI,2128
81
84
  duckdb_kernel/visualization/SchemaDrawer.py,sha256=9K-TUUmyeGdMYMTFQJ7evIU3p8p2KyMKeizUc7-y8co,3015
82
85
  duckdb_kernel/visualization/__init__.py,sha256=5eMJmxJ01XAXcgWDn3t70eSZF2PGaXdNo6GK-x-0H3s,78
83
- jupyter_duckdb-1.2.0.6.dist-info/METADATA,sha256=CpGdT2u47HAdtsRNJpQJeQvQPIuBVXVLfYyybbrxQnY,9115
84
- jupyter_duckdb-1.2.0.6.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
85
- jupyter_duckdb-1.2.0.6.dist-info/top_level.txt,sha256=KvRRPMnmkQNuhyBsXoPmwyt26LRDp0O-0HN6u0Dm5jA,14
86
- jupyter_duckdb-1.2.0.6.dist-info/RECORD,,
86
+ jupyter_duckdb-1.2.7.dist-info/METADATA,sha256=g002q8FOyFbbZlRm-5qyDrf-yb_7n2bok9HqNXSvpbY,9113
87
+ jupyter_duckdb-1.2.7.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
88
+ jupyter_duckdb-1.2.7.dist-info/top_level.txt,sha256=KvRRPMnmkQNuhyBsXoPmwyt26LRDp0O-0HN6u0Dm5jA,14
89
+ jupyter_duckdb-1.2.7.dist-info/RECORD,,