duckrun 0.3.17.dev4__tar.gz → 0.3.17.dev6__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.dev6}/PKG-INFO +2 -2
  2. duckrun-0.3.17.dev6/dbt/adapters/duckrun/__version__.py +1 -0
  3. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev6}/dbt/adapters/duckrun/delta_dml.py +30 -7
  4. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev6}/dbt/adapters/duckrun/engine.py +17 -0
  5. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev6/duckrun.egg-info}/PKG-INFO +2 -2
  6. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev6}/duckrun.egg-info/requires.txt +1 -1
  7. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev6}/pyproject.toml +3 -4
  8. duckrun-0.3.17.dev4/dbt/adapters/duckrun/__version__.py +0 -1
  9. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev6}/LICENSE +0 -0
  10. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev6}/MANIFEST.in +0 -0
  11. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev6}/README.md +0 -0
  12. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev6}/dbt/adapters/duckrun/__init__.py +0 -0
  13. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev6}/dbt/adapters/duckrun/credentials.py +0 -0
  14. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev6}/dbt/adapters/duckrun/delta_plugin.py +0 -0
  15. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev6}/dbt/adapters/duckrun/environment.py +0 -0
  16. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev6}/dbt/adapters/duckrun/impl.py +0 -0
  17. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev6}/dbt/adapters/duckrun/remote.py +0 -0
  18. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev6}/dbt/adapters/duckrun/secret.py +0 -0
  19. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev6}/dbt/include/duckrun/__init__.py +0 -0
  20. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev6}/dbt/include/duckrun/dbt_project.yml +0 -0
  21. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev6}/dbt/include/duckrun/macros/catalog.sql +0 -0
  22. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev6}/dbt/include/duckrun/macros/materializations/_delta_core.sql +0 -0
  23. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev6}/dbt/include/duckrun/macros/materializations/delta.sql +0 -0
  24. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev6}/dbt/include/duckrun/macros/materializations/incremental.sql +0 -0
  25. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev6}/dbt/include/duckrun/macros/materializations/snapshot.sql +0 -0
  26. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev6}/dbt/include/duckrun/macros/materializations/table.sql +0 -0
  27. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev6}/duckrun/__init__.py +0 -0
  28. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev6}/duckrun/auth.py +0 -0
  29. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev6}/duckrun/delta_table.py +0 -0
  30. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev6}/duckrun/session.py +0 -0
  31. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev6}/duckrun.egg-info/SOURCES.txt +0 -0
  32. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev6}/duckrun.egg-info/dependency_links.txt +0 -0
  33. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev6}/duckrun.egg-info/top_level.txt +0 -0
  34. {duckrun-0.3.17.dev4 → duckrun-0.3.17.dev6}/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.dev6
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
@@ -12,7 +12,7 @@ Description-Content-Type: text/markdown
12
12
  License-File: LICENSE
13
13
  Requires-Dist: dbt-duckdb>=1.8
14
14
  Requires-Dist: dbt-core<2.0,>=1.8
15
- Requires-Dist: duckdb==1.5.4.dev18
15
+ Requires-Dist: duckdb>=1.5.4
16
16
  Requires-Dist: deltalake<1.5.1,>=1.5.0
17
17
  Requires-Dist: requests
18
18
  Provides-Extra: local
@@ -0,0 +1 @@
1
+ version = "0.3.17.dev6"
@@ -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.dev6
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
@@ -12,7 +12,7 @@ Description-Content-Type: text/markdown
12
12
  License-File: LICENSE
13
13
  Requires-Dist: dbt-duckdb>=1.8
14
14
  Requires-Dist: dbt-core<2.0,>=1.8
15
- Requires-Dist: duckdb==1.5.4.dev18
15
+ Requires-Dist: duckdb>=1.5.4
16
16
  Requires-Dist: deltalake<1.5.1,>=1.5.0
17
17
  Requires-Dist: requests
18
18
  Provides-Extra: local
@@ -1,6 +1,6 @@
1
1
  dbt-duckdb>=1.8
2
2
  dbt-core<2.0,>=1.8
3
- duckdb==1.5.4.dev18
3
+ duckdb>=1.5.4
4
4
  deltalake<1.5.1,>=1.5.0
5
5
  requests
6
6
 
@@ -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.dev6"
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"}
@@ -21,8 +21,7 @@ dependencies = [
21
21
  # fails at `from dbt.cli.main import dbtRunner`. Declared directly because we only depend on
22
22
  # dbt-core transitively, so the ceiling has to live here to bite.
23
23
  "dbt-core>=1.8,<2.0",
24
- # TEMPORARY pin to a duckdb dev build — TODO: move to "==1.5.4" (or a range) once stable
25
- # 1.5.4 ships (~end of month). 1.5.4.dev18 is the first build whose bundled duckdb-delta
24
+ # Floor at the 1.5.4 stable release. 1.5.4 is the first stable build whose bundled duckdb-delta
26
25
  # extension supports `delta_scan('...', version => N)` (duckdb-delta #312) — the version-pinned
27
26
  # read this project now relies on to make the incremental read and the write commit resolve at
28
27
  # ONE Delta snapshot (Spark single-snapshot MERGE parity; see the staging-read pin in
@@ -33,7 +32,7 @@ dependencies = [
33
32
  # disk-spill config (max_spill_size), which engine.merge_delta relies on to cap the merge's RAM
34
33
  # and avoid OOM on large upserts; the matching <1.5.1 ceiling avoids the deltalake delta-log
35
34
  # write-side regression, pinning exactly 1.5.0.
36
- "duckdb==1.5.4.dev18",
35
+ "duckdb>=1.5.4",
37
36
  "deltalake>=1.5.0,<1.5.1",
38
37
  # The top-level connection API (duckrun.connect) discovers OneLake tables via the DFS REST
39
38
  # API directly; requests is otherwise only a transitive dbt dependency.
@@ -1 +0,0 @@
1
- version = "0.3.17.dev4"
File without changes
File without changes
File without changes
File without changes