@crvouga/sqlite-mem 1.3.0 → 1.4.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.
@@ -48,7 +48,7 @@
48
48
  "scope": "select",
49
49
  "predicate": "INDEXED BY / NOT INDEXED is accepted and ignored",
50
50
  "specifiedBehavior": "Query results match the unhinted plan; missing-index errors are not raised.",
51
- "pinnedBy": ["indexes/indexed-by.test.ts", "COMPATIBILITY.md"]
51
+ "pinnedBy": ["tests/contract/indexes/indexed-by.test.ts"]
52
52
  },
53
53
  {
54
54
  "id": "materialized-hint-ignored",
@@ -119,6 +119,27 @@
119
119
  "predicate": "user_version is not restored from SQLM",
120
120
  "specifiedBehavior": "PRAGMA user_version after restore is the default unless re-set.",
121
121
  "pinnedBy": ["PRG-beh-05", "SNP-omit-04"]
122
+ },
123
+ {
124
+ "id": "pragma-setter-noop",
125
+ "scope": "pragma",
126
+ "predicate": "Some pragma setters are accepted but do not change engine state yet",
127
+ "specifiedBehavior": "defer_foreign_keys, recursive_triggers, and application_id getters remain 0 after SET.",
128
+ "pinnedBy": ["PRG-beh-02", "PRG-beh-03", "PRG-beh-07"]
129
+ },
130
+ {
131
+ "id": "generate-series-extension",
132
+ "scope": "tvf",
133
+ "predicate": "generate_series is a sqlite-mem extension",
134
+ "specifiedBehavior": "Present in sqlite-mem; not claimed vs bun:sqlite default inventory.",
135
+ "pinnedBy": ["FTS-series-01"]
136
+ },
137
+ {
138
+ "id": "datetime-localtime-utc",
139
+ "scope": "datetime",
140
+ "predicate": "localtime/utc modifiers do not apply host timezone conversion",
141
+ "specifiedBehavior": "Modifiers are accepted as no-ops; storage remains UTC-like fixed strings.",
142
+ "pinnedBy": ["tests/contract/date-time/modifiers.test.ts"]
122
143
  }
123
144
  ]
124
145
  }
@@ -37,7 +37,10 @@ function divergenceIdFor(id: string): string | undefined {
37
37
  }
38
38
  if (id === "PRG-fn-01" || id === "PRG-comp-01") return "compile-options-function-list";
39
39
  if (id === "PRG-beh-05") return "user-version-snapshot";
40
+ if (id === "PRG-beh-02" || id === "PRG-beh-03" || id === "PRG-beh-07") return "pragma-setter-noop";
41
+ if (id === "FTS-series-01") return "generate-series-extension";
40
42
  if (id === "FTS-chg-01") return "fts-shadow-counters";
43
+ if (id === "DAT-mod-localtime" || id === "datetime-localtime-utc") return "datetime-localtime-utc";
41
44
  if (id === "ATT-att-01") return "attach-empty-schema";
42
45
  if (id === "TOK-07") return "double-quote-string-fallback";
43
46
  if (id === "UNI-surr-01") return "lone-surrogate-bind";
@@ -660,12 +663,12 @@ const TAIL: CatalogSection[] = [
660
663
  ["tl-01", "table_list"],
661
664
  ["tvf-01", "pragma_* TVFs correlated"],
662
665
  ["beh-01", "foreign_keys pragma"],
663
- ["beh-02", "defer_foreign_keys"],
664
- ["beh-03", "recursive_triggers"],
666
+ ["beh-02", "defer_foreign_keys", D, "setter currently no-op; getter returns 0"],
667
+ ["beh-03", "recursive_triggers", D, "setter currently no-op; getter returns 0"],
665
668
  ["beh-04", "case_sensitive_like"],
666
669
  ["beh-05", "user_version get/set", D, "snapshot exclusion"],
667
670
  ["beh-06", "schema_version bumps on DDL"],
668
- ["beh-07", "application_id"],
671
+ ["beh-07", "application_id", D, "setter currently no-op; getter returns 0"],
669
672
  ["health-01", "integrity_check quick_check ok"],
670
673
  ["health-02", "foreign_key_check rows"],
671
674
  ["stor-01", "journal_mode memory default"],
@@ -701,7 +704,7 @@ const TAIL: CatalogSection[] = [
701
704
  ["f34-02", "matchinfo offsets"],
702
705
  ["chg-01", "shadow-table change counters", D, "README"],
703
706
  ["snap-01", "virtual tables not in snapshots", D, "README"],
704
- ["series-01", "generate_series"],
707
+ ["series-01", "generate_series", D, "sqlite-mem extension; not in bun:sqlite default"],
705
708
  ]),
706
709
  section("ATT", "ATTACH / DETACH / schemas", true, [
707
710
  ["att-01", "ATTACH anything is empty in-memory schema", D, "filename ignored for data"],
@@ -1,15 +1,3 @@
1
1
  {
2
- "ids": [
3
- "CON-fk-09",
4
- "DDL-auto-03",
5
- "FTS-series-01",
6
- "LIM-vals-01",
7
- "PRG-beh-01",
8
- "PRG-beh-02",
9
- "PRG-beh-03",
10
- "PRG-beh-04",
11
- "PRG-beh-05",
12
- "PRG-beh-06",
13
- "PRG-beh-07"
14
- ]
2
+ "ids": []
15
3
  }
package/dist/index.js CHANGED
@@ -3804,6 +3804,7 @@ function valueOf(node) {
3804
3804
  return jsonNodeToSql(node, "sql");
3805
3805
  }
3806
3806
  function jsonEachRows(json, path) {
3807
+ if (json === null) return [];
3807
3808
  const root = ensureJson(json);
3808
3809
  const blob = encodeJsonb(root);
3809
3810
  const walk2 = walkJsonbTree(blob);
@@ -3833,6 +3834,7 @@ function jsonEachRows(json, path) {
3833
3834
  return walk2.filter((e) => e.parent === focus.idOffset).map((e) => rowFromWalk(e, true));
3834
3835
  }
3835
3836
  function jsonTreeRows(json, path) {
3837
+ if (json === null) return [];
3836
3838
  const root = ensureJson(json);
3837
3839
  const blob = encodeJsonb(root);
3838
3840
  const walk2 = walkJsonbTree(blob);
@@ -4291,11 +4293,16 @@ function parseDate(value, context) {
4291
4293
  const date = new Date(source);
4292
4294
  return Number.isNaN(date.getTime()) ? null : date;
4293
4295
  }
4294
- function applyModifier(date, modifier) {
4296
+ function applyModifier(date, modifier, flags) {
4295
4297
  const result = new Date(date);
4296
4298
  const normalized = modifier.trim().toLowerCase();
4297
4299
  if (normalized === "unixepoch") return new Date((date.getTime() / 864e5 + JULIAN_UNIX_EPOCH) * 1e3);
4298
4300
  if (normalized === "utc" || normalized === "localtime") return result;
4301
+ if (normalized === "subsec" || normalized === "subsecond") {
4302
+ flags.subsec = true;
4303
+ return result;
4304
+ }
4305
+ if (normalized === "floor" || normalized === "ceiling") return result;
4299
4306
  const weekday = /^weekday\s+([0-6])$/.exec(normalized);
4300
4307
  if (weekday) {
4301
4308
  const target = Number(weekday[1]);
@@ -4343,15 +4350,21 @@ function resolveDate(args, context) {
4343
4350
  if (seconds === null) return null;
4344
4351
  source = seconds / 86400 + JULIAN_UNIX_EPOCH;
4345
4352
  modifiers = modifiers.slice(1);
4353
+ } else if (typeof modifiers[0] === "string" && modifiers[0].trim().toLowerCase() === "auto") {
4354
+ const number = coerceToNumber(source);
4355
+ if (number === null) return null;
4356
+ source = number >= 0 && number < 53734845e-1 ? number : number / 86400 + JULIAN_UNIX_EPOCH;
4357
+ modifiers = modifiers.slice(1);
4346
4358
  }
4347
4359
  let date = parseDate(source, context);
4348
4360
  if (!date) return null;
4361
+ const flags = { subsec: false };
4349
4362
  for (const modifier of modifiers) {
4350
4363
  if (typeof modifier !== "string") return null;
4351
- date = applyModifier(date, modifier);
4364
+ date = applyModifier(date, modifier, flags);
4352
4365
  if (!date) return null;
4353
4366
  }
4354
- return date;
4367
+ return { date, subsec: flags.subsec };
4355
4368
  }
4356
4369
  function pad(value, length = 2) {
4357
4370
  return String(value).padStart(length, "0");
@@ -4359,8 +4372,9 @@ function pad(value, length = 2) {
4359
4372
  function isoDate(date) {
4360
4373
  return `${pad(date.getUTCFullYear(), 4)}-${pad(date.getUTCMonth() + 1)}-${pad(date.getUTCDate())}`;
4361
4374
  }
4362
- function isoTime(date) {
4363
- return `${pad(date.getUTCHours())}:${pad(date.getUTCMinutes())}:${pad(date.getUTCSeconds())}`;
4375
+ function isoTime(date, subsec = false) {
4376
+ const base = `${pad(date.getUTCHours())}:${pad(date.getUTCMinutes())}:${pad(date.getUTCSeconds())}`;
4377
+ return subsec ? `${base}.${pad(date.getUTCMilliseconds(), 3)}` : base;
4364
4378
  }
4365
4379
  function dayOfYear(date) {
4366
4380
  return Math.floor(
@@ -4404,24 +4418,24 @@ function formatDate(date, format) {
4404
4418
  var dateTimeFunctions = {
4405
4419
  date(args, context) {
4406
4420
  const value = resolveDate(args, context);
4407
- return value ? isoDate(value) : null;
4421
+ return value ? isoDate(value.date) : null;
4408
4422
  },
4409
4423
  time(args, context) {
4410
4424
  const value = resolveDate(args, context);
4411
- return value ? isoTime(value) : null;
4425
+ return value ? isoTime(value.date, value.subsec) : null;
4412
4426
  },
4413
4427
  datetime(args, context) {
4414
4428
  const value = resolveDate(args, context);
4415
- return value ? `${isoDate(value)} ${isoTime(value)}` : null;
4429
+ return value ? `${isoDate(value.date)} ${isoTime(value.date, value.subsec)}` : null;
4416
4430
  },
4417
4431
  julianday(args, context) {
4418
4432
  const value = resolveDate(args, context);
4419
- return value ? value.getTime() / 864e5 + JULIAN_UNIX_EPOCH : null;
4433
+ return value ? value.date.getTime() / 864e5 + JULIAN_UNIX_EPOCH : null;
4420
4434
  },
4421
4435
  strftime(args, context) {
4422
4436
  if (typeof args[0] !== "string") return null;
4423
4437
  const value = resolveDate(args.slice(1), context);
4424
- return value ? formatDate(value, args[0]) : null;
4438
+ return value ? formatDate(value.date, args[0]) : null;
4425
4439
  },
4426
4440
  current_date(args, context) {
4427
4441
  return dateTimeFunctions.date(args.length === 0 ? ["now"] : args, context);
@@ -4434,7 +4448,7 @@ var dateTimeFunctions = {
4434
4448
  },
4435
4449
  unixepoch(args, context) {
4436
4450
  const value = resolveDate(args.length === 0 ? ["now"] : args, context);
4437
- return value ? Math.floor(value.getTime() / 1e3) : null;
4451
+ return value ? Math.floor(value.date.getTime() / 1e3) : null;
4438
4452
  },
4439
4453
  timediff(args) {
4440
4454
  if (args.length !== 2) return null;
@@ -5828,9 +5842,9 @@ function evalExpr(expr, ctx) {
5828
5842
  return result.rows[0]?.[0] ?? null;
5829
5843
  }
5830
5844
  case "aggregate":
5831
- throw new SqliteError("aggregate expression requires aggregate evaluation", "misuse");
5832
- case "window":
5833
5845
  throw new SqliteError("window expression requires window evaluation", "misuse");
5846
+ case "window":
5847
+ throw new SqliteError("misuse of window function", "misuse");
5834
5848
  case "row":
5835
5849
  throw new SqliteError("row value cannot be used as a scalar value", "misuse");
5836
5850
  }
@@ -8077,8 +8091,17 @@ var Table = class _Table {
8077
8091
  }
8078
8092
  return this.maximumRowid === null ? 1 : incrementRowid(this.maximumRowid);
8079
8093
  }
8094
+ const maxSigned = 9223372036854775807n;
8080
8095
  let candidate = canonicalRowid(this.nextRowid);
8081
- while (this.rows.has(candidate)) candidate = incrementRowid(candidate);
8096
+ while (this.rows.has(candidate)) {
8097
+ if (BigInt(candidate) >= maxSigned) {
8098
+ throw new SqliteError("database or disk is full", "other", "SQLITE_FULL");
8099
+ }
8100
+ candidate = incrementRowid(candidate);
8101
+ }
8102
+ if (BigInt(candidate) > maxSigned) {
8103
+ throw new SqliteError("database or disk is full", "other", "SQLITE_FULL");
8104
+ }
8082
8105
  return candidate;
8083
8106
  }
8084
8107
  advanceNextRowid(rowid) {
@@ -12758,7 +12781,6 @@ function executeUpdateCore(stmt, env) {
12758
12781
  };
12759
12782
  if (stmt.where && isTruthySql(evalExpr(stmt.where, env.createEvalContext(joined))) !== true) continue;
12760
12783
  matchedScope = joined;
12761
- break;
12762
12784
  }
12763
12785
  if (matchedScope) candidates.push({ row, scope: matchedScope });
12764
12786
  }
@@ -13241,7 +13263,9 @@ function applyReferentialDelete(parent, row, env) {
13241
13263
  for (const candidate of matches) {
13242
13264
  if (constraint.onDelete === "CASCADE") {
13243
13265
  changes += applyReferentialDelete(child, candidate, env);
13266
+ if (fireDeleteTriggers("BEFORE", child, candidate, env) === "ignore") continue;
13244
13267
  removeOne(child, candidate, env);
13268
+ fireDeleteTriggers("AFTER", child, candidate, env);
13245
13269
  changes++;
13246
13270
  } else if (constraint.onDelete === "SET NULL") {
13247
13271
  const updated = updateOne(