@sixb/ducklake 0.1.0 → 0.1.2

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 (40) hide show
  1. package/README.md +48 -4
  2. package/dist/ducklake-storage.d.ts +2 -1
  3. package/dist/ducklake-storage.d.ts.map +1 -1
  4. package/dist/index.js +637 -50
  5. package/dist/index.js.map +16 -14
  6. package/dist/internal/dataset-row-commit.d.ts +6 -0
  7. package/dist/internal/dataset-row-commit.d.ts.map +1 -1
  8. package/dist/internal/dataset-row-merge.d.ts +16 -0
  9. package/dist/internal/dataset-row-merge.d.ts.map +1 -0
  10. package/dist/internal/ducklake-catalog-schema.d.ts +4 -1
  11. package/dist/internal/ducklake-catalog-schema.d.ts.map +1 -1
  12. package/dist/internal/ducklake-current-dataset-definitions.d.ts.map +1 -1
  13. package/dist/internal/ducklake-dataset-catalog.d.ts +1 -0
  14. package/dist/internal/ducklake-dataset-catalog.d.ts.map +1 -1
  15. package/dist/internal/ducklake-merge-session.d.ts +21 -0
  16. package/dist/internal/ducklake-merge-session.d.ts.map +1 -0
  17. package/dist/internal/ducklake-row-reader.d.ts.map +1 -1
  18. package/dist/internal/ducklake-snapshot-reader.d.ts +1 -0
  19. package/dist/internal/ducklake-snapshot-reader.d.ts.map +1 -1
  20. package/dist/internal/ducklake-write-coordinator.d.ts +5 -1
  21. package/dist/internal/ducklake-write-coordinator.d.ts.map +1 -1
  22. package/dist/internal/ducklake-write-session.d.ts.map +1 -1
  23. package/dist/internal/schema.d.ts +2 -0
  24. package/dist/internal/schema.d.ts.map +1 -1
  25. package/dist/internal/versions.d.ts +1 -0
  26. package/dist/internal/versions.d.ts.map +1 -1
  27. package/package.json +7 -4
  28. package/src/ducklake-storage.ts +6 -0
  29. package/src/internal/dataset-row-commit.ts +95 -2
  30. package/src/internal/dataset-row-merge.ts +268 -0
  31. package/src/internal/ducklake-catalog-schema.ts +90 -1
  32. package/src/internal/ducklake-current-dataset-definitions.ts +14 -5
  33. package/src/internal/ducklake-dataset-catalog.ts +43 -9
  34. package/src/internal/ducklake-merge-session.ts +188 -0
  35. package/src/internal/ducklake-row-reader.ts +51 -27
  36. package/src/internal/ducklake-snapshot-reader.ts +9 -2
  37. package/src/internal/ducklake-write-coordinator.ts +160 -20
  38. package/src/internal/ducklake-write-session.ts +32 -5
  39. package/src/internal/schema.ts +7 -0
  40. package/src/internal/versions.ts +17 -1
package/README.md CHANGED
@@ -94,15 +94,22 @@ const report = await lakeStorage.runMaintenance({
94
94
  Reads, writes, SQL previews, and SQL transforms use the same DuckDB runtime and
95
95
  the same DuckLake PostgreSQL metadata pool. Work is serialized inside one
96
96
  `DuckLakeStorage` instance, so a queued DuckDB operation makes later operations
97
- wait. Only actual DuckDB work holds the runtime: batch appends, commits, SQL
98
- transforms, and metadata reads. A large streaming read can also make a later
99
- write wait until the stream is consumed or closed.
97
+ wait. Only actual DuckDB work holds the runtime: bounded read pages, batch
98
+ appends, commits, SQL transforms, and metadata reads.
99
+
100
+ Large `readRows(...)` calls materialize bounded pages, using a physical-row keyset when available,
101
+ and release the DuckDB queue between pages. This also applies when an explicit limit exceeds one
102
+ page. A JavaScript pipeline can therefore stream one DuckLake dataset directly into another on the
103
+ same provider without buffering the complete input or deadlocking at the destination appender's
104
+ first flush. The read remains pinned to one immutable snapshot and keeps its attachment lease until
105
+ the iterator completes or closes.
100
106
 
101
107
  A write does not hold the runtime while its source iterable is producing rows.
102
108
  `writeRows(...)` validates and stages rows in bounded in-memory batches, then
103
109
  takes a queue slot only to flush each batch into the staging table. Slow external
104
110
  reads (pagination, APIs, SFTP, retries) run outside the queue, so other reads and
105
- write batches can interleave between a write's batches.
111
+ write batches can interleave between a write's batches. Large in-memory writes
112
+ also yield to the event loop between batches.
106
113
 
107
114
  ```txt
108
115
  same provider instance:
@@ -146,6 +153,43 @@ use the same schema that DuckLake materializes.
146
153
 
147
154
  DuckLake stores Sixb `decimal` columns as `DECIMAL(38, 9)` and returns them as exact strings, including from SQL previews. Writes that need more than 29 integer digits or 9 fractional digits are rejected before DuckDB can round or overflow them.
148
155
 
156
+ ## Keyed Merges
157
+
158
+ Datasets with a primary key can apply ordered complete-row changes directly through the lake
159
+ provider. Key columns must be non-null strings; composite key order is significant.
160
+
161
+ ```ts
162
+ import { change, col, defineDataset } from "@sixb/core"
163
+
164
+ const invoices = defineDataset("erp.invoices", {
165
+ schema: [
166
+ col("id", "string"),
167
+ col("status", "string"),
168
+ col("customerId", "string"),
169
+ ],
170
+ primaryKey: "id",
171
+ })
172
+
173
+ await lakeStorage.createDataset(invoices)
174
+
175
+ const merge = await lakeStorage.beginMerge({ dataset: invoices })
176
+ await merge.writeChanges([
177
+ change.upsert({ id: "inv_1", status: "paid", customerId: "cust_1" }),
178
+ change.delete({ id: "inv_2" }),
179
+ ])
180
+ const result = await merge.commit()
181
+ ```
182
+
183
+ Changes remain ordered across `writeChanges(...)` calls, and the final change for a repeated key
184
+ wins. Upserts are complete rows rather than patches. Commit checks the dataset version captured by
185
+ `beginMerge`, applies effective changes atomically, and creates a version only when visible rows
186
+ change. An initial no-op returns `{ outcome: "unchanged", version: null }`; a later no-op returns the
187
+ existing latest version.
188
+
189
+ Snapshot, append, and SQL-transform writes to keyed datasets also enforce unique keys so a later
190
+ merge never starts from an ambiguous baseline. Application authors normally use
191
+ `defineSync(..., { mode: "merge" })`; the sync worker stages those changes through this contract.
192
+
149
193
  ## DuckLake SQL Transforms
150
194
 
151
195
  DuckLake SQL transforms let the provider run dataset-to-dataset transforms in
@@ -1,5 +1,5 @@
1
1
  import type { DatasetDefinition, DatasetRow, LakeStorageWithSql } from "@sixb/core";
2
- import type { BeginDatasetWriteInput, DatasetCatalogState, DatasetVersion, LakeWriteSession, ReadDatasetRowsInput } from "@sixb/core/lake-storage";
2
+ import type { BeginDatasetMergeInput, BeginDatasetWriteInput, DatasetCatalogState, DatasetVersion, LakeMergeSession, LakeWriteSession, ReadDatasetRowsInput } from "@sixb/core/lake-storage";
3
3
  import { DuckLakeSqlExecutor } from "./internal/ducklake-sql-executor";
4
4
  import type { DuckLakeMaintenanceOptions, DuckLakeMaintenanceReport, DuckLakeStorageOptions } from "./types";
5
5
  /**
@@ -29,6 +29,7 @@ export declare class DuckLakeStorage implements LakeStorageWithSql<"duckdb"> {
29
29
  listDatasetCatalogState(datasetIds: readonly string[]): Promise<readonly DatasetCatalogState[]>;
30
30
  listVersions(datasetId: string, limit?: number): Promise<readonly DatasetVersion[]>;
31
31
  beginWrite(input: BeginDatasetWriteInput): Promise<LakeWriteSession>;
32
+ beginMerge(input: BeginDatasetMergeInput): Promise<LakeMergeSession>;
32
33
  getLatestVersion(datasetId: string): Promise<DatasetVersion | null>;
33
34
  getVersion(datasetId: string, versionId: string): Promise<DatasetVersion | null>;
34
35
  readRows(input: ReadDatasetRowsInput): AsyncIterable<DatasetRow>;
@@ -1 +1 @@
1
- {"version":3,"file":"ducklake-storage.d.ts","sourceRoot":"","sources":["../src/ducklake-storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AACnF,OAAO,KAAK,EACV,sBAAsB,EACtB,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACrB,MAAM,yBAAyB,CAAA;AAMhC,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAA;AAEtE,OAAO,KAAK,EACV,0BAA0B,EAC1B,yBAAyB,EACzB,sBAAsB,EACvB,MAAM,SAAS,CAAA;AAEhB;;;;;;GAMG;AACH,qBAAa,eAAgB,YAAW,kBAAkB,CAAC,QAAQ,CAAC;IAClE,QAAQ,CAAC,QAAQ;;;MAA8C;IAC/D,QAAQ,CAAC,GAAG,EAAE,mBAAmB,CAAA;IAEjC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA2B;IACvD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAwB;IACjD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;IACjD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAmB;IACxC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAwB;IACvD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0B;gBAErC,OAAO,EAAE,sBAAsB;IAmCrC,aAAa,CAAC,UAAU,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAIxE,kCAAkC,CACtC,WAAW,EAAE,SAAS,iBAAiB,EAAE,GACxC,OAAO,CAAC,IAAI,CAAC;IAIV,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAIhE,YAAY,IAAI,OAAO,CAAC,SAAS,iBAAiB,EAAE,CAAC;IAIrD,uBAAuB,CAC3B,UAAU,EAAE,SAAS,MAAM,EAAE,GAC5B,OAAO,CAAC,SAAS,mBAAmB,EAAE,CAAC;IAIpC,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,cAAc,EAAE,CAAC;IAInF,UAAU,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAIpE,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAInE,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAItF,QAAQ,CAAC,KAAK,EAAE,oBAAoB,GAAG,aAAa,CAAC,UAAU,CAAC;IAI1D,cAAc,CAAC,OAAO,CAAC,EAAE,0BAA0B,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAI9F;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
1
+ {"version":3,"file":"ducklake-storage.d.ts","sourceRoot":"","sources":["../src/ducklake-storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AACnF,OAAO,KAAK,EACV,sBAAsB,EACtB,sBAAsB,EACtB,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,EACrB,MAAM,yBAAyB,CAAA;AAMhC,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAA;AAEtE,OAAO,KAAK,EACV,0BAA0B,EAC1B,yBAAyB,EACzB,sBAAsB,EACvB,MAAM,SAAS,CAAA;AAEhB;;;;;;GAMG;AACH,qBAAa,eAAgB,YAAW,kBAAkB,CAAC,QAAQ,CAAC;IAClE,QAAQ,CAAC,QAAQ;;;MAA8C;IAC/D,QAAQ,CAAC,GAAG,EAAE,mBAAmB,CAAA;IAEjC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA2B;IACvD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAwB;IACjD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;IACjD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAmB;IACxC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAwB;IACvD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0B;gBAErC,OAAO,EAAE,sBAAsB;IAmCrC,aAAa,CAAC,UAAU,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAIxE,kCAAkC,CACtC,WAAW,EAAE,SAAS,iBAAiB,EAAE,GACxC,OAAO,CAAC,IAAI,CAAC;IAIV,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAIhE,YAAY,IAAI,OAAO,CAAC,SAAS,iBAAiB,EAAE,CAAC;IAIrD,uBAAuB,CAC3B,UAAU,EAAE,SAAS,MAAM,EAAE,GAC5B,OAAO,CAAC,SAAS,mBAAmB,EAAE,CAAC;IAIpC,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,cAAc,EAAE,CAAC;IAInF,UAAU,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAIpE,UAAU,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAIpE,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAInE,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAItF,QAAQ,CAAC,KAAK,EAAE,oBAAoB,GAAG,aAAa,CAAC,UAAU,CAAC;IAI1D,cAAc,CAAC,OAAO,CAAC,EAAE,0BAA0B,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAI9F;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}