jupyter-duckdb 1.4.105__py3-none-any.whl → 1.4.107__py3-none-any.whl

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