@crvouga/sqlite-mem 1.9.0 → 1.11.0

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/unstable.js CHANGED
@@ -5964,6 +5964,10 @@ var IndexStore = class _IndexStore {
5964
5964
  rememberKeyValues(key, values) {
5965
5965
  this.keyValues.set(key, [...values]);
5966
5966
  }
5967
+ /** Key component values for snapshot encode (binary keys). */
5968
+ keyValuesFor(key) {
5969
+ return [...this.keyValues.get(key) ?? []];
5970
+ }
5967
5971
  get size() {
5968
5972
  return this.entries.size;
5969
5973
  }
@@ -6061,14 +6065,6 @@ function indexKeyValues(columns, row, ctx, table) {
6061
6065
  return normalizeForCollation(raw, column.collate ?? "BINARY");
6062
6066
  });
6063
6067
  }
6064
- function rebuildIndexFromTable(index, table, ctxForRow) {
6065
- index.store.clear();
6066
- for (const row of table.scan()) {
6067
- const ctx = ctxForRow(row);
6068
- if (index.where && isTruthySql(evalExpr(index.where, ctx)) !== true) continue;
6069
- index.store.insert(indexKeyValues(index.columns, row, ctx, table), row.rowid, index.unique);
6070
- }
6071
- }
6072
6068
  function tableRowEvalContext(table, row) {
6073
6069
  return {
6074
6070
  functions: defaultFunctionRegistry,
@@ -6089,6 +6085,126 @@ function tableRowEvalContext(table, row) {
6089
6085
  };
6090
6086
  }
6091
6087
 
6088
+ // src/storage/columnar-slab.ts
6089
+ var PACK_NULL = 0;
6090
+ var PACK_I32 = 1;
6091
+ var PACK_I64 = 2;
6092
+ var PACK_F64 = 3;
6093
+ var PACK_TEXT_INTERN = 4;
6094
+ var PACK_TEXT_INLINE = 5;
6095
+ var PACK_BLOB = 6;
6096
+ var PACK_TAGGED = 7;
6097
+ var ColumnarSlab = class {
6098
+ buffer;
6099
+ rowCount;
6100
+ rowids;
6101
+ columns;
6102
+ intern;
6103
+ rowidIndex = null;
6104
+ constructor(buffer, rowCount, rowids, columns, intern) {
6105
+ this.buffer = buffer;
6106
+ this.rowCount = rowCount;
6107
+ this.rowids = rowids;
6108
+ this.columns = columns;
6109
+ this.intern = intern;
6110
+ }
6111
+ rowIndex(rowid) {
6112
+ this.rowidIndex ??= new Map(this.rowids.map((id, i) => [canonicalRowid(id), i]));
6113
+ const hit = this.rowidIndex.get(canonicalRowid(rowid));
6114
+ if (hit === void 0) return -1;
6115
+ return hit;
6116
+ }
6117
+ cell(rowIndex, col) {
6118
+ if (rowIndex < 0 || rowIndex >= this.rowCount) return null;
6119
+ const column = this.columns[col];
6120
+ if (!column) return null;
6121
+ if (column.nullBitmap && isNull(column.nullBitmap, rowIndex)) return null;
6122
+ return readSlabCell(column, rowIndex, this.intern);
6123
+ }
6124
+ rowAt(rowIndex) {
6125
+ const values = new Array(this.columns.length);
6126
+ for (let c = 0; c < this.columns.length; c++) values[c] = this.cell(rowIndex, c);
6127
+ return { rowid: this.rowids[rowIndex], values };
6128
+ }
6129
+ get(rowid) {
6130
+ const i = this.rowIndex(rowid);
6131
+ if (i < 0) return void 0;
6132
+ return this.rowAt(i);
6133
+ }
6134
+ *scan() {
6135
+ for (let i = 0; i < this.rowCount; i++) yield this.rowAt(i);
6136
+ }
6137
+ materialize() {
6138
+ const map = /* @__PURE__ */ new Map();
6139
+ for (let i = 0; i < this.rowCount; i++) {
6140
+ const row = this.rowAt(i);
6141
+ map.set(row.rowid, row);
6142
+ }
6143
+ return map;
6144
+ }
6145
+ };
6146
+ function canonicalRowid(rowid) {
6147
+ return typeof rowid === "bigint" ? rowid : rowid;
6148
+ }
6149
+ function isNull(bits, i) {
6150
+ return (bits[i >> 3] & 1 << (i & 7)) !== 0;
6151
+ }
6152
+ function readSlabCell(column, rowIndex, intern) {
6153
+ const pack = column.pack;
6154
+ if (pack === PACK_NULL) return null;
6155
+ const nonNullIndex = nonNullRowIndex(column, rowIndex);
6156
+ const view = new DataView(column.payload.buffer, column.payload.byteOffset, column.payload.byteLength);
6157
+ if (pack === PACK_I32) {
6158
+ return view.getInt32(nonNullIndex * 4, true);
6159
+ }
6160
+ if (pack === PACK_I64) {
6161
+ const integer = view.getBigInt64(nonNullIndex * 8, true);
6162
+ return integer <= BigInt(Number.MAX_SAFE_INTEGER) && integer >= BigInt(Number.MIN_SAFE_INTEGER) ? Number(integer) : integer;
6163
+ }
6164
+ if (pack === PACK_F64) {
6165
+ const value = view.getFloat64(nonNullIndex * 8, true);
6166
+ return Number.isInteger(value) && Number.isFinite(value) ? asSqlReal(value) : value;
6167
+ }
6168
+ if (pack === PACK_TEXT_INTERN) {
6169
+ const id = view.getUint32(nonNullIndex * 4, true);
6170
+ return intern[id] ?? "";
6171
+ }
6172
+ if (pack === PACK_TEXT_INLINE) {
6173
+ const offsets = column.inlineOffsets;
6174
+ const start = offsets[nonNullIndex];
6175
+ const end = nonNullIndex + 1 < offsets.length ? offsets[nonNullIndex + 1] : column.payload.length;
6176
+ return new TextDecoder().decode(column.payload.subarray(start, end));
6177
+ }
6178
+ if (pack === PACK_BLOB) {
6179
+ const blob = column.blobChunks[nonNullIndex];
6180
+ return blob;
6181
+ }
6182
+ if (pack === PACK_TAGGED) {
6183
+ return column.tagged[nonNullIndex] ?? null;
6184
+ }
6185
+ return null;
6186
+ }
6187
+ function nonNullRowIndex(column, rowIndex) {
6188
+ if (!column.nullBitmap) return rowIndex;
6189
+ let idx = 0;
6190
+ for (let i = 0; i < rowIndex; i++) {
6191
+ if (!isNull(column.nullBitmap, i)) idx++;
6192
+ }
6193
+ return idx;
6194
+ }
6195
+ function packKindOf(value) {
6196
+ if (value instanceof SqlReal) return PACK_F64;
6197
+ if (typeof value === "bigint") return PACK_I64;
6198
+ if (typeof value === "number" && Number.isInteger(value)) {
6199
+ return value >= -2147483648 && value <= 2147483647 ? PACK_I32 : PACK_I64;
6200
+ }
6201
+ if (typeof value === "number") return PACK_F64;
6202
+ if (value instanceof SqlJsonText) return PACK_TAGGED;
6203
+ if (typeof value === "string") return PACK_TEXT_INTERN;
6204
+ if (value instanceof Uint8Array) return PACK_BLOB;
6205
+ return PACK_TAGGED;
6206
+ }
6207
+
6092
6208
  // src/types/strict.ts
6093
6209
  var STRICT_TYPES = /* @__PURE__ */ new Set(["INT", "INTEGER", "REAL", "TEXT", "BLOB", "ANY"]);
6094
6210
  function isStrictTypeName(typeName) {
@@ -7709,6 +7825,8 @@ var Table = class _Table {
7709
7825
  strict;
7710
7826
  /** Clustered PK key string → row for WITHOUT ROWID tables. */
7711
7827
  clusteredRows;
7828
+ /** Frozen columnar storage after snapshot hydrate; `rows` stays empty until materialized. */
7829
+ slab = null;
7712
7830
  scanCache = null;
7713
7831
  /** Lazy covering hashes: column nameLower → serializeIndexKey → rowids. */
7714
7832
  equalityHashes = null;
@@ -7772,12 +7890,49 @@ var Table = class _Table {
7772
7890
  return this.integerPrimaryKeyAlias();
7773
7891
  }
7774
7892
  get(rowid) {
7893
+ if (this.slab) {
7894
+ const hit = this.slab.get(rowid);
7895
+ return hit ?? void 0;
7896
+ }
7775
7897
  try {
7776
- return this.rows.get(canonicalRowid(rowid));
7898
+ return this.rows.get(canonicalRowid2(rowid));
7777
7899
  } catch {
7778
7900
  return void 0;
7779
7901
  }
7780
7902
  }
7903
+ /** Row count (slab-backed or map-backed). */
7904
+ rowCount() {
7905
+ return this.slab ? this.slab.rowCount : this.rows.size;
7906
+ }
7907
+ /** Rows sorted by rowid for snapshot encode. */
7908
+ sortedRows() {
7909
+ if (this.slab) return [...this.slab.scan()].map((r) => ({ rowid: r.rowid, values: [...r.values] }));
7910
+ return [...this.rows.values()].sort((a, b) => compareRowids(a.rowid, b.rowid));
7911
+ }
7912
+ /** Attach decoded columnar slab (hydrate path). */
7913
+ attachSlab(slab) {
7914
+ this.slab = slab;
7915
+ this.invalidateScan();
7916
+ }
7917
+ /** Materialize slab into `rows` Map for mutation. */
7918
+ materializeSlab() {
7919
+ if (!this.slab) return;
7920
+ for (const row of this.slab.scan()) this.rows.set(row.rowid, { rowid: row.rowid, values: [...row.values] });
7921
+ this.slab = null;
7922
+ this.invalidateScan();
7923
+ }
7924
+ hasRow(rowid) {
7925
+ if (this.slab) return this.slab.get(rowid) !== void 0;
7926
+ try {
7927
+ return this.rows.has(canonicalRowid2(rowid));
7928
+ } catch {
7929
+ return false;
7930
+ }
7931
+ }
7932
+ allRowids() {
7933
+ if (this.slab) return this.slab.rowids;
7934
+ return this.rows.keys();
7935
+ }
7781
7936
  getByKey(value) {
7782
7937
  if (value === null || this.withoutRowid) return void 0;
7783
7938
  try {
@@ -7821,20 +7976,21 @@ var Table = class _Table {
7821
7976
  if (!rowids || rowids.length === 0) return [];
7822
7977
  const rows = [];
7823
7978
  for (const rowid of rowids) {
7824
- const row = this.rows.get(rowid);
7979
+ const row = this.get(rowid);
7825
7980
  if (row) rows.push(row);
7826
7981
  }
7827
7982
  return rows;
7828
7983
  }
7829
7984
  ensureEqualityHash(columnLower) {
7830
- if (this.frozen || this.rows.size < EQUALITY_HASH_MIN_ROWS) return false;
7985
+ if (this.frozen || this.rowCount() < EQUALITY_HASH_MIN_ROWS) return false;
7831
7986
  const column = this.columns.find((item) => item.nameLower === columnLower);
7832
7987
  if (!column) return false;
7833
7988
  this.equalityHashes ??= /* @__PURE__ */ new Map();
7834
7989
  if (this.equalityHashes.has(columnLower)) return true;
7835
7990
  const map = /* @__PURE__ */ new Map();
7836
7991
  const collate = column.collate ?? "BINARY";
7837
- for (const row of this.rows.values()) {
7992
+ const iter = this.slab ? this.slab.scan() : this.rows.values();
7993
+ for (const row of iter) {
7838
7994
  const key = serializeIndexKey([normalizeForCollation(this.cell(row, columnLower), collate)]);
7839
7995
  if (key === null) continue;
7840
7996
  const bucket = map.get(key);
@@ -7880,7 +8036,7 @@ var Table = class _Table {
7880
8036
  if (supplied.rowid !== void 0) {
7881
8037
  throw new SqliteError(`table ${this.name} has no column named rowid`, "other");
7882
8038
  }
7883
- const rowid2 = canonicalRowid(this.allocateRowid());
8039
+ const rowid2 = canonicalRowid2(this.allocateRowid());
7884
8040
  const candidate2 = { rowid: rowid2, values };
7885
8041
  if (!options?.skipValidate) this.validate(candidate2);
7886
8042
  const clusterKey = this.makeClusterKey(values);
@@ -7899,8 +8055,8 @@ var Table = class _Table {
7899
8055
  const value = this.cell({ rowid: 0, values }, normalizeColumnName(alias.name));
7900
8056
  if (rowid === void 0 && value !== null) rowid = asRowid(value, alias.name);
7901
8057
  }
7902
- rowid = canonicalRowid(rowid ?? this.allocateRowid());
7903
- if (this.rows.has(rowid)) {
8058
+ rowid = canonicalRowid2(rowid ?? this.allocateRowid());
8059
+ if (this.hasRow(rowid)) {
7904
8060
  throw new SqliteError(
7905
8061
  `UNIQUE constraint failed: ${this.name}.rowid`,
7906
8062
  "constraint_primary",
@@ -7917,7 +8073,7 @@ var Table = class _Table {
7917
8073
  }
7918
8074
  update(rowid, updates) {
7919
8075
  this.assertMutable();
7920
- const key = canonicalRowid(rowid);
8076
+ const key = canonicalRowid2(rowid);
7921
8077
  const existing = this.rows.get(key);
7922
8078
  if (!existing) return void 0;
7923
8079
  const values = existing.values.slice();
@@ -7952,7 +8108,7 @@ var Table = class _Table {
7952
8108
  const alias = this.integerPrimaryKeyAlias();
7953
8109
  const aliasRow = { rowid: key, values };
7954
8110
  const targetKey = alias ? asRowid(this.cell(aliasRow, normalizeColumnName(alias.name)), alias.name) : key;
7955
- if (targetKey !== key && this.rows.has(targetKey)) {
8111
+ if (targetKey !== key && this.hasRow(targetKey)) {
7956
8112
  throw new SqliteError(
7957
8113
  `UNIQUE constraint failed: ${this.name}.${alias?.name ?? "rowid"}`,
7958
8114
  "constraint_unique",
@@ -7975,7 +8131,7 @@ var Table = class _Table {
7975
8131
  }
7976
8132
  delete(rowid) {
7977
8133
  this.assertMutable();
7978
- const key = canonicalRowid(rowid);
8134
+ const key = canonicalRowid2(rowid);
7979
8135
  const existing = this.rows.get(key);
7980
8136
  if (!existing) return false;
7981
8137
  if (this.withoutRowid) this.clusteredRows.delete(this.makeClusterKey(existing.values));
@@ -7987,6 +8143,10 @@ var Table = class _Table {
7987
8143
  return this.rows.delete(key);
7988
8144
  }
7989
8145
  *scan() {
8146
+ if (this.slab) {
8147
+ yield* this.slab.scan();
8148
+ return;
8149
+ }
7990
8150
  if (!this.scanCache) {
7991
8151
  if (this.withoutRowid) {
7992
8152
  this.scanCache = [...this.clusteredRows.values()].sort((a, b) => this.comparePrimaryKeys(a, b));
@@ -8006,7 +8166,16 @@ var Table = class _Table {
8006
8166
  });
8007
8167
  copy.nextRowid = this.nextRowid;
8008
8168
  copy.maximumRowid = this.maximumRowid;
8009
- for (const [rowid, row] of this.rows) copy.rows.set(rowid, cloneRow(row));
8169
+ if (this.slab) {
8170
+ let max = null;
8171
+ for (const row of this.slab.scan()) {
8172
+ copy.rows.set(row.rowid, cloneRow(row));
8173
+ if (max === null || compareRowids(row.rowid, max) > 0) max = row.rowid;
8174
+ }
8175
+ copy.maximumRowid = max ?? void 0;
8176
+ } else {
8177
+ for (const [rowid, row] of this.rows) copy.rows.set(rowid, cloneRow(row));
8178
+ }
8010
8179
  for (const [clusterKey, row] of this.clusteredRows) copy.clusteredRows.set(clusterKey, cloneRow(row));
8011
8180
  return copy;
8012
8181
  }
@@ -8015,13 +8184,15 @@ var Table = class _Table {
8015
8184
  }
8016
8185
  assertMutable() {
8017
8186
  if (this.frozen) throw new SqliteError("internal: cannot mutate a frozen table", "other");
8187
+ if (this.slab) this.materializeSlab();
8018
8188
  }
8019
8189
  /** Rebuild clustered storage after snapshot decode or bulk load. */
8020
8190
  rebuildClusteredRows() {
8021
8191
  this.maximumRowid = void 0;
8022
8192
  if (!this.withoutRowid) return;
8023
8193
  this.clusteredRows.clear();
8024
- for (const row of this.rows.values()) {
8194
+ const iter = this.slab ? this.slab.scan() : this.rows.values();
8195
+ for (const row of iter) {
8025
8196
  this.clusteredRows.set(this.makeClusterKey(row.values), row);
8026
8197
  }
8027
8198
  this.invalidateScan();
@@ -8145,15 +8316,19 @@ var Table = class _Table {
8145
8316
  if (!this.columns.some((column) => column.autoincrement)) {
8146
8317
  if (this.maximumRowid === void 0) {
8147
8318
  this.maximumRowid = null;
8148
- for (const rowid of this.rows.keys()) {
8319
+ for (const rowid of this.allRowids()) {
8320
+ if (this.maximumRowid === null || compareRowids(rowid, this.maximumRowid) > 0) this.maximumRowid = rowid;
8321
+ }
8322
+ } else if (this.maximumRowid === null && this.rowCount() > 0) {
8323
+ for (const rowid of this.allRowids()) {
8149
8324
  if (this.maximumRowid === null || compareRowids(rowid, this.maximumRowid) > 0) this.maximumRowid = rowid;
8150
8325
  }
8151
8326
  }
8152
8327
  return this.maximumRowid === null ? 1 : incrementRowid(this.maximumRowid);
8153
8328
  }
8154
8329
  const maxSigned = 9223372036854775807n;
8155
- let candidate = canonicalRowid(this.nextRowid);
8156
- while (this.rows.has(candidate)) {
8330
+ let candidate = canonicalRowid2(this.nextRowid);
8331
+ while (this.hasRow(candidate)) {
8157
8332
  if (BigInt(candidate) >= maxSigned) {
8158
8333
  throw new SqliteError("database or disk is full", "other", "SQLITE_FULL");
8159
8334
  }
@@ -8193,7 +8368,7 @@ function namedFromArray(table, values) {
8193
8368
  return named;
8194
8369
  }
8195
8370
  function asRowid(value, column) {
8196
- if (typeof value === "bigint") return canonicalRowid(value);
8371
+ if (typeof value === "bigint") return canonicalRowid2(value);
8197
8372
  if (typeof value === "number" && Number.isSafeInteger(value)) return value;
8198
8373
  throw new SqliteError(
8199
8374
  `datatype mismatch for INTEGER PRIMARY KEY column: ${column}`,
@@ -8201,7 +8376,7 @@ function asRowid(value, column) {
8201
8376
  "SQLITE_MISMATCH"
8202
8377
  );
8203
8378
  }
8204
- function canonicalRowid(value) {
8379
+ function canonicalRowid2(value) {
8205
8380
  if (typeof value === "number") {
8206
8381
  if (!Number.isSafeInteger(value))
8207
8382
  throw new SqliteError("rowid must be a safe integer or bigint", "datatype_mismatch", "SQLITE_MISMATCH");
@@ -8798,24 +8973,53 @@ function keyOf(name) {
8798
8973
  return name.toLowerCase();
8799
8974
  }
8800
8975
 
8801
- // src/serialization/codec.ts
8802
- var MAGIC = utf8Encode("SQLM");
8803
- var VERSION = 4;
8804
- var VERSION_V1 = 1;
8805
- var VERSION_V2 = 2;
8806
- var VERSION_V3 = 3;
8976
+ // src/serialization/wire.ts
8977
+ function writeVarintU32(w, value) {
8978
+ let v = value >>> 0;
8979
+ while (v >= 128) {
8980
+ w.u8(v & 127 | 128);
8981
+ v >>>= 7;
8982
+ }
8983
+ w.u8(v);
8984
+ }
8985
+ function readVarintU32(r) {
8986
+ let result = 0;
8987
+ let shift = 0;
8988
+ for (; ; ) {
8989
+ const byte = r.u8();
8990
+ result |= (byte & 127) << shift;
8991
+ if ((byte & 128) === 0) return result >>> 0;
8992
+ shift += 7;
8993
+ if (shift > 28) r.fail();
8994
+ }
8995
+ }
8807
8996
  var Writer = class {
8808
- buf = new Uint8Array(4096);
8809
- view = new DataView(this.buf.buffer);
8997
+ buf;
8998
+ view;
8810
8999
  len = 0;
9000
+ constructor(capacity = 4096) {
9001
+ this.buf = new Uint8Array(capacity);
9002
+ this.view = new DataView(this.buf.buffer);
9003
+ }
9004
+ get position() {
9005
+ return this.len;
9006
+ }
9007
+ reserve(capacity) {
9008
+ if (capacity <= this.buf.length) return;
9009
+ const next = new Uint8Array(capacity);
9010
+ next.set(this.buf.subarray(0, this.len));
9011
+ this.buf = next;
9012
+ this.view = new DataView(next.buffer);
9013
+ }
8811
9014
  ensure(needed) {
8812
9015
  if (this.len + needed <= this.buf.length) return;
8813
9016
  let cap = this.buf.length;
8814
9017
  while (cap < this.len + needed) cap *= 2;
8815
- const next = new Uint8Array(cap);
8816
- next.set(this.buf.subarray(0, this.len));
8817
- this.buf = next;
8818
- this.view = new DataView(next.buffer);
9018
+ this.reserve(cap);
9019
+ }
9020
+ align4() {
9021
+ const pad2 = 4 - (this.len & 3) & 3;
9022
+ for (let i = 0; i < pad2; i++) this.u8(0);
8819
9023
  }
8820
9024
  u8(value) {
8821
9025
  this.ensure(1);
@@ -8846,52 +9050,28 @@ var Writer = class {
8846
9050
  this.buf.set(value, this.len);
8847
9051
  this.len += value.length;
8848
9052
  }
8849
- text(value) {
8850
- const bytes = utf8Encode(value);
8851
- this.u32(bytes.length);
8852
- this.raw(bytes);
9053
+ rawAt(offset, value) {
9054
+ if (offset + value.length > this.len) this.fail();
9055
+ this.buf.set(value, offset);
8853
9056
  }
8854
- json(value) {
8855
- this.text(JSON.stringify(value, jsonReplacer));
9057
+ /** Length-prefixed UTF-8 via encodeInto when possible. */
9058
+ text(value) {
9059
+ const encoded = utf8Encode(value);
9060
+ writeVarintU32(this, encoded.length);
9061
+ this.raw(encoded);
8856
9062
  }
8857
- value(value) {
8858
- if (value === null) {
8859
- this.u8(0);
8860
- return;
8861
- }
8862
- if (value instanceof SqlReal) {
8863
- this.u8(2);
8864
- this.f64(value.value);
8865
- return;
8866
- }
8867
- if (typeof value === "bigint" || typeof value === "number" && Number.isInteger(value)) {
8868
- this.u8(1);
8869
- this.i64(BigInt(value));
8870
- return;
8871
- }
8872
- if (typeof value === "number") {
8873
- this.u8(2);
8874
- this.f64(value);
8875
- return;
8876
- }
8877
- if (typeof value === "string") {
8878
- this.u8(3);
8879
- this.text(value);
8880
- return;
8881
- }
8882
- if (value instanceof SqlJsonText) {
8883
- this.u8(3);
8884
- this.text(value.value);
8885
- return;
8886
- }
8887
- this.u8(4);
8888
- this.u32(value.length);
8889
- this.raw(value);
9063
+ /** Write UTF-8 at current position without length prefix (intern blob region). */
9064
+ textBytes(value) {
9065
+ const encoded = utf8Encode(value);
9066
+ this.raw(encoded);
8890
9067
  }
8891
9068
  finish() {
8892
9069
  if (this.len === this.buf.length) return this.buf;
8893
9070
  return this.buf.subarray(0, this.len).slice();
8894
9071
  }
9072
+ fail() {
9073
+ throw new SqliteError("invalid or truncated sqlite-mem snapshot", "other");
9074
+ }
8895
9075
  };
8896
9076
  var Reader = class {
8897
9077
  constructor(bytes) {
@@ -8901,6 +9081,13 @@ var Reader = class {
8901
9081
  bytes;
8902
9082
  offset = 0;
8903
9083
  view;
9084
+ get position() {
9085
+ return this.offset;
9086
+ }
9087
+ skipAlign4() {
9088
+ const pad2 = 4 - (this.offset & 3) & 3;
9089
+ this.offset += pad2;
9090
+ }
8904
9091
  u8() {
8905
9092
  if (this.offset >= this.bytes.length) this.fail();
8906
9093
  return this.bytes[this.offset++];
@@ -8935,33 +9122,9 @@ var Reader = class {
8935
9122
  this.offset += length;
8936
9123
  return value;
8937
9124
  }
8938
- owned(length) {
8939
- return this.raw(length).slice();
8940
- }
8941
9125
  text() {
8942
- return utf8Decode(this.raw(this.u32()));
8943
- }
8944
- json() {
8945
- try {
8946
- return JSON.parse(this.text(), jsonReviver);
8947
- } catch {
8948
- throw new SqliteError("invalid or truncated sqlite-mem snapshot", "other");
8949
- }
8950
- }
8951
- value() {
8952
- const tag = this.u8();
8953
- if (tag === 0) return null;
8954
- if (tag === 1) {
8955
- const integer = this.i64();
8956
- return integer <= BigInt(Number.MAX_SAFE_INTEGER) && integer >= BigInt(Number.MIN_SAFE_INTEGER) ? Number(integer) : integer;
8957
- }
8958
- if (tag === 2) {
8959
- const value = this.f64();
8960
- return Number.isInteger(value) && Number.isFinite(value) ? asSqlReal(value) : value;
8961
- }
8962
- if (tag === 3) return this.text();
8963
- if (tag === 4) return this.owned(this.u32());
8964
- this.fail();
9126
+ const length = readVarintU32(this);
9127
+ return utf8Decode(this.raw(length));
8965
9128
  }
8966
9129
  remaining() {
8967
9130
  return this.bytes.length - this.offset;
@@ -8973,409 +9136,317 @@ var Reader = class {
8973
9136
  throw new SqliteError("invalid or truncated sqlite-mem snapshot", "other");
8974
9137
  }
8975
9138
  };
8976
- function encodeDatabaseState(state, runtime, formatVersion = VERSION) {
8977
- if (formatVersion >= 4) return encodeV4(state, runtime);
8978
- return encodeLegacy(state, runtime, formatVersion);
8979
- }
8980
- function encodeLegacy(state, runtime, formatVersion) {
8981
- const writer = new Writer();
8982
- writer.raw(MAGIC);
8983
- writer.u32(formatVersion);
8984
- writer.u8(state.foreignKeysEnabled ? 1 : 0);
8985
- writer.u32(state.schemaVersion);
8986
- writer.u32(state.changes);
8987
- writer.u32(state.totalChanges);
8988
- writer.value(state.lastInsertRowid);
8989
- writer.u32(state.tables.size);
8990
- for (const table of sortedValues(state.tables)) {
8991
- writer.json({
8992
- name: table.name,
8993
- columns: table.columns,
8994
- constraints: table.constraints,
8995
- indexes: [...table.indexes].sort(compareNames),
8996
- originalSql: table.originalSql,
8997
- withoutRowid: table.withoutRowid || void 0,
8998
- strict: table.strict || void 0
8999
- });
9000
- writer.value(table.nextRowid);
9001
- const rows = [...table.rows.values()].sort((a, b) => compareRowids2(a.rowid, b.rowid));
9002
- writer.u32(rows.length);
9003
- for (const row of rows) {
9004
- writer.value(row.rowid);
9005
- writer.u32(table.columns.length);
9006
- for (const column of table.columns) writer.value(table.cell(row, column.nameLower ?? column.name.toLowerCase()));
9139
+ var BJV_NULL = 0;
9140
+ var BJV_FALSE = 1;
9141
+ var BJV_TRUE = 2;
9142
+ var BJV_I32 = 3;
9143
+ var BJV_I64 = 4;
9144
+ var BJV_F64 = 5;
9145
+ var BJV_INTERN = 6;
9146
+ var BJV_STRING = 7;
9147
+ var BJV_BYTES = 8;
9148
+ var BJV_ARRAY = 9;
9149
+ var BJV_OBJECT = 10;
9150
+ function writeBjv(w, value, forceIntern) {
9151
+ if (value === null || value === void 0) {
9152
+ w.u8(BJV_NULL);
9153
+ return;
9154
+ }
9155
+ if (typeof value === "boolean") {
9156
+ w.u8(value ? BJV_TRUE : BJV_FALSE);
9157
+ return;
9158
+ }
9159
+ if (typeof value === "number") {
9160
+ if (Number.isInteger(value) && value >= -2147483648 && value <= 2147483647) {
9161
+ w.u8(BJV_I32);
9162
+ w.u32(value | 0);
9163
+ return;
9007
9164
  }
9165
+ w.u8(BJV_F64);
9166
+ w.f64(value);
9167
+ return;
9008
9168
  }
9009
- const views = sortedValues(state.views);
9010
- writer.u32(views.length);
9011
- for (const view of views) writer.json(view);
9012
- const indexes = sortedValues(state.indexes);
9013
- writer.u32(indexes.length);
9014
- for (const index of indexes) {
9015
- writer.json({
9016
- name: index.name,
9017
- tableName: index.tableName,
9018
- unique: index.unique,
9019
- columns: index.columns,
9020
- where: index.where,
9021
- originalSql: index.originalSql
9022
- });
9169
+ if (typeof value === "bigint") {
9170
+ w.u8(BJV_I64);
9171
+ w.i64(value);
9172
+ return;
9023
9173
  }
9024
- if (formatVersion >= 3) {
9025
- for (const index of indexes) writeIndexStore(writer, index.store);
9174
+ if (typeof value === "string") {
9175
+ w.u8(BJV_INTERN);
9176
+ writeVarintU32(w, forceIntern(value));
9177
+ return;
9026
9178
  }
9027
- if (formatVersion >= VERSION_V2) {
9028
- writer.u64(runtime.prngState);
9029
- writer.i64(BigInt(Math.trunc(runtime.nowMs)));
9179
+ if (value instanceof Uint8Array) {
9180
+ w.u8(BJV_BYTES);
9181
+ writeVarintU32(w, value.length);
9182
+ w.raw(value);
9183
+ return;
9030
9184
  }
9031
- return writer.finish();
9032
- }
9033
- function decodeDatabaseState(snapshot) {
9034
- try {
9035
- return decodeDatabaseStateInner(snapshot);
9036
- } catch (error) {
9037
- if (error instanceof SqliteError) throw error;
9038
- throw new SqliteError("invalid or truncated sqlite-mem snapshot", "other");
9185
+ if (Array.isArray(value)) {
9186
+ w.u8(BJV_ARRAY);
9187
+ writeVarintU32(w, value.length);
9188
+ for (const item of value) writeBjv(w, item, forceIntern);
9189
+ return;
9039
9190
  }
9040
- }
9041
- function decodeDatabaseStateInner(snapshot) {
9042
- const reader = new Reader(snapshot);
9043
- const magic = reader.raw(4);
9044
- if (!magic.every((byte, index) => byte === MAGIC[index]))
9045
- throw new SqliteError("invalid sqlite-mem snapshot magic", "other");
9046
- const version = reader.u32();
9047
- if (version < VERSION_V1 || version > VERSION) {
9048
- throw new SqliteError(`unsupported sqlite-mem snapshot version: ${version}`, "snapshot_version", "SQLITE_FORMAT");
9191
+ if (typeof value === "object") {
9192
+ const entries = Object.entries(value);
9193
+ w.u8(BJV_OBJECT);
9194
+ writeVarintU32(w, entries.length);
9195
+ for (const [k, v] of entries) {
9196
+ w.u8(BJV_INTERN);
9197
+ writeVarintU32(w, forceIntern(k));
9198
+ writeBjv(w, v, forceIntern);
9199
+ }
9200
+ return;
9049
9201
  }
9050
- if (version > VERSION_V3) return decodeV4(reader);
9051
- const state = new DatabaseState();
9052
- state.foreignKeysEnabled = reader.u8() !== 0;
9053
- state.schemaVersion = reader.u32();
9054
- state.changes = reader.u32();
9055
- state.totalChanges = reader.u32();
9056
- state.lastInsertRowid = asRowid2(reader.value());
9057
- const tableCount = reader.u32();
9058
- for (let tableIndex = 0; tableIndex < tableCount; tableIndex++) {
9059
- const meta = reader.json();
9060
- const table = new Table(meta.name, meta.columns, {
9061
- constraints: meta.constraints,
9062
- indexes: meta.indexes,
9063
- originalSql: meta.originalSql,
9064
- withoutRowid: meta.withoutRowid ?? false,
9065
- strict: meta.strict ?? false
9066
- });
9067
- table.nextRowid = asRowid2(reader.value());
9068
- const rowCount = reader.u32();
9069
- for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
9070
- const rowid = asRowid2(reader.value());
9071
- const valueCount = reader.u32();
9072
- if (valueCount !== table.columns.length) throw new SqliteError("snapshot row column count mismatch", "other");
9073
- const values = [];
9074
- for (let i = 0; i < valueCount; i++) values.push(reader.value());
9075
- table.rows.set(rowid, { rowid, values });
9202
+ w.u8(BJV_NULL);
9203
+ }
9204
+ function readBjv(r, intern) {
9205
+ const tag = r.u8();
9206
+ switch (tag) {
9207
+ case BJV_NULL:
9208
+ return null;
9209
+ case BJV_FALSE:
9210
+ return false;
9211
+ case BJV_TRUE:
9212
+ return true;
9213
+ case BJV_I32:
9214
+ return r.u32() | 0;
9215
+ case BJV_I64:
9216
+ return r.i64();
9217
+ case BJV_F64:
9218
+ return r.f64();
9219
+ case BJV_INTERN:
9220
+ return intern[readVarintU32(r)] ?? "";
9221
+ case BJV_STRING:
9222
+ return r.text();
9223
+ case BJV_BYTES:
9224
+ return r.raw(readVarintU32(r)).slice();
9225
+ case BJV_ARRAY: {
9226
+ const count = readVarintU32(r);
9227
+ const out = new Array(count);
9228
+ for (let i = 0; i < count; i++) out[i] = readBjv(r, intern);
9229
+ return out;
9076
9230
  }
9077
- table.rebuildClusteredRows();
9078
- state.tables.set(table.name.toLowerCase(), table);
9231
+ case BJV_OBJECT: {
9232
+ const count = readVarintU32(r);
9233
+ const out = {};
9234
+ for (let i = 0; i < count; i++) {
9235
+ const key = readBjv(r, intern);
9236
+ out[key] = readBjv(r, intern);
9237
+ }
9238
+ return out;
9239
+ }
9240
+ default:
9241
+ return r.fail();
9079
9242
  }
9080
- const viewCount = reader.u32();
9081
- for (let index = 0; index < viewCount; index++) {
9082
- const view = reader.json();
9083
- state.views.set(view.name.toLowerCase(), view);
9243
+ }
9244
+ var InternPool = class {
9245
+ counts = /* @__PURE__ */ new Map();
9246
+ ids = /* @__PURE__ */ new Map();
9247
+ list = [];
9248
+ constructor() {
9249
+ this.list.push("");
9250
+ this.ids.set("", 0);
9084
9251
  }
9085
- const indexCount = reader.u32();
9086
- const loadedIndexes = [];
9087
- for (let indexPosition = 0; indexPosition < indexCount; indexPosition++) {
9088
- const meta = reader.json();
9089
- const info = { ...meta, store: new IndexStore(meta.name) };
9090
- state.indexes.set(info.name.toLowerCase(), info);
9091
- loadedIndexes.push(info);
9252
+ count(s) {
9253
+ this.counts.set(s, (this.counts.get(s) ?? 0) + 1);
9092
9254
  }
9093
- if (version >= 3) {
9094
- for (const info of loadedIndexes) {
9095
- info.store = readIndexStore(reader, info.name);
9255
+ /** Assign ids only to strings seen ≥2 times (plus empty string). */
9256
+ finalize() {
9257
+ for (const [s, c] of this.counts) {
9258
+ if (c >= 2 && !this.ids.has(s)) {
9259
+ const id = this.list.length;
9260
+ this.ids.set(s, id);
9261
+ this.list.push(s);
9262
+ }
9096
9263
  }
9097
- } else {
9098
- for (const info of loadedIndexes) rebuildIndexStore(state, info);
9099
- }
9100
- let runtime = null;
9101
- if (version >= VERSION_V2) {
9102
- if (reader.remaining() < 16) throw new SqliteError("invalid or truncated sqlite-mem snapshot", "other");
9103
- runtime = {
9104
- prngState: reader.u64(),
9105
- nowMs: finiteNowMs(Number(reader.i64()))
9106
- };
9107
9264
  }
9108
- if (!reader.done()) throw new SqliteError("snapshot has trailing data", "other");
9109
- return { state, runtime };
9110
- }
9111
- function writeIndexStore(writer, store) {
9112
- const entries = store.snapshotEntries();
9113
- writer.u32(entries.length);
9114
- for (const entry of entries) {
9115
- writer.text(entry.key);
9116
- writer.u32(entry.rowids.length);
9117
- for (const id of entry.rowids) writer.value(id);
9118
- writer.u32(entry.values.length);
9119
- for (const value of entry.values) writer.value(value);
9265
+ /** Always intern (schema / catalog strings). */
9266
+ forceId(s) {
9267
+ const hit = this.ids.get(s);
9268
+ if (hit !== void 0) return hit;
9269
+ const id = this.list.length;
9270
+ this.ids.set(s, id);
9271
+ this.list.push(s);
9272
+ return id;
9120
9273
  }
9121
- }
9122
- function readIndexStore(reader, name) {
9123
- const count = reader.u32();
9124
- const entries = /* @__PURE__ */ new Map();
9125
- const keyValues = /* @__PURE__ */ new Map();
9274
+ id(s) {
9275
+ const hit = this.ids.get(s);
9276
+ if (hit !== void 0) return hit;
9277
+ return -1;
9278
+ }
9279
+ has(s) {
9280
+ return this.ids.has(s);
9281
+ }
9282
+ };
9283
+ function writeInternTable(w, strings) {
9284
+ writeVarintU32(w, strings.length);
9285
+ if (strings.length === 0) return;
9286
+ const offsets = [];
9287
+ let total = 0;
9288
+ for (const s of strings) {
9289
+ offsets.push(total);
9290
+ total += utf8Encode(s).length;
9291
+ }
9292
+ writeVarintU32(w, total);
9293
+ const base = w.position + offsets.length * 4;
9294
+ for (const off of offsets) w.u32(base + off);
9295
+ for (const s of strings) w.textBytes(s);
9296
+ }
9297
+ function readInternTable(r) {
9298
+ const count = readVarintU32(r);
9299
+ if (count === 0) return [];
9300
+ const total = readVarintU32(r);
9301
+ const offsets = [];
9302
+ for (let i = 0; i < count; i++) offsets.push(r.u32());
9303
+ const blobStart = r.position;
9304
+ const blob = r.raw(total);
9305
+ const intern = new Array(count);
9126
9306
  for (let i = 0; i < count; i++) {
9127
- const key = reader.text();
9128
- const rowidCount = reader.u32();
9129
- const rowids = [];
9130
- for (let r = 0; r < rowidCount; r++) rowids.push(asRowid2(reader.value()));
9131
- const valueCount = reader.u32();
9132
- const values = [];
9133
- for (let v = 0; v < valueCount; v++) values.push(reader.value());
9134
- entries.set(key, rowids);
9135
- keyValues.set(key, values);
9307
+ const start = offsets[i] - blobStart;
9308
+ const end = i + 1 < count ? offsets[i + 1] - blobStart : total;
9309
+ intern[i] = utf8Decode(blob.subarray(start, end));
9136
9310
  }
9137
- return new IndexStore(name, entries, keyValues);
9138
- }
9139
- function rebuildIndexStore(state, info) {
9140
- const table = state.getTable(info.tableName);
9141
- rebuildIndexFromTable(info, table, (row) => tableRowEvalContext(table, row));
9142
- }
9143
- function asRowid2(value) {
9144
- if (typeof value === "number" && Number.isSafeInteger(value) || typeof value === "bigint") return value;
9145
- throw new SqliteError("invalid rowid in snapshot", "other");
9146
- }
9147
- function compareNames(a, b) {
9148
- return a < b ? -1 : a > b ? 1 : 0;
9149
- }
9150
- function finiteNowMs(value) {
9151
- if (!Number.isFinite(value)) return 0;
9152
- const max = 864e13;
9153
- if (value > max) return max;
9154
- if (value < -max) return -max;
9155
- return value;
9156
- }
9157
- function compareRowids2(a, b) {
9158
- const left = typeof a === "bigint" ? a : BigInt(a);
9159
- const right = typeof b === "bigint" ? b : BigInt(b);
9160
- if (left < right) return -1;
9161
- if (left > right) return 1;
9162
- return 0;
9163
- }
9164
- function sortedValues(map) {
9165
- return [...map.values()].sort((a, b) => compareNames(a.name, b.name));
9166
- }
9167
- function jsonReplacer(_key, value) {
9168
- if (typeof value === "bigint") return { $sqlm: "bigint", value: value.toString() };
9169
- if (value instanceof Uint8Array) return { $sqlm: "blob", value: Array.from(value) };
9170
- return value;
9171
- }
9172
- function jsonReviver(_key, value) {
9173
- if (!value || typeof value !== "object" || !("$sqlm" in value)) return value;
9174
- const tagged = value;
9175
- if (tagged.$sqlm === "bigint") return BigInt(tagged.value);
9176
- if (tagged.$sqlm === "blob") return Uint8Array.from(tagged.value);
9177
- return value;
9311
+ return intern;
9178
9312
  }
9179
- var PACK_NULL = 0;
9180
- var PACK_INT = 1;
9181
- var PACK_FLOAT = 2;
9182
- var PACK_TEXT = 3;
9183
- var PACK_BLOB = 4;
9184
- var PACK_TAGGED = 5;
9313
+
9314
+ // src/serialization/codec.ts
9315
+ var MAGIC = utf8Encode("SQLM");
9316
+ var VERSION = 5;
9185
9317
  var AFFINITIES = ["TEXT", "NUMERIC", "INTEGER", "REAL", "BLOB"];
9186
- function encodeV4(state, runtime) {
9187
- const intern = /* @__PURE__ */ new Map();
9188
- const internList = [];
9189
- const internId = (s) => {
9190
- const hit = intern.get(s);
9191
- if (hit !== void 0) return hit;
9192
- const id = internList.length;
9193
- intern.set(s, id);
9194
- internList.push(s);
9195
- return id;
9196
- };
9197
- internId("");
9318
+ function encodeDatabaseState(state, runtime) {
9319
+ const pool = new InternPool();
9198
9320
  const tables = sortedValues(state.tables);
9199
9321
  const views = sortedValues(state.views);
9200
9322
  const indexes = sortedValues(state.indexes);
9201
9323
  for (const table of tables) {
9202
- internId(table.name);
9203
- internId(table.originalSql ?? "");
9324
+ pool.count(table.name);
9325
+ pool.count(table.originalSql ?? "");
9204
9326
  for (const column of table.columns) {
9205
- internId(column.name);
9206
- internId(column.typeName ?? "");
9207
- internId(column.collate ?? "");
9327
+ pool.count(column.name);
9328
+ pool.count(column.typeName ?? "");
9329
+ pool.count(column.collate ?? "");
9208
9330
  }
9209
- for (const name of table.indexes) internId(name);
9210
- for (const row of table.rows.values()) {
9331
+ for (const name of table.indexes) pool.count(name);
9332
+ for (const row of table.sortedRows()) {
9211
9333
  for (const value of row.values) {
9212
- if (typeof value === "string") internId(value);
9213
- else if (value instanceof SqlJsonText) internId(value.value);
9334
+ if (typeof value === "string") pool.count(value);
9335
+ else if (value instanceof SqlJsonText) pool.count(value.value);
9214
9336
  }
9215
9337
  }
9216
9338
  }
9217
- const w = new Writer();
9339
+ for (const view of views) pool.count(JSON.stringify(view));
9340
+ for (const index of indexes) pool.count(index.name);
9341
+ pool.finalize();
9342
+ forceSchemaIntern(pool, tables, views, indexes);
9343
+ const internId = (s) => pool.id(s);
9344
+ const forceId = (s) => pool.forceId(s);
9345
+ const w = new Writer(64 * 1024);
9218
9346
  w.raw(MAGIC);
9219
9347
  w.u32(VERSION);
9220
9348
  w.u8(state.foreignKeysEnabled ? 1 : 0);
9221
9349
  w.u32(state.schemaVersion);
9222
9350
  w.u32(state.changes);
9223
9351
  w.u32(state.totalChanges);
9224
- w.value(state.lastInsertRowid);
9225
- w.u32(internList.length);
9226
- for (const s of internList) w.text(s);
9227
- w.u32(tables.length);
9352
+ writeTaggedValue(w, state.lastInsertRowid, internId);
9353
+ writeInternTable(w, pool.list);
9354
+ writeVarintU32(w, tables.length);
9228
9355
  for (const table of tables) {
9229
- w.u32(internId(table.name));
9230
- w.u32(table.columns.length);
9356
+ writeVarintU32(w, forceId(table.name));
9357
+ writeVarintU32(w, table.columns.length);
9231
9358
  for (const column of table.columns) {
9232
- w.u32(internId(column.name));
9233
- w.u32(internId(column.typeName ?? ""));
9359
+ writeVarintU32(w, forceId(column.name));
9360
+ writeVarintU32(w, forceId(column.typeName ?? ""));
9234
9361
  const aff = AFFINITIES.indexOf(column.affinity);
9235
9362
  w.u8(aff < 0 ? 2 : aff);
9236
9363
  w.u8(
9237
9364
  (column.notNull ? 1 : 0) | (column.primaryKey ? 2 : 0) | (column.autoincrement ? 4 : 0) | (column.unique ? 8 : 0)
9238
9365
  );
9239
- w.u32(internId(column.collate ?? ""));
9366
+ writeVarintU32(w, forceId(column.collate ?? ""));
9240
9367
  if (column.defaultExpr) {
9241
9368
  w.u8(1);
9242
- w.json(column.defaultExpr);
9369
+ writeBjv(w, column.defaultExpr, forceId);
9243
9370
  } else w.u8(0);
9244
9371
  if (column.generated) {
9245
9372
  w.u8(1);
9246
- w.json(column.generated);
9373
+ writeBjv(w, column.generated, forceId);
9247
9374
  } else w.u8(0);
9248
9375
  }
9249
- w.json(table.constraints);
9250
- w.u32(internId(table.originalSql ?? ""));
9376
+ writeBjv(w, table.constraints, forceId);
9377
+ writeVarintU32(w, forceId(table.originalSql ?? ""));
9251
9378
  w.u8((table.withoutRowid ? 1 : 0) | (table.strict ? 2 : 0));
9252
9379
  const indexNames = [...table.indexes].sort(compareNames);
9253
- w.u32(indexNames.length);
9254
- for (const name of indexNames) w.u32(internId(name));
9255
- w.value(table.nextRowid);
9256
- const rows = [...table.rows.values()].sort((a, b) => compareRowids2(a.rowid, b.rowid));
9257
- w.u32(rows.length);
9258
- for (const row of rows) w.value(row.rowid);
9259
- for (let c = 0; c < table.columns.length; c++) {
9260
- writePackedColumn(w, rows, c, internId);
9261
- }
9262
- }
9263
- w.u32(views.length);
9264
- for (const view of views) w.json(view);
9265
- w.u32(indexes.length);
9380
+ writeVarintU32(w, indexNames.length);
9381
+ for (const name of indexNames) writeVarintU32(w, forceId(name));
9382
+ writeTaggedValue(w, table.nextRowid, internId);
9383
+ const rows = table.sortedRows();
9384
+ writeVarintU32(w, rows.length);
9385
+ for (const row of rows) writeTaggedValue(w, row.rowid, internId);
9386
+ for (let c = 0; c < table.columns.length; c++) writePackedColumn(w, rows, c, internId);
9387
+ }
9388
+ writeVarintU32(w, views.length);
9389
+ for (const view of views) writeBjv(w, view, forceId);
9390
+ writeVarintU32(w, indexes.length);
9266
9391
  for (const index of indexes) {
9267
- w.json({
9268
- name: index.name,
9269
- tableName: index.tableName,
9270
- unique: index.unique,
9271
- columns: index.columns,
9272
- where: index.where,
9273
- originalSql: index.originalSql
9274
- });
9275
- }
9276
- for (const index of indexes) {
9277
- const entries = index.store.snapshotKeys();
9278
- w.u32(entries.length);
9279
- for (const entry of entries) {
9280
- w.text(entry.key);
9281
- w.u32(entry.rowids.length);
9282
- for (const id of entry.rowids) w.value(id);
9283
- }
9392
+ writeBjv(
9393
+ w,
9394
+ {
9395
+ name: index.name,
9396
+ tableName: index.tableName,
9397
+ unique: index.unique,
9398
+ columns: index.columns,
9399
+ where: index.where,
9400
+ originalSql: index.originalSql
9401
+ },
9402
+ forceId
9403
+ );
9284
9404
  }
9405
+ for (const index of indexes) writeIndexStoreBinary(w, index.store, internId);
9285
9406
  w.u64(runtime.prngState);
9286
9407
  w.i64(BigInt(Math.trunc(runtime.nowMs)));
9287
9408
  return w.finish();
9288
9409
  }
9289
- function writePackedColumn(w, rows, col, internId) {
9290
- const n = rows.length;
9291
- if (n === 0) {
9292
- w.u8(PACK_NULL);
9293
- return;
9294
- }
9295
- const bits = new Uint8Array(n + 7 >> 3);
9296
- let nulls = 0;
9297
- let kind = null;
9298
- for (let i = 0; i < n; i++) {
9299
- const value = rows[i].values[col] ?? null;
9300
- if (value === null) {
9301
- bits[i >> 3] = bits[i >> 3] | 1 << (i & 7);
9302
- nulls++;
9303
- continue;
9304
- }
9305
- const cellKind = packKindOf(value);
9306
- if (kind === null) kind = cellKind;
9307
- else if (kind !== cellKind) kind = PACK_TAGGED;
9308
- }
9309
- if (nulls === n) {
9310
- w.u8(PACK_NULL);
9311
- return;
9312
- }
9313
- const pack = kind ?? PACK_TAGGED;
9314
- w.u8(pack);
9315
- w.raw(bits);
9316
- for (let i = 0; i < n; i++) {
9317
- if (bits[i >> 3] & 1 << (i & 7)) continue;
9318
- const value = rows[i].values[col];
9319
- writePackedCell(w, pack, value, internId);
9410
+ function decodeDatabaseState(snapshot) {
9411
+ try {
9412
+ return decodeInner(snapshot);
9413
+ } catch (error) {
9414
+ if (error instanceof SqliteError) throw error;
9415
+ throw new SqliteError("invalid or truncated sqlite-mem snapshot", "other");
9320
9416
  }
9321
9417
  }
9322
- function packKindOf(value) {
9323
- if (value instanceof SqlReal) return PACK_FLOAT;
9324
- if (typeof value === "bigint" || typeof value === "number" && Number.isInteger(value)) return PACK_INT;
9325
- if (typeof value === "number") return PACK_FLOAT;
9326
- if (value instanceof SqlJsonText) return PACK_TAGGED;
9327
- if (typeof value === "string") return PACK_TEXT;
9328
- if (value instanceof Uint8Array) return PACK_BLOB;
9329
- return PACK_TAGGED;
9330
- }
9331
- function writePackedCell(w, pack, value, internId) {
9332
- if (pack === PACK_INT) {
9333
- w.i64(typeof value === "bigint" ? value : BigInt(value));
9334
- return;
9335
- }
9336
- if (pack === PACK_FLOAT) {
9337
- w.f64(value instanceof SqlReal ? value.value : value);
9338
- return;
9339
- }
9340
- if (pack === PACK_TEXT) {
9341
- const text2 = value instanceof SqlJsonText ? value.value : value;
9342
- w.u32(internId(text2));
9343
- return;
9344
- }
9345
- if (pack === PACK_BLOB) {
9346
- const blob = value;
9347
- w.u32(blob.length);
9348
- w.raw(blob);
9349
- return;
9418
+ function decodeInner(snapshot) {
9419
+ const r = new Reader(snapshot);
9420
+ const magic = r.raw(4);
9421
+ if (!magic.every((byte, index) => byte === MAGIC[index]))
9422
+ throw new SqliteError("invalid sqlite-mem snapshot magic", "other");
9423
+ const version = r.u32();
9424
+ if (version !== VERSION) {
9425
+ throw new SqliteError(`unsupported sqlite-mem snapshot version: ${version}`, "snapshot_version", "SQLITE_FORMAT");
9350
9426
  }
9351
- w.value(value);
9352
- }
9353
- function decodeV4(reader) {
9354
9427
  const state = new DatabaseState();
9355
- state.foreignKeysEnabled = reader.u8() !== 0;
9356
- state.schemaVersion = reader.u32();
9357
- state.changes = reader.u32();
9358
- state.totalChanges = reader.u32();
9359
- state.lastInsertRowid = asRowid2(reader.value());
9360
- const internCount = reader.u32();
9361
- const intern = [];
9362
- for (let i = 0; i < internCount; i++) intern.push(reader.text());
9428
+ state.foreignKeysEnabled = r.u8() !== 0;
9429
+ state.schemaVersion = r.u32();
9430
+ state.changes = r.u32();
9431
+ state.totalChanges = r.u32();
9432
+ state.lastInsertRowid = asRowid2(readTaggedValue(r, []));
9433
+ const intern = readInternTable(r);
9363
9434
  const str = (id) => intern[id] ?? "";
9364
- const tableCount = reader.u32();
9435
+ const tableCount = readVarintU32(r);
9365
9436
  for (let t = 0; t < tableCount; t++) {
9366
- const name = str(reader.u32());
9367
- const colCount = reader.u32();
9437
+ const name = str(readVarintU32(r));
9438
+ const colCount = readVarintU32(r);
9368
9439
  const columns = [];
9369
9440
  for (let c = 0; c < colCount; c++) {
9370
- const colName = str(reader.u32());
9371
- const typeName = str(reader.u32()) || null;
9372
- const affIndex = reader.u8();
9373
- const flags = reader.u8();
9374
- const collate = str(reader.u32()) || null;
9375
- const hasDefault = reader.u8() === 1;
9376
- const defaultExpr = hasDefault ? reader.json() : null;
9377
- const hasGenerated = reader.u8() === 1;
9378
- const generated = hasGenerated ? reader.json() : null;
9441
+ const colName = str(readVarintU32(r));
9442
+ const typeName = str(readVarintU32(r)) || null;
9443
+ const affIndex = r.u8();
9444
+ const flags = r.u8();
9445
+ const collate = str(readVarintU32(r)) || null;
9446
+ const hasDefault = r.u8() === 1;
9447
+ const defaultExpr = hasDefault ? readBjv(r, intern) : null;
9448
+ const hasGenerated = r.u8() === 1;
9449
+ const generated = hasGenerated ? readBjv(r, intern) : null;
9379
9450
  columns.push({
9380
9451
  name: colName,
9381
9452
  nameLower: colName.toLowerCase(),
@@ -9390,12 +9461,12 @@ function decodeV4(reader) {
9390
9461
  generated
9391
9462
  });
9392
9463
  }
9393
- const constraints = reader.json();
9394
- const originalSql = str(reader.u32()) || null;
9395
- const tableFlags = reader.u8();
9396
- const indexCount2 = reader.u32();
9464
+ const constraints = readBjv(r, intern);
9465
+ const originalSql = str(readVarintU32(r)) || null;
9466
+ const tableFlags = r.u8();
9467
+ const indexNameCount = readVarintU32(r);
9397
9468
  const indexNames = [];
9398
- for (let i = 0; i < indexCount2; i++) indexNames.push(str(reader.u32()));
9469
+ for (let i = 0; i < indexNameCount; i++) indexNames.push(str(readVarintU32(r)));
9399
9470
  const table = new Table(name, columns, {
9400
9471
  constraints,
9401
9472
  indexes: indexNames,
@@ -9403,42 +9474,37 @@ function decodeV4(reader) {
9403
9474
  withoutRowid: (tableFlags & 1) !== 0,
9404
9475
  strict: (tableFlags & 2) !== 0
9405
9476
  });
9406
- table.nextRowid = asRowid2(reader.value());
9407
- const rowCount = reader.u32();
9477
+ table.nextRowid = asRowid2(readTaggedValue(r, intern));
9478
+ const rowCount = readVarintU32(r);
9408
9479
  const rowids = [];
9409
- for (let r = 0; r < rowCount; r++) rowids.push(asRowid2(reader.value()));
9410
- const cols = [];
9411
- for (let c = 0; c < colCount; c++) cols.push(readPackedColumn(reader, rowCount, intern));
9412
- for (let r = 0; r < rowCount; r++) {
9413
- const values = [];
9414
- for (let c = 0; c < colCount; c++) values.push(cols[c][r] ?? null);
9415
- const rowid = rowids[r];
9416
- table.rows.set(rowid, { rowid, values });
9417
- }
9418
- table.rebuildClusteredRows();
9480
+ for (let ri = 0; ri < rowCount; ri++) rowids.push(asRowid2(readTaggedValue(r, intern)));
9481
+ const slabColumns = [];
9482
+ for (let c = 0; c < colCount; c++) slabColumns.push(readPackedColumn(r, rowCount, intern));
9483
+ table.attachSlab(new ColumnarSlab(snapshot, rowCount, rowids, slabColumns, intern));
9484
+ if (table.withoutRowid) table.rebuildClusteredRows();
9419
9485
  state.tables.set(table.name.toLowerCase(), table);
9420
9486
  }
9421
- const viewCount = reader.u32();
9487
+ const viewCount = readVarintU32(r);
9422
9488
  for (let i = 0; i < viewCount; i++) {
9423
- const view = reader.json();
9489
+ const view = readBjv(r, intern);
9424
9490
  state.views.set(view.name.toLowerCase(), view);
9425
9491
  }
9426
- const indexCount = reader.u32();
9492
+ const indexCount = readVarintU32(r);
9427
9493
  const loadedIndexes = [];
9428
9494
  for (let i = 0; i < indexCount; i++) {
9429
- const meta = reader.json();
9495
+ const meta = readBjv(r, intern);
9430
9496
  const info = { ...meta, store: new IndexStore(meta.name) };
9431
9497
  state.indexes.set(info.name.toLowerCase(), info);
9432
9498
  loadedIndexes.push(info);
9433
9499
  }
9434
9500
  for (const info of loadedIndexes) {
9435
- info.store = readIndexStoreKeys(reader, info.name);
9501
+ info.store = readIndexStoreBinary(r, info.name, intern);
9436
9502
  const table = state.tables.get(info.tableName.toLowerCase());
9437
9503
  if (!table) continue;
9438
9504
  for (const entry of info.store.snapshotKeys()) {
9439
9505
  const rowid = entry.rowids[0];
9440
9506
  if (rowid === void 0) continue;
9441
- const row = table.rows.get(rowid);
9507
+ const row = table.get(rowid);
9442
9508
  if (!row) continue;
9443
9509
  info.store.rememberKeyValues(
9444
9510
  entry.key,
@@ -9446,52 +9512,299 @@ function decodeV4(reader) {
9446
9512
  );
9447
9513
  }
9448
9514
  }
9449
- if (reader.remaining() < 16) throw new SqliteError("invalid or truncated sqlite-mem snapshot", "other");
9450
- const runtime = { prngState: reader.u64(), nowMs: finiteNowMs(Number(reader.i64())) };
9451
- if (!reader.done()) throw new SqliteError("snapshot has trailing data", "other");
9515
+ if (r.remaining() < 16) throw new SqliteError("invalid or truncated sqlite-mem snapshot", "other");
9516
+ const runtime = { prngState: r.u64(), nowMs: finiteNowMs(Number(r.i64())) };
9517
+ if (!r.done()) throw new SqliteError("snapshot has trailing data", "other");
9452
9518
  return { state, runtime };
9453
9519
  }
9454
- function readPackedColumn(reader, n, intern) {
9455
- const pack = reader.u8();
9456
- const out = new Array(n);
9457
- if (pack === PACK_NULL) {
9458
- for (let i = 0; i < n; i++) out[i] = null;
9459
- return out;
9520
+ function writeTaggedValue(w, value, internId) {
9521
+ if (value === null) {
9522
+ w.u8(0);
9523
+ return;
9460
9524
  }
9461
- const bits = reader.raw(n + 7 >> 3);
9462
- for (let i = 0; i < n; i++) {
9463
- if (bits[i >> 3] & 1 << (i & 7)) {
9464
- out[i] = null;
9465
- continue;
9525
+ if (value instanceof SqlReal) {
9526
+ w.u8(2);
9527
+ w.f64(value.value);
9528
+ return;
9529
+ }
9530
+ if (typeof value === "bigint" || typeof value === "number" && Number.isInteger(value)) {
9531
+ w.u8(1);
9532
+ w.i64(BigInt(value));
9533
+ return;
9534
+ }
9535
+ if (typeof value === "number") {
9536
+ w.u8(2);
9537
+ w.f64(value);
9538
+ return;
9539
+ }
9540
+ if (typeof value === "string") {
9541
+ const id = internId(value);
9542
+ if (id >= 0) {
9543
+ w.u8(3);
9544
+ writeVarintU32(w, id);
9545
+ return;
9466
9546
  }
9467
- out[i] = readPackedCell(reader, pack, intern);
9547
+ w.u8(4);
9548
+ w.text(value);
9549
+ return;
9468
9550
  }
9469
- return out;
9551
+ if (value instanceof SqlJsonText) {
9552
+ w.u8(4);
9553
+ w.text(value.value);
9554
+ return;
9555
+ }
9556
+ w.u8(5);
9557
+ writeVarintU32(w, value.length);
9558
+ w.raw(value);
9470
9559
  }
9471
- function readPackedCell(reader, pack, intern) {
9472
- if (pack === PACK_INT) {
9473
- const integer = reader.i64();
9560
+ function readTaggedValue(r, intern) {
9561
+ const tag = r.u8();
9562
+ if (tag === 0) return null;
9563
+ if (tag === 1) {
9564
+ const integer = r.i64();
9474
9565
  return integer <= BigInt(Number.MAX_SAFE_INTEGER) && integer >= BigInt(Number.MIN_SAFE_INTEGER) ? Number(integer) : integer;
9475
9566
  }
9476
- if (pack === PACK_FLOAT) {
9477
- const value = reader.f64();
9567
+ if (tag === 2) {
9568
+ const value = r.f64();
9478
9569
  return Number.isInteger(value) && Number.isFinite(value) ? asSqlReal(value) : value;
9479
9570
  }
9480
- if (pack === PACK_TEXT) return intern[reader.u32()] ?? "";
9481
- if (pack === PACK_BLOB) return reader.owned(reader.u32());
9482
- return reader.value();
9571
+ if (tag === 3) return intern[readVarintU32(r)] ?? "";
9572
+ if (tag === 4) return r.text();
9573
+ return r.raw(readVarintU32(r));
9483
9574
  }
9484
- function readIndexStoreKeys(reader, name) {
9485
- const count = reader.u32();
9575
+ function writePackedColumn(w, rows, col, internId) {
9576
+ const n = rows.length;
9577
+ if (n === 0) {
9578
+ w.u8(PACK_NULL);
9579
+ return;
9580
+ }
9581
+ const bits = new Uint8Array(n + 7 >> 3);
9582
+ let nulls = 0;
9583
+ let kind = null;
9584
+ let useInlineText = false;
9585
+ for (let i = 0; i < n; i++) {
9586
+ const value = rows[i].values[col] ?? null;
9587
+ if (value === null) {
9588
+ bits[i >> 3] = bits[i >> 3] | 1 << (i & 7);
9589
+ nulls++;
9590
+ continue;
9591
+ }
9592
+ const cellKind = packKindOf(value);
9593
+ if (kind === null) kind = cellKind;
9594
+ else if (kind !== cellKind) kind = PACK_TAGGED;
9595
+ if (cellKind === PACK_TEXT_INTERN && typeof value === "string" && internId(value) < 0) useInlineText = true;
9596
+ if (value instanceof SqlJsonText) kind = PACK_TAGGED;
9597
+ }
9598
+ if (nulls === n) {
9599
+ w.u8(PACK_NULL);
9600
+ return;
9601
+ }
9602
+ let pack = kind ?? PACK_TAGGED;
9603
+ if (pack === PACK_TEXT_INTERN && useInlineText) pack = PACK_TEXT_INLINE;
9604
+ w.u8(pack);
9605
+ w.raw(bits);
9606
+ if (pack === PACK_I32) {
9607
+ w.align4();
9608
+ for (let i = 0; i < n; i++) {
9609
+ if (bits[i >> 3] & 1 << (i & 7)) continue;
9610
+ w.u32(rows[i].values[col]);
9611
+ }
9612
+ return;
9613
+ }
9614
+ if (pack === PACK_I64) {
9615
+ w.align4();
9616
+ for (let i = 0; i < n; i++) {
9617
+ if (bits[i >> 3] & 1 << (i & 7)) continue;
9618
+ const v = rows[i].values[col];
9619
+ w.i64(typeof v === "bigint" ? v : BigInt(v));
9620
+ }
9621
+ return;
9622
+ }
9623
+ if (pack === PACK_F64) {
9624
+ w.align4();
9625
+ for (let i = 0; i < n; i++) {
9626
+ if (bits[i >> 3] & 1 << (i & 7)) continue;
9627
+ const v = rows[i].values[col];
9628
+ w.f64(v instanceof SqlReal ? v.value : v);
9629
+ }
9630
+ return;
9631
+ }
9632
+ if (pack === PACK_TEXT_INTERN) {
9633
+ w.align4();
9634
+ for (let i = 0; i < n; i++) {
9635
+ if (bits[i >> 3] & 1 << (i & 7)) continue;
9636
+ const text2 = rows[i].values[col];
9637
+ w.u32(internId(text2));
9638
+ }
9639
+ return;
9640
+ }
9641
+ if (pack === PACK_TEXT_INLINE) {
9642
+ const offsets = [];
9643
+ let blobLen = 0;
9644
+ for (let i = 0; i < n; i++) {
9645
+ if (bits[i >> 3] & 1 << (i & 7)) continue;
9646
+ offsets.push(blobLen);
9647
+ const text2 = rows[i].values[col] instanceof SqlJsonText ? rows[i].values[col].value : rows[i].values[col];
9648
+ blobLen += utf8Encode(text2).length;
9649
+ }
9650
+ writeVarintU32(w, offsets.length);
9651
+ for (const off of offsets) writeVarintU32(w, off);
9652
+ writeVarintU32(w, blobLen);
9653
+ for (let i = 0; i < n; i++) {
9654
+ if (bits[i >> 3] & 1 << (i & 7)) continue;
9655
+ const text2 = rows[i].values[col] instanceof SqlJsonText ? rows[i].values[col].value : rows[i].values[col];
9656
+ w.textBytes(text2);
9657
+ }
9658
+ return;
9659
+ }
9660
+ if (pack === PACK_BLOB) {
9661
+ for (let i = 0; i < n; i++) {
9662
+ if (bits[i >> 3] & 1 << (i & 7)) continue;
9663
+ const blob = rows[i].values[col];
9664
+ writeVarintU32(w, blob.length);
9665
+ w.raw(blob);
9666
+ }
9667
+ return;
9668
+ }
9669
+ for (let i = 0; i < n; i++) {
9670
+ if (bits[i >> 3] & 1 << (i & 7)) continue;
9671
+ writeTaggedValue(w, rows[i].values[col], internId);
9672
+ }
9673
+ }
9674
+ function readPackedColumn(r, n, intern) {
9675
+ const pack = r.u8();
9676
+ if (pack === PACK_NULL) return { pack, nullBitmap: null, payload: new Uint8Array(0) };
9677
+ const bits = r.raw(n + 7 >> 3);
9678
+ const nonNull = countNonNull(bits, n);
9679
+ if (pack === PACK_I32 || pack === PACK_I64 || pack === PACK_F64 || pack === PACK_TEXT_INTERN) {
9680
+ r.skipAlign4();
9681
+ const width = pack === PACK_I32 || pack === PACK_TEXT_INTERN ? 4 : 8;
9682
+ const payload = r.raw(nonNull * width);
9683
+ return { pack, nullBitmap: bits, payload };
9684
+ }
9685
+ if (pack === PACK_TEXT_INLINE) {
9686
+ const count = readVarintU32(r);
9687
+ const offsets = new Uint32Array(count);
9688
+ for (let i = 0; i < count; i++) offsets[i] = readVarintU32(r);
9689
+ const total = readVarintU32(r);
9690
+ const payload = r.raw(total);
9691
+ return { pack, nullBitmap: bits, payload, inlineOffsets: offsets };
9692
+ }
9693
+ if (pack === PACK_BLOB) {
9694
+ const chunks = [];
9695
+ for (let i = 0; i < n; i++) {
9696
+ if (bits[i >> 3] & 1 << (i & 7)) continue;
9697
+ const len = readVarintU32(r);
9698
+ chunks.push(r.raw(len));
9699
+ }
9700
+ return { pack, nullBitmap: bits, payload: new Uint8Array(0), blobChunks: chunks };
9701
+ }
9702
+ const tagged = [];
9703
+ for (let i = 0; i < n; i++) {
9704
+ if (bits[i >> 3] & 1 << (i & 7)) continue;
9705
+ tagged.push(readTaggedValue(r, intern));
9706
+ }
9707
+ return { pack: PACK_TAGGED, nullBitmap: bits, payload: new Uint8Array(0), tagged };
9708
+ }
9709
+ function countNonNull(bits, n) {
9710
+ let c = 0;
9711
+ for (let i = 0; i < n; i++) if ((bits[i >> 3] & 1 << (i & 7)) === 0) c++;
9712
+ return c;
9713
+ }
9714
+ function writeIndexStoreBinary(w, store, internId) {
9715
+ const entries = store.snapshotKeys();
9716
+ writeVarintU32(w, entries.length);
9717
+ for (const entry of entries) {
9718
+ const values = store.keyValuesFor(entry.key);
9719
+ writeVarintU32(w, values.length);
9720
+ for (const v of values) writeTaggedValue(w, v, internId);
9721
+ writeVarintU32(w, entry.rowids.length);
9722
+ for (const id of entry.rowids) writeTaggedValue(w, id, internId);
9723
+ }
9724
+ }
9725
+ function readIndexStoreBinary(r, name, intern) {
9726
+ const count = readVarintU32(r);
9486
9727
  const entries = /* @__PURE__ */ new Map();
9728
+ const keyValues = /* @__PURE__ */ new Map();
9487
9729
  for (let i = 0; i < count; i++) {
9488
- const key = reader.text();
9489
- const rowidCount = reader.u32();
9730
+ const valueCount = readVarintU32(r);
9731
+ const values = [];
9732
+ for (let v = 0; v < valueCount; v++) values.push(readTaggedValue(r, intern));
9733
+ const key = serializeIndexEntry(values);
9734
+ const rowidCount = readVarintU32(r);
9490
9735
  const rowids = [];
9491
- for (let r = 0; r < rowidCount; r++) rowids.push(asRowid2(reader.value()));
9736
+ for (let ri = 0; ri < rowidCount; ri++) rowids.push(asRowid2(readTaggedValue(r, intern)));
9492
9737
  entries.set(key, rowids);
9738
+ keyValues.set(key, values);
9739
+ }
9740
+ return new IndexStore(name, entries, keyValues);
9741
+ }
9742
+ function asRowid2(value) {
9743
+ if (typeof value === "number" && Number.isSafeInteger(value) || typeof value === "bigint") return value;
9744
+ throw new SqliteError("invalid rowid in snapshot", "other");
9745
+ }
9746
+ function compareNames(a, b) {
9747
+ return a < b ? -1 : a > b ? 1 : 0;
9748
+ }
9749
+ function finiteNowMs(value) {
9750
+ if (!Number.isFinite(value)) return 0;
9751
+ const max = 864e13;
9752
+ if (value > max) return max;
9753
+ if (value < -max) return -max;
9754
+ return value;
9755
+ }
9756
+ function sortedValues(map) {
9757
+ return [...map.values()].sort((a, b) => compareNames(a.name, b.name));
9758
+ }
9759
+ function forceSchemaIntern(pool, tables, views, indexes) {
9760
+ for (const table of tables) {
9761
+ pool.forceId(table.name);
9762
+ pool.forceId(table.originalSql ?? "");
9763
+ for (const column of table.columns) {
9764
+ pool.forceId(column.name);
9765
+ pool.forceId(column.typeName ?? "");
9766
+ pool.forceId(column.collate ?? "");
9767
+ }
9768
+ for (const name of table.indexes) pool.forceId(name);
9769
+ forceBjvStrings(pool, table.constraints);
9770
+ for (const column of table.columns) {
9771
+ if (column.defaultExpr) forceBjvStrings(pool, column.defaultExpr);
9772
+ if (column.generated) forceBjvStrings(pool, column.generated);
9773
+ }
9774
+ }
9775
+ for (const view of views) forceBjvStrings(pool, view);
9776
+ for (const index of indexes) {
9777
+ pool.forceId(index.name);
9778
+ pool.forceId(index.tableName);
9779
+ pool.forceId(index.originalSql ?? "");
9780
+ forceBjvStrings(pool, {
9781
+ name: index.name,
9782
+ tableName: index.tableName,
9783
+ unique: index.unique,
9784
+ columns: index.columns,
9785
+ where: index.where,
9786
+ originalSql: index.originalSql
9787
+ });
9788
+ }
9789
+ }
9790
+ function forceBjvStrings(pool, value) {
9791
+ if (value === null || value === void 0) return;
9792
+ if (typeof value === "string") {
9793
+ pool.forceId(value);
9794
+ return;
9795
+ }
9796
+ if (typeof value === "bigint" || typeof value === "boolean" || typeof value === "number") return;
9797
+ if (value instanceof Uint8Array) return;
9798
+ if (Array.isArray(value)) {
9799
+ for (const item of value) forceBjvStrings(pool, item);
9800
+ return;
9801
+ }
9802
+ if (typeof value === "object") {
9803
+ for (const [k, v] of Object.entries(value)) {
9804
+ pool.forceId(k);
9805
+ forceBjvStrings(pool, v);
9806
+ }
9493
9807
  }
9494
- return new IndexStore(name, entries);
9495
9808
  }
9496
9809
  export {
9497
9810
  DEFAULT_DATABASE_SEED,