duckrun 0.3.17.dev4__tar.gz → 0.3.17.dev5__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 (34) hide show
  1. {duckrun-0.3.17.dev4/duckrun.egg-info → duckrun-0.3.17.dev5}/PKG-INFO +1 -1
  2. duckrun-0.3.17.dev5/dbt/adapters/duckrun/__version__.py +1 -0
  3. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev5}/dbt/adapters/duckrun/delta_dml.py +30 -7
  4. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev5}/dbt/adapters/duckrun/engine.py +17 -0
  5. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev5/duckrun.egg-info}/PKG-INFO +1 -1
  6. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev5}/pyproject.toml +1 -1
  7. duckrun-0.3.17.dev4/dbt/adapters/duckrun/__version__.py +0 -1
  8. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev5}/LICENSE +0 -0
  9. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev5}/MANIFEST.in +0 -0
  10. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev5}/README.md +0 -0
  11. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev5}/dbt/adapters/duckrun/__init__.py +0 -0
  12. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev5}/dbt/adapters/duckrun/credentials.py +0 -0
  13. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev5}/dbt/adapters/duckrun/delta_plugin.py +0 -0
  14. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev5}/dbt/adapters/duckrun/environment.py +0 -0
  15. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev5}/dbt/adapters/duckrun/impl.py +0 -0
  16. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev5}/dbt/adapters/duckrun/remote.py +0 -0
  17. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev5}/dbt/adapters/duckrun/secret.py +0 -0
  18. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev5}/dbt/include/duckrun/__init__.py +0 -0
  19. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev5}/dbt/include/duckrun/dbt_project.yml +0 -0
  20. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev5}/dbt/include/duckrun/macros/catalog.sql +0 -0
  21. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev5}/dbt/include/duckrun/macros/materializations/_delta_core.sql +0 -0
  22. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev5}/dbt/include/duckrun/macros/materializations/delta.sql +0 -0
  23. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev5}/dbt/include/duckrun/macros/materializations/incremental.sql +0 -0
  24. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev5}/dbt/include/duckrun/macros/materializations/snapshot.sql +0 -0
  25. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev5}/dbt/include/duckrun/macros/materializations/table.sql +0 -0
  26. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev5}/duckrun/__init__.py +0 -0
  27. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev5}/duckrun/auth.py +0 -0
  28. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev5}/duckrun/delta_table.py +0 -0
  29. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev5}/duckrun/session.py +0 -0
  30. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev5}/duckrun.egg-info/SOURCES.txt +0 -0
  31. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev5}/duckrun.egg-info/dependency_links.txt +0 -0
  32. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev5}/duckrun.egg-info/requires.txt +0 -0
  33. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev5}/duckrun.egg-info/top_level.txt +0 -0
  34. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev5}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: duckrun
3
- Version: 0.3.17.dev4
3
+ Version: 0.3.17.dev5
4
4
  Summary: A dbt adapter that runs SQL in DuckDB and materializes to Delta Lake (delta_rs).
5
5
  Author: mim
6
6
  License: MIT
@@ -0,0 +1 @@
1
+ version = "0.3.17.dev5"
@@ -30,8 +30,11 @@ view`` (not ``table``), so they pass through too.
30
30
 
31
31
  Supported / unsupported (what reaches delta_rs):
32
32
 
33
- create [or replace] table x [if not exists] as <query> Delta overwrite (query: select/with/(…))
34
- create table x (<col defs>) empty Delta table (connection API only)
33
+ create [or replace] table x [if not exists] as <query> Delta CTAS (query: select/with/(…)); a
34
+ plain create errors if x is live, `or
35
+ replace` overwrites, `if not exists` no-ops
36
+ create [or replace] table x [if not exists] (<col defs>) empty Delta table (connection API only);
37
+ logs a CREATE TABLE op, same exists rules
35
38
  create temp/temporary table … native DuckDB (pass through) ── invariant:
36
39
  create view … native DuckDB (pass through) ── only TEMP
37
40
  and VIEW are
@@ -91,7 +94,7 @@ _CREATE_AS = re.compile(
91
94
  # `create [or replace] table [if not exists] <rel> (<col defs>)` — no `as`. Connection-API only
92
95
  # (see _create_coldefs): materializes an EMPTY Delta table so `CREATE TABLE` is always Delta-backed.
93
96
  _CREATE_COLDEFS = re.compile(
94
- r"\s*create\s+(?:or\s+replace\s+)?table\s+(?:if\s+not\s+exists\s+)?"
97
+ r"\s*create\s+(?P<orrep>or\s+replace\s+)?table\s+(?P<ine>if\s+not\s+exists\s+)?"
95
98
  r"(?P<rel>.+?)\s*\((?P<defs>.+)\)\s*;?\s*",
96
99
  re.I | re.S,
97
100
  )
@@ -293,10 +296,18 @@ class _DeltaDML:
293
296
  m.group("orrep") or not re.match(r"select\b", m.group("body").lstrip(), re.I)
294
297
  ):
295
298
  return False
299
+ live = self._exists(loc) and not is_dropped(self.cursor, loc, self.so)
296
300
  # `if not exists` over a live (non-tombstone) table is a no-op — just (re)surface the view.
297
- if m.group("ine") and self._exists(loc) and not is_dropped(self.cursor, loc, self.so):
301
+ if m.group("ine") and live:
298
302
  self._refresh_view(rel, schema, loc)
299
303
  return True
304
+ # Connection API: a plain `create table` must NOT silently clobber a live table — that's what
305
+ # `or replace` is for. (The dbt/cursor path keeps overwriting: dbt owns idempotent re-runs.)
306
+ if self.default_schema is not None and live and not m.group("orrep"):
307
+ raise ValueError(
308
+ f"table {schema}.{identifier} already exists — "
309
+ f"use CREATE OR REPLACE TABLE to replace it"
310
+ )
300
311
  data = self.cursor.sql(m.group("body"))
301
312
  # overwrite_schema so this replaces a prior table (or a drop-tombstone) wholesale — a live
302
313
  # table is recreated with the real schema, clearing any tombstone marker.
@@ -316,15 +327,27 @@ class _DeltaDML:
316
327
  schema, identifier, loc = self._resolve(rel)
317
328
  if not loc:
318
329
  return False
330
+ live = self._exists(loc) and not is_dropped(self.cursor, loc, self.so)
331
+ if m.group("ine") and live: # IF NOT EXISTS over a live table → no-op
332
+ self._refresh_view(rel, schema, loc)
333
+ return True
334
+ if live and not m.group("orrep"): # plain CREATE over a live table → error
335
+ raise ValueError(
336
+ f"table {schema}.{identifier} already exists — "
337
+ f"use CREATE OR REPLACE TABLE to replace it"
338
+ )
319
339
  # Let DuckDB parse the column defs (types, constraints, nested parens) by building the table
320
- # as a TEMP, then take a 0-row typed relation from it and write that as an empty Delta table.
340
+ # as a TEMP, then take its Arrow schema and create an EMPTY Delta table from it. DeltaTable.create
341
+ # logs a CREATE TABLE operation (not a WRITE/Overwrite). A live table or a drop-tombstone already
342
+ # has files at ``loc``, so it must be replaced (overwrite); otherwise create-if-absent (error).
321
343
  tmp = f"__duckrun_empty_{abs(hash((schema, identifier))) & 0xFFFFFFFF}"
322
344
  self.cursor.execute(f'create or replace temp table "{tmp}" ({m.group("defs")})')
323
345
  try:
324
- empty = self.cursor.sql(f'select * from "{tmp}" limit 0')
325
- engine.write_delta(loc, empty, "overwrite", overwrite_schema=True, storage_options=self.so)
346
+ arrow_schema = self.cursor.sql(f'select * from "{tmp}" limit 0').arrow().schema
326
347
  finally:
327
348
  self.cursor.execute(f'drop table if exists "{tmp}"')
349
+ mode = "overwrite" if self._exists(loc) else "error"
350
+ engine.create_empty_delta(loc, arrow_schema, mode=mode, storage_options=self.so)
328
351
  self._refresh_view(rel, schema, loc)
329
352
  return True
330
353
 
@@ -732,6 +732,23 @@ def write_delta(
732
732
  _maintain(dt, compaction_threshold)
733
733
 
734
734
 
735
+ def create_empty_delta(
736
+ path: str,
737
+ schema,
738
+ *,
739
+ mode: str = "error",
740
+ storage_options: Optional[Dict[str, str]] = None,
741
+ ) -> None:
742
+ """Create an EMPTY Delta table at ``path`` from an Arrow ``schema`` (no data files).
743
+
744
+ Used by the connection API's bare ``CREATE TABLE (col defs)``: it logs a ``CREATE TABLE``
745
+ operation rather than a ``WRITE``/``Overwrite``, which is what a create — not an overwrite —
746
+ should record. ``mode`` follows delta-rs: ``error`` (fail if the table exists), ``overwrite``
747
+ (replace an existing table or drop-tombstone), or ``ignore`` (no-op if it exists).
748
+ """
749
+ DeltaTable.create(path, schema, mode=mode, storage_options=storage_options)
750
+
751
+
735
752
  def append_if_unchanged(
736
753
  path: str,
737
754
  data,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: duckrun
3
- Version: 0.3.17.dev4
3
+ Version: 0.3.17.dev5
4
4
  Summary: A dbt adapter that runs SQL in DuckDB and materializes to Delta Lake (delta_rs).
5
5
  Author: mim
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "duckrun"
7
- version = "0.3.17.dev4"
7
+ version = "0.3.17.dev5"
8
8
  description = "A dbt adapter that runs SQL in DuckDB and materializes to Delta Lake (delta_rs)."
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -1 +0,0 @@
1
- version = "0.3.17.dev4"
File without changes
File without changes
File without changes
File without changes