jupyter-duckdb 1.4.100__tar.gz → 1.4.105__tar.gz

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.
Files changed (105) hide show
  1. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/PKG-INFO +4 -2
  2. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/README.md +3 -1
  3. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/setup.py +1 -1
  4. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/kernel.py +9 -5
  5. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/RAParser.py +5 -0
  6. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/RAElement.py +4 -1
  7. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/binary/ConditionalSet.py +7 -1
  8. jupyter_duckdb-1.4.105/src/duckdb_kernel/parser/util/QuerySplitter.py +87 -0
  9. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/tests/__init__.py +2 -2
  10. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/tests/test_ra.py +23 -0
  11. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/jupyter_duckdb.egg-info/PKG-INFO +4 -2
  12. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/jupyter_duckdb.egg-info/SOURCES.txt +1 -0
  13. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/setup.cfg +0 -0
  14. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/__init__.py +0 -0
  15. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/__main__.py +0 -0
  16. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/db/Column.py +0 -0
  17. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/db/Connection.py +0 -0
  18. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/db/Constraint.py +0 -0
  19. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/db/DatabaseError.py +0 -0
  20. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/db/ForeignKey.py +0 -0
  21. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/db/Table.py +0 -0
  22. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/db/__init__.py +0 -0
  23. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/db/error/EmptyResultError.py +0 -0
  24. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/db/error/__init__.py +0 -0
  25. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/db/implementation/duckdb/Connection.py +0 -0
  26. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/db/implementation/duckdb/__init__.py +0 -0
  27. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/db/implementation/postgres/Connection.py +0 -0
  28. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/db/implementation/postgres/__init__.py +0 -0
  29. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/db/implementation/postgres/util.py +0 -0
  30. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/db/implementation/sqlite/Connection.py +0 -0
  31. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/db/implementation/sqlite/__init__.py +0 -0
  32. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/kernel.json +0 -0
  33. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/magics/MagicCommand.py +0 -0
  34. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/magics/MagicCommandCallback.py +0 -0
  35. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/magics/MagicCommandException.py +0 -0
  36. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/magics/MagicCommandHandler.py +0 -0
  37. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/magics/MagicState.py +0 -0
  38. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/magics/__init__.py +0 -0
  39. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/DCParser.py +0 -0
  40. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/LogicParser.py +0 -0
  41. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/ParserError.py +0 -0
  42. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/__init__.py +0 -0
  43. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/DCOperand.py +0 -0
  44. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/LogicElement.py +0 -0
  45. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/LogicOperand.py +0 -0
  46. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/LogicOperator.py +0 -0
  47. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/RABinaryOperator.py +0 -0
  48. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/RAOperand.py +0 -0
  49. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/RAOperator.py +0 -0
  50. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/RAUnaryOperator.py +0 -0
  51. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/__init__.py +0 -0
  52. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/binary/Add.py +0 -0
  53. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/binary/And.py +0 -0
  54. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/binary/ArrowLeft.py +0 -0
  55. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/binary/Cross.py +0 -0
  56. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/binary/Difference.py +0 -0
  57. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/binary/Divide.py +0 -0
  58. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/binary/Division.py +0 -0
  59. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/binary/Equal.py +0 -0
  60. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/binary/FullOuterJoin.py +0 -0
  61. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/binary/GreaterThan.py +0 -0
  62. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/binary/GreaterThanEqual.py +0 -0
  63. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/binary/Intersection.py +0 -0
  64. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/binary/Join.py +0 -0
  65. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/binary/LeftOuterJoin.py +0 -0
  66. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/binary/LessThan.py +0 -0
  67. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/binary/LessThanEqual.py +0 -0
  68. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/binary/Minus.py +0 -0
  69. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/binary/Multiply.py +0 -0
  70. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/binary/Or.py +0 -0
  71. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/binary/RightOuterJoin.py +0 -0
  72. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/binary/Unequal.py +0 -0
  73. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/binary/Union.py +0 -0
  74. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/binary/__init__.py +0 -0
  75. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/unary/Not.py +0 -0
  76. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/unary/Projection.py +0 -0
  77. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/unary/Rename.py +0 -0
  78. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/unary/Selection.py +0 -0
  79. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/elements/unary/__init__.py +0 -0
  80. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/tokenizer/Token.py +0 -0
  81. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/tokenizer/Tokenizer.py +0 -0
  82. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/tokenizer/__init__.py +0 -0
  83. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/util/RenamableColumn.py +0 -0
  84. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/util/RenamableColumnList.py +0 -0
  85. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/parser/util/__init__.py +0 -0
  86. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/tests/test_dc.py +0 -0
  87. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/tests/test_result_comparison.py +0 -0
  88. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/tests/test_sql.py +0 -0
  89. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/util/ResultSetComparator.py +0 -0
  90. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/util/SQL.py +0 -0
  91. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/util/TestError.py +0 -0
  92. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/util/__init__.py +0 -0
  93. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/util/formatting.py +0 -0
  94. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/visualization/Drawer.py +0 -0
  95. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/visualization/Plotly.py +0 -0
  96. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/visualization/RATreeDrawer.py +0 -0
  97. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/visualization/SchemaDrawer.py +0 -0
  98. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/visualization/__init__.py +0 -0
  99. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/visualization/lib/__init__.py +0 -0
  100. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/visualization/lib/plotly-3.0.1.min.js +0 -0
  101. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/visualization/lib/ra.css +0 -0
  102. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/duckdb_kernel/visualization/lib/ra.js +0 -0
  103. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/jupyter_duckdb.egg-info/dependency_links.txt +0 -0
  104. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/jupyter_duckdb.egg-info/requires.txt +0 -0
  105. {jupyter_duckdb-1.4.100 → jupyter_duckdb-1.4.105}/src/jupyter_duckdb.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jupyter-duckdb
3
- Version: 1.4.100
3
+ Version: 1.4.105
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
@@ -45,6 +45,7 @@ There are some magic commands that make teaching easier with this kernel.
45
45
  - [Ship Tests With Your Notebook](#ship-tests-with-your-notebooks)
46
46
  - [Relational Algebra](#relational-algebra)
47
47
  - [Domain Calculus](#domain-calculus)
48
+ - [Automated Parser Selection](#automated-parser-selection)
48
49
 
49
50
  ## Setup
50
51
 
@@ -281,6 +282,8 @@ The supported operations are:
281
282
  The optional flag `ANALYZE` can be used to add an execution diagram to the
282
283
  output.
283
284
 
285
+ You can also add comments to queries using `--` or `/* */`, just like in SQL.
286
+
284
287
  The Dockerfile also installs the Jupyter Lab plugin
285
288
  [jupyter-ra-extension](https://pypi.org/project/jupyter-ra-extension/). It adds
286
289
  the symbols mentioned above and some other supported symbols to the toolbar for
@@ -304,4 +307,3 @@ executed cells.
304
307
  If the magic command `%AUTO_PARSER` is added to a cell, a parser is
305
308
  automatically selected. If `%GUESS_PARSER` is executed, the parser is
306
309
  automatically selected for all subsequent cells.
307
-
@@ -17,6 +17,7 @@ There are some magic commands that make teaching easier with this kernel.
17
17
  - [Ship Tests With Your Notebook](#ship-tests-with-your-notebooks)
18
18
  - [Relational Algebra](#relational-algebra)
19
19
  - [Domain Calculus](#domain-calculus)
20
+ - [Automated Parser Selection](#automated-parser-selection)
20
21
 
21
22
  ## Setup
22
23
 
@@ -253,6 +254,8 @@ The supported operations are:
253
254
  The optional flag `ANALYZE` can be used to add an execution diagram to the
254
255
  output.
255
256
 
257
+ You can also add comments to queries using `--` or `/* */`, just like in SQL.
258
+
256
259
  The Dockerfile also installs the Jupyter Lab plugin
257
260
  [jupyter-ra-extension](https://pypi.org/project/jupyter-ra-extension/). It adds
258
261
  the symbols mentioned above and some other supported symbols to the toolbar for
@@ -276,4 +279,3 @@ executed cells.
276
279
  If the magic command `%AUTO_PARSER` is added to a cell, a parser is
277
280
  automatically selected. If `%GUESS_PARSER` is executed, the parser is
278
281
  automatically selected for all subsequent cells.
279
-
@@ -1,7 +1,7 @@
1
1
  import os
2
2
 
3
3
  # configuration
4
- PACKAGE_VERSION = '1.4.100'
4
+ PACKAGE_VERSION = '1.4.105'
5
5
  DUCKDB_VERSION = '1.4.1'
6
6
 
7
7
  DEPENDENCIES = [
@@ -13,6 +13,7 @@ from .db import Connection, DatabaseError, Table
13
13
  from .db.error import *
14
14
  from .magics import *
15
15
  from .parser import RAParser, DCParser, ParserError
16
+ from .parser.util.QuerySplitter import split_queries, get_last_query
16
17
  from .util.ResultSetComparator import ResultSetComparator
17
18
  from .util.SQL import SQL_KEYWORDS
18
19
  from .util.TestError import TestError
@@ -27,9 +28,11 @@ class DuckDBKernel(Kernel):
27
28
  implementation_version = '1.0'
28
29
  banner = 'DuckDB Kernel'
29
30
  language_info = {
30
- 'name': 'duckdb',
31
- 'mimetype': 'application/sql',
31
+ 'name': 'sql',
32
32
  'file_extension': '.sql',
33
+ 'mimetype': 'text/x-sql',
34
+ 'codemirror_mode': 'sql',
35
+ 'pygments_lexer': 'sql',
33
36
  }
34
37
 
35
38
  def __init__(self, **kwargs):
@@ -166,7 +169,9 @@ class DuckDBKernel(Kernel):
166
169
  # print result if not silent
167
170
  if not silent:
168
171
  # print EXPLAIN queries as raw text if using DuckDB
169
- if query.strip().startswith('EXPLAIN') and state.db.plain_explain():
172
+ last_query = get_last_query(query, remove_comments=True).strip()
173
+
174
+ if last_query.startswith('EXPLAIN') and state.db.plain_explain():
170
175
  for ekey, evalue in rows:
171
176
  html = f'<b>{ekey}</b><br><pre>{evalue}</pre>'
172
177
  break
@@ -273,8 +278,7 @@ class DuckDBKernel(Kernel):
273
278
 
274
279
  # You can only execute one statement at a time using SQLite.
275
280
  if not state.db.multiple_statements_per_query():
276
- statements = re.split(r';\r?\n', content)
277
- for statement in statements:
281
+ for statement in split_queries(content):
278
282
  try:
279
283
  state.db.execute(statement)
280
284
  except EmptyResultError:
@@ -2,6 +2,7 @@ from .LogicParser import LogicParser
2
2
  from .ParserError import RAParserError
3
3
  from .elements import *
4
4
  from .tokenizer import *
5
+ from .util.QuerySplitter import get_last_query
5
6
 
6
7
 
7
8
  # Instead of multiple nested loops, a tree with rotation can
@@ -10,6 +11,10 @@ from .tokenizer import *
10
11
  class RAParser:
11
12
  @staticmethod
12
13
  def parse_query(query: str) -> RAElement:
14
+ # remove comments from query
15
+ query = get_last_query(query, split_at=None, remove_comments=True)
16
+
17
+ # parse query
13
18
  initial_token = Token(query)
14
19
  return RAParser.parse_tokens(initial_token, depth=0)
15
20
 
@@ -36,10 +36,13 @@ class RAElement:
36
36
  # if all columns are from the same relation we can skip the relation name
37
37
  if len(set(c.table for c in columns)) == 1:
38
38
  column_names = ', '.join(f'{c.current_name} AS "{c.name}"' for c in columns)
39
+ order_names = ', '.join(f'"{c.name}" ASC' for c in columns)
39
40
  else:
40
41
  column_names = ', '.join(f'{c.current_name} AS "{c.full_name}"' for c in columns)
42
+ order_names = ', '.join(f'"{c.full_name}" ASC' for c in columns)
41
43
 
42
- return f'SELECT {column_names} FROM ({sql}) {self._name()}'
44
+ # create sql
45
+ return f'SELECT {column_names} FROM ({sql}) {self._name()} ORDER BY {order_names}'
43
46
 
44
47
  def to_sql_with_count(self, tables: Dict[str, Table]) -> str:
45
48
  sql, _ = self.to_sql(tables)
@@ -347,7 +347,13 @@ class ConditionalSet:
347
347
  sql_join_filters += f' AND {join_filter}'
348
348
 
349
349
  sql_condition = condition.to_sql(joined_columns) if condition is not None else '1=1'
350
- sql_query = f'SELECT DISTINCT {sql_select} FROM {sql_tables} WHERE ({sql_join_filters}) AND ({sql_condition})'
350
+
351
+ if self.projection == ('*',):
352
+ sql_order = ', '.join(f'{rc.name} ASC' for rcl in rcls for rc in rcl)
353
+ else:
354
+ sql_order = ', '.join(f'{col} ASC' for col in self.projection)
355
+
356
+ sql_query = f'SELECT DISTINCT {sql_select} FROM {sql_tables} WHERE ({sql_join_filters}) AND ({sql_condition}) ORDER BY {sql_order}'
351
357
 
352
358
  # Create a mapping from intermediate column names to constant values.
353
359
  column_name_mapping = {
@@ -0,0 +1,87 @@
1
+ from typing import Iterator
2
+
3
+
4
+ def split_queries(query: str, split_at: str | None = ';', remove_comments: bool = False) -> Iterator[str]:
5
+ quotes = '\'"`'
6
+
7
+ escaped = False
8
+ in_quotes = None
9
+ in_singleline_comment = False
10
+ in_multiline_comment = False
11
+
12
+ previous = None
13
+ current_query = []
14
+
15
+ for symbol in query:
16
+ keep_symbol = True
17
+
18
+ # escaped symbol
19
+ if escaped:
20
+ escaped = False
21
+
22
+ # backslash (escape)
23
+ elif symbol == '\\':
24
+ escaped = True
25
+
26
+ # if in quotes
27
+ elif in_quotes is not None:
28
+ if symbol == in_quotes:
29
+ in_quotes = False
30
+
31
+ # if in single line comment
32
+ elif in_singleline_comment:
33
+ if symbol == '\n':
34
+ in_singleline_comment = False
35
+ elif remove_comments:
36
+ keep_symbol = False
37
+
38
+ # if in multiline comment
39
+ elif in_multiline_comment:
40
+ if previous == '*' and symbol == '/':
41
+ in_multiline_comment = False
42
+
43
+ if remove_comments:
44
+ keep_symbol = False
45
+
46
+ # start of quotes
47
+ elif symbol in quotes:
48
+ in_quotes = symbol
49
+
50
+ # start of single line comment
51
+ elif previous == '-' and symbol == '-':
52
+ in_singleline_comment = True
53
+
54
+ if remove_comments:
55
+ keep_symbol = False
56
+ current_query.pop()
57
+
58
+ # start of multiline comment
59
+ elif previous == '/' and symbol == '*':
60
+ in_multiline_comment = True
61
+
62
+ if remove_comments:
63
+ keep_symbol = False
64
+ current_query.pop()
65
+
66
+ # semicolon
67
+ elif split_at is not None and symbol == split_at:
68
+ yield ''.join(current_query)
69
+
70
+ current_query = []
71
+ keep_symbol = False
72
+
73
+ # store symbol
74
+ if keep_symbol:
75
+ current_query.append(symbol)
76
+
77
+ previous = symbol
78
+
79
+ # yield remaining symbols
80
+ yield ''.join(current_query)
81
+
82
+
83
+ def get_last_query(query: str, split_at: str | None = ';', remove_comments: bool = False) -> str:
84
+ for query in split_queries(query, split_at, remove_comments):
85
+ pass
86
+
87
+ return query
@@ -56,7 +56,7 @@ class Connection:
56
56
  sql = root.to_sql_with_renamed_columns(self.tables)
57
57
  cols, rows = self.execute_sql_return_cols(sql)
58
58
 
59
- return cols, sorted(rows, key=lambda t: tuple(-1 if x is None else x for x in t))
59
+ return cols, rows # sorted(rows, key=lambda t: tuple(-1 if x is None else x for x in t))
60
60
 
61
61
  def execute_ra(self, root: RAElement) -> List:
62
62
  _, rows = self.execute_ra_return_cols(root)
@@ -66,7 +66,7 @@ class Connection:
66
66
  sql, cnm = root.to_sql_with_renamed_columns(self.tables)
67
67
  cols, rows = self.execute_sql_return_cols(sql)
68
68
 
69
- return [cnm.get(c, c) for c in cols], sorted(rows)
69
+ return [cnm.get(c, c) for c in cols], rows # sorted(rows)
70
70
 
71
71
  def execute_dc(self, root: ConditionalSet) -> List:
72
72
  _, rows = self.execute_dc_return_cols(root)
@@ -79,6 +79,29 @@ def test_case_insensitivity():
79
79
  ]
80
80
 
81
81
 
82
+ def test_comments():
83
+ for query in (
84
+ # single line
85
+ 'Shows -- x Users\n x Seasons',
86
+ 'Shows x Seasons -- x Users',
87
+ 'Shows x Seasons--',
88
+ 'Shows x Seasons--\n',
89
+ # multi line
90
+ 'Shows /* x Users */ x Seasons',
91
+ 'Shows /* x Users */\n x Seasons',
92
+ 'Shows /* x Users\n */ x Seasons',
93
+ 'Shows x Seasons/**/',
94
+ 'Shows x Seasons/*\n*/',
95
+ 'Shows x Seasons\n/**/',
96
+ 'Shows x Seasons/* x Users'
97
+ ):
98
+ root = RAParser.parse_query(query)
99
+
100
+ assert isinstance(root, BinaryOperators.Cross)
101
+ assert isinstance(root.left, RAOperand) and root.left.name == 'Shows'
102
+ assert isinstance(root.right, RAOperand) and root.right.name == 'Seasons'
103
+
104
+
82
105
  def test_binary_operator_cross():
83
106
  for query in (
84
107
  r'Shows x Seasons',
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jupyter-duckdb
3
- Version: 1.4.100
3
+ Version: 1.4.105
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
@@ -45,6 +45,7 @@ There are some magic commands that make teaching easier with this kernel.
45
45
  - [Ship Tests With Your Notebook](#ship-tests-with-your-notebooks)
46
46
  - [Relational Algebra](#relational-algebra)
47
47
  - [Domain Calculus](#domain-calculus)
48
+ - [Automated Parser Selection](#automated-parser-selection)
48
49
 
49
50
  ## Setup
50
51
 
@@ -281,6 +282,8 @@ The supported operations are:
281
282
  The optional flag `ANALYZE` can be used to add an execution diagram to the
282
283
  output.
283
284
 
285
+ You can also add comments to queries using `--` or `/* */`, just like in SQL.
286
+
284
287
  The Dockerfile also installs the Jupyter Lab plugin
285
288
  [jupyter-ra-extension](https://pypi.org/project/jupyter-ra-extension/). It adds
286
289
  the symbols mentioned above and some other supported symbols to the toolbar for
@@ -304,4 +307,3 @@ executed cells.
304
307
  If the magic command `%AUTO_PARSER` is added to a cell, a parser is
305
308
  automatically selected. If `%GUESS_PARSER` is executed, the parser is
306
309
  automatically selected for all subsequent cells.
307
-
@@ -73,6 +73,7 @@ src/duckdb_kernel/parser/elements/unary/__init__.py
73
73
  src/duckdb_kernel/parser/tokenizer/Token.py
74
74
  src/duckdb_kernel/parser/tokenizer/Tokenizer.py
75
75
  src/duckdb_kernel/parser/tokenizer/__init__.py
76
+ src/duckdb_kernel/parser/util/QuerySplitter.py
76
77
  src/duckdb_kernel/parser/util/RenamableColumn.py
77
78
  src/duckdb_kernel/parser/util/RenamableColumnList.py
78
79
  src/duckdb_kernel/parser/util/__init__.py