@crvouga/sqlite-mem 1.8.0 → 1.9.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
@@ -260,11 +260,13 @@ function comparisonClass(v) {
260
260
  if (typeof v === "string" || v instanceof SqlJsonText) return 2;
261
261
  return 3;
262
262
  }
263
+ var TEXT_ENCODER = new TextEncoder();
264
+ var TEXT_DECODER = new TextDecoder();
263
265
  function utf8Encode(s) {
264
- return new TextEncoder().encode(s);
266
+ return TEXT_ENCODER.encode(s);
265
267
  }
266
268
  function utf8Decode(b) {
267
- return new TextDecoder().decode(b);
269
+ return TEXT_DECODER.decode(b);
268
270
  }
269
271
  function cloneSqlValue(v) {
270
272
  if (v instanceof Uint8Array) return new Uint8Array(v);
@@ -5827,8 +5829,8 @@ var IndexStore = class _IndexStore {
5827
5829
  }
5828
5830
  }
5829
5831
  checkUnique(values, rowid) {
5830
- const key = serializeIndexKey(values);
5831
- if (key === null) return;
5832
+ if (values.some((value) => value === null)) return;
5833
+ const key = serializeIndexEntry(values);
5832
5834
  const existing = this.entries.get(key);
5833
5835
  if (!existing) return;
5834
5836
  for (const id of existing) {
@@ -5843,8 +5845,7 @@ var IndexStore = class _IndexStore {
5843
5845
  }
5844
5846
  insert(values, rowid, unique = true) {
5845
5847
  this.assertMutable();
5846
- const key = serializeIndexKey(values);
5847
- if (key === null) return;
5848
+ const key = serializeIndexEntry(values);
5848
5849
  if (unique) this.checkUnique(values, rowid);
5849
5850
  const existing = this.entries.get(key);
5850
5851
  if (!existing) {
@@ -5857,15 +5858,15 @@ var IndexStore = class _IndexStore {
5857
5858
  existing.push(rowid);
5858
5859
  }
5859
5860
  lookup(values) {
5860
- const key = serializeIndexKey(values);
5861
- if (key === null) return [];
5861
+ if (values.some((value) => value === null)) return [];
5862
+ const key = serializeIndexEntry(values);
5862
5863
  return this.entries.get(key) ?? [];
5863
5864
  }
5864
5865
  /** Leftmost prefix match: INDEX(a,b) used for WHERE a = ?. */
5865
5866
  lookupPrefix(values) {
5866
5867
  if (values.length === 0) return [];
5867
- const prefix = serializeIndexKey(values);
5868
- if (prefix === null) return [];
5868
+ if (values.some((value) => value === null)) return [];
5869
+ const prefix = serializeIndexEntry(values);
5869
5870
  const exact = this.entries.get(prefix);
5870
5871
  const needle = `${prefix}|`;
5871
5872
  const rowids = exact ? [...exact] : [];
@@ -5883,7 +5884,7 @@ var IndexStore = class _IndexStore {
5883
5884
  const keys = this.orderedKeys();
5884
5885
  for (const key of keys) {
5885
5886
  const values = this.keyValues.get(key);
5886
- if (!values || values[0] === void 0) continue;
5887
+ if (!values || values[0] === void 0 || values[0] === null) continue;
5887
5888
  const cmp = compareSerializedOrder(values[0], bound);
5888
5889
  let ok = false;
5889
5890
  if (op === ">") ok = cmp > 0;
@@ -5912,8 +5913,7 @@ var IndexStore = class _IndexStore {
5912
5913
  }
5913
5914
  remove(values, rowid) {
5914
5915
  this.assertMutable();
5915
- const key = serializeIndexKey(values);
5916
- if (key === null) return false;
5916
+ const key = serializeIndexEntry(values);
5917
5917
  const existing = this.entries.get(key);
5918
5918
  if (!existing) return false;
5919
5919
  if (rowid === void 0) {
@@ -5944,6 +5944,26 @@ var IndexStore = class _IndexStore {
5944
5944
  freeze() {
5945
5945
  this.frozen = true;
5946
5946
  }
5947
+ /** Sorted entries for SQLM v3 persistence. */
5948
+ snapshotEntries() {
5949
+ const keys = [...this.entries.keys()].sort();
5950
+ return keys.map((key) => ({
5951
+ key,
5952
+ rowids: [...this.entries.get(key) ?? []],
5953
+ values: [...this.keyValues.get(key) ?? []]
5954
+ }));
5955
+ }
5956
+ /** Sorted keys + rowids for SQLM v4 (values rebuilt from the table). */
5957
+ snapshotKeys() {
5958
+ const keys = [...this.entries.keys()].sort();
5959
+ return keys.map((key) => ({
5960
+ key,
5961
+ rowids: [...this.entries.get(key) ?? []]
5962
+ }));
5963
+ }
5964
+ rememberKeyValues(key, values) {
5965
+ this.keyValues.set(key, [...values]);
5966
+ }
5947
5967
  get size() {
5948
5968
  return this.entries.size;
5949
5969
  }
@@ -5956,7 +5976,12 @@ var IndexStore = class _IndexStore {
5956
5976
  if (!left || !right) return a < b ? -1 : a > b ? 1 : 0;
5957
5977
  const n = Math.min(left.length, right.length);
5958
5978
  for (let i = 0; i < n; i++) {
5959
- const cmp = compareSql(left[i] ?? null, right[i] ?? null);
5979
+ const a2 = left[i] ?? null;
5980
+ const b2 = right[i] ?? null;
5981
+ if (a2 === null && b2 === null) continue;
5982
+ if (a2 === null) return -1;
5983
+ if (b2 === null) return 1;
5984
+ const cmp = compareSql(a2, b2);
5960
5985
  if (cmp !== 0) return cmp ?? 0;
5961
5986
  }
5962
5987
  return left.length - right.length;
@@ -5970,8 +5995,15 @@ var IndexStore = class _IndexStore {
5970
5995
  };
5971
5996
  function serializeIndexKey(values) {
5972
5997
  if (values.some((value) => value === null)) return null;
5973
- return values.map(serializeValue).map((part) => `${part.length}:${part}`).join("|");
5998
+ return serializeIndexEntry(values);
5974
5999
  }
6000
+ function serializeIndexEntry(values) {
6001
+ return values.map((value) => {
6002
+ const part = value === null ? NULL_PART : serializeValue(value);
6003
+ return `${part.length}:${part}`;
6004
+ }).join("|");
6005
+ }
6006
+ var NULL_PART = "z";
5975
6007
  function serializeValue(value) {
5976
6008
  if (isSqlReal(value)) {
5977
6009
  const n = value.value;
@@ -6001,6 +6033,62 @@ function sameRowid(left, right) {
6001
6033
  return typeof left === "bigint" || typeof right === "bigint" ? BigInt(left) === BigInt(right) : left === right;
6002
6034
  }
6003
6035
 
6036
+ // src/storage/row.ts
6037
+ function normalizeColumnName(name) {
6038
+ return name.toLowerCase();
6039
+ }
6040
+ function rowValues(values) {
6041
+ const result = /* @__PURE__ */ new Map();
6042
+ const entries = values instanceof Map ? values.entries() : Object.entries(values);
6043
+ for (const [name, value] of entries) {
6044
+ result.set(normalizeColumnName(name), value);
6045
+ }
6046
+ return result;
6047
+ }
6048
+ function cloneRow(row) {
6049
+ const values = new Array(row.values.length);
6050
+ for (let i = 0; i < row.values.length; i++) values[i] = cloneSqlValue(row.values[i]);
6051
+ return { rowid: row.rowid, values };
6052
+ }
6053
+ function isValueArray(values) {
6054
+ return Array.isArray(values);
6055
+ }
6056
+
6057
+ // src/indexes/keys.ts
6058
+ function indexKeyValues(columns, row, ctx, table) {
6059
+ return columns.map((column) => {
6060
+ const raw = column.expr && ctx ? evalExpr(column.expr, ctx) : table ? table.cell(row, normalizeColumnName(column.name)) : null;
6061
+ return normalizeForCollation(raw, column.collate ?? "BINARY");
6062
+ });
6063
+ }
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
+ function tableRowEvalContext(table, row) {
6073
+ return {
6074
+ functions: defaultFunctionRegistry,
6075
+ resolveColumn: (qualifier, name) => {
6076
+ if (qualifier && qualifier.toLowerCase() !== table.name.toLowerCase()) {
6077
+ throw new SqliteError(`no such column: ${qualifier}.${name}`, "no_such_column");
6078
+ }
6079
+ const key = name.toLowerCase();
6080
+ if (key === "rowid" || key === "_rowid_" || key === "oid") return row.rowid;
6081
+ if (!table.hasColumn(key) && key !== "rowid") {
6082
+ throw new SqliteError(`no such column: ${name}`, "no_such_column");
6083
+ }
6084
+ return table.cell(row, key);
6085
+ },
6086
+ getParameter: () => {
6087
+ throw new SqliteError("parameters are not allowed in index predicates", "misuse");
6088
+ }
6089
+ };
6090
+ }
6091
+
6004
6092
  // src/types/strict.ts
6005
6093
  var STRICT_TYPES = /* @__PURE__ */ new Set(["INT", "INTEGER", "REAL", "TEXT", "BLOB", "ANY"]);
6006
6094
  function isStrictTypeName(typeName) {
@@ -7607,26 +7695,6 @@ var FtsVocabVirtualTable = class _FtsVocabVirtualTable {
7607
7695
  }
7608
7696
  };
7609
7697
 
7610
- // src/storage/row.ts
7611
- function normalizeColumnName(name) {
7612
- return name.toLowerCase();
7613
- }
7614
- function rowValues(values) {
7615
- const result = /* @__PURE__ */ new Map();
7616
- const entries = values instanceof Map ? values.entries() : Object.entries(values);
7617
- for (const [name, value] of entries) {
7618
- result.set(normalizeColumnName(name), value);
7619
- }
7620
- return result;
7621
- }
7622
- function cloneRow(row) {
7623
- const values = /* @__PURE__ */ new Map();
7624
- for (const [name, value] of row.values) {
7625
- values.set(name, cloneSqlValue(value));
7626
- }
7627
- return { rowid: row.rowid, values };
7628
- }
7629
-
7630
7698
  // src/storage/table.ts
7631
7699
  var EQUALITY_HASH_MIN_ROWS = 16;
7632
7700
  var Table = class _Table {
@@ -7647,6 +7715,8 @@ var Table = class _Table {
7647
7715
  /** Cached maximum rowid. `undefined` means recompute after deleting the maximum. */
7648
7716
  maximumRowid = null;
7649
7717
  frozen = false;
7718
+ /** nameLower → column index; rebuilt after ALTER. */
7719
+ colIndex = /* @__PURE__ */ new Map();
7650
7720
  constructor(name, columns, options = {}) {
7651
7721
  this.name = name;
7652
7722
  this.columns = columns.map(cloneColumn);
@@ -7659,6 +7729,44 @@ var Table = class _Table {
7659
7729
  this.strict = options.strict ?? false;
7660
7730
  this.clusteredRows = /* @__PURE__ */ new Map();
7661
7731
  this.scanCache = null;
7732
+ this.rebuildColIndex();
7733
+ }
7734
+ rebuildColIndex() {
7735
+ this.colIndex = /* @__PURE__ */ new Map();
7736
+ for (let i = 0; i < this.columns.length; i++) {
7737
+ const column = this.columns[i];
7738
+ this.colIndex.set(column.nameLower ?? column.name.toLowerCase(), i);
7739
+ }
7740
+ }
7741
+ columnOffset(nameLower) {
7742
+ return this.colIndex.get(nameLower);
7743
+ }
7744
+ hasColumn(nameLower) {
7745
+ return this.colIndex.has(nameLower);
7746
+ }
7747
+ cell(row, nameLower) {
7748
+ const i = this.colIndex.get(nameLower);
7749
+ return i === void 0 ? null : row.values[i] ?? null;
7750
+ }
7751
+ setCell(row, nameLower, value) {
7752
+ const i = this.colIndex.get(nameLower);
7753
+ if (i === void 0) throw new SqliteError(`no such column: ${nameLower}`, "no_such_column");
7754
+ row.values[i] = value;
7755
+ }
7756
+ namedValues(row) {
7757
+ const map = /* @__PURE__ */ new Map();
7758
+ for (let i = 0; i < this.columns.length; i++) {
7759
+ const column = this.columns[i];
7760
+ map.set(column.nameLower ?? column.name.toLowerCase(), row.values[i] ?? null);
7761
+ }
7762
+ return map;
7763
+ }
7764
+ rowFromNamed(values, rowid = 0) {
7765
+ const cells = [];
7766
+ for (const column of this.columns) {
7767
+ cells.push(values.get(normalizeColumnName(column.name)) ?? null);
7768
+ }
7769
+ return { rowid, values: cells };
7662
7770
  }
7663
7771
  integerPkColumn() {
7664
7772
  return this.integerPrimaryKeyAlias();
@@ -7727,7 +7835,7 @@ var Table = class _Table {
7727
7835
  const map = /* @__PURE__ */ new Map();
7728
7836
  const collate = column.collate ?? "BINARY";
7729
7837
  for (const row of this.rows.values()) {
7730
- const key = serializeIndexKey([normalizeForCollation(row.values.get(columnLower) ?? null, collate)]);
7838
+ const key = serializeIndexKey([normalizeForCollation(this.cell(row, columnLower), collate)]);
7731
7839
  if (key === null) continue;
7732
7840
  const bucket = map.get(key);
7733
7841
  if (bucket) bucket.push(row.rowid);
@@ -7743,9 +7851,7 @@ var Table = class _Table {
7743
7851
  if (!this.equalityHashes) return;
7744
7852
  for (const [columnLower, map] of this.equalityHashes) {
7745
7853
  const column = this.columns.find((item) => item.nameLower === columnLower);
7746
- const key = serializeIndexKey([
7747
- normalizeForCollation(row.values.get(columnLower) ?? null, column?.collate ?? "BINARY")
7748
- ]);
7854
+ const key = serializeIndexKey([normalizeForCollation(this.cell(row, columnLower), column?.collate ?? "BINARY")]);
7749
7855
  if (key === null) continue;
7750
7856
  const bucket = map.get(key);
7751
7857
  if (bucket) {
@@ -7757,9 +7863,7 @@ var Table = class _Table {
7757
7863
  if (!this.equalityHashes) return;
7758
7864
  for (const [columnLower, map] of this.equalityHashes) {
7759
7865
  const column = this.columns.find((item) => item.nameLower === columnLower);
7760
- const key = serializeIndexKey([
7761
- normalizeForCollation(row.values.get(columnLower) ?? null, column?.collate ?? "BINARY")
7762
- ]);
7866
+ const key = serializeIndexKey([normalizeForCollation(this.cell(row, columnLower), column?.collate ?? "BINARY")]);
7763
7867
  if (key === null) continue;
7764
7868
  const bucket = map.get(key);
7765
7869
  if (!bucket) continue;
@@ -7771,7 +7875,7 @@ var Table = class _Table {
7771
7875
  insert(input, options) {
7772
7876
  this.assertMutable();
7773
7877
  const supplied = isInsertRow(input) ? input : { values: input };
7774
- const values = options?.prepared ? supplied.values instanceof Map ? supplied.values : rowValues(supplied.values) : this.prepareValues(supplied.values);
7878
+ const values = this.cellsFromInput(supplied.values, options?.prepared === true);
7775
7879
  if (this.withoutRowid) {
7776
7880
  if (supplied.rowid !== void 0) {
7777
7881
  throw new SqliteError(`table ${this.name} has no column named rowid`, "other");
@@ -7792,7 +7896,7 @@ var Table = class _Table {
7792
7896
  const alias = this.integerPrimaryKeyAlias();
7793
7897
  let rowid = supplied.rowid;
7794
7898
  if (alias) {
7795
- const value = values.get(normalizeColumnName(alias.name)) ?? null;
7899
+ const value = this.cell({ rowid: 0, values }, normalizeColumnName(alias.name));
7796
7900
  if (rowid === void 0 && value !== null) rowid = asRowid(value, alias.name);
7797
7901
  }
7798
7902
  rowid = canonicalRowid(rowid ?? this.allocateRowid());
@@ -7803,7 +7907,7 @@ var Table = class _Table {
7803
7907
  "SQLITE_CONSTRAINT_PRIMARYKEY"
7804
7908
  );
7805
7909
  }
7806
- if (alias) values.set(normalizeColumnName(alias.name), rowid);
7910
+ if (alias) this.setCell({ rowid, values }, normalizeColumnName(alias.name), rowid);
7807
7911
  const candidate = { rowid, values };
7808
7912
  if (!options?.skipValidate) this.validate(candidate);
7809
7913
  this.rows.set(rowid, candidate);
@@ -7816,11 +7920,20 @@ var Table = class _Table {
7816
7920
  const key = canonicalRowid(rowid);
7817
7921
  const existing = this.rows.get(key);
7818
7922
  if (!existing) return void 0;
7819
- const values = new Map(existing.values);
7820
- const incoming = rowValues(updates);
7821
- for (const [name, value] of incoming) {
7822
- const column = this.column(name);
7823
- values.set(normalizeColumnName(column.name), applyAffinity(cloneSqlValue(value), column.affinity));
7923
+ const values = existing.values.slice();
7924
+ const incoming = isValueArray(updates) ? updates : rowValues(updates);
7925
+ if (isValueArray(updates)) {
7926
+ for (let i = 0; i < updates.length && i < this.columns.length; i++) {
7927
+ const column = this.columns[i];
7928
+ values[i] = applyAffinity(cloneSqlValue(updates[i] ?? null), column.affinity);
7929
+ }
7930
+ } else {
7931
+ for (const [name, value] of incoming) {
7932
+ const column = this.column(name);
7933
+ const offset = this.columnOffset(normalizeColumnName(column.name));
7934
+ if (offset === void 0) continue;
7935
+ values[offset] = applyAffinity(cloneSqlValue(value), column.affinity);
7936
+ }
7824
7937
  }
7825
7938
  if (this.withoutRowid) {
7826
7939
  const oldClusterKey = this.makeClusterKey(existing.values);
@@ -7837,7 +7950,8 @@ var Table = class _Table {
7837
7950
  return candidate2;
7838
7951
  }
7839
7952
  const alias = this.integerPrimaryKeyAlias();
7840
- const targetKey = alias ? asRowid(values.get(normalizeColumnName(alias.name)) ?? null, alias.name) : key;
7953
+ const aliasRow = { rowid: key, values };
7954
+ const targetKey = alias ? asRowid(this.cell(aliasRow, normalizeColumnName(alias.name)), alias.name) : key;
7841
7955
  if (targetKey !== key && this.rows.has(targetKey)) {
7842
7956
  throw new SqliteError(
7843
7957
  `UNIQUE constraint failed: ${this.name}.${alias?.name ?? "rowid"}`,
@@ -7845,7 +7959,7 @@ var Table = class _Table {
7845
7959
  "SQLITE_CONSTRAINT_UNIQUE"
7846
7960
  );
7847
7961
  }
7848
- if (alias) values.set(normalizeColumnName(alias.name), targetKey);
7962
+ if (alias) this.setCell(aliasRow, normalizeColumnName(alias.name), targetKey);
7849
7963
  const candidate = { rowid: targetKey, values };
7850
7964
  this.validate(candidate, key);
7851
7965
  if (targetKey !== key) {
@@ -7913,14 +8027,26 @@ var Table = class _Table {
7913
8027
  this.invalidateScan();
7914
8028
  this.clearEqualityHashes();
7915
8029
  }
8030
+ cellsFromInput(input, prepared) {
8031
+ if (isValueArray(input)) {
8032
+ if (prepared && input.length === this.columns.length) return [...input];
8033
+ return this.prepareValues(namedFromArray(this, input));
8034
+ }
8035
+ if (prepared) {
8036
+ const named = rowValues(input);
8037
+ const cells = [];
8038
+ for (const column of this.columns) cells.push(named.get(normalizeColumnName(column.name)) ?? null);
8039
+ return cells;
8040
+ }
8041
+ return this.prepareValues(input);
8042
+ }
7916
8043
  prepareValues(input) {
7917
8044
  const supplied = rowValues(input);
7918
8045
  for (const name of supplied.keys()) this.column(name);
7919
- const result = /* @__PURE__ */ new Map();
8046
+ const result = [];
7920
8047
  for (const column of this.columns) {
7921
8048
  const key = normalizeColumnName(column.name);
7922
- result.set(
7923
- key,
8049
+ result.push(
7924
8050
  this.strict ? applyStrictValue(cloneSqlValue(supplied.get(key) ?? null), column.typeName ?? "", this.name, column.name) : applyAffinity(cloneSqlValue(supplied.get(key) ?? null), column.affinity)
7925
8051
  );
7926
8052
  }
@@ -7933,8 +8059,9 @@ var Table = class _Table {
7933
8059
  return column;
7934
8060
  }
7935
8061
  validate(row, excludedRowid) {
7936
- for (const column of this.columns) {
7937
- const value = row.values.get(normalizeColumnName(column.name)) ?? null;
8062
+ for (let i = 0; i < this.columns.length; i++) {
8063
+ const column = this.columns[i];
8064
+ const value = row.values[i] ?? null;
7938
8065
  if ((column.notNull || column.primaryKey) && value === null) {
7939
8066
  const category = column.primaryKey ? "constraint_primary" : "constraint_notnull";
7940
8067
  const code = column.primaryKey ? "SQLITE_CONSTRAINT_PRIMARYKEY" : "SQLITE_CONSTRAINT_NOTNULL";
@@ -7948,13 +8075,13 @@ var Table = class _Table {
7948
8075
  const uniqueSets = this.uniqueColumnSets();
7949
8076
  if (this.indexes.length === 0) {
7950
8077
  for (const names of uniqueSets) {
7951
- const values = names.map((name) => row.values.get(normalizeColumnName(name)) ?? null);
8078
+ const values = names.map((name) => this.cell(row, normalizeColumnName(name)));
7952
8079
  if (values.some((value) => value === null)) continue;
7953
8080
  for (const other of this.rows.values()) {
7954
8081
  if (excludedRowid !== void 0 && other.rowid === excludedRowid) continue;
7955
8082
  if (values.every((value, index) => {
7956
8083
  const column = this.column(names[index]);
7957
- const otherValue = other.values.get(normalizeColumnName(names[index])) ?? null;
8084
+ const otherValue = this.cell(other, normalizeColumnName(names[index]));
7958
8085
  const collation = column.collate ?? "BINARY";
7959
8086
  return compareWithCollation(value, otherValue, collation) === 0;
7960
8087
  })) {
@@ -7992,15 +8119,17 @@ var Table = class _Table {
7992
8119
  }
7993
8120
  makeClusterKey(values) {
7994
8121
  return this.primaryKeyColumns().map((column) => {
7995
- const value = values.get(normalizeColumnName(column.name)) ?? null;
8122
+ const offset = this.columnOffset(normalizeColumnName(column.name)) ?? 0;
8123
+ const value = values[offset] ?? null;
7996
8124
  const normalized = normalizeForCollation(value, column.collate ?? "BINARY");
7997
8125
  return serializePkComponent(normalized);
7998
8126
  }).join("\0");
7999
8127
  }
8000
8128
  comparePrimaryKeys(left, right) {
8001
8129
  for (const column of this.primaryKeyColumns()) {
8002
- const leftValue = left.values.get(normalizeColumnName(column.name)) ?? null;
8003
- const rightValue = right.values.get(normalizeColumnName(column.name)) ?? null;
8130
+ const key = normalizeColumnName(column.name);
8131
+ const leftValue = this.cell(left, key);
8132
+ const rightValue = this.cell(right, key);
8004
8133
  const comparison = column.collate ? compareWithCollation(leftValue, rightValue, column.collate) : compareSql(leftValue, rightValue);
8005
8134
  if (comparison !== 0) return comparison ?? 0;
8006
8135
  }
@@ -8054,7 +8183,14 @@ function cloneAst(value) {
8054
8183
  return structuredClone(value);
8055
8184
  }
8056
8185
  function isInsertRow(input) {
8057
- return !(input instanceof Map) && "values" in input;
8186
+ return typeof input === "object" && input !== null && !Array.isArray(input) && !(input instanceof Map) && "values" in input;
8187
+ }
8188
+ function namedFromArray(table, values) {
8189
+ const named = /* @__PURE__ */ new Map();
8190
+ for (let i = 0; i < table.columns.length; i++) {
8191
+ named.set(normalizeColumnName(table.columns[i].name), values[i] ?? null);
8192
+ }
8193
+ return named;
8058
8194
  }
8059
8195
  function asRowid(value, column) {
8060
8196
  if (typeof value === "bigint") return canonicalRowid(value);
@@ -8664,10 +8800,13 @@ function keyOf(name) {
8664
8800
 
8665
8801
  // src/serialization/codec.ts
8666
8802
  var MAGIC = utf8Encode("SQLM");
8667
- var VERSION = 2;
8803
+ var VERSION = 4;
8668
8804
  var VERSION_V1 = 1;
8805
+ var VERSION_V2 = 2;
8806
+ var VERSION_V3 = 3;
8669
8807
  var Writer = class {
8670
- buf = new Uint8Array(1024);
8808
+ buf = new Uint8Array(4096);
8809
+ view = new DataView(this.buf.buffer);
8671
8810
  len = 0;
8672
8811
  ensure(needed) {
8673
8812
  if (this.len + needed <= this.buf.length) return;
@@ -8676,6 +8815,7 @@ var Writer = class {
8676
8815
  const next = new Uint8Array(cap);
8677
8816
  next.set(this.buf.subarray(0, this.len));
8678
8817
  this.buf = next;
8818
+ this.view = new DataView(next.buffer);
8679
8819
  }
8680
8820
  u8(value) {
8681
8821
  this.ensure(1);
@@ -8683,20 +8823,23 @@ var Writer = class {
8683
8823
  }
8684
8824
  u32(value) {
8685
8825
  this.ensure(4);
8686
- this.buf[this.len++] = value & 255;
8687
- this.buf[this.len++] = value >>> 8 & 255;
8688
- this.buf[this.len++] = value >>> 16 & 255;
8689
- this.buf[this.len++] = value >>> 24 & 255;
8826
+ this.view.setUint32(this.len, value >>> 0, true);
8827
+ this.len += 4;
8690
8828
  }
8691
8829
  u64(value) {
8692
- const bytes = new Uint8Array(8);
8693
- new DataView(bytes.buffer).setBigUint64(0, BigInt.asUintN(64, value), true);
8694
- this.raw(bytes);
8830
+ this.ensure(8);
8831
+ this.view.setBigUint64(this.len, BigInt.asUintN(64, value), true);
8832
+ this.len += 8;
8695
8833
  }
8696
8834
  i64(value) {
8697
- const bytes = new Uint8Array(8);
8698
- new DataView(bytes.buffer).setBigInt64(0, value, true);
8699
- this.raw(bytes);
8835
+ this.ensure(8);
8836
+ this.view.setBigInt64(this.len, value, true);
8837
+ this.len += 8;
8838
+ }
8839
+ f64(value) {
8840
+ this.ensure(8);
8841
+ this.view.setFloat64(this.len, value, true);
8842
+ this.len += 8;
8700
8843
  }
8701
8844
  raw(value) {
8702
8845
  this.ensure(value.length);
@@ -8718,23 +8861,17 @@ var Writer = class {
8718
8861
  }
8719
8862
  if (value instanceof SqlReal) {
8720
8863
  this.u8(2);
8721
- const bytes = new Uint8Array(8);
8722
- new DataView(bytes.buffer).setFloat64(0, value.value, true);
8723
- this.raw(bytes);
8864
+ this.f64(value.value);
8724
8865
  return;
8725
8866
  }
8726
8867
  if (typeof value === "bigint" || typeof value === "number" && Number.isInteger(value)) {
8727
8868
  this.u8(1);
8728
- const bytes = new Uint8Array(8);
8729
- new DataView(bytes.buffer).setBigInt64(0, BigInt(value), true);
8730
- this.raw(bytes);
8869
+ this.i64(BigInt(value));
8731
8870
  return;
8732
8871
  }
8733
8872
  if (typeof value === "number") {
8734
8873
  this.u8(2);
8735
- const bytes = new Uint8Array(8);
8736
- new DataView(bytes.buffer).setFloat64(0, value, true);
8737
- this.raw(bytes);
8874
+ this.f64(value);
8738
8875
  return;
8739
8876
  }
8740
8877
  if (typeof value === "string") {
@@ -8753,39 +8890,54 @@ var Writer = class {
8753
8890
  }
8754
8891
  finish() {
8755
8892
  if (this.len === this.buf.length) return this.buf;
8756
- return this.buf.slice(0, this.len);
8893
+ return this.buf.subarray(0, this.len).slice();
8757
8894
  }
8758
8895
  };
8759
8896
  var Reader = class {
8760
8897
  constructor(bytes) {
8761
8898
  this.bytes = bytes;
8899
+ this.view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
8762
8900
  }
8763
8901
  bytes;
8764
8902
  offset = 0;
8903
+ view;
8765
8904
  u8() {
8766
8905
  if (this.offset >= this.bytes.length) this.fail();
8767
8906
  return this.bytes[this.offset++];
8768
8907
  }
8769
8908
  u32() {
8770
8909
  if (this.offset + 4 > this.bytes.length) this.fail();
8771
- const value = new DataView(this.bytes.buffer, this.bytes.byteOffset + this.offset, 4).getUint32(0, true);
8910
+ const value = this.view.getUint32(this.offset, true);
8772
8911
  this.offset += 4;
8773
8912
  return value;
8774
8913
  }
8775
8914
  u64() {
8776
- const bytes = this.raw(8);
8777
- return new DataView(bytes.buffer, bytes.byteOffset, 8).getBigUint64(0, true);
8915
+ if (this.offset + 8 > this.bytes.length) this.fail();
8916
+ const value = this.view.getBigUint64(this.offset, true);
8917
+ this.offset += 8;
8918
+ return value;
8778
8919
  }
8779
8920
  i64() {
8780
- const bytes = this.raw(8);
8781
- return new DataView(bytes.buffer, bytes.byteOffset, 8).getBigInt64(0, true);
8921
+ if (this.offset + 8 > this.bytes.length) this.fail();
8922
+ const value = this.view.getBigInt64(this.offset, true);
8923
+ this.offset += 8;
8924
+ return value;
8925
+ }
8926
+ f64() {
8927
+ if (this.offset + 8 > this.bytes.length) this.fail();
8928
+ const value = this.view.getFloat64(this.offset, true);
8929
+ this.offset += 8;
8930
+ return value;
8782
8931
  }
8783
8932
  raw(length) {
8784
8933
  if (length < 0 || this.offset + length > this.bytes.length) this.fail();
8785
- const value = this.bytes.slice(this.offset, this.offset + length);
8934
+ const value = this.bytes.subarray(this.offset, this.offset + length);
8786
8935
  this.offset += length;
8787
8936
  return value;
8788
8937
  }
8938
+ owned(length) {
8939
+ return this.raw(length).slice();
8940
+ }
8789
8941
  text() {
8790
8942
  return utf8Decode(this.raw(this.u32()));
8791
8943
  }
@@ -8800,17 +8952,15 @@ var Reader = class {
8800
8952
  const tag = this.u8();
8801
8953
  if (tag === 0) return null;
8802
8954
  if (tag === 1) {
8803
- const bytes = this.raw(8);
8804
- const integer = new DataView(bytes.buffer, bytes.byteOffset, 8).getBigInt64(0, true);
8955
+ const integer = this.i64();
8805
8956
  return integer <= BigInt(Number.MAX_SAFE_INTEGER) && integer >= BigInt(Number.MIN_SAFE_INTEGER) ? Number(integer) : integer;
8806
8957
  }
8807
8958
  if (tag === 2) {
8808
- const bytes = this.raw(8);
8809
- const value = new DataView(bytes.buffer, bytes.byteOffset, 8).getFloat64(0, true);
8959
+ const value = this.f64();
8810
8960
  return Number.isInteger(value) && Number.isFinite(value) ? asSqlReal(value) : value;
8811
8961
  }
8812
8962
  if (tag === 3) return this.text();
8813
- if (tag === 4) return this.raw(this.u32());
8963
+ if (tag === 4) return this.owned(this.u32());
8814
8964
  this.fail();
8815
8965
  }
8816
8966
  remaining() {
@@ -8823,10 +8973,14 @@ var Reader = class {
8823
8973
  throw new SqliteError("invalid or truncated sqlite-mem snapshot", "other");
8824
8974
  }
8825
8975
  };
8826
- function encodeDatabaseState(state, runtime) {
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) {
8827
8981
  const writer = new Writer();
8828
8982
  writer.raw(MAGIC);
8829
- writer.u32(VERSION);
8983
+ writer.u32(formatVersion);
8830
8984
  writer.u8(state.foreignKeysEnabled ? 1 : 0);
8831
8985
  writer.u32(state.schemaVersion);
8832
8986
  writer.u32(state.changes);
@@ -8849,7 +9003,7 @@ function encodeDatabaseState(state, runtime) {
8849
9003
  for (const row of rows) {
8850
9004
  writer.value(row.rowid);
8851
9005
  writer.u32(table.columns.length);
8852
- for (const column of table.columns) writer.value(row.values.get(column.name.toLowerCase()) ?? null);
9006
+ for (const column of table.columns) writer.value(table.cell(row, column.nameLower ?? column.name.toLowerCase()));
8853
9007
  }
8854
9008
  }
8855
9009
  const views = sortedValues(state.views);
@@ -8867,8 +9021,13 @@ function encodeDatabaseState(state, runtime) {
8867
9021
  originalSql: index.originalSql
8868
9022
  });
8869
9023
  }
8870
- writer.u64(runtime.prngState);
8871
- writer.i64(BigInt(Math.trunc(runtime.nowMs)));
9024
+ if (formatVersion >= 3) {
9025
+ for (const index of indexes) writeIndexStore(writer, index.store);
9026
+ }
9027
+ if (formatVersion >= VERSION_V2) {
9028
+ writer.u64(runtime.prngState);
9029
+ writer.i64(BigInt(Math.trunc(runtime.nowMs)));
9030
+ }
8872
9031
  return writer.finish();
8873
9032
  }
8874
9033
  function decodeDatabaseState(snapshot) {
@@ -8885,9 +9044,10 @@ function decodeDatabaseStateInner(snapshot) {
8885
9044
  if (!magic.every((byte, index) => byte === MAGIC[index]))
8886
9045
  throw new SqliteError("invalid sqlite-mem snapshot magic", "other");
8887
9046
  const version = reader.u32();
8888
- if (version !== VERSION && version !== VERSION_V1) {
9047
+ if (version < VERSION_V1 || version > VERSION) {
8889
9048
  throw new SqliteError(`unsupported sqlite-mem snapshot version: ${version}`, "snapshot_version", "SQLITE_FORMAT");
8890
9049
  }
9050
+ if (version > VERSION_V3) return decodeV4(reader);
8891
9051
  const state = new DatabaseState();
8892
9052
  state.foreignKeysEnabled = reader.u8() !== 0;
8893
9053
  state.schemaVersion = reader.u32();
@@ -8910,8 +9070,8 @@ function decodeDatabaseStateInner(snapshot) {
8910
9070
  const rowid = asRowid2(reader.value());
8911
9071
  const valueCount = reader.u32();
8912
9072
  if (valueCount !== table.columns.length) throw new SqliteError("snapshot row column count mismatch", "other");
8913
- const values = /* @__PURE__ */ new Map();
8914
- for (const column of table.columns) values.set(column.name.toLowerCase(), reader.value());
9073
+ const values = [];
9074
+ for (let i = 0; i < valueCount; i++) values.push(reader.value());
8915
9075
  table.rows.set(rowid, { rowid, values });
8916
9076
  }
8917
9077
  table.rebuildClusteredRows();
@@ -8923,50 +9083,63 @@ function decodeDatabaseStateInner(snapshot) {
8923
9083
  state.views.set(view.name.toLowerCase(), view);
8924
9084
  }
8925
9085
  const indexCount = reader.u32();
9086
+ const loadedIndexes = [];
8926
9087
  for (let indexPosition = 0; indexPosition < indexCount; indexPosition++) {
8927
9088
  const meta = reader.json();
8928
9089
  const info = { ...meta, store: new IndexStore(meta.name) };
8929
9090
  state.indexes.set(info.name.toLowerCase(), info);
8930
- const table = state.getTable(info.tableName);
8931
- for (const row of table.scan()) {
8932
- if (info.where && isTruthySql(
8933
- evalExpr(info.where, {
8934
- functions: defaultFunctionRegistry,
8935
- resolveColumn: (qualifier, name) => {
8936
- if (qualifier && qualifier.toLowerCase() !== table.name.toLowerCase()) {
8937
- throw new SqliteError(`no such column: ${qualifier}.${name}`, "no_such_column");
8938
- }
8939
- if (name.toLowerCase() === "rowid") return row.rowid;
8940
- if (!row.values.has(name.toLowerCase()))
8941
- throw new SqliteError(`no such column: ${name}`, "no_such_column");
8942
- return row.values.get(name.toLowerCase()) ?? null;
8943
- },
8944
- getParameter: () => {
8945
- throw new SqliteError("parameters are not allowed in index predicates", "misuse");
8946
- }
8947
- })
8948
- ) !== true)
8949
- continue;
8950
- info.store.insert(
8951
- info.columns.map(
8952
- (column) => normalizeForCollation(row.values.get(column.name.toLowerCase()) ?? null, column.collate ?? "BINARY")
8953
- ),
8954
- row.rowid,
8955
- info.unique
8956
- );
9091
+ loadedIndexes.push(info);
9092
+ }
9093
+ if (version >= 3) {
9094
+ for (const info of loadedIndexes) {
9095
+ info.store = readIndexStore(reader, info.name);
8957
9096
  }
9097
+ } else {
9098
+ for (const info of loadedIndexes) rebuildIndexStore(state, info);
8958
9099
  }
8959
9100
  let runtime = null;
8960
- if (version >= VERSION) {
9101
+ if (version >= VERSION_V2) {
8961
9102
  if (reader.remaining() < 16) throw new SqliteError("invalid or truncated sqlite-mem snapshot", "other");
8962
9103
  runtime = {
8963
9104
  prngState: reader.u64(),
8964
- nowMs: Number(reader.i64())
9105
+ nowMs: finiteNowMs(Number(reader.i64()))
8965
9106
  };
8966
9107
  }
8967
9108
  if (!reader.done()) throw new SqliteError("snapshot has trailing data", "other");
8968
9109
  return { state, runtime };
8969
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);
9120
+ }
9121
+ }
9122
+ function readIndexStore(reader, name) {
9123
+ const count = reader.u32();
9124
+ const entries = /* @__PURE__ */ new Map();
9125
+ const keyValues = /* @__PURE__ */ new Map();
9126
+ 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);
9136
+ }
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
+ }
8970
9143
  function asRowid2(value) {
8971
9144
  if (typeof value === "number" && Number.isSafeInteger(value) || typeof value === "bigint") return value;
8972
9145
  throw new SqliteError("invalid rowid in snapshot", "other");
@@ -8974,6 +9147,13 @@ function asRowid2(value) {
8974
9147
  function compareNames(a, b) {
8975
9148
  return a < b ? -1 : a > b ? 1 : 0;
8976
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
+ }
8977
9157
  function compareRowids2(a, b) {
8978
9158
  const left = typeof a === "bigint" ? a : BigInt(a);
8979
9159
  const right = typeof b === "bigint" ? b : BigInt(b);
@@ -8996,6 +9176,323 @@ function jsonReviver(_key, value) {
8996
9176
  if (tagged.$sqlm === "blob") return Uint8Array.from(tagged.value);
8997
9177
  return value;
8998
9178
  }
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;
9185
+ 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("");
9198
+ const tables = sortedValues(state.tables);
9199
+ const views = sortedValues(state.views);
9200
+ const indexes = sortedValues(state.indexes);
9201
+ for (const table of tables) {
9202
+ internId(table.name);
9203
+ internId(table.originalSql ?? "");
9204
+ for (const column of table.columns) {
9205
+ internId(column.name);
9206
+ internId(column.typeName ?? "");
9207
+ internId(column.collate ?? "");
9208
+ }
9209
+ for (const name of table.indexes) internId(name);
9210
+ for (const row of table.rows.values()) {
9211
+ for (const value of row.values) {
9212
+ if (typeof value === "string") internId(value);
9213
+ else if (value instanceof SqlJsonText) internId(value.value);
9214
+ }
9215
+ }
9216
+ }
9217
+ const w = new Writer();
9218
+ w.raw(MAGIC);
9219
+ w.u32(VERSION);
9220
+ w.u8(state.foreignKeysEnabled ? 1 : 0);
9221
+ w.u32(state.schemaVersion);
9222
+ w.u32(state.changes);
9223
+ 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);
9228
+ for (const table of tables) {
9229
+ w.u32(internId(table.name));
9230
+ w.u32(table.columns.length);
9231
+ for (const column of table.columns) {
9232
+ w.u32(internId(column.name));
9233
+ w.u32(internId(column.typeName ?? ""));
9234
+ const aff = AFFINITIES.indexOf(column.affinity);
9235
+ w.u8(aff < 0 ? 2 : aff);
9236
+ w.u8(
9237
+ (column.notNull ? 1 : 0) | (column.primaryKey ? 2 : 0) | (column.autoincrement ? 4 : 0) | (column.unique ? 8 : 0)
9238
+ );
9239
+ w.u32(internId(column.collate ?? ""));
9240
+ if (column.defaultExpr) {
9241
+ w.u8(1);
9242
+ w.json(column.defaultExpr);
9243
+ } else w.u8(0);
9244
+ if (column.generated) {
9245
+ w.u8(1);
9246
+ w.json(column.generated);
9247
+ } else w.u8(0);
9248
+ }
9249
+ w.json(table.constraints);
9250
+ w.u32(internId(table.originalSql ?? ""));
9251
+ w.u8((table.withoutRowid ? 1 : 0) | (table.strict ? 2 : 0));
9252
+ 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);
9266
+ 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
+ }
9284
+ }
9285
+ w.u64(runtime.prngState);
9286
+ w.i64(BigInt(Math.trunc(runtime.nowMs)));
9287
+ return w.finish();
9288
+ }
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);
9320
+ }
9321
+ }
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;
9350
+ }
9351
+ w.value(value);
9352
+ }
9353
+ function decodeV4(reader) {
9354
+ 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());
9363
+ const str = (id) => intern[id] ?? "";
9364
+ const tableCount = reader.u32();
9365
+ for (let t = 0; t < tableCount; t++) {
9366
+ const name = str(reader.u32());
9367
+ const colCount = reader.u32();
9368
+ const columns = [];
9369
+ 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;
9379
+ columns.push({
9380
+ name: colName,
9381
+ nameLower: colName.toLowerCase(),
9382
+ typeName,
9383
+ affinity: AFFINITIES[affIndex] ?? "NUMERIC",
9384
+ notNull: (flags & 1) !== 0,
9385
+ primaryKey: (flags & 2) !== 0,
9386
+ autoincrement: (flags & 4) !== 0,
9387
+ unique: (flags & 8) !== 0,
9388
+ defaultExpr,
9389
+ collate,
9390
+ generated
9391
+ });
9392
+ }
9393
+ const constraints = reader.json();
9394
+ const originalSql = str(reader.u32()) || null;
9395
+ const tableFlags = reader.u8();
9396
+ const indexCount2 = reader.u32();
9397
+ const indexNames = [];
9398
+ for (let i = 0; i < indexCount2; i++) indexNames.push(str(reader.u32()));
9399
+ const table = new Table(name, columns, {
9400
+ constraints,
9401
+ indexes: indexNames,
9402
+ originalSql,
9403
+ withoutRowid: (tableFlags & 1) !== 0,
9404
+ strict: (tableFlags & 2) !== 0
9405
+ });
9406
+ table.nextRowid = asRowid2(reader.value());
9407
+ const rowCount = reader.u32();
9408
+ 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();
9419
+ state.tables.set(table.name.toLowerCase(), table);
9420
+ }
9421
+ const viewCount = reader.u32();
9422
+ for (let i = 0; i < viewCount; i++) {
9423
+ const view = reader.json();
9424
+ state.views.set(view.name.toLowerCase(), view);
9425
+ }
9426
+ const indexCount = reader.u32();
9427
+ const loadedIndexes = [];
9428
+ for (let i = 0; i < indexCount; i++) {
9429
+ const meta = reader.json();
9430
+ const info = { ...meta, store: new IndexStore(meta.name) };
9431
+ state.indexes.set(info.name.toLowerCase(), info);
9432
+ loadedIndexes.push(info);
9433
+ }
9434
+ for (const info of loadedIndexes) {
9435
+ info.store = readIndexStoreKeys(reader, info.name);
9436
+ const table = state.tables.get(info.tableName.toLowerCase());
9437
+ if (!table) continue;
9438
+ for (const entry of info.store.snapshotKeys()) {
9439
+ const rowid = entry.rowids[0];
9440
+ if (rowid === void 0) continue;
9441
+ const row = table.rows.get(rowid);
9442
+ if (!row) continue;
9443
+ info.store.rememberKeyValues(
9444
+ entry.key,
9445
+ indexKeyValues(info.columns, row, tableRowEvalContext(table, row), table)
9446
+ );
9447
+ }
9448
+ }
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");
9452
+ return { state, runtime };
9453
+ }
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;
9460
+ }
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;
9466
+ }
9467
+ out[i] = readPackedCell(reader, pack, intern);
9468
+ }
9469
+ return out;
9470
+ }
9471
+ function readPackedCell(reader, pack, intern) {
9472
+ if (pack === PACK_INT) {
9473
+ const integer = reader.i64();
9474
+ return integer <= BigInt(Number.MAX_SAFE_INTEGER) && integer >= BigInt(Number.MIN_SAFE_INTEGER) ? Number(integer) : integer;
9475
+ }
9476
+ if (pack === PACK_FLOAT) {
9477
+ const value = reader.f64();
9478
+ return Number.isInteger(value) && Number.isFinite(value) ? asSqlReal(value) : value;
9479
+ }
9480
+ if (pack === PACK_TEXT) return intern[reader.u32()] ?? "";
9481
+ if (pack === PACK_BLOB) return reader.owned(reader.u32());
9482
+ return reader.value();
9483
+ }
9484
+ function readIndexStoreKeys(reader, name) {
9485
+ const count = reader.u32();
9486
+ const entries = /* @__PURE__ */ new Map();
9487
+ for (let i = 0; i < count; i++) {
9488
+ const key = reader.text();
9489
+ const rowidCount = reader.u32();
9490
+ const rowids = [];
9491
+ for (let r = 0; r < rowidCount; r++) rowids.push(asRowid2(reader.value()));
9492
+ entries.set(key, rowids);
9493
+ }
9494
+ return new IndexStore(name, entries);
9495
+ }
8999
9496
  export {
9000
9497
  DEFAULT_DATABASE_SEED,
9001
9498
  DEFAULT_NOW,