jupyter-duckdb 1.2.0.0__tar.gz → 1.2.0.2__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 (90) hide show
  1. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/PKG-INFO +1 -1
  2. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/db/Table.py +8 -0
  3. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/db/implementation/duckdb/Connection.py +19 -12
  4. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/db/implementation/postgres/Connection.py +19 -11
  5. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/db/implementation/sqlite/Connection.py +4 -2
  6. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/kernel.py +1 -1
  7. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/binary/ConditionalSet.py +1 -1
  8. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/util/RenamableColumn.py +1 -1
  9. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/jupyter_duckdb.egg-info/PKG-INFO +1 -1
  10. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/test/test_dc.py +49 -31
  11. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/test/test_ra.py +155 -125
  12. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/README.md +0 -0
  13. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/setup.cfg +0 -0
  14. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/setup.py +0 -0
  15. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/__init__.py +0 -0
  16. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/__main__.py +0 -0
  17. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/db/Column.py +0 -0
  18. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/db/Connection.py +0 -0
  19. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/db/Constraint.py +0 -0
  20. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/db/DatabaseError.py +0 -0
  21. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/db/ForeignKey.py +0 -0
  22. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/db/__init__.py +0 -0
  23. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/db/error/EmptyResultError.py +0 -0
  24. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/db/error/__init__.py +0 -0
  25. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/db/implementation/duckdb/__init__.py +0 -0
  26. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/db/implementation/postgres/__init__.py +0 -0
  27. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/db/implementation/postgres/util.py +0 -0
  28. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/db/implementation/sqlite/__init__.py +0 -0
  29. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/kernel.json +0 -0
  30. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/magics/MagicCommand.py +0 -0
  31. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/magics/MagicCommandCallback.py +0 -0
  32. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/magics/MagicCommandException.py +0 -0
  33. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/magics/MagicCommandHandler.py +0 -0
  34. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/magics/__init__.py +0 -0
  35. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/DCParser.py +0 -0
  36. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/LogicParser.py +0 -0
  37. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/RAParser.py +0 -0
  38. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/__init__.py +0 -0
  39. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/DCOperand.py +0 -0
  40. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/LogicElement.py +0 -0
  41. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/LogicOperand.py +0 -0
  42. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/LogicOperator.py +0 -0
  43. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/RABinaryOperator.py +0 -0
  44. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/RAElement.py +0 -0
  45. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/RAOperand.py +0 -0
  46. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/RAOperator.py +0 -0
  47. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/RAUnaryOperator.py +0 -0
  48. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/__init__.py +0 -0
  49. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/binary/Add.py +0 -0
  50. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/binary/And.py +0 -0
  51. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/binary/ArrowLeft.py +0 -0
  52. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/binary/Cross.py +0 -0
  53. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/binary/Difference.py +0 -0
  54. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/binary/Divide.py +0 -0
  55. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/binary/Division.py +0 -0
  56. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/binary/Equal.py +0 -0
  57. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/binary/GreaterThan.py +0 -0
  58. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/binary/GreaterThanEqual.py +0 -0
  59. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/binary/Intersection.py +0 -0
  60. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/binary/Join.py +0 -0
  61. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/binary/LessThan.py +0 -0
  62. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/binary/LessThanEqual.py +0 -0
  63. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/binary/Minus.py +0 -0
  64. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/binary/Multiply.py +0 -0
  65. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/binary/Or.py +0 -0
  66. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/binary/Unequal.py +0 -0
  67. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/binary/Union.py +0 -0
  68. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/binary/__init__.py +0 -0
  69. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/unary/Not.py +0 -0
  70. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/unary/Projection.py +0 -0
  71. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/unary/Rename.py +0 -0
  72. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/unary/Selection.py +0 -0
  73. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/elements/unary/__init__.py +0 -0
  74. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/tokenizer/Token.py +0 -0
  75. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/tokenizer/Tokenizer.py +0 -0
  76. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/tokenizer/__init__.py +0 -0
  77. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/util/RenamableColumnList.py +0 -0
  78. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/parser/util/__init__.py +0 -0
  79. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/util/ResultSetComparator.py +0 -0
  80. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/util/__init__.py +0 -0
  81. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/util/formatting.py +0 -0
  82. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/visualization/Drawer.py +0 -0
  83. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/visualization/RATreeDrawer.py +0 -0
  84. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/visualization/SchemaDrawer.py +0 -0
  85. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/duckdb_kernel/visualization/__init__.py +0 -0
  86. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/jupyter_duckdb.egg-info/SOURCES.txt +0 -0
  87. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/jupyter_duckdb.egg-info/dependency_links.txt +0 -0
  88. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/jupyter_duckdb.egg-info/requires.txt +0 -0
  89. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/src/jupyter_duckdb.egg-info/top_level.txt +0 -0
  90. {jupyter_duckdb-1.2.0.0 → jupyter_duckdb-1.2.0.2}/test/test_result_comparison.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: jupyter-duckdb
3
- Version: 1.2.0.0
3
+ Version: 1.2.0.2
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
@@ -14,11 +14,19 @@ class Table:
14
14
  self.unique_keys: List[Constraint] = []
15
15
  self.foreign_keys: List[ForeignKey] = []
16
16
 
17
+ @staticmethod
18
+ def normalize_name(name: str) -> str:
19
+ return name.lower()
20
+
17
21
  @property
18
22
  def id(self) -> str:
19
23
  name = re.sub(r'[^A-Za-z]', '_', self.name)
20
24
  return f'table_{name}'
21
25
 
26
+ @property
27
+ def normalized_name(self) -> str:
28
+ return self.normalize_name(self.name)
29
+
22
30
  def get_column(self, name: str) -> "Column":
23
31
  for column in self.columns:
24
32
  if column.name == name:
@@ -59,7 +59,7 @@ class Connection(Base):
59
59
  WHERE table_type == 'BASE TABLE'
60
60
  ''').fetchall():
61
61
  table = Table(table_name)
62
- tables[table_name] = table
62
+ tables[table.normalized_name] = table
63
63
 
64
64
  # Get column names and data types for each table.
65
65
  for table_name, column_name, data_type, is_nullable in self.con.execute('''
@@ -71,8 +71,9 @@ class Connection(Base):
71
71
  FROM information_schema.columns
72
72
  ORDER BY ordinal_position ASC
73
73
  ''').fetchall():
74
- if table_name in tables:
75
- table = tables[table_name]
74
+ normalized_table_name = Table.normalize_name(table_name)
75
+ if normalized_table_name in tables:
76
+ table = tables[normalized_table_name]
76
77
 
77
78
  column = Column(table, column_name, data_type, is_nullable == 'YES')
78
79
  table.columns.append(column)
@@ -88,10 +89,12 @@ class Connection(Base):
88
89
  ORDER BY constraint_index ASC
89
90
  ''').fetchall():
90
91
  # get table
91
- if table_name not in tables:
92
+ normalized_table_name = Table.normalize_name(table_name)
93
+
94
+ if normalized_table_name not in tables:
92
95
  raise AssertionError(f'unknown table {table_name} for constraint {constraint_index}')
93
96
 
94
- table = tables[table_name]
97
+ table = tables[normalized_table_name]
95
98
 
96
99
  # store constraint
97
100
  if constraint_index in constraints:
@@ -102,7 +105,7 @@ class Connection(Base):
102
105
  table,
103
106
  tuple(table.get_column(c) for c in constraint_columns)
104
107
  )
105
- constraints[(table_name, *constraint_columns)] = constraint
108
+ constraints[(normalized_table_name, *constraint_columns)] = constraint
106
109
 
107
110
  # store key
108
111
  if table.primary_key is not None:
@@ -121,10 +124,12 @@ class Connection(Base):
121
124
  ORDER BY constraint_index ASC
122
125
  ''').fetchall():
123
126
  # get table
124
- if table_name not in tables:
127
+ normalized_table_name = Table.normalize_name(table_name)
128
+
129
+ if normalized_table_name not in tables:
125
130
  raise AssertionError(f'unknown table {table_name} for constraint {constraint_index}')
126
131
 
127
- table = tables[table_name]
132
+ table = tables[normalized_table_name]
128
133
 
129
134
  # store constraint
130
135
  if constraint_index in constraints:
@@ -135,7 +140,7 @@ class Connection(Base):
135
140
  table,
136
141
  tuple(table.get_column(c) for c in constraint_columns)
137
142
  )
138
- constraints[(table_name, *constraint_columns)] = constraint
143
+ constraints[(normalized_table_name, *constraint_columns)] = constraint
139
144
 
140
145
  # store key
141
146
  table.unique_keys.append(constraint)
@@ -153,13 +158,15 @@ class Connection(Base):
153
158
  ORDER BY constraint_index ASC
154
159
  ''').fetchall():
155
160
  # get table
156
- if table_name not in tables:
161
+ normalized_table_name = Table.normalize_name(table_name)
162
+
163
+ if normalized_table_name not in tables:
157
164
  raise AssertionError(f'unknown table {table_name} for constraint {constraint_index}')
158
165
 
159
- table = tables[table_name]
166
+ table = tables[normalized_table_name]
160
167
 
161
168
  # lookup constraint
162
- constraint_key = (referenced_table, *referenced_column_names)
169
+ constraint_key = (Table.normalize_name(referenced_table), *referenced_column_names)
163
170
  if constraint_key not in constraints:
164
171
  raise AssertionError(f'constraint with key {constraint_key} not discovered previously')
165
172
 
@@ -88,7 +88,7 @@ class Connection(Base):
88
88
  WHERE table_schema='public' AND table_type='BASE TABLE'
89
89
  ''').fetchall():
90
90
  table = Table(table_name)
91
- tables[table_name] = table
91
+ tables[table.normalized_name] = table
92
92
 
93
93
  # Get column names and data types for each table.
94
94
  for table_name, column_name, data_type, is_nullable in self.con.execute('''
@@ -100,8 +100,9 @@ class Connection(Base):
100
100
  FROM information_schema.columns
101
101
  ORDER BY ordinal_position ASC
102
102
  ''').fetchall():
103
- if table_name in tables:
104
- table = tables[table_name]
103
+ normalized_table_name = Table.normalize_name(table_name)
104
+ if normalized_table_name in tables:
105
+ table = tables[normalized_table_name]
105
106
 
106
107
  column = Column(table, column_name, data_type, is_nullable == 'YES')
107
108
  table.columns.append(column)
@@ -126,10 +127,12 @@ class Connection(Base):
126
127
 
127
128
  for constraint_name, (table_name, column_names) in constraints_dict.items():
128
129
  # get table
129
- if table_name not in tables:
130
+ normalized_table_name = Table.normalize_name(table_name)
131
+
132
+ if normalized_table_name not in tables:
130
133
  raise AssertionError(f'unknown table {table_name} for constraint {constraint_index}')
131
134
 
132
- table = tables[table_name]
135
+ table = tables[normalized_table_name]
133
136
 
134
137
  # store constraint
135
138
  constraint = Constraint(
@@ -166,10 +169,12 @@ class Connection(Base):
166
169
 
167
170
  for constraint_name, (table_name, column_names) in constraints_dict.items():
168
171
  # get table
169
- if table_name not in tables:
172
+ normalized_table_name = Table.normalize_name(table_name)
173
+
174
+ if normalized_table_name not in tables:
170
175
  raise AssertionError(f'unknown table {table_name} for constraint {constraint_index}')
171
176
 
172
- table = tables[table_name]
177
+ table = tables[normalized_table_name]
173
178
 
174
179
  # store constraint
175
180
  constraint = Constraint(
@@ -197,20 +202,23 @@ class Connection(Base):
197
202
  raise AssertionError(f'could not parse foreign key definitions for table {source_table_name}')
198
203
 
199
204
  source_table_name = strip_delimiters(source_table_name)
205
+ normalized_source_table_name = Table.normalize_name(source_table_name)
200
206
  source_table_column_names = [strip_delimiters(c) for c in match.group(1).split(',')]
207
+
201
208
  target_table_name = strip_delimiters(match.group(2))
209
+ normalized_target_table_name = Table.normalize_name(target_table_name)
202
210
  target_table_column_names = [strip_delimiters(c) for c in match.group(3).split(',')]
203
211
 
204
212
  # get tables
205
- if source_table_name not in tables:
213
+ if normalized_source_table_name not in tables:
206
214
  raise AssertionError(f'unknown table {source_table_name} for foreign key {fk_name}')
207
215
 
208
- source_table = tables[source_table_name]
216
+ source_table = tables[normalized_source_table_name]
209
217
 
210
- if target_table_name not in tables:
218
+ if normalized_target_table_name not in tables:
211
219
  raise AssertionError(f'unknown table {target_table_name} for foreign key {fk_name}')
212
220
 
213
- target_table = tables[target_table_name]
221
+ target_table = tables[normalized_target_table_name]
214
222
 
215
223
  # store constraint
216
224
  constraint = Constraint(
@@ -61,7 +61,7 @@ class Connection(Base):
61
61
  WHERE type ='table' AND name NOT LIKE 'sqlite_%';
62
62
  ''').fetchall():
63
63
  table = Table(table_name)
64
- tables[table_name] = table
64
+ tables[table.normalized_name] = table
65
65
 
66
66
  # Get column names and data types for each table.
67
67
  for table_name, table in tables.items():
@@ -174,8 +174,10 @@ class Connection(Base):
174
174
  current_targets = []
175
175
 
176
176
  # add columns to parse later
177
+ normalized_to_table_name = Table.normalize_name(to_table_name)
178
+
177
179
  current_sources.append(table.get_column(from_col))
178
- current_targets.append(tables[to_table_name].get_column(to_col))
180
+ current_targets.append(tables[normalized_to_table_name].get_column(to_col))
179
181
 
180
182
  if len(current_sources) > 0:
181
183
  store()
@@ -313,7 +313,7 @@ class DuckDBKernel(Kernel):
313
313
  for dc in data_columns:
314
314
  found = 0
315
315
  for i, rc in enumerate(result_columns):
316
- if dc == rc:
316
+ if dc.lower() == rc.lower():
317
317
  column_order.append(i)
318
318
  found += 1
319
319
 
@@ -116,7 +116,7 @@ class ConditionalSet:
116
116
  underscore_regex = re.compile(r'_{1,}')
117
117
 
118
118
  for operand_i, operand in enumerate(dc_operands):
119
- source_columns = tables[operand.relation].columns
119
+ source_columns = tables[Table.normalize_name(operand.relation)].columns
120
120
 
121
121
  # Raise an exception if the given number of operands does not match
122
122
  # the number of attributes in the relation.
@@ -13,7 +13,7 @@ class RenamableColumn(Column):
13
13
  return f'{self.table.name}.{self.name}'
14
14
 
15
15
  def matches(self, name: str) -> bool:
16
- return self.name == name or self.full_name == name
16
+ return self.name.lower() == name.lower() or self.full_name.lower() == name.lower()
17
17
 
18
18
  def rename(self):
19
19
  old_name = self.current_name
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: jupyter-duckdb
3
- Version: 1.2.0.0
3
+ Version: 1.2.0.2
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
@@ -2,14 +2,32 @@ from duckdb_kernel.parser import DCParser
2
2
  from . import Connection
3
3
 
4
4
 
5
+ def test_case_insensitivity():
6
+ for query in (
7
+ '{ username | users(id, username) }',
8
+ '{ username | Users(id, username) }',
9
+ '{ username | USERS(id, username) }',
10
+ '{ username | uSers(id, username) }'
11
+ ):
12
+ root = DCParser.parse_query(query)
13
+
14
+ # execute to test case insensitivity
15
+ with Connection() as con:
16
+ assert con.execute_dc(root) == [
17
+ ('Alice',),
18
+ ('Bob',),
19
+ ('Charlie',)
20
+ ]
21
+
22
+
5
23
  def test_simple_queries():
6
24
  with Connection() as con:
7
25
  for query in [
8
- '{ id | users(id, _) }',
9
- '{ id | users (id, _) }',
10
- '{ id | users id,_ }',
11
- '{id|users(id,_)}',
12
- 'id | users (id ,_)',
26
+ '{ id | Users(id, _) }',
27
+ '{ id | Users (id, _) }',
28
+ '{ id | Users id,_ }',
29
+ '{id|Users(id,_)}',
30
+ 'id | Users (id ,_)',
13
31
  ]:
14
32
  root = DCParser.parse_query(query)
15
33
  assert con.execute_dc(root) == [
@@ -19,8 +37,8 @@ def test_simple_queries():
19
37
  ]
20
38
 
21
39
  for query in [
22
- '{ id, name | users(id, name) }',
23
- '{ id,name | users(id, name) }'
40
+ '{ id, name | Users(id, name) }',
41
+ '{ id,name | Users(id, name) }'
24
42
  ]:
25
43
  root = DCParser.parse_query(query)
26
44
  assert con.execute_dc(root) == [
@@ -32,14 +50,14 @@ def test_simple_queries():
32
50
 
33
51
  def test_asterisk_projection():
34
52
  with Connection() as con:
35
- root = DCParser.parse_query('{ * | users(id, _) }')
53
+ root = DCParser.parse_query('{ * | Users(id, _) }')
36
54
  assert con.execute_dc(root) == [
37
55
  (1,),
38
56
  (2,),
39
57
  (3,)
40
58
  ]
41
59
 
42
- root = DCParser.parse_query('{ * | users(id, name) }')
60
+ root = DCParser.parse_query('{ * | Users(id, name) }')
43
61
  assert con.execute_dc(root) == [
44
62
  (1, 'Alice'),
45
63
  (2, 'Bob'),
@@ -50,9 +68,9 @@ def test_asterisk_projection():
50
68
  def test_conditions():
51
69
  with Connection() as con:
52
70
  for query in [
53
- '{ name | users(id, name) ∧ id > 1 }',
54
- '{ name | users(id, name) ∧ id ≠ 1 }',
55
- '{ name | users(id, name) ∧ (id = 2 ∨ id = 3) }'
71
+ '{ name | Users(id, name) ∧ id > 1 }',
72
+ '{ name | Users(id, name) ∧ id ≠ 1 }',
73
+ '{ name | Users(id, name) ∧ (id = 2 ∨ id = 3) }'
56
74
  ]:
57
75
  root = DCParser.parse_query(query)
58
76
  assert con.execute_dc(root) == [
@@ -61,7 +79,7 @@ def test_conditions():
61
79
  ]
62
80
 
63
81
  for query in [
64
- '{ id | users(id, name) ∧ name > "B" ∧ name < "C" }'
82
+ '{ id | Users(id, name) ∧ name > "B" ∧ name < "C" }'
65
83
  ]:
66
84
  root = DCParser.parse_query(query)
67
85
  assert con.execute_dc(root) == [
@@ -73,7 +91,7 @@ def test_shortcut_conditions():
73
91
  with Connection() as con:
74
92
  # single shortcut conditions
75
93
  for query in [
76
- '{ name | users(1, name) }'
94
+ '{ name | Users(1, name) }'
77
95
  ]:
78
96
  root = DCParser.parse_query(query)
79
97
  assert con.execute_dc(root) == [
@@ -81,7 +99,7 @@ def test_shortcut_conditions():
81
99
  ]
82
100
 
83
101
  for query in [
84
- '{ season_name | seasons(1, 1, season_name) }'
102
+ '{ season_name | Seasons(1, 1, season_name) }'
85
103
  ]:
86
104
  root = DCParser.parse_query(query)
87
105
  assert con.execute_dc(root) == [
@@ -90,7 +108,7 @@ def test_shortcut_conditions():
90
108
 
91
109
  # multiple shortcut conditions
92
110
  for query in [
93
- '{ sname, ename | seasons(snum, 2, sname) ∧ episodes(enum, snum, 2, ename) }'
111
+ '{ sname, ename | Seasons(snum, 2, sname) ∧ Episodes(enum, snum, 2, ename) }'
94
112
  ]:
95
113
  root = DCParser.parse_query(query)
96
114
  assert con.execute_dc(root) == [
@@ -108,7 +126,7 @@ def test_joins():
108
126
  with Connection() as con:
109
127
  # with one attribute
110
128
  for query in [
111
- '{ sename | shows(shid, shname) ∧ seasons(senum, shid, sename) }'
129
+ '{ sename | Shows(shid, shname) ∧ Seasons(senum, shid, sename) }'
112
130
  ]:
113
131
  root = DCParser.parse_query(query)
114
132
  assert con.execute_dc(root) == [
@@ -119,8 +137,8 @@ def test_joins():
119
137
  ]
120
138
 
121
139
  for query in [
122
- '{ sename | shows(shid, shname) ∧ seasons(senum, shid, sename) ∧ shname = "Show 1" }',
123
- '{ sename | seasons(senum, shid, sename) ∧ shows(shid, "Show 1") }'
140
+ '{ sename | Shows(shid, shname) ∧ Seasons(senum, shid, sename) ∧ shname = "Show 1" }',
141
+ '{ sename | Seasons(senum, shid, sename) ∧ Shows(shid, "Show 1") }'
124
142
  ]:
125
143
  root = DCParser.parse_query(query)
126
144
  assert con.execute_dc(root) == [
@@ -130,7 +148,7 @@ def test_joins():
130
148
 
131
149
  # with multiple attributes
132
150
  for query in [
133
- '{ sname, ename | seasons(snum, shid, sname) ∧ episodes(enum, snum, shid, ename) ∧ shid = 2 }'
151
+ '{ sname, ename | Seasons(snum, shid, sname) ∧ Episodes(enum, snum, shid, ename) ∧ shid = 2 }'
134
152
  ]:
135
153
  root = DCParser.parse_query(query)
136
154
  assert con.execute_dc(root) == [
@@ -145,7 +163,7 @@ def test_joins():
145
163
 
146
164
  # join three relations
147
165
  for query in [
148
- '{ s2,c5 | shows(s1,s2) ∧ episodes(e1,e2,s1,e4) ∧ characters(c1,e1,c3,s1,c5) ∧ s1=2 ∧ e4="Show 2 / Season 1 / Episode 2" }'
166
+ '{ s2,c5 | Shows(s1,s2) ∧ Episodes(e1,e2,s1,e4) ∧ Characters(c1,e1,c3,s1,c5) ∧ s1=2 ∧ e4="Show 2 / Season 1 / Episode 2" }'
149
167
  ]:
150
168
  root = DCParser.parse_query(query)
151
169
  assert con.execute_dc(root) == [
@@ -153,7 +171,7 @@ def test_joins():
153
171
  ]
154
172
 
155
173
  # cross join
156
- root = DCParser.parse_query('{ sename | shows(shid1, shname) ∧ seasons(senum, shid2, sename) ∧ shid1 = shid2 }')
174
+ root = DCParser.parse_query('{ sename | Shows(shid1, shname) ∧ Seasons(senum, shid2, sename) ∧ shid1 = shid2 }')
157
175
  assert con.execute_dc(root) == [
158
176
  ('Show 1 / Season 1',),
159
177
  ('Show 1 / Season 2',),
@@ -162,8 +180,8 @@ def test_joins():
162
180
  ]
163
181
 
164
182
  for query in [
165
- '{ s2,c5 | shows(sa1,s2) ∧ episodes(e1,e2,sb1,e4) ∧ characters(c1,e1,c3,sb1,c5) ∧ sa1=2 ∧ sa1 = sb1 ∧ e4="Show 2 / Season 1 / Episode 2" }',
166
- '{ s2,c5 | shows(sa1,s2) ∧ episodes(e1,e2,sb1,e4) ∧ characters(c1,e1,c3,sc1,c5) ∧ sa1=2 ∧ sa1 = sb1 ∧ sb1 = sc1 ∧ e4="Show 2 / Season 1 / Episode 2" }'
183
+ '{ s2,c5 | Shows(sa1,s2) ∧ Episodes(e1,e2,sb1,e4) ∧ Characters(c1,e1,c3,sb1,c5) ∧ sa1=2 ∧ sa1 = sb1 ∧ e4="Show 2 / Season 1 / Episode 2" }',
184
+ '{ s2,c5 | Shows(sa1,s2) ∧ Episodes(e1,e2,sb1,e4) ∧ Characters(c1,e1,c3,sc1,c5) ∧ sa1=2 ∧ sa1 = sb1 ∧ sb1 = sc1 ∧ e4="Show 2 / Season 1 / Episode 2" }'
167
185
  ]:
168
186
  root = DCParser.parse_query(query)
169
187
  assert con.execute_dc(root) == [
@@ -175,10 +193,10 @@ def test_underscores():
175
193
  with Connection() as con:
176
194
  # distinct underscores
177
195
  for query in [
178
- '{ ename | seasons(snum, shid, sname) ∧ episodes(_, snum, shid, ename) ∧ shid = 2 }',
179
- '{ ename | seasons(snum, shid, sname) ∧ episodes(enum, _, shid, ename) ∧ shid = 2 }',
180
- '{ ename | seasons(snum, shid, sname) ∧ episodes(__, snum, shid, ename) ∧ shid = 2 }',
181
- '{ ename | seasons(snum, shid, sname) ∧ episodes(_, __, shid, ename) ∧ shid = 2 }'
196
+ '{ ename | Seasons(snum, shid, sname) ∧ Episodes(_, snum, shid, ename) ∧ shid = 2 }',
197
+ '{ ename | Seasons(snum, shid, sname) ∧ Episodes(enum, _, shid, ename) ∧ shid = 2 }',
198
+ '{ ename | Seasons(snum, shid, sname) ∧ Episodes(__, snum, shid, ename) ∧ shid = 2 }',
199
+ '{ ename | Seasons(snum, shid, sname) ∧ Episodes(_, __, shid, ename) ∧ shid = 2 }'
182
200
  ]:
183
201
  root = DCParser.parse_query(query)
184
202
  assert con.execute_dc(root) == [
@@ -193,7 +211,7 @@ def test_underscores():
193
211
 
194
212
  # reused underscores in a single relation
195
213
  for query in [
196
- '{ ename | seasons(snum, shid, sname) ∧ episodes(_, _, shid, ename) ∧ shid = 2 }'
214
+ '{ ename | Seasons(snum, shid, sname) ∧ Episodes(_, _, shid, ename) ∧ shid = 2 }'
197
215
  ]:
198
216
  root = DCParser.parse_query(query)
199
217
  assert con.execute_dc(root) == [
@@ -208,8 +226,8 @@ def test_underscores():
208
226
 
209
227
  # reused underscores in two different relations
210
228
  for query in [
211
- '{ ename | seasons(_, shid, _) ∧ episodes(_, _, shid, ename) ∧ shid = 2 }',
212
- '{ ename | seasons(_, shid, __) ∧ episodes(_, __, shid, ename) ∧ shid = 2 }'
229
+ '{ ename | Seasons(_, shid, _) ∧ Episodes(_, _, shid, ename) ∧ shid = 2 }',
230
+ '{ ename | Seasons(_, shid, __) ∧ Episodes(_, __, shid, ename) ∧ shid = 2 }'
213
231
  ]:
214
232
  root = DCParser.parse_query(query)
215
233
  assert con.execute_dc(root) == [