@sixb/ducklake 0.1.6 → 0.1.7

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.
package/dist/index.js CHANGED
@@ -771,7 +771,7 @@ function rowImage(row, prefix, columns) {
771
771
  }
772
772
 
773
773
  // src/internal/ducklake-connection-manager.ts
774
- import { LakeStorageError as LakeStorageError10 } from "@sixb/core/lake-storage";
774
+ import { LakeStorageError as LakeStorageError11 } from "@sixb/core/lake-storage";
775
775
 
776
776
  // src/internal/catalog-key.ts
777
777
  import { resolve } from "path";
@@ -791,9 +791,14 @@ function localCatalogCoordinationKey(options) {
791
791
  }
792
792
 
793
793
  // src/internal/duckdb-runtime.ts
794
+ import { mkdir, mkdtemp, rm } from "fs/promises";
795
+ import { join, resolve as resolve2 } from "path";
794
796
  import {
795
797
  DuckDBInstance
796
798
  } from "@duckdb/node-api";
799
+ import { LakeStorageError as LakeStorageError10 } from "@sixb/core/lake-storage";
800
+
801
+ // src/internal/duckdb-reader.ts
797
802
  import { LakeStorageError as LakeStorageError9 } from "@sixb/core/lake-storage";
798
803
 
799
804
  // src/internal/duckdb-value-converter.ts
@@ -816,16 +821,147 @@ var sixbDuckDbValueConverter = (value, type, converter) => {
816
821
  return JSDuckDBValueConverter(value, type, converter);
817
822
  };
818
823
 
824
+ // src/internal/duckdb-reader.ts
825
+ class NodeDuckDbReader {
826
+ connection;
827
+ options;
828
+ resultPromise;
829
+ pending;
830
+ closePromise;
831
+ finished = false;
832
+ consumed = false;
833
+ onAbort = () => {
834
+ this.close().catch(() => {});
835
+ };
836
+ constructor(connection, options) {
837
+ this.connection = connection;
838
+ this.options = options;
839
+ }
840
+ async start(sql) {
841
+ this.options.signal?.throwIfAborted();
842
+ this.options.signal?.addEventListener("abort", this.onAbort, { once: true });
843
+ await this.track(this.connection.run("SET preserve_insertion_order = true"));
844
+ this.assertOpen();
845
+ const prepared = await this.track(this.connection.prepare(sql));
846
+ try {
847
+ this.assertOpen();
848
+ this.resultPromise = this.track(prepared.startStream().getResult()).finally(() => {
849
+ prepared.destroySync();
850
+ });
851
+ this.resultPromise.catch(() => {});
852
+ } catch (error) {
853
+ prepared.destroySync();
854
+ throw error;
855
+ }
856
+ }
857
+ async* rows() {
858
+ if (this.consumed)
859
+ throw new LakeStorageError9("[SixbDuckLake] Reader can only be consumed once.");
860
+ this.consumed = true;
861
+ try {
862
+ this.assertOpen();
863
+ const result = await this.resultPromise;
864
+ this.assertOpen();
865
+ const batches = result.yieldConvertedRowObjects(sixbDuckDbValueConverter)[Symbol.asyncIterator]();
866
+ while (true) {
867
+ this.assertOpen();
868
+ const batch = await this.track(batches.next());
869
+ this.assertOpen();
870
+ if (batch.done) {
871
+ this.finished = true;
872
+ return;
873
+ }
874
+ for (const row of batch.value) {
875
+ this.assertOpen();
876
+ yield row;
877
+ }
878
+ }
879
+ } finally {
880
+ await this.close();
881
+ }
882
+ }
883
+ close() {
884
+ if (!this.closePromise) {
885
+ this.options.signal?.removeEventListener("abort", this.onAbort);
886
+ if (this.pending)
887
+ this.connection.interrupt();
888
+ this.closePromise = this.finish();
889
+ }
890
+ return this.closePromise;
891
+ }
892
+ async finish() {
893
+ try {
894
+ await this.pending?.catch(() => {});
895
+ if (!this.finished) {
896
+ await this.connection.run("SELECT 1");
897
+ }
898
+ } finally {
899
+ this.resultPromise = undefined;
900
+ try {
901
+ this.connection.closeSync();
902
+ } finally {
903
+ await this.options.onClose?.();
904
+ }
905
+ }
906
+ }
907
+ async track(operation) {
908
+ this.pending = operation;
909
+ try {
910
+ return await operation;
911
+ } catch (error) {
912
+ this.assertOpen();
913
+ throw error;
914
+ } finally {
915
+ if (this.pending === operation)
916
+ this.pending = undefined;
917
+ }
918
+ }
919
+ assertOpen() {
920
+ this.options.signal?.throwIfAborted();
921
+ if (this.closePromise)
922
+ throw new LakeStorageError9("[SixbDuckLake] Reader is closed.");
923
+ }
924
+ }
925
+
819
926
  // src/internal/duckdb-runtime.ts
820
927
  class NodeDuckDbRuntime {
821
928
  instance;
822
929
  connection;
930
+ temporaryDirectory;
823
931
  closing = false;
824
932
  closed = false;
825
933
  operations = Promise.resolve();
826
- constructor(instance, connection) {
934
+ readers = new Set;
935
+ closePromise;
936
+ constructor(instance, connection, temporaryDirectory) {
827
937
  this.instance = instance;
828
938
  this.connection = connection;
939
+ this.temporaryDirectory = temporaryDirectory;
940
+ }
941
+ async openReader(sql, options = {}) {
942
+ return this.enqueue(async () => {
943
+ this.assertAcceptingOperations();
944
+ const connection = await this.instance.connect();
945
+ if (this.closing) {
946
+ connection.closeSync();
947
+ this.assertAcceptingOperations();
948
+ }
949
+ const reader = new NodeDuckDbReader(connection, {
950
+ ...options,
951
+ onClose: async () => {
952
+ this.readers.delete(reader);
953
+ await options.onClose?.();
954
+ }
955
+ });
956
+ this.readers.add(reader);
957
+ try {
958
+ await reader.start(sql);
959
+ return reader;
960
+ } catch (error) {
961
+ await reader.close();
962
+ throw error;
963
+ }
964
+ });
829
965
  }
830
966
  async run(sql, values) {
831
967
  await this.enqueue(async () => {
@@ -845,28 +981,6 @@ class NodeDuckDbRuntime {
845
981
  return reader.convertRowObjects(sixbDuckDbValueConverter);
846
982
  });
847
983
  }
848
- async* streamRows(sql, values) {
849
- this.assertAcceptingOperations();
850
- let releaseOperation;
851
- const operationFinished = new Promise((resolve) => {
852
- releaseOperation = resolve;
853
- });
854
- const waitForTurn = this.operations.then(() => {
855
- this.assertNotClosed();
856
- });
857
- this.operations = waitForTurn.then(() => operationFinished).then(() => {}, () => {});
858
- try {
859
- await waitForTurn;
860
- const result = await this.connection.stream(sql, values === undefined ? undefined : [...values]);
861
- for await (const batch of result.yieldConvertedRowObjects(sixbDuckDbValueConverter)) {
862
- for (const row of batch) {
863
- yield row;
864
- }
865
- }
866
- } finally {
867
- releaseOperation?.();
868
- }
869
- }
870
984
  async withAppender(tableName, useAppender) {
871
985
  return this.enqueue(async () => {
872
986
  const appender = await this.connection.createAppender(tableName);
@@ -882,15 +996,28 @@ class NodeDuckDbRuntime {
882
996
  return useRuntime(new NodeDuckDbExclusiveRuntime(this.connection));
883
997
  });
884
998
  }
885
- async close() {
886
- if (this.closed) {
887
- return;
888
- }
999
+ close() {
1000
+ this.closePromise ??= this.finish();
1001
+ return this.closePromise;
1002
+ }
1003
+ async stopReaders() {
1004
+ const results = await Promise.allSettled([...this.readers].map((reader) => reader.close()));
1005
+ const failed = results.find((result) => result.status === "rejected");
1006
+ if (failed?.status === "rejected")
1007
+ throw failed.reason;
1008
+ }
1009
+ async finish() {
889
1010
  this.closing = true;
1011
+ const results = await Promise.allSettled([...this.readers].map((reader) => reader.close()));
890
1012
  await this.operations.catch(() => {});
891
1013
  this.closed = true;
892
1014
  this.connection.closeSync();
893
1015
  this.instance.closeSync();
1016
+ if (this.temporaryDirectory)
1017
+ await rm(this.temporaryDirectory, { recursive: true, force: true });
1018
+ const failed = results.find((result) => result.status === "rejected");
1019
+ if (failed?.status === "rejected")
1020
+ throw failed.reason;
894
1021
  }
895
1022
  enqueue(operation) {
896
1023
  this.assertAcceptingOperations();
@@ -903,12 +1030,12 @@ class NodeDuckDbRuntime {
903
1030
  }
904
1031
  assertAcceptingOperations() {
905
1032
  if (this.closing || this.closed) {
906
- throw new LakeStorageError9("[SixbDuckLake] DuckDB runtime is closed.");
1033
+ throw new LakeStorageError10("[SixbDuckLake] DuckDB runtime is closed.");
907
1034
  }
908
1035
  }
909
1036
  assertNotClosed() {
910
1037
  if (this.closed) {
911
- throw new LakeStorageError9("[SixbDuckLake] DuckDB runtime is closed.");
1038
+ throw new LakeStorageError10("[SixbDuckLake] DuckDB runtime is closed.");
912
1039
  }
913
1040
  }
914
1041
  }
@@ -968,8 +1095,27 @@ class NodeDuckDbAppenderAdapter {
968
1095
  }
969
1096
  }
970
1097
  async function createDuckDbRuntime(options = {}) {
971
- const instance = await DuckDBInstance.create(options.path ?? ":memory:", options.config ?? {});
972
- return new NodeDuckDbRuntime(instance, await instance.connect());
1098
+ const path = options.path ?? ":memory:";
1099
+ const base = options.config?.temp_directory ?? (path === ":memory:" ? ".tmp" : `${path}.tmp`);
1100
+ let temporaryDirectory;
1101
+ if (base !== "") {
1102
+ const directory = resolve2(base);
1103
+ await mkdir(directory, { recursive: true });
1104
+ temporaryDirectory = await mkdtemp(join(directory, "sixb-"));
1105
+ }
1106
+ let instance;
1107
+ try {
1108
+ instance = await DuckDBInstance.create(path, {
1109
+ ...options.config,
1110
+ ...temporaryDirectory ? { temp_directory: temporaryDirectory } : {}
1111
+ });
1112
+ return new NodeDuckDbRuntime(instance, await instance.connect(), temporaryDirectory);
1113
+ } catch (error) {
1114
+ instance?.closeSync();
1115
+ if (temporaryDirectory)
1116
+ await rm(temporaryDirectory, { recursive: true, force: true });
1117
+ throw error;
1118
+ }
973
1119
  }
974
1120
  async function installDuckLakeExtensions(runtime, options) {
975
1121
  await runtime.run("INSTALL ducklake");
@@ -1002,6 +1148,62 @@ async function setupDuckLake(runtime, options, setupOptions = {}) {
1002
1148
  }
1003
1149
  }
1004
1150
 
1151
+ // src/internal/ducklake-read-gate.ts
1152
+ class DuckLakeReadGate {
1153
+ active = 0;
1154
+ maintenance = false;
1155
+ waiters = new Set;
1156
+ async acquire(signal) {
1157
+ while (true) {
1158
+ signal.throwIfAborted();
1159
+ if (!this.maintenance) {
1160
+ this.active++;
1161
+ let released = false;
1162
+ return () => {
1163
+ if (released)
1164
+ return;
1165
+ released = true;
1166
+ this.active--;
1167
+ this.wake();
1168
+ };
1169
+ }
1170
+ await this.wait(signal);
1171
+ }
1172
+ }
1173
+ async withMaintenance(signal, run) {
1174
+ while (this.active > 0 || this.maintenance)
1175
+ await this.wait(signal);
1176
+ signal.throwIfAborted();
1177
+ this.maintenance = true;
1178
+ try {
1179
+ return await run();
1180
+ } finally {
1181
+ this.maintenance = false;
1182
+ this.wake();
1183
+ }
1184
+ }
1185
+ wait(signal) {
1186
+ return new Promise((resolve, reject) => {
1187
+ const wake = () => {
1188
+ signal.removeEventListener("abort", abort);
1189
+ this.waiters.delete(wake);
1190
+ resolve();
1191
+ };
1192
+ const abort = () => {
1193
+ this.waiters.delete(wake);
1194
+ reject(signal.reason);
1195
+ };
1196
+ signal.throwIfAborted();
1197
+ this.waiters.add(wake);
1198
+ signal.addEventListener("abort", abort, { once: true });
1199
+ });
1200
+ }
1201
+ wake() {
1202
+ for (const wake of this.waiters)
1203
+ wake();
1204
+ }
1205
+ }
1206
+
1005
1207
  // src/internal/ducklake-connection-manager.ts
1006
1208
  class DuckLakeConnectionManager {
1007
1209
  options;
@@ -1009,18 +1211,77 @@ class DuckLakeConnectionManager {
1009
1211
  installExtensionsPromise;
1010
1212
  attachPromise;
1011
1213
  refreshPromise;
1012
- localAttachmentLock = Promise.resolve();
1214
+ attachmentLock = Promise.resolve();
1013
1215
  observedLocalCatalogGeneration;
1014
1216
  attached = false;
1015
1217
  closed = false;
1218
+ closePromise;
1016
1219
  runtimePoisoned = false;
1220
+ pinnedReaders = 0;
1221
+ refreshRequested = false;
1222
+ shutdown = new AbortController;
1223
+ reads = new DuckLakeReadGate;
1224
+ maxStreamingReads;
1017
1225
  constructor(options) {
1018
1226
  this.options = options;
1019
1227
  this.observedLocalCatalogGeneration = currentLocalCatalogGeneration(options);
1228
+ this.maxStreamingReads = options.maxStreamingReads ?? 4;
1229
+ if (!Number.isSafeInteger(this.maxStreamingReads) || this.maxStreamingReads < 1) {
1230
+ throw new LakeStorageError11("[SixbDuckLake] maxStreamingReads must be a positive integer.");
1231
+ }
1232
+ }
1233
+ async acquireRead(signal) {
1234
+ this.assertOpen();
1235
+ const combined = signal ? AbortSignal.any([signal, this.shutdown.signal]) : this.shutdown.signal;
1236
+ return { signal: combined, release: await this.reads.acquire(combined) };
1237
+ }
1238
+ async nativeReaderLimit(runtime) {
1239
+ if (this.options.catalog.type === "duckdb")
1240
+ return this.maxStreamingReads;
1241
+ if (this.options.catalog.type !== "postgres")
1242
+ return 0;
1243
+ const [setting] = await runtime.query("SELECT current_setting('pg_pool_max_connections') AS value");
1244
+ const budget = Number(setting?.value);
1245
+ return Number.isFinite(budget) ? Math.min(this.maxStreamingReads, Math.max(0, budget - 4)) : 0;
1246
+ }
1247
+ async openReader(runtime, sql, signal, releaseRead) {
1248
+ const limit = await this.nativeReaderLimit(runtime);
1249
+ signal.throwIfAborted();
1250
+ if (this.pinnedReaders >= limit)
1251
+ return null;
1252
+ this.pinnedReaders++;
1253
+ let starting = true;
1254
+ let released = false;
1255
+ const onClose = async () => {
1256
+ if (released)
1257
+ return;
1258
+ released = true;
1259
+ this.pinnedReaders--;
1260
+ if (signal.aborted || this.closed || this.runtimePoisoned)
1261
+ releaseRead();
1262
+ if (starting || this.closed || this.runtimePoisoned)
1263
+ return;
1264
+ await this.withAttachmentLock(async () => {
1265
+ if (this.pinnedReaders === 0 && this.refreshRequested)
1266
+ await this.resetRuntimeUnlocked();
1267
+ await this.detachDuckDbCatalogAfterLease();
1268
+ });
1269
+ };
1270
+ try {
1271
+ return await runtime.openReader(sql, { signal, onClose });
1272
+ } catch (error) {
1273
+ await onClose();
1274
+ throw error;
1275
+ } finally {
1276
+ starting = false;
1277
+ }
1278
+ }
1279
+ async withMaintenanceRuntime(run) {
1280
+ return this.reads.withMaintenance(this.shutdown.signal, () => this.withExclusiveAttached(run));
1020
1281
  }
1021
1282
  assertOpen() {
1022
1283
  if (this.closed) {
1023
- throw new LakeStorageError10("[SixbDuckLake] DuckLakeStorage is closed.");
1284
+ throw new LakeStorageError11("[SixbDuckLake] DuckLakeStorage is closed.");
1024
1285
  }
1025
1286
  }
1026
1287
  async runtime() {
@@ -1051,7 +1312,7 @@ class DuckLakeConnectionManager {
1051
1312
  }
1052
1313
  async acquireAttachedRuntime() {
1053
1314
  this.assertOpen();
1054
- const releaseLock = await this.acquireLocalAttachmentLock();
1315
+ const releaseLock = await this.acquireAttachmentLock();
1055
1316
  let released = false;
1056
1317
  const release = async () => {
1057
1318
  if (released) {
@@ -1060,8 +1321,8 @@ class DuckLakeConnectionManager {
1060
1321
  released = true;
1061
1322
  try {
1062
1323
  if (this.runtimePoisoned) {
1063
- this.runtimePoisoned = false;
1064
1324
  await this.discardRuntimeUnlocked();
1325
+ this.runtimePoisoned = false;
1065
1326
  } else {
1066
1327
  await this.detachDuckDbCatalogAfterLease();
1067
1328
  }
@@ -1110,7 +1371,7 @@ class DuckLakeConnectionManager {
1110
1371
  }
1111
1372
  }
1112
1373
  async resetRuntime() {
1113
- const releaseLock = await this.acquireLocalAttachmentLock();
1374
+ const releaseLock = await this.acquireAttachmentLock();
1114
1375
  try {
1115
1376
  await this.resetRuntimeUnlocked();
1116
1377
  } finally {
@@ -1118,6 +1379,11 @@ class DuckLakeConnectionManager {
1118
1379
  }
1119
1380
  }
1120
1381
  async resetRuntimeUnlocked() {
1382
+ if (this.pinnedReaders > 0) {
1383
+ this.refreshRequested = true;
1384
+ return;
1385
+ }
1386
+ this.refreshRequested = false;
1121
1387
  const runtimePromise = this.runtimePromise;
1122
1388
  if (runtimePromise === undefined) {
1123
1389
  return;
@@ -1158,7 +1424,7 @@ class DuckLakeConnectionManager {
1158
1424
  }
1159
1425
  if (this.refreshPromise === undefined) {
1160
1426
  let refreshPromise;
1161
- refreshPromise = this.withLocalAttachmentLock(() => this.refreshForExternalChangesUnlocked()).finally(() => {
1427
+ refreshPromise = this.withAttachmentLock(() => this.refreshForExternalChangesUnlocked()).finally(() => {
1162
1428
  if (this.refreshPromise === refreshPromise) {
1163
1429
  this.refreshPromise = undefined;
1164
1430
  }
@@ -1178,8 +1444,10 @@ class DuckLakeConnectionManager {
1178
1444
  return;
1179
1445
  }
1180
1446
  try {
1181
- await runtime.run(`DETACH ${quoteIdentifier(duckLakeAlias(this.options))}`);
1182
- this.attached = false;
1447
+ if (this.pinnedReaders === 0) {
1448
+ await runtime.run(`DETACH ${quoteIdentifier(duckLakeAlias(this.options))}`);
1449
+ this.attached = false;
1450
+ }
1183
1451
  } catch {} finally {
1184
1452
  this.markLocalCatalogChanged();
1185
1453
  }
@@ -1195,11 +1463,13 @@ class DuckLakeConnectionManager {
1195
1463
  needsLocalCatalogRefresh() {
1196
1464
  return this.observedLocalCatalogGeneration !== currentLocalCatalogGeneration(this.options);
1197
1465
  }
1198
- async close() {
1199
- if (this.closed) {
1200
- return;
1201
- }
1466
+ close() {
1467
+ this.closePromise ??= this.finishClose();
1468
+ return this.closePromise;
1469
+ }
1470
+ async finishClose() {
1202
1471
  this.closed = true;
1472
+ this.shutdown.abort(new LakeStorageError11("[SixbDuckLake] DuckLakeStorage is closed."));
1203
1473
  const runtimePromise = this.runtimePromise;
1204
1474
  this.runtimePromise = undefined;
1205
1475
  await this.closeRuntimePromise(runtimePromise, {
@@ -1258,13 +1528,13 @@ class DuckLakeConnectionManager {
1258
1528
  ]);
1259
1529
  }
1260
1530
  async detachRuntime() {
1261
- await this.withLocalAttachmentLock(() => this.detachRuntimeUnlocked());
1531
+ await this.withAttachmentLock(() => this.detachRuntimeUnlocked());
1262
1532
  }
1263
1533
  poisonRuntime() {
1264
1534
  this.runtimePoisoned = true;
1265
1535
  }
1266
1536
  async detachDuckDbCatalogAfterLease() {
1267
- if (this.options.catalog.type !== "duckdb" || !this.attached) {
1537
+ if (this.options.catalog.type !== "duckdb" || !this.attached || this.pinnedReaders > 0) {
1268
1538
  return;
1269
1539
  }
1270
1540
  try {
@@ -1280,6 +1550,8 @@ class DuckLakeConnectionManager {
1280
1550
  await this.closeRuntimePromise(runtimePromise, { detach: false }).catch(() => {});
1281
1551
  }
1282
1552
  async detachRuntimeUnlocked() {
1553
+ if (this.pinnedReaders > 0)
1554
+ return;
1283
1555
  if (this.attachPromise !== undefined) {
1284
1556
  await this.attachPromise;
1285
1557
  }
@@ -1290,24 +1562,21 @@ class DuckLakeConnectionManager {
1290
1562
  await runtime.run(`DETACH ${quoteIdentifier(duckLakeAlias(this.options))}`);
1291
1563
  this.attached = false;
1292
1564
  }
1293
- async withLocalAttachmentLock(run) {
1294
- const releaseLock = await this.acquireLocalAttachmentLock();
1565
+ async withAttachmentLock(run) {
1566
+ const releaseLock = await this.acquireAttachmentLock();
1295
1567
  try {
1296
1568
  return await run();
1297
1569
  } finally {
1298
1570
  releaseLock();
1299
1571
  }
1300
1572
  }
1301
- async acquireLocalAttachmentLock() {
1302
- if (this.options.catalog.type === "postgres") {
1303
- return () => {};
1304
- }
1305
- const previous = this.localAttachmentLock.catch(() => {});
1573
+ async acquireAttachmentLock() {
1574
+ const previous = this.attachmentLock.catch(() => {});
1306
1575
  let release;
1307
1576
  const current = new Promise((resolve) => {
1308
1577
  release = resolve;
1309
1578
  });
1310
- this.localAttachmentLock = previous.then(() => current);
1579
+ this.attachmentLock = previous.then(() => current);
1311
1580
  await previous;
1312
1581
  let released = false;
1313
1582
  return () => {
@@ -1331,12 +1600,16 @@ class DuckLakeConnectionManager {
1331
1600
  await this.closeRuntime(runtime, options);
1332
1601
  }
1333
1602
  async closeRuntime(runtime, options) {
1334
- if (options.detach) {
1335
- try {
1336
- await runtime.run(`DETACH ${quoteIdentifier(duckLakeAlias(this.options))}`);
1337
- } catch {}
1603
+ try {
1604
+ await runtime.stopReaders();
1605
+ if (options.detach) {
1606
+ try {
1607
+ await runtime.run(`DETACH ${quoteIdentifier(duckLakeAlias(this.options))}`);
1608
+ } catch {}
1609
+ }
1610
+ } finally {
1611
+ await runtime.close();
1338
1612
  }
1339
- await runtime.close();
1340
1613
  }
1341
1614
  }
1342
1615
  var localCatalogGenerations = new Map;
@@ -1358,12 +1631,12 @@ function incrementLocalCatalogGeneration(options) {
1358
1631
  import { randomUUID as randomUUID2 } from "crypto";
1359
1632
  import {
1360
1633
  assertDatasetDefinition,
1361
- LakeStorageError as LakeStorageError13,
1634
+ LakeStorageError as LakeStorageError14,
1362
1635
  planDatasetDefinitionUpdate
1363
1636
  } from "@sixb/core/lake-storage";
1364
1637
 
1365
1638
  // src/internal/ducklake-catalog-schema.ts
1366
- import { LakeStorageError as LakeStorageError11 } from "@sixb/core/lake-storage";
1639
+ import { LakeStorageError as LakeStorageError12 } from "@sixb/core/lake-storage";
1367
1640
  var SIXB_PRIMARY_KEY_COMMENT_NAMESPACE = "sixb:primary-key:";
1368
1641
  var DATASET_SEQUENCE_COLUMN_COMMENT = "sixb.sequenceBy.v1";
1369
1642
  var SIXB_PRIMARY_KEY_COMMENT_PREFIX = `${SIXB_PRIMARY_KEY_COMMENT_NAMESPACE}v1:`;
@@ -1414,14 +1687,14 @@ function duckLakeCatalogColumnsToDatasetPrimaryKey(tableName, rows) {
1414
1687
  throwInvalidPrimaryKeyMetadata(tableName, column, comment);
1415
1688
  }
1416
1689
  if (seenOrdinals.has(ordinal)) {
1417
- throw new LakeStorageError11(`[SixbDuckLake] Dataset table '${tableName}' has duplicate primary-key ordinal '${ordinal}'.`);
1690
+ throw new LakeStorageError12(`[SixbDuckLake] Dataset table '${tableName}' has duplicate primary-key ordinal '${ordinal}'.`);
1418
1691
  }
1419
1692
  seenOrdinals.add(ordinal);
1420
1693
  if (duckDbTypeToDatasetColumnType(column.columnType) !== "string") {
1421
- throw new LakeStorageError11(`[SixbDuckLake] Dataset table '${tableName}' primary-key column '${column.columnName}' must map to type 'string'.`);
1694
+ throw new LakeStorageError12(`[SixbDuckLake] Dataset table '${tableName}' primary-key column '${column.columnName}' must map to type 'string'.`);
1422
1695
  }
1423
1696
  if (column.nullsAllowed) {
1424
- throw new LakeStorageError11(`[SixbDuckLake] Dataset table '${tableName}' primary-key column '${column.columnName}' must not be nullable.`);
1697
+ throw new LakeStorageError12(`[SixbDuckLake] Dataset table '${tableName}' primary-key column '${column.columnName}' must not be nullable.`);
1425
1698
  }
1426
1699
  keyedColumns.push({ column, ordinal });
1427
1700
  }
@@ -1431,7 +1704,7 @@ function duckLakeCatalogColumnsToDatasetPrimaryKey(tableName, rows) {
1431
1704
  keyedColumns.sort((left, right) => left.ordinal - right.ordinal);
1432
1705
  for (const [expectedOrdinal, keyedColumn] of keyedColumns.entries()) {
1433
1706
  if (keyedColumn.ordinal !== expectedOrdinal) {
1434
- throw new LakeStorageError11(`[SixbDuckLake] Dataset table '${tableName}' primary-key ordinals must be contiguous from 0.`);
1707
+ throw new LakeStorageError12(`[SixbDuckLake] Dataset table '${tableName}' primary-key ordinals must be contiguous from 0.`);
1435
1708
  }
1436
1709
  }
1437
1710
  const columnNames = keyedColumns.map(({ column }) => column.columnName);
@@ -1441,7 +1714,7 @@ function duckLakeCatalogColumnsToDatasetPrimaryKey(tableName, rows) {
1441
1714
  return columnNames;
1442
1715
  }
1443
1716
  function throwInvalidPrimaryKeyMetadata(tableName, column, comment) {
1444
- throw new LakeStorageError11(`[SixbDuckLake] Dataset table '${tableName}' has malformed primary-key metadata '${comment}' on column '${column.columnName}'.`);
1717
+ throw new LakeStorageError12(`[SixbDuckLake] Dataset table '${tableName}' has malformed primary-key metadata '${comment}' on column '${column.columnName}'.`);
1445
1718
  }
1446
1719
  function duckLakeCatalogColumnToDefinition(tableName, column, childrenByParentId) {
1447
1720
  const children = [...childrenByParentId.get(column.columnId) ?? []].sort(compareDuckLakeCatalogColumnOrder);
@@ -1458,7 +1731,7 @@ function duckLakeCatalogColumnTypeToDatasetType(tableName, column, children) {
1458
1731
  if (isFileRefStruct(children)) {
1459
1732
  return "fileRef";
1460
1733
  }
1461
- throw new LakeStorageError11(`[SixbDuckLake] DuckDB column type '${formatDuckLakeCatalogColumnType(column, children)}' in dataset table '${tableName}' cannot be mapped to a Sixb dataset column type.`);
1734
+ throw new LakeStorageError12(`[SixbDuckLake] DuckDB column type '${formatDuckLakeCatalogColumnType(column, children)}' in dataset table '${tableName}' cannot be mapped to a Sixb dataset column type.`);
1462
1735
  }
1463
1736
  function compareDuckLakeCatalogColumnOrder(left, right) {
1464
1737
  return Number(left.columnOrder - right.columnOrder);
@@ -1480,7 +1753,7 @@ function formatDuckLakeCatalogColumnType(column, children) {
1480
1753
  }
1481
1754
 
1482
1755
  // src/internal/ducklake-current-dataset-definitions.ts
1483
- import { LakeStorageError as LakeStorageError12 } from "@sixb/core/lake-storage";
1756
+ import { LakeStorageError as LakeStorageError13 } from "@sixb/core/lake-storage";
1484
1757
  async function readCurrentDatasetDefinitions(input) {
1485
1758
  if (input.datasetIds?.length === 0) {
1486
1759
  return new Map;
@@ -1607,7 +1880,7 @@ async function readCurrentDatasetPartitions(input, tableNames) {
1607
1880
  transform: getString(row, "transform")
1608
1881
  };
1609
1882
  if (partition.transform !== "identity") {
1610
- throw new LakeStorageError12(`[SixbDuckLake] Dataset table '${partition.tableName}' uses unsupported DuckLake partition transform '${partition.transform}'.`);
1883
+ throw new LakeStorageError13(`[SixbDuckLake] Dataset table '${partition.tableName}' uses unsupported DuckLake partition transform '${partition.transform}'.`);
1611
1884
  }
1612
1885
  return partition;
1613
1886
  });
@@ -1709,7 +1982,7 @@ class DuckLakeDatasetCatalog {
1709
1982
  if (failures.length > 0) {
1710
1983
  const details = failures.join(`
1711
1984
  `);
1712
- throw new LakeStorageError13(`[SixbLake] Lake dataset definition check failed for ${failures.length} dataset(s).
1985
+ throw new LakeStorageError14(`[SixbLake] Lake dataset definition check failed for ${failures.length} dataset(s).
1713
1986
  ${details}`);
1714
1987
  }
1715
1988
  }
@@ -1745,12 +2018,12 @@ ${details}`);
1745
2018
  assertDuckLakeSnapshotId(snapshotId);
1746
2019
  const columns = await this.readDatasetColumnsAtSnapshot(runtime, tableName, tableId, snapshotId);
1747
2020
  if (columns.length === 0) {
1748
- throw new LakeStorageError13(`[SixbDuckLake] Could not reconstruct schema for dataset '${datasetId}' at DuckLake snapshot '${snapshotId}'.`);
2021
+ throw new LakeStorageError14(`[SixbDuckLake] Could not reconstruct schema for dataset '${datasetId}' at DuckLake snapshot '${snapshotId}'.`);
1749
2022
  }
1750
2023
  return duckLakeCatalogColumnsToDatasetSchema(tableName, columns);
1751
2024
  }
1752
2025
  assertSchema(definition) {
1753
- assertDatasetDefinition(definition, (message) => new LakeStorageError13(`[SixbDuckLake] ${message}`));
2026
+ assertDatasetDefinition(definition, (message) => new LakeStorageError14(`[SixbDuckLake] ${message}`));
1754
2027
  }
1755
2028
  async applyExistingDatasetUpdate(plan) {
1756
2029
  const tableName = encodeDatasetTableName(plan.definition.id);
@@ -1797,7 +2070,7 @@ ${details}`);
1797
2070
  await runtime.run(`ALTER TABLE ${qualifiedName} SET PARTITIONED BY (${definition.partitionBy.map((columnName) => quoteIdentifier(columnName)).join(", ")})`);
1798
2071
  } catch (error) {
1799
2072
  const message = error instanceof Error ? error.message : String(error);
1800
- throw new LakeStorageError13(`[SixbDuckLake] Dataset '${definition.id}' cannot apply partitionBy because DuckLake rejected ALTER TABLE SET PARTITIONED BY: ${message}`);
2073
+ throw new LakeStorageError14(`[SixbDuckLake] Dataset '${definition.id}' cannot apply partitionBy because DuckLake rejected ALTER TABLE SET PARTITIONED BY: ${message}`);
1801
2074
  }
1802
2075
  }
1803
2076
  async applyPrimaryKey(runtime, qualifiedName, definition) {
@@ -1856,12 +2129,12 @@ ${details}`);
1856
2129
  }
1857
2130
  function assertDuckLakeSnapshotId(snapshotId) {
1858
2131
  if (!/^\d+$/.test(snapshotId)) {
1859
- throw new LakeStorageError13(`[SixbDuckLake] Invalid DuckLake snapshot id '${snapshotId}'.`);
2132
+ throw new LakeStorageError14(`[SixbDuckLake] Invalid DuckLake snapshot id '${snapshotId}'.`);
1860
2133
  }
1861
2134
  }
1862
2135
 
1863
2136
  // src/internal/ducklake-maintenance.ts
1864
- import { LakeStorageError as LakeStorageError14 } from "@sixb/core/lake-storage";
2137
+ import { LakeStorageError as LakeStorageError15 } from "@sixb/core/lake-storage";
1865
2138
  var DEFAULT_RETENTION = "7 days";
1866
2139
 
1867
2140
  class DuckLakeMaintenance {
@@ -1877,9 +2150,9 @@ class DuckLakeMaintenance {
1877
2150
  const deleteOlderThan = options.deleteOlderThan ?? expireOlderThan;
1878
2151
  const dryRun = options.dryRun ?? false;
1879
2152
  if (this.options.readOnly && !dryRun) {
1880
- throw new LakeStorageError14("[SixbDuckLake] DuckLake maintenance cannot run in read-only mode.");
2153
+ throw new LakeStorageError15("[SixbDuckLake] DuckLake maintenance cannot run in read-only mode.");
1881
2154
  }
1882
- return this.connections.withExclusiveAttached(async (runtime) => {
2155
+ return this.connections.withMaintenanceRuntime(async (runtime) => {
1883
2156
  const counts = await runMaintenanceProcedures(runtime, this.options, {
1884
2157
  expireOlderThan,
1885
2158
  deleteOlderThan
@@ -1914,7 +2187,7 @@ function maintenanceProcedureSql(procedure, aliasSql, olderThan, dryRun) {
1914
2187
  }
1915
2188
 
1916
2189
  // src/internal/ducklake-row-reader.ts
1917
- import { LakeStorageError as LakeStorageError15 } from "@sixb/core/lake-storage";
2190
+ import { LakeStorageError as LakeStorageError16 } from "@sixb/core/lake-storage";
1918
2191
  var READ_PAGE_ROWS = 5000;
1919
2192
  var PHYSICAL_ROW_ID_ALIAS = "__sixb_physical_row_id";
1920
2193
 
@@ -1928,58 +2201,68 @@ class DuckLakeRowReader {
1928
2201
  this.snapshots = snapshots;
1929
2202
  }
1930
2203
  async* readRows(input) {
1931
- this.connections.assertOpen();
1932
- const lease = await this.connections.acquireAttachedRuntime();
2204
+ const read = await this.connections.acquireRead(input.signal);
2205
+ let reader = null;
1933
2206
  try {
1934
- const runtime = lease.runtime;
1935
- const tableRef = await resolveDatasetTableRef(this.options, runtime, input.datasetId);
1936
- if (!tableRef) {
1937
- throw new LakeStorageError15(`[SixbDuckLake] Unknown dataset '${input.datasetId}'.`);
1938
- }
1939
- const version = await this.resolveVersion(runtime, tableRef, input.versionId);
1940
- const selectedColumns = this.resolveReadColumns(tableRef.datasetId, version.schema, input.columns);
1941
- const snapshotId = parseVersionId(version.versionId);
1942
- const columnsSql = selectedColumns.map((column) => quoteIdentifier(column.name)).join(", ");
1943
- const tableSql = qualifiedTableName(this.options, tableRef.tableName);
1944
- const schemaNames = new Set(version.schema.columns.map((column) => column.name.toLowerCase()));
1945
- const canUsePhysicalRowId = !schemaNames.has("rowid") && !schemaNames.has(PHYSICAL_ROW_ID_ALIAS.toLowerCase());
1946
- const orderSql = canUsePhysicalRowId ? " ORDER BY rowid" : "";
1947
- const baseSql = `SELECT ${columnsSql} FROM ${tableSql} AT (VERSION => ${snapshotId})`;
1948
- const requestedOffset = Math.max(0, Math.trunc(input.offset ?? 0));
1949
- let remaining = input.limit === undefined ? undefined : Math.max(0, Math.trunc(input.limit));
1950
- if (remaining === 0)
2207
+ const prepared = await this.connections.withAttachedRuntime(async (runtime) => {
2208
+ read.signal.throwIfAborted();
2209
+ const tableRef = await resolveDatasetTableRef(this.options, runtime, input.datasetId);
2210
+ if (!tableRef) {
2211
+ throw new LakeStorageError16(`[SixbDuckLake] Unknown dataset '${input.datasetId}'.`);
2212
+ }
2213
+ const version = await this.resolveVersion(runtime, tableRef, input.versionId);
2214
+ const columns = this.resolveReadColumns(tableRef.datasetId, version.schema, input.columns);
2215
+ const names = new Set(version.schema.columns.map((column) => column.name.toLowerCase()));
2216
+ const physicalOrder = !names.has("rowid") && !names.has(PHYSICAL_ROW_ID_ALIAS);
2217
+ const relation = `${qualifiedTableName(this.options, tableRef.tableName)} AT (VERSION => ${parseVersionId(version.versionId)})`;
2218
+ const columnsSql = columns.map((column) => quoteIdentifier(column.name)).join(", ");
2219
+ const offset = Math.max(0, Math.trunc(input.offset ?? 0));
2220
+ const limit = input.limit === undefined ? undefined : Math.max(0, Math.trunc(input.limit));
2221
+ const sql = `SELECT ${columnsSql} FROM ${relation}${physicalOrder ? " ORDER BY rowid" : ""}${limit === undefined ? "" : ` LIMIT ${limit}`}${offset > 0 ? ` OFFSET ${offset}` : ""}`;
2222
+ const cursor = limit === undefined || limit > READ_PAGE_ROWS ? await this.connections.openReader(runtime, sql, read.signal, read.release) : null;
2223
+ const query = { columnsSql, relation, physicalOrder };
2224
+ const firstPage = cursor || limit === 0 ? [] : await runtime.query(pageSql(query, Math.min(limit ?? READ_PAGE_ROWS, READ_PAGE_ROWS), offset, null));
2225
+ return { columns, ...query, offset, limit, cursor, firstPage };
2226
+ });
2227
+ reader = prepared.cursor;
2228
+ if (!reader)
2229
+ read.signal.addEventListener("abort", read.release, { once: true });
2230
+ read.signal.throwIfAborted();
2231
+ if (reader) {
2232
+ yield* this.normalizeRows(reader.rows(), prepared.columns, read.signal);
1951
2233
  return;
1952
- let offset = requestedOffset;
1953
- let physicalCursor = null;
1954
- while (true) {
1955
- const pageRows = remaining === undefined ? READ_PAGE_ROWS : Math.min(READ_PAGE_ROWS, remaining);
1956
- const pageSql = canUsePhysicalRowId ? `SELECT rowid AS ${quoteIdentifier(PHYSICAL_ROW_ID_ALIAS)}, ${columnsSql}
1957
- FROM ${tableSql} AT (VERSION => ${snapshotId})
1958
- ${physicalCursor === null ? "" : `WHERE rowid > ${physicalCursor}`}
1959
- ORDER BY rowid LIMIT ${pageRows}
1960
- ${physicalCursor === null && offset > 0 ? `OFFSET ${offset}` : ""}` : `${baseSql}${orderSql} LIMIT ${pageRows} OFFSET ${offset}`;
1961
- const rows = await runtime.query(pageSql);
1962
- if (rows.length === 0)
1963
- return;
1964
- yield* this.normalizeRows(rows, selectedColumns);
1965
- offset += rows.length;
1966
- if (remaining !== undefined) {
2234
+ }
2235
+ let offset = prepared.offset;
2236
+ let remaining = prepared.limit;
2237
+ let cursor = null;
2238
+ let page = prepared.firstPage;
2239
+ while (remaining !== 0) {
2240
+ read.signal.throwIfAborted();
2241
+ const pageSize = Math.min(remaining ?? READ_PAGE_ROWS, READ_PAGE_ROWS);
2242
+ const rows = page ?? await this.connections.withAttachedRuntime((runtime) => runtime.query(pageSql(prepared, pageSize, offset, cursor)));
2243
+ page = undefined;
2244
+ read.signal.throwIfAborted();
2245
+ yield* this.normalizeRows(rows, prepared.columns, read.signal);
2246
+ if (remaining !== undefined)
1967
2247
  remaining -= rows.length;
1968
- if (remaining === 0)
1969
- return;
1970
- }
1971
- if (canUsePhysicalRowId) {
1972
- physicalCursor = getBigIntLike(rows[rows.length - 1], PHYSICAL_ROW_ID_ALIAS);
1973
- }
1974
- if (rows.length < pageRows)
2248
+ if (rows.length < pageSize)
1975
2249
  return;
2250
+ if (prepared.physicalOrder)
2251
+ cursor = getBigIntLike(rows[rows.length - 1], PHYSICAL_ROW_ID_ALIAS);
2252
+ offset += rows.length;
1976
2253
  }
1977
2254
  } finally {
1978
- await lease.release();
2255
+ read.signal.removeEventListener("abort", read.release);
2256
+ try {
2257
+ await reader?.close();
2258
+ } finally {
2259
+ read.release();
2260
+ }
1979
2261
  }
1980
2262
  }
1981
- async* normalizeRows(rows, selectedColumns) {
2263
+ async* normalizeRows(rows, selectedColumns, signal) {
1982
2264
  for await (const row of rows) {
2265
+ signal.throwIfAborted();
1983
2266
  const output = {};
1984
2267
  for (const column of selectedColumns) {
1985
2268
  output[column.name] = normalizeReadValue(row[column.name], column);
@@ -2010,18 +2293,23 @@ class DuckLakeRowReader {
2010
2293
  return columns.map((columnName) => {
2011
2294
  const column = columnsByName.get(columnName);
2012
2295
  if (!column) {
2013
- throw new LakeStorageError15(`[SixbDuckLake] Dataset '${datasetId}' does not have column '${columnName}' at the requested version.`);
2296
+ throw new LakeStorageError16(`[SixbDuckLake] Dataset '${datasetId}' does not have column '${columnName}' at the requested version.`);
2014
2297
  }
2015
2298
  return column;
2016
2299
  });
2017
2300
  }
2018
2301
  throwNoCommittedVersion(datasetId) {
2019
- throw new LakeStorageError15(`[SixbDuckLake] No committed version found for dataset '${datasetId}'.`);
2302
+ throw new LakeStorageError16(`[SixbDuckLake] No committed version found for dataset '${datasetId}'.`);
2020
2303
  }
2021
2304
  }
2305
+ function pageSql(read, limit, offset, cursor) {
2306
+ return read.physicalOrder ? `SELECT rowid AS ${quoteIdentifier(PHYSICAL_ROW_ID_ALIAS)}, ${read.columnsSql}
2307
+ FROM ${read.relation} ${cursor === null ? "" : `WHERE rowid > ${cursor}`}
2308
+ ORDER BY rowid LIMIT ${limit} ${cursor === null && offset > 0 ? `OFFSET ${offset}` : ""}` : `SELECT ${read.columnsSql} FROM ${read.relation} LIMIT ${limit} OFFSET ${offset}`;
2309
+ }
2022
2310
 
2023
2311
  // src/internal/ducklake-snapshot-reader.ts
2024
- import { LakeStorageError as LakeStorageError16 } from "@sixb/core/lake-storage";
2312
+ import { LakeStorageError as LakeStorageError17 } from "@sixb/core/lake-storage";
2025
2313
  var SNAPSHOT_ROW_BATCH_SIZE = 128;
2026
2314
  var CATALOG_SNAPSHOT_SCAN_LIMIT = 512;
2027
2315
 
@@ -2234,7 +2522,7 @@ class DuckLakeSnapshotReader {
2234
2522
  }
2235
2523
  assertNoMetadataConflict(snapshotId, datasetId, metadata) {
2236
2524
  if (metadata !== undefined && metadata.datasetId !== datasetId) {
2237
- throw new LakeStorageError16(`[SixbDuckLake] DuckLake snapshot '${snapshotId}' changed dataset '${datasetId}' but Sixb commit metadata references dataset '${metadata.datasetId}'.`);
2525
+ throw new LakeStorageError17(`[SixbDuckLake] DuckLake snapshot '${snapshotId}' changed dataset '${datasetId}' but Sixb commit metadata references dataset '${metadata.datasetId}'.`);
2238
2526
  }
2239
2527
  }
2240
2528
  async getLatestVersionForDefinition(runtime, dataset) {
@@ -2379,7 +2667,10 @@ class DuckLakeSnapshotReader {
2379
2667
  if (input.limit !== undefined && input.limit <= 0) {
2380
2668
  return [];
2381
2669
  }
2382
- const where = [];
2670
+ const ducklakeTable = duckLakeMetadataTableName(this.options, "ducklake_table");
2671
+ const where = [
2672
+ `snapshot.snapshot_id >= (SELECT min(begin_snapshot) FROM ${ducklakeTable} WHERE table_id = ${input.tableId})`
2673
+ ];
2383
2674
  if (input.exactSnapshotId !== undefined) {
2384
2675
  assertDuckLakeSnapshotId2(input.exactSnapshotId);
2385
2676
  where.push(`snapshot.snapshot_id = ${input.exactSnapshotId}`);
@@ -2388,7 +2679,7 @@ class DuckLakeSnapshotReader {
2388
2679
  assertDuckLakeSnapshotId2(input.beforeSnapshotId);
2389
2680
  where.push(`snapshot.snapshot_id < ${input.beforeSnapshotId}`);
2390
2681
  }
2391
- const whereSql = where.length === 0 ? "" : `WHERE ${where.join(" AND ")}`;
2682
+ const whereSql = `WHERE ${where.join(" AND ")}`;
2392
2683
  const limitSql = input.limit === undefined ? "" : `LIMIT ${Math.max(0, Math.trunc(input.limit))}`;
2393
2684
  const ducklakeSnapshot = duckLakeMetadataTableName(this.options, "ducklake_snapshot");
2394
2685
  const ducklakeSnapshotChanges = duckLakeMetadataTableName(this.options, "ducklake_snapshot_changes");
@@ -2514,7 +2805,7 @@ class DuckLakeSnapshotReader {
2514
2805
  }
2515
2806
  function assertDuckLakeSnapshotId2(snapshotId) {
2516
2807
  if (!/^\d+$/.test(snapshotId)) {
2517
- throw new LakeStorageError16(`[SixbDuckLake] Invalid DuckLake snapshot id '${snapshotId}'.`);
2808
+ throw new LakeStorageError17(`[SixbDuckLake] Invalid DuckLake snapshot id '${snapshotId}'.`);
2518
2809
  }
2519
2810
  }
2520
2811
  function fileChangeKey(snapshotId, tableId) {
@@ -2524,17 +2815,17 @@ function fileChangeKey(snapshotId, tableId) {
2524
2815
  // src/internal/ducklake-sql-executor.ts
2525
2816
  import { randomUUID as randomUUID4 } from "crypto";
2526
2817
  import {
2527
- LakeStorageError as LakeStorageError19
2818
+ LakeStorageError as LakeStorageError20
2528
2819
  } from "@sixb/core/lake-storage";
2529
2820
 
2530
2821
  // src/internal/dataset-row-commit.ts
2531
2822
  import {
2532
2823
  getDatasetPrimaryKeyColumns,
2533
- LakeStorageError as LakeStorageError17
2824
+ LakeStorageError as LakeStorageError18
2534
2825
  } from "@sixb/core/lake-storage";
2535
2826
  function assertDatasetWriteMode(mode, operation) {
2536
2827
  if (mode !== "snapshot" && mode !== "append") {
2537
- throw new LakeStorageError17(`[SixbDuckLake] Invalid ${operation} mode '${String(mode)}'. Expected 'snapshot' or 'append'.`);
2828
+ throw new LakeStorageError18(`[SixbDuckLake] Invalid ${operation} mode '${String(mode)}'. Expected 'snapshot' or 'append'.`);
2538
2829
  }
2539
2830
  }
2540
2831
  async function applyDatasetRowsFromRelation(input) {
@@ -2594,7 +2885,7 @@ async function applyDatasetRowsFromRelation(input) {
2594
2885
  async function inspectUniqueKeyedRelation(input) {
2595
2886
  const primaryKeyColumns = getDatasetPrimaryKeyColumns(input.dataset);
2596
2887
  if (primaryKeyColumns === null) {
2597
- throw new LakeStorageError17(`[SixbDuckLake] Dataset '${input.dataset.id}' must define a primaryKey before rows can be keyed.`);
2888
+ throw new LakeStorageError18(`[SixbDuckLake] Dataset '${input.dataset.id}' must define a primaryKey before rows can be keyed.`);
2598
2889
  }
2599
2890
  const keysSql = primaryKeyColumns.map((column) => quoteIdentifier(column)).join(", ");
2600
2891
  const [row] = await input.runtime.query(`
@@ -2609,7 +2900,7 @@ async function inspectUniqueKeyedRelation(input) {
2609
2900
  const rowCount = row === undefined ? 0 : Number(getBigIntLike(row, "row_count"));
2610
2901
  const maxKeyCount = row === undefined ? 0 : Number(getBigIntLike(row, "max_key_count"));
2611
2902
  if (maxKeyCount > 1) {
2612
- throw new LakeStorageError17(`[SixbDuckLake] Dataset '${input.dataset.id}' ${input.context} contains duplicate primary key.`);
2903
+ throw new LakeStorageError18(`[SixbDuckLake] Dataset '${input.dataset.id}' ${input.context} contains duplicate primary key.`);
2613
2904
  }
2614
2905
  return rowCount;
2615
2906
  }
@@ -2626,7 +2917,7 @@ async function assertNoPrimaryKeyOverlap(input) {
2626
2917
  LIMIT 1
2627
2918
  `);
2628
2919
  if (collision !== undefined) {
2629
- throw new LakeStorageError17(`[SixbDuckLake] Dataset '${input.dataset.id}' ${input.context} contains duplicate primary key.`);
2920
+ throw new LakeStorageError18(`[SixbDuckLake] Dataset '${input.dataset.id}' ${input.context} contains duplicate primary key.`);
2630
2921
  }
2631
2922
  }
2632
2923
  async function fingerprintRelation(runtime, relationSql, columnsSql) {
@@ -2660,7 +2951,7 @@ async function countRows(runtime, relationSql) {
2660
2951
  // src/internal/sql-transform-relations.ts
2661
2952
  import { randomUUID as randomUUID3 } from "crypto";
2662
2953
  import {
2663
- LakeStorageError as LakeStorageError18
2954
+ LakeStorageError as LakeStorageError19
2664
2955
  } from "@sixb/core/lake-storage";
2665
2956
  var RELATION_PLACEHOLDER_PREFIX = "__sixb_sql_transform_relation_";
2666
2957
  var RELATION_PLACEHOLDER_PATTERN = /__sixb_sql_transform_relation_[0-9a-f]{32}_[0-9]+__/g;
@@ -2678,7 +2969,7 @@ function renderDuckLakeSqlTransformSql(input) {
2678
2969
  const context = createDuckLakeSqlTransformRelationContext(input);
2679
2970
  const sql = input.sql(context.relations);
2680
2971
  if (typeof sql !== "string") {
2681
- throw new LakeStorageError18("[SixbDuckLake] SQL transform body must return a SQL string.");
2972
+ throw new LakeStorageError19("[SixbDuckLake] SQL transform body must return a SQL string.");
2682
2973
  }
2683
2974
  return context.render(sql);
2684
2975
  }
@@ -2716,7 +3007,7 @@ function renderDuckLakeSourceRelation(options, source) {
2716
3007
  return `(SELECT * FROM ${qualifiedTableName(options, tableName)} AT (VERSION => ${snapshotId}))`;
2717
3008
  }
2718
3009
  function throwUnresolvedPlaceholder() {
2719
- throw new LakeStorageError18("[SixbDuckLake] SQL transform contains an unresolved relation placeholder.");
3010
+ throw new LakeStorageError19("[SixbDuckLake] SQL transform contains an unresolved relation placeholder.");
2720
3011
  }
2721
3012
 
2722
3013
  // src/internal/ducklake-sql-executor.ts
@@ -2810,14 +3101,14 @@ class DuckLakeSqlExecutor {
2810
3101
  async resolveSourceDataset(runtime, dataset) {
2811
3102
  const definition = await this.datasets.getDatasetOnRuntime(runtime, dataset.id);
2812
3103
  if (!definition) {
2813
- throw new LakeStorageError19(`[SixbDuckLake] Unknown SQL transform source dataset '${dataset.id}'.`);
3104
+ throw new LakeStorageError20(`[SixbDuckLake] Unknown SQL transform source dataset '${dataset.id}'.`);
2814
3105
  }
2815
3106
  return definition;
2816
3107
  }
2817
3108
  async resolveTargetDataset(runtime, dataset) {
2818
3109
  const definition = await this.datasets.getDatasetOnRuntime(runtime, dataset.id);
2819
3110
  if (!definition) {
2820
- throw new LakeStorageError19(`[SixbDuckLake] Unknown SQL transform target dataset '${dataset.id}'.`);
3111
+ throw new LakeStorageError20(`[SixbDuckLake] Unknown SQL transform target dataset '${dataset.id}'.`);
2821
3112
  }
2822
3113
  this.datasets.assertSchema(definition);
2823
3114
  return definition;
@@ -2938,10 +3229,10 @@ function normalizePreviewValue(value) {
2938
3229
  return value;
2939
3230
  }
2940
3231
  function throwNoCommittedSourceVersion(datasetId) {
2941
- throw new LakeStorageError19(`[SixbDuckLake] No committed version found for SQL transform source dataset '${datasetId}'.`);
3232
+ throw new LakeStorageError20(`[SixbDuckLake] No committed version found for SQL transform source dataset '${datasetId}'.`);
2942
3233
  }
2943
3234
  function throwResultSchemaMismatch(datasetId, detail) {
2944
- throw new LakeStorageError19(`[SixbDuckLake] SQL transform result schema does not match target dataset '${datasetId}': ${detail}.`);
3235
+ throw new LakeStorageError20(`[SixbDuckLake] SQL transform result schema does not match target dataset '${datasetId}': ${detail}.`);
2945
3236
  }
2946
3237
 
2947
3238
  // src/internal/ducklake-write-coordinator.ts
@@ -2951,20 +3242,20 @@ import {
2951
3242
  getDatasetPrimaryKeyColumns as getDatasetPrimaryKeyColumns4,
2952
3243
  hasDatasetInputChanges,
2953
3244
  LakeConcurrencyError,
2954
- LakeStorageError as LakeStorageError23,
3245
+ LakeStorageError as LakeStorageError24,
2955
3246
  retryDatasetMergeCommit
2956
3247
  } from "@sixb/core/lake-storage";
2957
3248
 
2958
3249
  // src/internal/dataset-row-merge.ts
2959
3250
  import {
2960
3251
  getDatasetPrimaryKeyColumns as getDatasetPrimaryKeyColumns2,
2961
- LakeStorageError as LakeStorageError20,
3252
+ LakeStorageError as LakeStorageError21,
2962
3253
  reconcileDatasetSequences
2963
3254
  } from "@sixb/core/lake-storage";
2964
3255
  async function applyDatasetMergeFromRelation(input) {
2965
3256
  const primaryKeyColumns = getDatasetPrimaryKeyColumns2(input.dataset);
2966
3257
  if (primaryKeyColumns === null) {
2967
- throw new LakeStorageError20(`[SixbDuckLake] Dataset '${input.dataset.id}' must define a primaryKey before it can be merged.`);
3258
+ throw new LakeStorageError21(`[SixbDuckLake] Dataset '${input.dataset.id}' must define a primaryKey before it can be merged.`);
2968
3259
  }
2969
3260
  const stagingTable = quoteIdentifier(input.stagingTableName);
2970
3261
  const targetTable = qualifiedTableName(input.options, encodeDatasetTableName(input.dataset.id));
@@ -3125,7 +3416,7 @@ function finalChangesSelectSql(input, primaryKeyColumns) {
3125
3416
  async function countMergeEffects(input, targetTable, finalChanges, primaryKeyColumns) {
3126
3417
  const matchColumn = primaryKeyColumns[0];
3127
3418
  if (matchColumn === undefined) {
3128
- throw new LakeStorageError20(`[SixbDuckLake] Dataset '${input.dataset.id}' primaryKey must contain at least one column.`);
3419
+ throw new LakeStorageError21(`[SixbDuckLake] Dataset '${input.dataset.id}' primaryKey must contain at least one column.`);
3129
3420
  }
3130
3421
  const keyMatchSql = primaryKeyMatchSql(primaryKeyColumns, "target", "source");
3131
3422
  const targetMatch = `target.${quoteIdentifier(matchColumn)} IS NOT NULL`;
@@ -3179,7 +3470,7 @@ import {
3179
3470
  cloneDatasetMergeChange,
3180
3471
  datasetSequenceChange,
3181
3472
  getDatasetMergeChangeValidationError,
3182
- LakeStorageError as LakeStorageError21
3473
+ LakeStorageError as LakeStorageError22
3183
3474
  } from "@sixb/core/lake-storage";
3184
3475
 
3185
3476
  // src/internal/row-appender.ts
@@ -3280,7 +3571,7 @@ class DuckLakeMergeSession {
3280
3571
  for await (const change of changes) {
3281
3572
  const validationError = getDatasetMergeChangeValidationError(change, this.input.dataset);
3282
3573
  if (validationError) {
3283
- throw new LakeStorageError21(`[SixbDuckLake] ${validationError}`);
3574
+ throw new LakeStorageError22(`[SixbDuckLake] ${validationError}`);
3284
3575
  }
3285
3576
  batch.push({
3286
3577
  sequence: this.nextSequence,
@@ -3343,7 +3634,7 @@ class DuckLakeMergeSession {
3343
3634
  }
3344
3635
  assertOpen() {
3345
3636
  if (this.closed) {
3346
- throw new LakeStorageError21("[SixbDuckLake] Merge session is already closed.");
3637
+ throw new LakeStorageError22("[SixbDuckLake] Merge session is already closed.");
3347
3638
  }
3348
3639
  }
3349
3640
  async cleanup() {
@@ -3363,7 +3654,7 @@ import { getDatasetRowValidationError } from "@sixb/core";
3363
3654
  import {
3364
3655
  encodeDatasetPrimaryKey,
3365
3656
  getDatasetPrimaryKeyColumns as getDatasetPrimaryKeyColumns3,
3366
- LakeStorageError as LakeStorageError22
3657
+ LakeStorageError as LakeStorageError23
3367
3658
  } from "@sixb/core/lake-storage";
3368
3659
  var WRITE_ROW_BATCH_SIZE = 1000;
3369
3660
  async function createDuckLakeWriteSession(input) {
@@ -3394,13 +3685,13 @@ class DuckLakeWriteSession {
3394
3685
  for await (const row of rows) {
3395
3686
  const validationError = getDatasetRowValidationError(row, this.input.dataset);
3396
3687
  if (validationError) {
3397
- throw new LakeStorageError22(`[SixbDuckLake] ${validationError}`);
3688
+ throw new LakeStorageError23(`[SixbDuckLake] ${validationError}`);
3398
3689
  }
3399
3690
  const clonedRow = structuredClone(row);
3400
3691
  if (getDatasetPrimaryKeyColumns3(this.input.dataset) !== null) {
3401
3692
  const primaryKey = encodeDatasetPrimaryKey(this.input.dataset, clonedRow);
3402
3693
  if (this.stagedPrimaryKeys.has(primaryKey) || batchPrimaryKeys.has(primaryKey)) {
3403
- throw new LakeStorageError22(`[SixbDuckLake] Dataset '${this.input.dataset.id}' ${this.input.mode ?? "snapshot"} source contains duplicate primary key.`);
3694
+ throw new LakeStorageError23(`[SixbDuckLake] Dataset '${this.input.dataset.id}' ${this.input.mode ?? "snapshot"} source contains duplicate primary key.`);
3404
3695
  }
3405
3696
  batchPrimaryKeys.add(primaryKey);
3406
3697
  }
@@ -3457,7 +3748,7 @@ class DuckLakeWriteSession {
3457
3748
  }
3458
3749
  assertOpen() {
3459
3750
  if (this.closed) {
3460
- throw new LakeStorageError22("[SixbDuckLake] Write session is already closed.");
3751
+ throw new LakeStorageError23("[SixbDuckLake] Write session is already closed.");
3461
3752
  }
3462
3753
  }
3463
3754
  async cleanup() {
@@ -3465,6 +3756,7 @@ class DuckLakeWriteSession {
3465
3756
  return;
3466
3757
  }
3467
3758
  this.cleanedUp = true;
3759
+ this.stagedPrimaryKeys.clear();
3468
3760
  await this.dropStagingTable();
3469
3761
  }
3470
3762
  async dropStagingTable() {
@@ -3490,7 +3782,7 @@ class DuckLakeWriteCoordinator {
3490
3782
  this.connections.assertOpen();
3491
3783
  const definition = await this.datasets.getDataset(input.dataset.id);
3492
3784
  if (!definition) {
3493
- throw new LakeStorageError23(`[SixbDuckLake] Unknown dataset '${input.dataset.id}'.`);
3785
+ throw new LakeStorageError24(`[SixbDuckLake] Unknown dataset '${input.dataset.id}'.`);
3494
3786
  }
3495
3787
  this.datasets.assertSchema(definition);
3496
3788
  assertUnsequencedDatasetWrite(definition);
@@ -3511,10 +3803,10 @@ class DuckLakeWriteCoordinator {
3511
3803
  this.connections.assertOpen();
3512
3804
  const definition = await this.datasets.getDataset(input.dataset.id);
3513
3805
  if (!definition) {
3514
- throw new LakeStorageError23(`[SixbDuckLake] Unknown dataset '${input.dataset.id}'.`);
3806
+ throw new LakeStorageError24(`[SixbDuckLake] Unknown dataset '${input.dataset.id}'.`);
3515
3807
  }
3516
3808
  if (getDatasetPrimaryKeyColumns4(definition) === null) {
3517
- throw new LakeStorageError23(`[SixbDuckLake] Dataset '${definition.id}' must define a primaryKey before it can be merged.`);
3809
+ throw new LakeStorageError24(`[SixbDuckLake] Dataset '${definition.id}' must define a primaryKey before it can be merged.`);
3518
3810
  }
3519
3811
  this.datasets.assertSchema(definition);
3520
3812
  const latestVersion = await this.connections.withAttachedRuntime((runtime) => this.snapshots.getLatestVersionForDefinition(runtime, definition));
@@ -3532,7 +3824,7 @@ class DuckLakeWriteCoordinator {
3532
3824
  async commitWrite(input) {
3533
3825
  const definition = await this.datasets.getDataset(input.write.dataset.id);
3534
3826
  if (!definition) {
3535
- throw new LakeStorageError23(`[SixbDuckLake] Unknown dataset '${input.write.dataset.id}'.`);
3827
+ throw new LakeStorageError24(`[SixbDuckLake] Unknown dataset '${input.write.dataset.id}'.`);
3536
3828
  }
3537
3829
  const mode = input.write.mode ?? "snapshot";
3538
3830
  assertDatasetWriteMode(mode, "write");
@@ -3553,10 +3845,10 @@ class DuckLakeWriteCoordinator {
3553
3845
  async commitMerge(input) {
3554
3846
  const definition = await this.datasets.getDataset(input.merge.dataset.id);
3555
3847
  if (!definition) {
3556
- throw new LakeStorageError23(`[SixbDuckLake] Unknown dataset '${input.merge.dataset.id}'.`);
3848
+ throw new LakeStorageError24(`[SixbDuckLake] Unknown dataset '${input.merge.dataset.id}'.`);
3557
3849
  }
3558
3850
  if (getDatasetPrimaryKeyColumns4(definition) === null) {
3559
- throw new LakeStorageError23(`[SixbDuckLake] Dataset '${definition.id}' must define a primaryKey before it can be merged.`);
3851
+ throw new LakeStorageError24(`[SixbDuckLake] Dataset '${definition.id}' must define a primaryKey before it can be merged.`);
3560
3852
  }
3561
3853
  return retryDatasetMergeCommit(input.merge, input.commit, (rebase) => this.withCommitRuntime(async (runtime) => {
3562
3854
  input.commit?.signal?.throwIfAborted();
@@ -3584,7 +3876,7 @@ class DuckLakeWriteCoordinator {
3584
3876
  validatedPrimaryKeyColumns: context.validatedPrimaryKeyColumns
3585
3877
  });
3586
3878
  if (result.sourceRowCount !== input.changesWritten) {
3587
- throw new LakeStorageError23(`[SixbDuckLake] Staged merge for dataset '${definition.id}' accepted ${input.changesWritten} change(s), but DuckLake saw ${result.sourceRowCount} source change(s) at commit time.`);
3879
+ throw new LakeStorageError24(`[SixbDuckLake] Staged merge for dataset '${definition.id}' accepted ${input.changesWritten} change(s), but DuckLake saw ${result.sourceRowCount} source change(s) at commit time.`);
3588
3880
  }
3589
3881
  return result;
3590
3882
  }
@@ -3606,7 +3898,7 @@ class DuckLakeWriteCoordinator {
3606
3898
  disableRetries: input.mode === "append" && getDatasetPrimaryKeyColumns4(input.dataset) !== null
3607
3899
  });
3608
3900
  if (result.version === null) {
3609
- throw new LakeStorageError23(`[SixbDuckLake] No DuckLake changes were committed for dataset '${input.dataset.id}', and no previous version exists.`);
3901
+ throw new LakeStorageError24(`[SixbDuckLake] No DuckLake changes were committed for dataset '${input.dataset.id}', and no previous version exists.`);
3610
3902
  }
3611
3903
  return { ...result.version, outcome: result.outcome };
3612
3904
  }
@@ -3637,10 +3929,9 @@ class DuckLakeWriteCoordinator {
3637
3929
  }
3638
3930
  async commitDatasetVersionUnlocked(input) {
3639
3931
  const previousWriteSnapshotId = await this.lastCommittedSnapshotId(input.runtime);
3640
- await input.runtime.run("BEGIN TRANSACTION");
3641
3932
  let committed = false;
3642
3933
  try {
3643
- const latestVersion = await this.latestVersionForCommit(input);
3934
+ const latestVersion = await this.beginVersionTransaction(input);
3644
3935
  if (input.expectedLatestVersionId !== undefined) {
3645
3936
  this.assertExpectedLatestVersion({
3646
3937
  datasetId: input.dataset.id,
@@ -3688,7 +3979,7 @@ class DuckLakeWriteCoordinator {
3688
3979
  if (version) {
3689
3980
  return { outcome: "created", version };
3690
3981
  }
3691
- throw new LakeStorageError23(`[SixbDuckLake] DuckLake committed snapshot '${ownSnapshotId}' for dataset '${input.dataset.id}', but Sixb could not hydrate it as a dataset version.`);
3982
+ throw new LakeStorageError24(`[SixbDuckLake] DuckLake committed snapshot '${ownSnapshotId}' for dataset '${input.dataset.id}', but Sixb could not hydrate it as a dataset version.`);
3692
3983
  }
3693
3984
  if (!input.changeResult.dataChangeExpected) {
3694
3985
  const version = await this.versionForNoOpCommit(input.runtime, input.dataset, input.allowInitialNoOp ?? false);
@@ -3706,9 +3997,9 @@ class DuckLakeWriteCoordinator {
3706
3997
  };
3707
3998
  }
3708
3999
  if (input.committedWriteSnapshotId === input.previousWriteSnapshotId) {
3709
- throw new LakeStorageError23(`[SixbDuckLake] DuckLake commit for dataset '${input.dataset.id}' completed without producing a snapshot for this non-empty write.`);
4000
+ throw new LakeStorageError24(`[SixbDuckLake] DuckLake commit for dataset '${input.dataset.id}' completed without producing a snapshot for this non-empty write.`);
3710
4001
  }
3711
- throw new LakeStorageError23(`[SixbDuckLake] DuckLake commit for dataset '${input.dataset.id}' completed, but Sixb could not find a matching snapshot for this write.`);
4002
+ throw new LakeStorageError24(`[SixbDuckLake] DuckLake commit for dataset '${input.dataset.id}' completed, but Sixb could not find a matching snapshot for this write.`);
3712
4003
  }
3713
4004
  async applyStagedRows(input) {
3714
4005
  const mode = input.write.mode ?? "snapshot";
@@ -3721,7 +4012,7 @@ class DuckLakeWriteCoordinator {
3721
4012
  previousRowCount: input.previousRowCount
3722
4013
  });
3723
4014
  if (result.sourceRowCount !== input.rowsWritten) {
3724
- throw new LakeStorageError23(`[SixbDuckLake] Staged write for dataset '${input.write.dataset.id}' accepted ${input.rowsWritten} row(s), but DuckLake saw ${result.sourceRowCount} source row(s) at commit time.`);
4015
+ throw new LakeStorageError24(`[SixbDuckLake] Staged write for dataset '${input.write.dataset.id}' accepted ${input.rowsWritten} row(s), but DuckLake saw ${result.sourceRowCount} source row(s) at commit time.`);
3725
4016
  }
3726
4017
  return result;
3727
4018
  }
@@ -3743,7 +4034,7 @@ class DuckLakeWriteCoordinator {
3743
4034
  if (changeResult.dataChangeExpected) {
3744
4035
  return;
3745
4036
  }
3746
- const latestVersion = knownLatestVersion ?? await this.snapshots.getLatestVersionSummaryForDefinition(input.runtime, input.dataset);
4037
+ const latestVersion = knownLatestVersion === undefined ? await this.snapshots.getLatestVersionSummaryForDefinition(input.runtime, input.dataset) : knownLatestVersion;
3747
4038
  if (latestVersion ? input.mode === "merge" || !hasDatasetInputChanges(latestVersion.inputs, input.inputs) : input.allowInitialNoOp) {
3748
4039
  return;
3749
4040
  }
@@ -3759,18 +4050,39 @@ class DuckLakeWriteCoordinator {
3759
4050
  if (allowInitialNoOp) {
3760
4051
  return null;
3761
4052
  }
3762
- throw new LakeStorageError23(`[SixbDuckLake] No DuckLake changes were committed for dataset '${definition.id}', and no previous version exists.`);
4053
+ throw new LakeStorageError24(`[SixbDuckLake] No DuckLake changes were committed for dataset '${definition.id}', and no previous version exists.`);
3763
4054
  }
3764
4055
  async rollbackTransaction(runtime) {
3765
4056
  try {
3766
4057
  await runtime.run("ROLLBACK");
3767
4058
  } catch {}
3768
4059
  }
3769
- async latestVersionForCommit(input) {
3770
- if (input.expectedLatestVersionId === undefined && input.mode !== "append") {
3771
- return null;
4060
+ async beginVersionTransaction(input) {
4061
+ if (!isSqliteCatalog(this.options.catalog)) {
4062
+ await input.runtime.run("BEGIN TRANSACTION");
4063
+ if (input.expectedLatestVersionId === undefined && input.mode !== "append") {
4064
+ return;
4065
+ }
4066
+ return this.snapshots.getLatestVersionSummaryForDefinition(input.runtime, input.dataset);
3772
4067
  }
3773
- return this.snapshots.getLatestVersionSummaryForDefinition(input.runtime, input.dataset);
4068
+ for (let attempt = 0;attempt < 3; attempt++) {
4069
+ input.signal?.throwIfAborted();
4070
+ const snapshotId = await this.currentSnapshotId(input.runtime);
4071
+ const latestVersion = await this.snapshots.getLatestVersionSummaryForDefinition(input.runtime, input.dataset);
4072
+ await input.runtime.run("BEGIN TRANSACTION");
4073
+ if (await this.currentSnapshotId(input.runtime) === snapshotId) {
4074
+ return latestVersion;
4075
+ }
4076
+ await input.runtime.run("ROLLBACK");
4077
+ }
4078
+ throw new LakeConcurrencyError(`[SixbDuckLake] Catalog changed during three write preparations for dataset '${input.dataset.id}'. Retry the write.`);
4079
+ }
4080
+ async currentSnapshotId(runtime) {
4081
+ const [row] = await runtime.query(`SELECT id FROM ${quoteIdentifier(duckLakeAlias(this.options))}.current_snapshot()`);
4082
+ if (row === undefined) {
4083
+ throw new LakeStorageError24("[SixbDuckLake] DuckLake did not return a current snapshot.");
4084
+ }
4085
+ return String(getBigIntLike(row, "id"));
3774
4086
  }
3775
4087
  async lastCommittedSnapshotId(runtime) {
3776
4088
  const [row] = await runtime.query(`SELECT id FROM ${quoteIdentifier(duckLakeAlias(this.options))}.last_committed_snapshot()`);
@@ -3819,6 +4131,9 @@ class DuckLakeWriteCoordinator {
3819
4131
  }
3820
4132
  }
3821
4133
  }
4134
+ function isSqliteCatalog(catalog) {
4135
+ return catalog.type === "sqlite" || catalog.type === "custom" && catalog.uri.toLowerCase().startsWith("sqlite:");
4136
+ }
3822
4137
  function commitRowCount(input, changeResult, latestVersion) {
3823
4138
  if (input.mode === "append" && input.expectedLatestVersionId === undefined) {
3824
4139
  return { kind: "unknown" };
@@ -3833,7 +4148,7 @@ function commitRowCount(input, changeResult, latestVersion) {
3833
4148
  }
3834
4149
  function assertDuckLakeSnapshotId3(snapshotId) {
3835
4150
  if (!/^\d+$/.test(snapshotId)) {
3836
- throw new LakeStorageError23(`[SixbDuckLake] Invalid DuckLake snapshot id '${snapshotId}'.`);
4151
+ throw new LakeStorageError24(`[SixbDuckLake] Invalid DuckLake snapshot id '${snapshotId}'.`);
3837
4152
  }
3838
4153
  }
3839
4154
  var localCatalogCommitLocks = new Map;
@@ -3939,4 +4254,4 @@ export {
3939
4254
  DuckLakeStorage
3940
4255
  };
3941
4256
 
3942
- //# debugId=555594FFA13F16F264756E2164756E21
4257
+ //# debugId=35ABBEC5A94F36A964756E2164756E21