@sixb/ducklake 0.2.0 → 0.2.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.
@@ -0,0 +1,15 @@
1
+ import type { DuckDbQueryRuntime } from "./duckdb-runtime";
2
+ /**
3
+ * Install missing core extensions from `https://extensions.duckdb.org`.
4
+ *
5
+ * DuckDB's `INSTALL` downloads from `http://extensions.duckdb.org`, and fetching over HTTPS needs
6
+ * `httpfs`, which DuckDB itself fetches over HTTP. A host that only allows HTTPS by name, such as
7
+ * a Vercel sandbox whose firewall filters on TLS SNI, can reach neither. So the file is fetched
8
+ * here and handed to `INSTALL '<file>'`, which puts it where DuckDB looks; the plain `INSTALL`
9
+ * that follows is then a no-op, and `LOAD` still checks the extension's signature.
10
+ *
11
+ * Best effort: a failure is logged and leaves the extension to DuckDB's own `INSTALL`. A project
12
+ * that set `custom_extension_repository` keeps its own repository.
13
+ */
14
+ export declare function prefetchDuckDbExtensions(runtime: DuckDbQueryRuntime, extensions: readonly string[]): Promise<void>;
15
+ //# sourceMappingURL=duckdb-extensions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"duckdb-extensions.d.ts","sourceRoot":"","sources":["../../src/internal/duckdb-extensions.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAO1D;;;;;;;;;;;GAWG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,kBAAkB,EAC3B,UAAU,EAAE,SAAS,MAAM,EAAE,GAC5B,OAAO,CAAC,IAAI,CAAC,CAIf"}
@@ -1 +1 @@
1
- {"version":3,"file":"duckdb-runtime.d.ts","sourceRoot":"","sources":["../../src/internal/duckdb-runtime.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,WAAW,EAEjB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,KAAK,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAA;AAC5E,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,mBAAmB,EAAoB,MAAM,iBAAiB,CAAA;AAW/F;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IACjC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAChE,aAAa,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3D,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,WAAW,EAAE,GAAG,OAAO,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAA;IAChG,YAAY,CAAC,CAAC,EACZ,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,CAAC,QAAQ,EAAE,cAAc,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GACxD,OAAO,CAAC,CAAC,CAAC,CAAA;CACd;AAED,MAAM,WAAW,aAAc,SAAQ,kBAAkB;IACvD,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;IAC7E,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IAC5B;;;;;OAKG;IACH,aAAa,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,OAAO,EAAE,sBAAsB,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;IACzF,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACvB;AAED;;;;;GAKG;AACH,MAAM,MAAM,sBAAsB,GAAG,kBAAkB,CAAA;AAEvD,MAAM,WAAW,cAAc;IAC7B,UAAU,IAAI,IAAI,CAAA;IAClB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAA;IACnC,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,YAAY,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,GAAG,IAAI,CAAA;IAChE,MAAM,IAAI,IAAI,CAAA;CACf;AAED,UAAU,oBAAoB;IAC5B,QAAQ,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAA;IACpC,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAC1B;AAsND;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,aAAa,CAAC,CAuBxB;AAED;;;;GAIG;AACH,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,IAAI,CAAC,CAMf;AAED;;;GAGG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE,sBAAsB,EAC/B,YAAY,GAAE,oBAAyB,GACtC,OAAO,CAAC,IAAI,CAAC,CA8Bf"}
1
+ {"version":3,"file":"duckdb-runtime.d.ts","sourceRoot":"","sources":["../../src/internal/duckdb-runtime.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,WAAW,EAEjB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,KAAK,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAA;AAE5E,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,mBAAmB,EAAoB,MAAM,iBAAiB,CAAA;AAW/F;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IACjC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAChE,aAAa,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3D,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,WAAW,EAAE,GAAG,OAAO,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAA;IAChG,YAAY,CAAC,CAAC,EACZ,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,CAAC,QAAQ,EAAE,cAAc,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GACxD,OAAO,CAAC,CAAC,CAAC,CAAA;CACd;AAED,MAAM,WAAW,aAAc,SAAQ,kBAAkB;IACvD,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;IAC7E,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IAC5B;;;;;OAKG;IACH,aAAa,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,OAAO,EAAE,sBAAsB,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;IACzF,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACvB;AAED;;;;;GAKG;AACH,MAAM,MAAM,sBAAsB,GAAG,kBAAkB,CAAA;AAEvD,MAAM,WAAW,cAAc;IAC7B,UAAU,IAAI,IAAI,CAAA;IAClB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAA;IACnC,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,YAAY,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,GAAG,IAAI,CAAA;IAChE,MAAM,IAAI,IAAI,CAAA;CACf;AAED,UAAU,oBAAoB;IAC5B,QAAQ,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAA;IACpC,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAC1B;AAsND;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,aAAa,CAAC,CAuBxB;AAED;;;;GAIG;AACH,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,IAAI,CAAC,CASf;AAED;;;GAGG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE,sBAAsB,EAC/B,YAAY,GAAE,oBAAyB,GACtC,OAAO,CAAC,IAAI,CAAC,CA8Bf"}
@@ -1 +1 @@
1
- {"version":3,"file":"ducklake-change-reader.d.ts","sourceRoot":"","sources":["../../src/internal/ducklake-change-reader.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,cAAc,EAGnB,KAAK,uBAAuB,EAE7B,MAAM,yBAAyB,CAAA;AAChC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAA;AAGtD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAA;AAE9E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAA;AAOxE,sGAAsG;AACtG,qBAAa,oBAAoB;IAE7B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAFT,OAAO,EAAE,sBAAsB,EAC/B,WAAW,EAAE,yBAAyB,EACtC,SAAS,EAAE,sBAAsB;IAG9C,WAAW,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;CA2FlF"}
1
+ {"version":3,"file":"ducklake-change-reader.d.ts","sourceRoot":"","sources":["../../src/internal/ducklake-change-reader.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,cAAc,EAGnB,KAAK,uBAAuB,EAE7B,MAAM,yBAAyB,CAAA;AAChC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAA;AAGtD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAA;AAE9E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAA;AAOxE,sGAAsG;AACtG,qBAAa,oBAAoB;IAE7B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAFT,OAAO,EAAE,sBAAsB,EAC/B,WAAW,EAAE,yBAAyB,EACtC,SAAS,EAAE,sBAAsB;IAG9C,WAAW,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;CAwGlF"}
@@ -12,6 +12,8 @@ export interface DatasetSnapshotRow {
12
12
  readonly tableId: bigint;
13
13
  readonly createdAt: Date;
14
14
  readonly mode: DatasetVersionMode;
15
+ readonly rowsChanged: boolean;
16
+ readonly lineageChanged: boolean;
15
17
  readonly parentSnapshotId?: string;
16
18
  readonly metadata?: SixbCommitMetadata;
17
19
  }
@@ -56,6 +58,15 @@ export declare class DuckLakeSnapshotReader {
56
58
  listVersions(datasetId: string, limit?: number): Promise<readonly DatasetVersion[]>;
57
59
  getLatestVersion(datasetId: string): Promise<DatasetVersion | null>;
58
60
  getVersion(datasetId: string, versionId: string): Promise<DatasetVersion | null>;
61
+ /**
62
+ * Whether a version holds exactly the rows of an earlier version of the dataset: every version
63
+ * committed after that one, up to this one, changed no rows.
64
+ *
65
+ * Reads the snapshots that name the dataset's tables between the two, from metadata only. More
66
+ * than `UNCHANGED_ROWS_WALK_LIMIT` of them, or one that is no Sixb version, such as a change
67
+ * made outside Sixb, reads as false: the caller compares the rows instead.
68
+ */
69
+ holdsRowsOf(datasetId: string, versionId: string, earlierVersionId: string): Promise<boolean>;
59
70
  /**
60
71
  * Bulk catalog-summary read used by the dataset list view.
61
72
  *
@@ -1 +1 @@
1
- {"version":3,"file":"ducklake-snapshot-reader.d.ts","sourceRoot":"","sources":["../../src/internal/ducklake-snapshot-reader.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ducklake-snapshot-reader.d.ts","sourceRoot":"","sources":["../../src/internal/ducklake-snapshot-reader.ts"],"names":[],"mappings":"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"}
@@ -64,18 +64,19 @@ export declare class DuckLakeWriteCoordinator {
64
64
  /** A commit that changes no rows still creates a version for a first version or new provenance. */
65
65
  private noOpCreatesVersion;
66
66
  /**
67
- * The latest version a write that began without reading it compared its rows with: the one at
68
- * the lake snapshot its first read fixed. The version metadata also shows versions committed
69
- * since. One of this dataset means the rows were compared with an older version, so the write
70
- * reruns.
67
+ * The latest version a write that began without reading it replaces and compared its rows with:
68
+ * the one at the lake snapshot its first read fixed. The version metadata also shows versions
69
+ * committed since. One of this dataset means the write was prepared on an older version, so it
70
+ * reruns: a snapshot that changed rows would conflict with that version at commit anyway.
71
71
  */
72
72
  private latestVersionAtReadSnapshot;
73
73
  private versionForNoOpCommit;
74
74
  private rollbackTransaction;
75
75
  /**
76
76
  * Every version but a snapshot keeps its parent's rows, and the lineage it records merges the
77
- * parent's. A snapshot replaces its parent: it reads it only to guard on it, or on SQLite, whose
78
- * later reads inside the transaction would block its commit.
77
+ * parent's. A snapshot replaces its parent: it reads it first only to guard on it, or on SQLite,
78
+ * whose later reads inside the transaction would block its commit. Otherwise it reads it once
79
+ * its rows are written (see `latestVersionAtReadSnapshot`).
79
80
  */
80
81
  private beginVersionTransaction;
81
82
  private lastCommittedSnapshotId;
@@ -1 +1 @@
1
- {"version":3,"file":"ducklake-write-coordinator.d.ts","sourceRoot":"","sources":["../../src/internal/ducklake-write-coordinator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ducklake-write-coordinator.d.ts","sourceRoot":"","sources":["../../src/internal/ducklake-write-coordinator.ts"],"names":[],"mappings":"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"}
@@ -14,6 +14,10 @@ export interface SixbCommitMetadata {
14
14
  readonly schemaChange?: SixbSchemaChangeMetadata;
15
15
  /** As `encodeLineage` stored it: decoded only for the versions a read returns. */
16
16
  readonly lineage?: unknown;
17
+ /** As `DatasetVersion.rowsChanged`. Absent on versions written before Sixb recorded it. */
18
+ readonly rowsChanged?: boolean;
19
+ /** As `DatasetVersion.lineageChanged`. Absent on versions written before Sixb recorded it. */
20
+ readonly lineageChanged?: boolean;
17
21
  }
18
22
  export declare function parseVersionId(versionId: string): string;
19
23
  export declare function toVersionId(snapshotId: string): string;
@@ -1 +1 @@
1
- {"version":3,"file":"versions.d.ts","sourceRoot":"","sources":["../../src/internal/versions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmB,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAG9E,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CACxC;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAA;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,IAAI,CAAC,EAAE,cAAc,CAAC,MAAM,CAAC,CAAA;IACtC,QAAQ,CAAC,QAAQ,CAAC,EAAE,cAAc,CAAC,UAAU,CAAC,CAAA;IAC9C,QAAQ,CAAC,MAAM,CAAC,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAA;IAC1C,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,0BAA0B,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACvD,QAAQ,CAAC,YAAY,CAAC,EAAE,wBAAwB,CAAA;IAChD,kFAAkF;IAClF,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAC3B;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAWxD;AAED,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,kBAAkB,GAAG,SAAS,CA6ClF;AAED,4FAA4F;AAC5F,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAG5F;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,GACd;IAAE,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAA;CAAE,CAsBxE"}
1
+ {"version":3,"file":"versions.d.ts","sourceRoot":"","sources":["../../src/internal/versions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmB,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAG9E,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CACxC;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAA;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,IAAI,CAAC,EAAE,cAAc,CAAC,MAAM,CAAC,CAAA;IACtC,QAAQ,CAAC,QAAQ,CAAC,EAAE,cAAc,CAAC,UAAU,CAAC,CAAA;IAC9C,QAAQ,CAAC,MAAM,CAAC,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAA;IAC1C,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,0BAA0B,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACvD,QAAQ,CAAC,YAAY,CAAC,EAAE,wBAAwB,CAAA;IAChD,kFAAkF;IAClF,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;IAC1B,2FAA2F;IAC3F,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAA;IAC9B,8FAA8F;IAC9F,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAA;CAClC;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAWxD;AAED,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,kBAAkB,GAAG,SAAS,CAgDlF;AAED,4FAA4F;AAC5F,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAG5F;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,GACd;IAAE,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAA;CAAE,CAsBxE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sixb/ducklake",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "DuckDB/DuckLake lake storage provider for Sixb",
5
5
  "keywords": [
6
6
  "sixb",
@@ -36,7 +36,7 @@
36
36
  "typecheck": "tsc --noEmit",
37
37
  "test": "bun test",
38
38
  "test:e2e": "bun run test:e2e:local && bun run test:e2e:remote",
39
- "test:e2e:local": "bun test --preload ./tests/extensions.ts ./tests/ducklake-reader.e2e.ts ./tests/ducklake-changes.e2e.ts ./tests/ducklake-contract.e2e.ts ./tests/ducklake-catalog-state.e2e.ts ./tests/ducklake-catalogs.e2e.ts ./tests/ducklake-concurrency.e2e.ts ./tests/ducklake-datasets.e2e.ts ./tests/ducklake-driver.e2e.ts ./tests/ducklake-maintenance.e2e.ts ./tests/ducklake-merges.e2e.ts ./tests/ducklake-sql-transforms.e2e.ts ./tests/ducklake-versions.e2e.ts ./tests/ducklake-long-history.e2e.ts ./tests/ducklake-writes.e2e.ts ./tests/ducklake-sqlite-writes.e2e.ts",
39
+ "test:e2e:local": "bun test --preload ./tests/extensions.ts ./tests/duckdb-extensions.e2e.ts ./tests/ducklake-reader.e2e.ts ./tests/ducklake-changes.e2e.ts ./tests/ducklake-contract.e2e.ts ./tests/ducklake-catalog-state.e2e.ts ./tests/ducklake-catalogs.e2e.ts ./tests/ducklake-concurrency.e2e.ts ./tests/ducklake-datasets.e2e.ts ./tests/ducklake-driver.e2e.ts ./tests/ducklake-maintenance.e2e.ts ./tests/ducklake-merges.e2e.ts ./tests/ducklake-sql-transforms.e2e.ts ./tests/ducklake-versions.e2e.ts ./tests/ducklake-long-history.e2e.ts ./tests/ducklake-writes.e2e.ts ./tests/ducklake-sqlite-writes.e2e.ts",
40
40
  "test:e2e:remote": "bun test --preload ./tests/extensions.ts --preload ./tests/setup.ts ./tests/ducklake-remote.e2e.ts",
41
41
  "prepack": "bun run build"
42
42
  },
@@ -44,10 +44,10 @@
44
44
  "@duckdb/node-api": "1.5.2-r.2"
45
45
  },
46
46
  "peerDependencies": {
47
- "@sixb/core": "^0.2.0"
47
+ "@sixb/core": "^0.2.2"
48
48
  },
49
49
  "devDependencies": {
50
- "@sixb/core": "0.2.0",
50
+ "@sixb/core": "0.2.2",
51
51
  "@types/bun": "latest",
52
52
  "typescript": "^5.7.0"
53
53
  },
@@ -313,19 +313,26 @@ function primaryKeyMatchSql(
313
313
  .join(" AND ")
314
314
  }
315
315
 
316
+ /**
317
+ * Whether a staged upsert changes the stored row of its key. A row that differs only in its
318
+ * `sequenceBy` column is the stored row delivered again (`isSequenceOnlyChange`): it stays as is,
319
+ * while the companion table still advances the key's ordering.
320
+ */
316
321
  function datasetRowDifferenceSql(
317
322
  dataset: DatasetDefinition,
318
323
  leftAlias: string,
319
324
  rightAlias: string
320
325
  ): string {
321
- return dataset.schema.columns
326
+ const differences = dataset.schema.columns
327
+ .filter((column) => column.name !== dataset.sequenceBy)
322
328
  .map(
323
329
  (column) =>
324
330
  `${leftAlias}.${quoteIdentifier(column.name)} IS DISTINCT FROM ${rightAlias}.${quoteIdentifier(
325
331
  column.name
326
332
  )}`
327
333
  )
328
- .join(" OR ")
334
+
335
+ return differences.length > 0 ? differences.join(" OR ") : "FALSE"
329
336
  }
330
337
 
331
338
  async function countRows(runtime: DuckDbQueryRuntime, relationSql: string): Promise<number> {
@@ -0,0 +1,102 @@
1
+ import { mkdtemp, rm, writeFile } from "node:fs/promises"
2
+ import { tmpdir } from "node:os"
3
+ import { join } from "node:path"
4
+ import { promisify } from "node:util"
5
+ import { gunzip } from "node:zlib"
6
+ import type { DuckDbQueryRuntime } from "./duckdb-runtime"
7
+ import { quoteSqlString, quoteSqlStringList } from "./sql"
8
+
9
+ const extensionsUrl = "https://extensions.duckdb.org"
10
+ const downloadTimeoutMillis = 60_000
11
+ const gunzipAsync = promisify(gunzip)
12
+
13
+ /**
14
+ * Install missing core extensions from `https://extensions.duckdb.org`.
15
+ *
16
+ * DuckDB's `INSTALL` downloads from `http://extensions.duckdb.org`, and fetching over HTTPS needs
17
+ * `httpfs`, which DuckDB itself fetches over HTTP. A host that only allows HTTPS by name, such as
18
+ * a Vercel sandbox whose firewall filters on TLS SNI, can reach neither. So the file is fetched
19
+ * here and handed to `INSTALL '<file>'`, which puts it where DuckDB looks; the plain `INSTALL`
20
+ * that follows is then a no-op, and `LOAD` still checks the extension's signature.
21
+ *
22
+ * Best effort: a failure is logged and leaves the extension to DuckDB's own `INSTALL`. A project
23
+ * that set `custom_extension_repository` keeps its own repository.
24
+ */
25
+ export async function prefetchDuckDbExtensions(
26
+ runtime: DuckDbQueryRuntime,
27
+ extensions: readonly string[]
28
+ ): Promise<void> {
29
+ await prefetch(runtime, extensions).catch((error: unknown) =>
30
+ warnFallback(extensions.join("', '"), error)
31
+ )
32
+ }
33
+
34
+ async function prefetch(runtime: DuckDbQueryRuntime, extensions: readonly string[]) {
35
+ const [target] = await runtime.query(`
36
+ SELECT
37
+ version() AS version,
38
+ (SELECT platform FROM pragma_platform()) AS platform,
39
+ current_setting('custom_extension_repository') AS repository
40
+ `)
41
+ if (target?.repository !== "") return
42
+
43
+ const missing = await missingExtensions(runtime, extensions)
44
+ if (missing.length === 0) return
45
+
46
+ const directory = await mkdtemp(join(tmpdir(), "sixb-duckdb-extensions-"))
47
+ try {
48
+ const downloads = await Promise.all(
49
+ missing.map(async (name) => ({
50
+ name,
51
+ file: await download(`${target.version}/${target.platform}/${name}`, directory, name).catch(
52
+ (error: unknown) => warnFallback(name, error)
53
+ ),
54
+ }))
55
+ )
56
+
57
+ // One at a time: the runtime runs statements in order anyway, and this keeps failures apart.
58
+ for (const { name, file } of downloads) {
59
+ if (file === undefined) continue
60
+ await runtime
61
+ .run(`INSTALL ${quoteSqlString(file)}`)
62
+ .catch((error: unknown) => warnFallback(name, error))
63
+ }
64
+ } finally {
65
+ await rm(directory, { recursive: true, force: true })
66
+ }
67
+ }
68
+
69
+ function warnFallback(name: string, error: unknown): undefined {
70
+ const reason = error instanceof Error ? error.message : String(error)
71
+ console.warn(
72
+ `[SixbDuckLake] Could not install DuckDB extension '${name}' over HTTPS (${reason}); falling back to DuckDB's INSTALL.`
73
+ )
74
+ return undefined
75
+ }
76
+
77
+ /** Canonical names of the requested extensions not installed yet: `sqlite` is `sqlite_scanner`. */
78
+ async function missingExtensions(
79
+ runtime: DuckDbQueryRuntime,
80
+ extensions: readonly string[]
81
+ ): Promise<string[]> {
82
+ const requested = `[${quoteSqlStringList(extensions.map((extension) => extension.toLowerCase()))}]`
83
+ const rows = await runtime.query(`
84
+ SELECT extension_name
85
+ FROM duckdb_extensions()
86
+ WHERE NOT installed
87
+ AND (list_contains(${requested}, extension_name) OR list_has_any(${requested}, aliases))
88
+ `)
89
+ return rows.map((row) => String(row.extension_name))
90
+ }
91
+
92
+ /** `INSTALL '<file>'` names the extension after the file, so it is written as `<name>.duckdb_extension`. */
93
+ async function download(path: string, directory: string, name: string): Promise<string> {
94
+ const response = await fetch(`${extensionsUrl}/${path}.duckdb_extension.gz`, {
95
+ signal: AbortSignal.timeout(downloadTimeoutMillis),
96
+ })
97
+ if (!response.ok) throw new Error(`HTTP ${response.status}`)
98
+
99
+ const file = join(directory, `${name}.duckdb_extension`)
100
+ await writeFile(file, await gunzipAsync(new Uint8Array(await response.arrayBuffer())))
101
+ return file
102
+ }
@@ -8,6 +8,7 @@ import {
8
8
  } from "@duckdb/node-api"
9
9
  import { LakeStorageError } from "@sixb/core/lake-storage"
10
10
  import type { DuckDbRuntimeOptions, DuckLakeStorageOptions } from "../types"
11
+ import { prefetchDuckDbExtensions } from "./duckdb-extensions"
11
12
  import { type DuckDbReader, type DuckDbReaderOptions, NodeDuckDbReader } from "./duckdb-reader"
12
13
  import { sixbDuckDbValueConverter } from "./duckdb-value-converter"
13
14
  import {
@@ -323,9 +324,12 @@ export async function installDuckLakeExtensions(
323
324
  runtime: DuckDbRuntime,
324
325
  options: DuckLakeStorageOptions
325
326
  ): Promise<void> {
327
+ const extensions = requiredExtensions(options)
328
+ await prefetchDuckDbExtensions(runtime, ["ducklake", ...extensions])
329
+
326
330
  await runtime.run("INSTALL ducklake")
327
331
 
328
- for (const extension of requiredExtensions(options)) {
332
+ for (const extension of extensions) {
329
333
  await runtime.run(`INSTALL ${quoteIdentifier(extension)}`)
330
334
  }
331
335
  }
@@ -33,6 +33,13 @@ export class DuckLakeChangeReader {
33
33
  const after = await this.snapshots.getVersion(input.datasetId, input.toVersionId)
34
34
  const columns = resolveDatasetChangeColumns(input, before, after)
35
35
  if (!columns) return null
36
+
37
+ // Versions that only record new provenance or source ordering hold their parent's rows: their
38
+ // change set is empty, whatever the keys, so it needs neither the key checks nor the join.
39
+ const unchanged =
40
+ (input.toVersionId === input.fromVersionId || !after!.rowsChanged) &&
41
+ (await this.snapshots.holdsRowsOf(input.datasetId, input.toVersionId, input.fromVersionId))
42
+
36
43
  const lease = await this.connections.acquireAttachedRuntime()
37
44
  const runtime = lease.runtime
38
45
  const temporary = quoteIdentifier(`sixb_delta_${randomUUID().replaceAll("-", "")}`)
@@ -44,6 +51,12 @@ export class DuckLakeChangeReader {
44
51
  const table = qualifiedTableName(this.options, ref.tableName)
45
52
  const oldRelation = `${table} AT (VERSION => ${parseVersionId(input.fromVersionId)})`
46
53
  const newRelation = `${table} AT (VERSION => ${parseVersionId(input.toVersionId)})`
54
+ if (unchanged) {
55
+ return noChanges(
56
+ after!.rowCount ?? before!.rowCount ?? (await countRows(runtime, newRelation))
57
+ )
58
+ }
59
+
47
60
  const previousCount = await uniqueRowCount(runtime, oldRelation, input.keyColumns)
48
61
  const nextCount = await uniqueRowCount(runtime, newRelation, input.keyColumns)
49
62
  if (previousCount === null || nextCount === null) return null
@@ -120,6 +133,23 @@ export class DuckLakeChangeReader {
120
133
  }
121
134
  }
122
135
 
136
+ function noChanges(rowCount: number): DatasetChanges {
137
+ return {
138
+ fromRowCount: rowCount,
139
+ toRowCount: rowCount,
140
+ changeCount: 0,
141
+ changes: (async function* () {
142
+ yield* []
143
+ })(),
144
+ async close() {},
145
+ }
146
+ }
147
+
148
+ async function countRows(runtime: DuckDbQueryRuntime, relation: string): Promise<number> {
149
+ const [row] = await runtime.query(`SELECT count(*) AS total FROM ${relation}`)
150
+ return safeCount(row!, "total")
151
+ }
152
+
123
153
  async function uniqueRowCount(
124
154
  runtime: DuckDbQueryRuntime,
125
155
  relation: string,
@@ -44,6 +44,8 @@ export interface DatasetSnapshotRow {
44
44
  readonly tableId: bigint
45
45
  readonly createdAt: Date
46
46
  readonly mode: DatasetVersionMode
47
+ readonly rowsChanged: boolean
48
+ readonly lineageChanged: boolean
47
49
  readonly parentSnapshotId?: string
48
50
  readonly metadata?: SixbCommitMetadata
49
51
  }
@@ -66,6 +68,8 @@ interface SnapshotCandidateQueryInput {
66
68
  readonly table: DatasetTableRef
67
69
  readonly exactSnapshotId?: string
68
70
  readonly beforeSnapshotId?: string
71
+ /** Inclusive lower bound. */
72
+ readonly fromSnapshotId?: string
69
73
  readonly limit: number
70
74
  }
71
75
 
@@ -110,6 +114,10 @@ const FEED_PAGE_SIZE = 512
110
114
  // metadata of its version, whose lineage may be large.
111
115
  const SHORT_READ_BATCH_SIZE = 8
112
116
 
117
+ // A change read between two versions of identical rows skips comparing them. Consumers read changes
118
+ // for every version they apply, so few versions usually stand between the two.
119
+ const UNCHANGED_ROWS_WALK_LIMIT = 32
120
+
113
121
  // The bulk catalog scan shares one descending walk of recent snapshots across
114
122
  // all requested datasets, so its cost is bounded by this window rather than by
115
123
  // the dataset count. A dataset whose latest version is older than the window
@@ -181,6 +189,60 @@ export class DuckLakeSnapshotReader {
181
189
  })
182
190
  }
183
191
 
192
+ /**
193
+ * Whether a version holds exactly the rows of an earlier version of the dataset: every version
194
+ * committed after that one, up to this one, changed no rows.
195
+ *
196
+ * Reads the snapshots that name the dataset's tables between the two, from metadata only. More
197
+ * than `UNCHANGED_ROWS_WALK_LIMIT` of them, or one that is no Sixb version, such as a change
198
+ * made outside Sixb, reads as false: the caller compares the rows instead.
199
+ */
200
+ async holdsRowsOf(
201
+ datasetId: string,
202
+ versionId: string,
203
+ earlierVersionId: string
204
+ ): Promise<boolean> {
205
+ const snapshotId = parseVersionId(versionId)
206
+ const earlierSnapshotId = parseVersionId(earlierVersionId)
207
+ if (snapshotId === earlierSnapshotId) {
208
+ return true
209
+ }
210
+ if (BigInt(snapshotId) < BigInt(earlierSnapshotId)) {
211
+ return false
212
+ }
213
+
214
+ this.connections.assertOpen()
215
+
216
+ return this.connections.withAttachedRuntime(async (runtime) => {
217
+ const tableRef = await resolveDatasetTableRef(this.options, runtime, datasetId)
218
+ if (!tableRef) {
219
+ return false
220
+ }
221
+
222
+ // Newest first: this version, the snapshots between, then the earlier version itself.
223
+ const candidates = await this.querySnapshotCandidates(runtime, {
224
+ table: tableRef,
225
+ beforeSnapshotId: String(BigInt(snapshotId) + 1n),
226
+ fromSnapshotId: earlierSnapshotId,
227
+ limit: UNCHANGED_ROWS_WALK_LIMIT + 1,
228
+ })
229
+ if (
230
+ candidates[0]?.snapshotId !== snapshotId ||
231
+ candidates[candidates.length - 1]?.snapshotId !== earlierSnapshotId
232
+ ) {
233
+ return false
234
+ }
235
+
236
+ return candidates
237
+ .slice(0, -1)
238
+ .every(
239
+ (candidate) =>
240
+ this.candidateToSnapshotRow(datasetId, tableRef.tableId, candidate)?.rowsChanged ===
241
+ false
242
+ )
243
+ })
244
+ }
245
+
184
246
  /**
185
247
  * Bulk catalog-summary read used by the dataset list view.
186
248
  *
@@ -905,6 +967,9 @@ export class DuckLakeSnapshotReader {
905
967
  if (input.beforeSnapshotId !== undefined) {
906
968
  assertDuckLakeSnapshotId(input.beforeSnapshotId)
907
969
  }
970
+ if (input.fromSnapshotId !== undefined) {
971
+ assertDuckLakeSnapshotId(input.fromSnapshotId)
972
+ }
908
973
 
909
974
  const rows = await runtime.query(
910
975
  buildDuckLakeMetadataQuery(this.options, (table) => {
@@ -924,6 +989,9 @@ export class DuckLakeSnapshotReader {
924
989
  if (input.beforeSnapshotId !== undefined) {
925
990
  bounds.push(`changes.snapshot_id < ${input.beforeSnapshotId}`)
926
991
  }
992
+ if (input.fromSnapshotId !== undefined) {
993
+ bounds.push(`changes.snapshot_id >= ${input.fromSnapshotId}`)
994
+ }
927
995
 
928
996
  const namesDatasetTable = datasetTableIds(input.table)
929
997
  .map(
@@ -1022,6 +1090,8 @@ export class DuckLakeSnapshotReader {
1022
1090
  tableId,
1023
1091
  createdAt: candidate.createdAt,
1024
1092
  mode: metadata.mode ?? "schema",
1093
+ rowsChanged: metadata.rowsChanged ?? true,
1094
+ lineageChanged: metadata.lineageChanged ?? true,
1025
1095
  metadata,
1026
1096
  }
1027
1097
  }
@@ -1031,11 +1101,14 @@ export class DuckLakeSnapshotReader {
1031
1101
  // points elsewhere, fail loudly rather than hydrating the wrong lineage.
1032
1102
  this.assertNoMetadataConflict(candidate.snapshotId, datasetId, candidate.metadata)
1033
1103
 
1104
+ // DuckLake recorded a change to the table's rows, whatever the metadata says.
1034
1105
  return {
1035
1106
  snapshotId: candidate.snapshotId,
1036
1107
  tableId,
1037
1108
  createdAt: candidate.createdAt,
1038
1109
  mode: candidate.metadata?.mode ?? (hasDeleteChange ? "snapshot" : "append"),
1110
+ rowsChanged: true,
1111
+ lineageChanged: candidate.metadata?.lineageChanged ?? true,
1039
1112
  ...(candidate.metadata !== undefined ? { metadata: candidate.metadata } : {}),
1040
1113
  }
1041
1114
  }
@@ -1089,6 +1162,8 @@ function snapshotToVersion(
1089
1162
  producer: row.metadata?.producer,
1090
1163
  inputs: row.metadata?.inputs,
1091
1164
  ...storedLineage(tableRef.datasetId, row),
1165
+ rowsChanged: row.rowsChanged,
1166
+ lineageChanged: row.lineageChanged,
1092
1167
  ...(row.metadata?.rowCount !== undefined ? { rowCount: row.metadata.rowCount } : {}),
1093
1168
  }
1094
1169
  }
@@ -15,6 +15,7 @@ import type {
15
15
  import {
16
16
  assertUnsequencedDatasetWrite,
17
17
  getDatasetPrimaryKeyColumns,
18
+ hasDatasetLineageChanges,
18
19
  hasDatasetProvenanceChanges,
19
20
  LakeConcurrencyError,
20
21
  LakeStorageError,
@@ -321,12 +322,12 @@ export class DuckLakeWriteCoordinator {
321
322
  })
322
323
  input.signal?.throwIfAborted()
323
324
 
325
+ // The version this one replaces or builds on: what it records having changed compares with.
326
+ const parent =
327
+ latestVersion === undefined ? await this.latestVersionAtReadSnapshot(input) : latestVersion
328
+
324
329
  // A commit that changes no rows is decided against the latest version it compared with.
325
- const noOpBase = changeResult.dataChangeExpected
326
- ? undefined
327
- : latestVersion === undefined
328
- ? await this.latestVersionAtReadSnapshot(input)
329
- : latestVersion
330
+ const noOpBase = changeResult.dataChangeExpected ? undefined : parent
330
331
 
331
332
  const createsVersion =
332
333
  noOpBase === undefined || this.noOpCreatesVersion(input, noOpBase, lineage)
@@ -339,7 +340,16 @@ export class DuckLakeWriteCoordinator {
339
340
  input,
340
341
  commitId,
341
342
  commitRowCount(input, changeResult, latestVersion),
342
- lineage
343
+ lineage,
344
+ {
345
+ rowsChanged: parent === null || changeResult.changedTableRows,
346
+ lineageChanged: hasDatasetLineageChanges(parent, {
347
+ datasetId: input.dataset.id,
348
+ schema: input.dataset.schema,
349
+ producer: input.producer,
350
+ lineage,
351
+ }),
352
+ }
343
353
  )
344
354
 
345
355
  await commitVersionTransaction(
@@ -477,7 +487,8 @@ export class DuckLakeWriteCoordinator {
477
487
  input: DuckLakeCommitVersionOutcomeRuntimeInput,
478
488
  commitId: string,
479
489
  rowCount: CommitRowCount,
480
- lineage: DatasetVersionLineage | undefined
490
+ lineage: DatasetVersionLineage | undefined,
491
+ changed: Pick<DatasetVersion, "rowsChanged" | "lineageChanged">
481
492
  ): Promise<void> {
482
493
  // DuckLake stores this JSON on the snapshot it creates for the current
483
494
  // transaction. Version id, timestamp, and data-change detection still come
@@ -498,6 +509,8 @@ export class DuckLakeWriteCoordinator {
498
509
  ? { validatedPrimaryKeyColumns: [...validatedPrimaryKeyColumns] }
499
510
  : {}),
500
511
  ...(lineage === undefined ? {} : { lineage: encodeLineage(lineage) }),
512
+ rowsChanged: changed.rowsChanged,
513
+ lineageChanged: changed.lineageChanged,
501
514
  }
502
515
 
503
516
  await input.runtime.run(
@@ -552,10 +565,10 @@ export class DuckLakeWriteCoordinator {
552
565
  }
553
566
 
554
567
  /**
555
- * The latest version a write that began without reading it compared its rows with: the one at
556
- * the lake snapshot its first read fixed. The version metadata also shows versions committed
557
- * since. One of this dataset means the rows were compared with an older version, so the write
558
- * reruns.
568
+ * The latest version a write that began without reading it replaces and compared its rows with:
569
+ * the one at the lake snapshot its first read fixed. The version metadata also shows versions
570
+ * committed since. One of this dataset means the write was prepared on an older version, so it
571
+ * reruns: a snapshot that changed rows would conflict with that version at commit anyway.
559
572
  */
560
573
  private async latestVersionAtReadSnapshot(
561
574
  input: DuckLakeCommitVersionOutcomeRuntimeInput
@@ -602,8 +615,9 @@ export class DuckLakeWriteCoordinator {
602
615
 
603
616
  /**
604
617
  * Every version but a snapshot keeps its parent's rows, and the lineage it records merges the
605
- * parent's. A snapshot replaces its parent: it reads it only to guard on it, or on SQLite, whose
606
- * later reads inside the transaction would block its commit.
618
+ * parent's. A snapshot replaces its parent: it reads it first only to guard on it, or on SQLite,
619
+ * whose later reads inside the transaction would block its commit. Otherwise it reads it once
620
+ * its rows are written (see `latestVersionAtReadSnapshot`).
607
621
  */
608
622
  private async beginVersionTransaction(
609
623
  input: DuckLakeCommitVersionOutcomeRuntimeInput
@@ -17,6 +17,10 @@ export interface SixbCommitMetadata {
17
17
  readonly schemaChange?: SixbSchemaChangeMetadata
18
18
  /** As `encodeLineage` stored it: decoded only for the versions a read returns. */
19
19
  readonly lineage?: unknown
20
+ /** As `DatasetVersion.rowsChanged`. Absent on versions written before Sixb recorded it. */
21
+ readonly rowsChanged?: boolean
22
+ /** As `DatasetVersion.lineageChanged`. Absent on versions written before Sixb recorded it. */
23
+ readonly lineageChanged?: boolean
20
24
  }
21
25
 
22
26
  export function parseVersionId(versionId: string): string {
@@ -62,6 +66,7 @@ export function parseCommitMetadata(value: unknown): SixbCommitMetadata | undefi
62
66
  const producer = parseDatasetProducer(parsed.sixb.producer)
63
67
  const rowCount = parsed.sixb.rowCount
64
68
  const validatedPrimaryKeyColumns = parsed.sixb.validatedPrimaryKeyColumns
69
+ const { rowsChanged, lineageChanged } = parsed.sixb
65
70
 
66
71
  return {
67
72
  kind: "datasetVersion",
@@ -80,6 +85,8 @@ export function parseCommitMetadata(value: unknown): SixbCommitMetadata | undefi
80
85
  ? { schemaChange: parsed.sixb.schemaChange }
81
86
  : {}),
82
87
  ...(parsed.sixb.lineage === undefined ? {} : { lineage: parsed.sixb.lineage }),
88
+ ...(typeof rowsChanged === "boolean" ? { rowsChanged } : {}),
89
+ ...(typeof lineageChanged === "boolean" ? { lineageChanged } : {}),
83
90
  }
84
91
  }
85
92