@crvouga/sqlite-mem 1.1.2 → 1.2.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
@@ -125,6 +125,23 @@ function applyAffinity(value, affinity) {
125
125
  return value;
126
126
  }
127
127
  }
128
+ function applyComparisonAffinity(left, right, leftAffinity, rightAffinity) {
129
+ const leftNumeric = leftAffinity === "INTEGER" || leftAffinity === "REAL" || leftAffinity === "NUMERIC";
130
+ const rightNumeric = rightAffinity === "INTEGER" || rightAffinity === "REAL" || rightAffinity === "NUMERIC";
131
+ const leftNone = leftAffinity === null || leftAffinity === "BLOB";
132
+ const rightNone = rightAffinity === null || rightAffinity === "BLOB";
133
+ if (leftNumeric && (rightAffinity === "TEXT" || rightNone)) {
134
+ const affinity = leftAffinity === "REAL" ? "REAL" : "NUMERIC";
135
+ return [left, applyAffinity(right, affinity)];
136
+ }
137
+ if (rightNumeric && (leftAffinity === "TEXT" || leftNone)) {
138
+ const affinity = rightAffinity === "REAL" ? "REAL" : "NUMERIC";
139
+ return [applyAffinity(left, affinity), right];
140
+ }
141
+ if (leftAffinity === "TEXT" && rightNone) return [left, applyAffinity(right, "TEXT")];
142
+ if (rightAffinity === "TEXT" && leftNone) return [applyAffinity(left, "TEXT"), right];
143
+ return [left, right];
144
+ }
128
145
  function coerceToNumber(value) {
129
146
  if (value === null) return null;
130
147
  if (value instanceof SqlReal) return value.value;
@@ -281,14 +298,18 @@ function jsonErrorPosition(input) {
281
298
  }
282
299
  }
283
300
  function isValidJsonText(input, flags = 0) {
284
- const allowJson5 = (flags & 2) !== 0 || (flags & 1) !== 0;
301
+ const allowCanonical = flags === 0 || (flags & 1) !== 0;
302
+ const allowJson5 = (flags & 2) !== 0;
285
303
  try {
286
304
  if (allowJson5) {
287
305
  parseJsonText(input);
288
306
  return true;
289
307
  }
290
- parseJsonText(input, { strictCanonical: true });
291
- return true;
308
+ if (allowCanonical) {
309
+ parseJsonText(input, { strictCanonical: true });
310
+ return true;
311
+ }
312
+ return false;
292
313
  } catch {
293
314
  return false;
294
315
  }
@@ -1694,7 +1715,11 @@ function applyModifier(date, modifier) {
1694
1715
  const normalized = modifier.trim().toLowerCase();
1695
1716
  if (normalized === "unixepoch") return new Date((date.getTime() / 864e5 + JULIAN_UNIX_EPOCH) * 1e3);
1696
1717
  if (normalized === "utc" || normalized === "localtime") return result;
1697
- if (normalized === "start of day") result.setUTCHours(0, 0, 0, 0);
1718
+ const weekday = /^weekday\s+([0-6])$/.exec(normalized);
1719
+ if (weekday) {
1720
+ const target = Number(weekday[1]);
1721
+ result.setUTCDate(result.getUTCDate() + (target - result.getUTCDay() + 7) % 7);
1722
+ } else if (normalized === "start of day") result.setUTCHours(0, 0, 0, 0);
1698
1723
  else if (normalized === "start of month") {
1699
1724
  result.setUTCDate(1);
1700
1725
  result.setUTCHours(0, 0, 0, 0);
@@ -2152,13 +2177,15 @@ var mathFunctions = {
2152
2177
  function escapeRegexChar(char) {
2153
2178
  return /[\\^$.*+?()[\]{}|]/.test(char) ? `\\${char}` : char;
2154
2179
  }
2155
- function likeLiteral(char) {
2156
- const code = char.codePointAt(0);
2157
- if (code >= 65 && code <= 90) return `[${char}${char.toLowerCase()}]`;
2158
- if (code >= 97 && code <= 122) return `[${char}${char.toUpperCase()}]`;
2180
+ function likeLiteral(char, caseSensitive) {
2181
+ if (!caseSensitive) {
2182
+ const code = char.codePointAt(0);
2183
+ if (code >= 65 && code <= 90) return `[${char}${char.toLowerCase()}]`;
2184
+ if (code >= 97 && code <= 122) return `[${char}${char.toUpperCase()}]`;
2185
+ }
2159
2186
  return escapeRegexChar(char);
2160
2187
  }
2161
- function likeMatch(text2, pattern, escape = null) {
2188
+ function likeMatch(text2, pattern, escape = null, caseSensitive = false) {
2162
2189
  if (escape !== null && [...escape].length !== 1) {
2163
2190
  throw new SqliteError("ESCAPE expression must be a single character", "other");
2164
2191
  }
@@ -2168,13 +2195,13 @@ function likeMatch(text2, pattern, escape = null) {
2168
2195
  const char = chars[i];
2169
2196
  if (escape !== null && char === escape) {
2170
2197
  const next = chars[++i];
2171
- source += next === void 0 ? likeLiteral(char) : likeLiteral(next);
2198
+ source += next === void 0 ? likeLiteral(char, caseSensitive) : likeLiteral(next, caseSensitive);
2172
2199
  } else if (char === "%") {
2173
2200
  source += "[\\s\\S]*";
2174
2201
  } else if (char === "_") {
2175
2202
  source += "[\\s\\S]";
2176
2203
  } else {
2177
- source += likeLiteral(char);
2204
+ source += likeLiteral(char, caseSensitive);
2178
2205
  }
2179
2206
  }
2180
2207
  return new RegExp(`${source}$`).test(text2);
@@ -2481,11 +2508,11 @@ var scalarFunctions = {
2481
2508
  requireArgs3("load_extension", args, 1, 2);
2482
2509
  throw new SqliteError("not authorized", "misuse");
2483
2510
  },
2484
- like(args) {
2511
+ like(args, context) {
2485
2512
  requireArgs3("like", args, 2, 3);
2486
2513
  if (args[0] === null || args[1] === null || args[2] === null) return null;
2487
2514
  const escape = args[2] === void 0 ? null : text(args[2]);
2488
- return likeMatch(text(args[1]), text(args[0]), escape) ? 1 : 0;
2515
+ return likeMatch(text(args[1]), text(args[0]), escape, context.caseSensitiveLike === true) ? 1 : 0;
2489
2516
  },
2490
2517
  glob(args) {
2491
2518
  requireArgs3("glob", args, 2);
@@ -2830,7 +2857,8 @@ function sqlOr(left, right) {
2830
2857
  if (leftTruth === null || rightTruth === null) return null;
2831
2858
  return 0;
2832
2859
  }
2833
- function compareResult(op, left, right, collation) {
2860
+ function compareResult(op, left, right, collation, leftAffinity = null, rightAffinity = null) {
2861
+ [left, right] = applyComparisonAffinity(left, right, leftAffinity, rightAffinity);
2834
2862
  if (op === "IS" || op === "IS NOT" || op === "IS DISTINCT FROM" || op === "IS NOT DISTINCT FROM") {
2835
2863
  const equal = left === null || right === null ? left === right : (collation ? compareWithCollation(left, right, collation) : compareSql(left, right)) === 0;
2836
2864
  if (op === "IS" || op === "IS NOT DISTINCT FROM") return booleanValue(equal);
@@ -2883,11 +2911,18 @@ function evalBinary(op, leftExpr, rightExpr, ctx) {
2883
2911
  if (["=", "==", "!=", "<>", "<", "<=", ">", ">=", "IS", "IS NOT", "IS DISTINCT FROM", "IS NOT DISTINCT FROM"].includes(
2884
2912
  op
2885
2913
  )) {
2886
- return compareResult(op, left, right, resolveComparisonCollation(leftExpr, rightExpr, ctx) ?? void 0);
2914
+ return compareResult(
2915
+ op,
2916
+ left,
2917
+ right,
2918
+ resolveComparisonCollation(leftExpr, rightExpr, ctx) ?? void 0,
2919
+ resolveComparisonAffinity(leftExpr, ctx),
2920
+ resolveComparisonAffinity(rightExpr, ctx)
2921
+ );
2887
2922
  }
2888
2923
  if (op === "LIKE" || op === "NOT LIKE" || op === "GLOB" || op === "NOT GLOB") {
2889
2924
  if (left === null || right === null) return null;
2890
- const matches = op.includes("LIKE") ? likeMatch(textValue(left), textValue(right)) : globMatch(textValue(left), textValue(right));
2925
+ const matches = op.includes("LIKE") ? likeMatch(textValue(left), textValue(right), null, ctx.functionContext?.caseSensitiveLike === true) : globMatch(textValue(left), textValue(right));
2891
2926
  return booleanValue(op.startsWith("NOT") ? !matches : matches);
2892
2927
  }
2893
2928
  if (left === null || right === null) return null;
@@ -3062,14 +3097,26 @@ function inheritedCollation(expr, ctx) {
3062
3097
  return null;
3063
3098
  }
3064
3099
  }
3065
- function evalIn(left, values, not) {
3100
+ function resolveComparisonAffinity(expr, ctx) {
3101
+ switch (expr.type) {
3102
+ case "column":
3103
+ return ctx.resolveAffinity?.(expr.table, expr.name) ?? ctx.parent?.resolveAffinity?.(expr.table, expr.name) ?? null;
3104
+ case "cast":
3105
+ return affinityFromTypeName(expr.typeName);
3106
+ case "collate":
3107
+ return resolveComparisonAffinity(expr.expr, ctx);
3108
+ default:
3109
+ return null;
3110
+ }
3111
+ }
3112
+ function evalIn(left, values, not, leftAffinity) {
3066
3113
  if (values.length === 0) return booleanValue(not);
3067
3114
  if (left === null) return null;
3068
3115
  let sawNull = false;
3069
3116
  for (const value of values) {
3070
3117
  if (value === null) {
3071
3118
  sawNull = true;
3072
- } else if (compareSql(left, value) === 0) {
3119
+ } else if (compareSql(...applyComparisonAffinity(left, value, leftAffinity, null)) === 0) {
3073
3120
  return booleanValue(!not);
3074
3121
  }
3075
3122
  }
@@ -3115,8 +3162,9 @@ function evalExpr(expr, ctx) {
3115
3162
  case "between": {
3116
3163
  const value = evalExpr(expr.expr, ctx);
3117
3164
  const collation = resolveComparisonCollation(expr.expr, expr.lower, ctx) ?? resolveComparisonCollation(expr.expr, expr.upper, ctx) ?? void 0;
3118
- const lower = compareResult(">=", value, evalExpr(expr.lower, ctx), collation);
3119
- const result = sqlAnd(lower, () => compareResult("<=", value, evalExpr(expr.upper, ctx), collation));
3165
+ const affinity = resolveComparisonAffinity(expr.expr, ctx);
3166
+ const lower = compareResult(">=", value, evalExpr(expr.lower, ctx), collation, affinity);
3167
+ const result = sqlAnd(lower, () => compareResult("<=", value, evalExpr(expr.upper, ctx), collation, affinity));
3120
3168
  if (result === null) return null;
3121
3169
  return expr.not ? booleanValue(result === 0) : result;
3122
3170
  }
@@ -3143,14 +3191,19 @@ function evalExpr(expr, ctx) {
3143
3191
  }
3144
3192
  const left = evalExpr(expr.expr, ctx);
3145
3193
  const values = Array.isArray(expr.values) ? expr.values.map((value) => evalExpr(value, ctx)) : executeSelect(ctx, expr.values).rows.map((row) => row[0] ?? null);
3146
- return evalIn(left, values, expr.not);
3194
+ return evalIn(left, values, expr.not, resolveComparisonAffinity(expr.expr, ctx));
3147
3195
  }
3148
3196
  case "like": {
3149
3197
  const value = evalExpr(expr.expr, ctx);
3150
3198
  const pattern = evalExpr(expr.pattern, ctx);
3151
3199
  const escape = expr.escape === null ? null : evalExpr(expr.escape, ctx);
3152
3200
  if (value === null || pattern === null || escape === null && expr.escape !== null) return null;
3153
- const match = expr.op === "LIKE" ? likeMatch(textValue(value), textValue(pattern), escape === null ? null : textValue(escape)) : globMatch(textValue(value), textValue(pattern));
3201
+ const match = expr.op === "LIKE" ? likeMatch(
3202
+ textValue(value),
3203
+ textValue(pattern),
3204
+ escape === null ? null : textValue(escape),
3205
+ ctx.functionContext?.caseSensitiveLike === true
3206
+ ) : globMatch(textValue(value), textValue(pattern));
3154
3207
  return booleanValue(expr.not ? !match : match);
3155
3208
  }
3156
3209
  case "case": {
@@ -3942,13 +3995,20 @@ var Parser = class {
3942
3995
  const stmt = this.parseStatement();
3943
3996
  return { type: "explain", queryPlan, statement: stmt };
3944
3997
  }
3945
- if (this.check("WITH", "SELECT")) return this.parseSelectStmt();
3998
+ if (this.at("WITH")) {
3999
+ const withClause = this.parseWithClause();
4000
+ if (this.at("SELECT")) return this.parseSelectStmt(withClause);
4001
+ if (this.at("INSERT") || this.at("REPLACE")) return this.parseInsertStmt(withClause);
4002
+ if (this.at("UPDATE")) return this.parseUpdateStmt(withClause);
4003
+ if (this.at("DELETE")) return this.parseDeleteStmt(withClause);
4004
+ this.syntaxError("expected SELECT, INSERT, UPDATE, or DELETE after WITH clause");
4005
+ }
3946
4006
  if (this.at("SELECT")) return this.parseSelectStmt();
3947
- if (this.check("WITH", "INSERT") || this.at("INSERT") || this.at("REPLACE")) {
4007
+ if (this.at("INSERT") || this.at("REPLACE")) {
3948
4008
  return this.parseInsertStmt();
3949
4009
  }
3950
- if (this.check("WITH", "UPDATE") || this.at("UPDATE")) return this.parseUpdateStmt();
3951
- if (this.check("WITH", "DELETE") || this.at("DELETE")) return this.parseDeleteStmt();
4010
+ if (this.at("UPDATE")) return this.parseUpdateStmt();
4011
+ if (this.at("DELETE")) return this.parseDeleteStmt();
3952
4012
  if (this.at("CREATE")) return this.parseCreateStmt();
3953
4013
  if (this.at("DROP")) return this.parseDropStmt();
3954
4014
  if (this.at("ALTER")) return this.parseAlterTableStmt();
@@ -4010,12 +4070,15 @@ var Parser = class {
4010
4070
  this.expect("RPAREN");
4011
4071
  }
4012
4072
  this.expect("AS");
4013
- if (this.match("NOT")) this.expect("MATERIALIZED", "expected MATERIALIZED after NOT");
4014
- else this.match("MATERIALIZED");
4073
+ let materialized = null;
4074
+ if (this.match("NOT")) {
4075
+ this.expect("MATERIALIZED", "expected MATERIALIZED after NOT");
4076
+ materialized = "not_materialized";
4077
+ } else if (this.match("MATERIALIZED")) materialized = "materialized";
4015
4078
  this.expect("LPAREN");
4016
- const select = this.at("VALUES") ? this.parseValuesAsSelect() : this.parseSelectCore();
4079
+ const select = this.at("VALUES") ? this.parseValuesAsSelect() : this.at("WITH") ? this.parseSelectStmt() : this.parseSelectCore();
4017
4080
  this.expect("RPAREN");
4018
- ctes.push({ name, columns, select });
4081
+ ctes.push({ name, columns, materialized, select });
4019
4082
  } while (this.match("COMMA"));
4020
4083
  return { recursive, ctes };
4021
4084
  }
@@ -4023,8 +4086,7 @@ var Parser = class {
4023
4086
  return this.at("WITH") ? this.parseWithClause() : null;
4024
4087
  }
4025
4088
  // ── SELECT ──────────────────────────────────────────────────────────────
4026
- parseSelectStmt() {
4027
- const withClause = this.parseOptionalWith();
4089
+ parseSelectStmt(withClause = this.parseOptionalWith()) {
4028
4090
  const select = this.parseSelectCore();
4029
4091
  select.with = withClause;
4030
4092
  return select;
@@ -4322,8 +4384,7 @@ var Parser = class {
4322
4384
  return { limit: first, offset };
4323
4385
  }
4324
4386
  // ── INSERT / REPLACE ────────────────────────────────────────────────────
4325
- parseInsertStmt() {
4326
- const withClause = this.parseOptionalWith();
4387
+ parseInsertStmt(withClause = this.parseOptionalWith()) {
4327
4388
  let mode = "insert";
4328
4389
  if (this.match("REPLACE")) {
4329
4390
  mode = "replace";
@@ -4426,8 +4487,7 @@ var Parser = class {
4426
4487
  return this.parseResultColumns();
4427
4488
  }
4428
4489
  // ── UPDATE ──────────────────────────────────────────────────────────────
4429
- parseUpdateStmt() {
4430
- const withClause = this.parseOptionalWith();
4490
+ parseUpdateStmt(withClause = this.parseOptionalWith()) {
4431
4491
  this.expect("UPDATE");
4432
4492
  const or = this.mapUpdateOr(this.parseOrConflict());
4433
4493
  const table = this.parseTableName();
@@ -4442,8 +4502,7 @@ var Parser = class {
4442
4502
  return { type: "update", with: withClause, or, table, alias, set, from, where, returning };
4443
4503
  }
4444
4504
  // ── DELETE ──────────────────────────────────────────────────────────────
4445
- parseDeleteStmt() {
4446
- const withClause = this.parseOptionalWith();
4505
+ parseDeleteStmt(withClause = this.parseOptionalWith()) {
4447
4506
  this.expect("DELETE");
4448
4507
  this.expect("FROM");
4449
4508
  const table = this.parseTableName();
@@ -5112,6 +5171,24 @@ var Parser = class {
5112
5171
  left = this.parseLikeRhs(left, true, "GLOB");
5113
5172
  continue;
5114
5173
  }
5174
+ if (n.kind === "REGEXP") {
5175
+ this.advance();
5176
+ this.advance();
5177
+ const pattern = this.parseExprPrec(PREC.IS_IN_LIKE + 1);
5178
+ left = {
5179
+ type: "unary",
5180
+ op: "NOT",
5181
+ expr: {
5182
+ type: "function",
5183
+ name: "REGEXP",
5184
+ distinct: false,
5185
+ args: [pattern, left],
5186
+ orderBy: [],
5187
+ filter: null
5188
+ }
5189
+ };
5190
+ continue;
5191
+ }
5115
5192
  if (n.kind === "BETWEEN") {
5116
5193
  this.advance();
5117
5194
  this.advance();
@@ -5167,6 +5244,12 @@ var Parser = class {
5167
5244
  left = this.parseLikeRhs(left, false, "GLOB");
5168
5245
  continue;
5169
5246
  }
5247
+ if (this.at("REGEXP") && PREC.IS_IN_LIKE >= minPrec) {
5248
+ this.advance();
5249
+ const pattern = this.parseExprPrec(PREC.IS_IN_LIKE + 1);
5250
+ left = { type: "function", name: "REGEXP", distinct: false, args: [pattern, left], orderBy: [], filter: null };
5251
+ continue;
5252
+ }
5170
5253
  if (this.at("MATCH") && PREC.IS_IN_LIKE >= minPrec) {
5171
5254
  this.advance();
5172
5255
  const right2 = this.parseExprPrec(PREC.IS_IN_LIKE + 1);
@@ -5325,7 +5408,7 @@ var Parser = class {
5325
5408
  }
5326
5409
  if (this.at("CURRENT_DATE") || this.at("CURRENT_TIME") || this.at("CURRENT_TIMESTAMP")) {
5327
5410
  const tok = this.advance();
5328
- return { type: "function", name: tok.value, distinct: false, args: [], filter: null };
5411
+ return { type: "function", name: tok.value, distinct: false, args: [], orderBy: [], filter: null };
5329
5412
  }
5330
5413
  if (this.at("NUMBER")) {
5331
5414
  const tok = this.advance();
@@ -5408,6 +5491,7 @@ var Parser = class {
5408
5491
  } while (this.match("COMMA"));
5409
5492
  }
5410
5493
  }
5494
+ const orderBy = this.parseOrderBy();
5411
5495
  this.expect("RPAREN");
5412
5496
  if (this.match("FILTER")) {
5413
5497
  this.expect("LPAREN");
@@ -5428,13 +5512,13 @@ var Parser = class {
5428
5512
  window = this.parseWindowSpec();
5429
5513
  this.expect("RPAREN");
5430
5514
  }
5431
- const func = isAgg ? { type: "aggregate", name: upper, distinct, args, filter } : { type: "function", name, distinct, args, filter };
5515
+ const func = isAgg ? { type: "aggregate", name: upper, distinct, args, orderBy, filter } : { type: "function", name, distinct, args, orderBy, filter };
5432
5516
  return { type: "window", func, window };
5433
5517
  }
5434
5518
  if (isAgg) {
5435
- return { type: "aggregate", name: upper, distinct, args, filter };
5519
+ return { type: "aggregate", name: upper, distinct, args, orderBy, filter };
5436
5520
  }
5437
- return { type: "function", name, distinct, args, filter };
5521
+ return { type: "function", name, distinct, args, orderBy, filter };
5438
5522
  }
5439
5523
  parseCaseExpr(base) {
5440
5524
  const whens = [];
@@ -5542,8 +5626,12 @@ function fixedClock(instant = DEFAULT_NOW) {
5542
5626
  if (Number.isNaN(ms)) throw new RangeError("invalid clock instant");
5543
5627
  return () => new Date(ms);
5544
5628
  }
5629
+ function systemClock() {
5630
+ return () => /* @__PURE__ */ new Date();
5631
+ }
5545
5632
  function resolveClock(now) {
5546
5633
  if (now === void 0) return fixedClock(DEFAULT_NOW);
5634
+ if (now === "system") return systemClock();
5547
5635
  if (typeof now === "function") return () => new Date(now().getTime());
5548
5636
  return fixedClock(now);
5549
5637
  }
@@ -5608,6 +5696,28 @@ var Prng = class _Prng {
5608
5696
  return copy;
5609
5697
  }
5610
5698
  };
5699
+ var OsEntropy = class _OsEntropy extends Prng {
5700
+ constructor() {
5701
+ super(1);
5702
+ }
5703
+ nextU64() {
5704
+ const bytes = new Uint8Array(8);
5705
+ crypto.getRandomValues(bytes);
5706
+ let value = 0n;
5707
+ for (let i = 0; i < 8; i++) {
5708
+ value |= BigInt(bytes[i]) << BigInt(i * 8);
5709
+ }
5710
+ return BigInt.asUintN(64, value);
5711
+ }
5712
+ getState() {
5713
+ return 0n;
5714
+ }
5715
+ setState(_state) {
5716
+ }
5717
+ clone() {
5718
+ return new _OsEntropy();
5719
+ }
5720
+ };
5611
5721
  function deriveSeed(...parts) {
5612
5722
  let hash = 2166136261;
5613
5723
  for (const part of parts) {
@@ -6683,7 +6793,7 @@ var Fts5VirtualTable = class _Fts5VirtualTable {
6683
6793
  insert(values, rowid) {
6684
6794
  const command = this.detectCommand(values);
6685
6795
  if (command !== null) {
6686
- this.runCommand(command, values);
6796
+ this.runCommand(command, values, rowid);
6687
6797
  return 0;
6688
6798
  }
6689
6799
  const assigned = rowid ?? this.nextRowid++;
@@ -6832,18 +6942,63 @@ var Fts5VirtualTable = class _Fts5VirtualTable {
6832
6942
  }
6833
6943
  return parts.join(" ");
6834
6944
  }
6835
- /** FTS3 matchinfo default format 'pcx' simplified blob of 32-bit LE ints. */
6836
- matchinfo(cursor, _format = "pcx") {
6945
+ /** FTS3 matchinfo format encoded as native-style 32-bit little-endian integers. */
6946
+ matchinfo(cursor, format = "pcx") {
6837
6947
  const row = this.rows.get(cursor.rowid);
6838
6948
  const nPhrase = Math.max(1, cursor.phraseTerms.length);
6839
6949
  const nCol = this.columns.length;
6840
- const values = [nPhrase, nCol];
6841
- for (let p = 0; p < nPhrase; p++) {
6842
- for (let c = 0; c < nCol; c++) {
6843
- const col = this.columns[c];
6844
- const term = cursor.phraseTerms[p]?.[0] ?? "";
6845
- const tf = row ? this.termFreq(row, col, term) : 0;
6846
- values.push(tf);
6950
+ const values = [];
6951
+ for (const request of format) {
6952
+ switch (request) {
6953
+ case "p":
6954
+ values.push(nPhrase);
6955
+ break;
6956
+ case "c":
6957
+ values.push(nCol);
6958
+ break;
6959
+ case "s":
6960
+ for (let c = 0; c < nCol; c++) {
6961
+ let longest = 0;
6962
+ let run = 0;
6963
+ for (let p = 0; p < nPhrase; p++) {
6964
+ const phrase = cursor.phraseTerms[p] ?? [];
6965
+ if (row && this.phraseFreq(row, this.columns[c], phrase) > 0) {
6966
+ run++;
6967
+ longest = Math.max(longest, run);
6968
+ } else {
6969
+ run = 0;
6970
+ }
6971
+ }
6972
+ values.push(longest);
6973
+ }
6974
+ break;
6975
+ case "x":
6976
+ for (let p = 0; p < nPhrase; p++) {
6977
+ const phrase = cursor.phraseTerms[p] ?? [];
6978
+ for (let c = 0; c < nCol; c++) {
6979
+ const column = this.columns[c];
6980
+ const localHits = row ? this.phraseFreq(row, column, phrase) : 0;
6981
+ let globalHits = 0;
6982
+ let matchingRows = 0;
6983
+ for (const candidate of this.rows.values()) {
6984
+ const hits = this.phraseFreq(candidate, column, phrase);
6985
+ globalHits += hits;
6986
+ if (hits > 0) matchingRows++;
6987
+ }
6988
+ values.push(localHits, globalHits, matchingRows);
6989
+ }
6990
+ }
6991
+ break;
6992
+ case "y":
6993
+ for (let p = 0; p < nPhrase; p++) {
6994
+ const phrase = cursor.phraseTerms[p] ?? [];
6995
+ for (let c = 0; c < nCol; c++) {
6996
+ values.push(row ? this.phraseFreq(row, this.columns[c], phrase) : 0);
6997
+ }
6998
+ }
6999
+ break;
7000
+ default:
7001
+ throw new SqliteError(`unrecognized matchinfo request: ${request}`, "other");
6847
7002
  }
6848
7003
  }
6849
7004
  const buf = new Uint8Array(values.length * 4);
@@ -6891,13 +7046,9 @@ var Fts5VirtualTable = class _Fts5VirtualTable {
6891
7046
  if (!values.has(key)) return null;
6892
7047
  const v = values.get(key);
6893
7048
  if (typeof v !== "string") return null;
6894
- const otherContent = [...values.entries()].some(
6895
- ([k, val]) => k !== key && val !== null && this.columns.some((c) => c.toLowerCase() === k)
6896
- );
6897
- if (otherContent) return null;
6898
7049
  return v;
6899
7050
  }
6900
- runCommand(command, _values) {
7051
+ runCommand(command, _values, rowid) {
6901
7052
  const cmd = command.toLowerCase();
6902
7053
  if (cmd === "optimize") return;
6903
7054
  if (cmd === "rebuild") {
@@ -6912,13 +7063,15 @@ var Fts5VirtualTable = class _Fts5VirtualTable {
6912
7063
  "other"
6913
7064
  );
6914
7065
  }
6915
- for (const rowid of [...this.rows.keys()]) this.delete(rowid);
7066
+ for (const rowid2 of [...this.rows.keys()]) this.delete(rowid2);
6916
7067
  return;
6917
7068
  }
6918
7069
  if (cmd.startsWith("merge=") || cmd.startsWith("automerge=")) {
6919
7070
  throw new SqliteError("SQL logic error", "other");
6920
7071
  }
6921
7072
  if (cmd === "delete") {
7073
+ if (rowid === void 0) throw new SqliteError("SQL logic error", "other");
7074
+ this.delete(rowid);
6922
7075
  return;
6923
7076
  }
6924
7077
  throw new SqliteError("SQL logic error", "other");
@@ -7151,11 +7304,6 @@ var Fts5VirtualTable = class _Fts5VirtualTable {
7151
7304
  }
7152
7305
  return n;
7153
7306
  }
7154
- termFreq(row, column, term) {
7155
- const needle = this.normalizeQueryTerm(term);
7156
- const tokens = row.tokensByColumn.get(column.toLowerCase()) ?? [];
7157
- return tokens.filter((t) => t.term === needle || t.term.startsWith(needle)).length;
7158
- }
7159
7307
  docLength(row) {
7160
7308
  let n = 0;
7161
7309
  for (const col of this.indexedColumns()) n += (row.tokensByColumn.get(col.toLowerCase()) ?? []).length;
@@ -7419,6 +7567,8 @@ var Table = class _Table {
7419
7567
  scanCache = null;
7420
7568
  /** Lazy covering hashes: column nameLower → serializeIndexKey → rowids. */
7421
7569
  equalityHashes = null;
7570
+ /** Cached maximum rowid. `undefined` means recompute after deleting the maximum. */
7571
+ maximumRowid = null;
7422
7572
  frozen = false;
7423
7573
  constructor(name, columns, options = {}) {
7424
7574
  this.name = name;
@@ -7621,7 +7771,12 @@ var Table = class _Table {
7621
7771
  if (alias) values.set(normalizeColumnName(alias.name), targetKey);
7622
7772
  const candidate = { rowid: targetKey, values };
7623
7773
  this.validate(candidate, key);
7624
- if (targetKey !== key) this.rows.delete(key);
7774
+ if (targetKey !== key) {
7775
+ this.rows.delete(key);
7776
+ if (this.maximumRowid !== null && this.maximumRowid !== void 0 && sameRowid2(key, this.maximumRowid)) {
7777
+ this.maximumRowid = void 0;
7778
+ }
7779
+ }
7625
7780
  this.rows.set(targetKey, candidate);
7626
7781
  this.advanceNextRowid(targetKey);
7627
7782
  this.reindexEquality(existing, candidate);
@@ -7635,6 +7790,9 @@ var Table = class _Table {
7635
7790
  if (this.withoutRowid) this.clusteredRows.delete(this.makeClusterKey(existing.values));
7636
7791
  this.unindexEquality(existing);
7637
7792
  this.invalidateScan();
7793
+ if (this.maximumRowid !== null && this.maximumRowid !== void 0 && sameRowid2(key, this.maximumRowid)) {
7794
+ this.maximumRowid = void 0;
7795
+ }
7638
7796
  return this.rows.delete(key);
7639
7797
  }
7640
7798
  *scan() {
@@ -7656,6 +7814,7 @@ var Table = class _Table {
7656
7814
  strict: this.strict
7657
7815
  });
7658
7816
  copy.nextRowid = this.nextRowid;
7817
+ copy.maximumRowid = this.maximumRowid;
7659
7818
  for (const [rowid, row] of this.rows) copy.rows.set(rowid, cloneRow(row));
7660
7819
  for (const [clusterKey, row] of this.clusteredRows) copy.clusteredRows.set(clusterKey, cloneRow(row));
7661
7820
  return copy;
@@ -7668,6 +7827,7 @@ var Table = class _Table {
7668
7827
  }
7669
7828
  /** Rebuild clustered storage after snapshot decode or bulk load. */
7670
7829
  rebuildClusteredRows() {
7830
+ this.maximumRowid = void 0;
7671
7831
  if (!this.withoutRowid) return;
7672
7832
  this.clusteredRows.clear();
7673
7833
  for (const row of this.rows.values()) {
@@ -7776,11 +7936,23 @@ var Table = class _Table {
7776
7936
  return primary[0];
7777
7937
  }
7778
7938
  allocateRowid() {
7939
+ if (!this.columns.some((column) => column.autoincrement)) {
7940
+ if (this.maximumRowid === void 0) {
7941
+ this.maximumRowid = null;
7942
+ for (const rowid of this.rows.keys()) {
7943
+ if (this.maximumRowid === null || compareRowids(rowid, this.maximumRowid) > 0) this.maximumRowid = rowid;
7944
+ }
7945
+ }
7946
+ return this.maximumRowid === null ? 1 : incrementRowid(this.maximumRowid);
7947
+ }
7779
7948
  let candidate = canonicalRowid(this.nextRowid);
7780
7949
  while (this.rows.has(candidate)) candidate = incrementRowid(candidate);
7781
7950
  return candidate;
7782
7951
  }
7783
7952
  advanceNextRowid(rowid) {
7953
+ if (this.maximumRowid === null || this.maximumRowid !== void 0 && compareRowids(rowid, this.maximumRowid) > 0) {
7954
+ this.maximumRowid = rowid;
7955
+ }
7784
7956
  if (compareRowids(rowid, this.nextRowid) >= 0) this.nextRowid = incrementRowid(rowid);
7785
7957
  }
7786
7958
  };
@@ -7855,6 +8027,8 @@ var DatabaseState = class _DatabaseState {
7855
8027
  changes = 0;
7856
8028
  totalChanges = 0;
7857
8029
  foreignKeysEnabled = false;
8030
+ /** When true, LIKE / like() are case-sensitive (SQLite `PRAGMA case_sensitive_like`). */
8031
+ caseSensitiveLike = false;
7858
8032
  schemaVersion = 0;
7859
8033
  userVersion = 0;
7860
8034
  databaseForSchema(schema, qualifiedForError) {
@@ -8299,6 +8473,7 @@ var DatabaseState = class _DatabaseState {
8299
8473
  copy.changes = this.changes;
8300
8474
  copy.totalChanges = this.totalChanges;
8301
8475
  copy.foreignKeysEnabled = this.foreignKeysEnabled;
8476
+ copy.caseSensitiveLike = this.caseSensitiveLike;
8302
8477
  copy.schemaVersion = this.schemaVersion;
8303
8478
  copy.userVersion = this.userVersion;
8304
8479
  return copy;
@@ -8318,6 +8493,7 @@ var DatabaseState = class _DatabaseState {
8318
8493
  copy.changes = this.changes;
8319
8494
  copy.totalChanges = this.totalChanges;
8320
8495
  copy.foreignKeysEnabled = this.foreignKeysEnabled;
8496
+ copy.caseSensitiveLike = this.caseSensitiveLike;
8321
8497
  copy.schemaVersion = this.schemaVersion;
8322
8498
  copy.userVersion = this.userVersion;
8323
8499
  return copy;
@@ -8379,6 +8555,7 @@ var DatabaseState = class _DatabaseState {
8379
8555
  this.changes = copy.changes;
8380
8556
  this.totalChanges = copy.totalChanges;
8381
8557
  this.foreignKeysEnabled = copy.foreignKeysEnabled;
8558
+ this.caseSensitiveLike = copy.caseSensitiveLike;
8382
8559
  this.schemaVersion = copy.schemaVersion;
8383
8560
  this.userVersion = copy.userVersion;
8384
8561
  }
@@ -8723,6 +8900,7 @@ function jsonReviver(_key, value) {
8723
8900
  export {
8724
8901
  DEFAULT_DATABASE_SEED,
8725
8902
  DEFAULT_NOW,
8903
+ OsEntropy,
8726
8904
  Prng,
8727
8905
  SqlJsonText,
8728
8906
  SqlReal,
@@ -8748,6 +8926,7 @@ export {
8748
8926
  resolveClock,
8749
8927
  sqlValueEquals,
8750
8928
  storageClassOf,
8929
+ systemClock,
8751
8930
  toInteger,
8752
8931
  tokenize,
8753
8932
  typeofSql,