@rotorsoft/act-sqlite 1.12.3 → 1.12.5

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.
@@ -37,10 +37,22 @@ export interface SqliteConfig {
37
37
  pii_encryption?: Encryption;
38
38
  }
39
39
  /** Translate a stream filter (regex-shaped or plain substring) into a
40
- * SQL LIKE pattern. Honors `^` / `$` anchors and converts `.*` → `%`,
41
- * `.` → `_`. Unanchored input gets `%` wildcards on both sides.
42
- * Literal `%` / `_` in the pattern are escaped with `\` so they match
43
- * themselves — every consumer appends `ESCAPE '\'` to its `LIKE`.
40
+ * SQLite `GLOB` pattern.
41
+ *
42
+ * #1197: `GLOB` — not `LIKE` — because `GLOB` is **case-sensitive**,
43
+ * matching PG's `~` and InMemory's `RegExp`. SQLite's `LIKE` is ASCII
44
+ * case-insensitive, and its per-connection `PRAGMA case_sensitive_like`
45
+ * override is unreliable under libsql's pooled connections (a
46
+ * transaction and a follow-up read can land on different connections).
47
+ * `GLOB` carries its case-sensitivity in the operator itself, so it is
48
+ * correct regardless of which pooled connection runs the statement.
49
+ *
50
+ * Honors `^` / `$` anchors and converts `.*` → `*`, `.` → `?`.
51
+ * Unanchored input gets `*` wildcards on both sides. `GLOB` has no
52
+ * ESCAPE clause and `%` / `_` are ordinary literals under it — so no
53
+ * escaping is needed. The portable grammar rejects `*`, `?`, and `[`
54
+ * as literals (they are metacharacters), so a literal can never collide
55
+ * with a `GLOB` wildcard.
44
56
  *
45
57
  * Only the portable filter grammar documented on
46
58
  * {@link QueryStreams.stream} is convertible: `^` / `$` anchors, `.`,
@@ -51,16 +63,16 @@ export interface SqliteConfig {
51
63
  *
52
64
  * Examples:
53
65
  * - `^abc$` → `abc` (exact)
54
- * - `^abc.*` → `abc%` (starts-with)
55
- * - `.*abc$` → `%abc` (ends-with)
56
- * - `abc` → `%abc%` (contains)
57
- * - `a.c` → `%a_c%` (single-char wildcard, contains)
58
- * - `^a_c$` → `a\_c` (literal underscore, escaped for LIKE)
66
+ * - `^abc.*` → `abc*` (starts-with)
67
+ * - `.*abc$` → `*abc` (ends-with)
68
+ * - `abc` → `*abc*` (contains)
69
+ * - `a.c` → `*a?c*` (single-char wildcard, contains)
70
+ * - `^a_c$` → `a_c` (literal underscore — ordinary under GLOB)
59
71
  * - `(a|b)` → throws {@link ValidationError}
60
72
  *
61
73
  * @internal exported for testing
62
74
  */
63
- export declare function streamPatternToLike(input: string): string;
75
+ export declare function streamPatternToGlob(input: string): string;
64
76
  /**
65
77
  * SQLite event store adapter for [@rotorsoft/act](https://www.npmjs.com/package/@rotorsoft/act).
66
78
  *
@@ -1 +1 @@
1
- {"version":3,"file":"sqlite-store.d.ts","sourceRoot":"","sources":["../../src/sqlite-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sqlite-store.d.ts","sourceRoot":"","sources":["../../src/sqlite-store.ts"],"names":[],"mappings":"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"}
package/dist/index.cjs CHANGED
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
- var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
6
  var __export = (target, all) => {
9
7
  for (var name in all)
@@ -17,21 +15,13 @@ var __copyProps = (to, from, except, desc) => {
17
15
  }
18
16
  return to;
19
17
  };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
19
 
30
20
  // src/index.ts
31
21
  var index_exports = {};
32
22
  __export(index_exports, {
33
23
  SqliteStore: () => SqliteStore,
34
- streamPatternToLike: () => streamPatternToLike
24
+ streamPatternToGlob: () => streamPatternToGlob
35
25
  });
36
26
  module.exports = __toCommonJS(index_exports);
37
27
 
@@ -42,8 +32,16 @@ var import_act_crypto = require("@rotorsoft/act-crypto");
42
32
  var DEFAULT_CONFIG = {
43
33
  url: "file::memory:"
44
34
  };
35
+ var ISO_8601 = /^(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])T([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])(\.\d+)?(Z|[+-][0-2][0-9]:[0-5][0-9])?$/;
36
+ var date_reviver = (_key, value) => typeof value === "string" && ISO_8601.test(value) ? new Date(value) : value;
37
+ var parse_json = (raw) => JSON.parse(raw, date_reviver);
38
+ var SQLITE_CONSTRAINT_UNIQUE = 2067;
39
+ var is_unique_violation = (e) => {
40
+ const err = e;
41
+ return err?.rawCode === SQLITE_CONSTRAINT_UNIQUE || typeof err?.message === "string" && err.message.includes("UNIQUE constraint failed");
42
+ };
45
43
  var PORTABLE_BODY = /^(?:\.\*|\.|[^\\^$.()[\]{}|+?*])*$/;
46
- function streamPatternToLike(input) {
44
+ function streamPatternToGlob(input) {
47
45
  let s = input;
48
46
  const start = s.startsWith("^");
49
47
  const end = s.endsWith("$");
@@ -51,27 +49,26 @@ function streamPatternToLike(input) {
51
49
  if (end) s = s.slice(0, -1);
52
50
  if (!PORTABLE_BODY.test(s))
53
51
  throw new import_act.ValidationError(
54
- `stream filter pattern "${input}" \u2014 the SQLite adapter supports only the portable subset: "^" and "$" anchors, "." (any single character), ".*" (any run), and literal characters. Escapes, character classes, grouping, alternation, and quantifiers cannot be converted to LIKE; use stream_exact/source_exact for literal names`,
52
+ `stream filter pattern "${input}" \u2014 the SQLite adapter supports only the portable subset: "^" and "$" anchors, "." (any single character), ".*" (any run), and literal characters. Escapes, character classes, grouping, alternation, and quantifiers cannot be converted to GLOB; use stream_exact/source_exact for literal names`,
55
53
  input,
56
54
  "non-portable stream filter pattern"
57
55
  );
58
56
  const tokens = [];
59
- if (!start) tokens.push("%");
57
+ if (!start) tokens.push("*");
60
58
  for (let i = 0; i < s.length; i++) {
61
59
  const c = s[i];
62
60
  if (c === ".") {
63
61
  if (s[i + 1] === "*") {
64
- tokens.push("%");
62
+ tokens.push("*");
65
63
  i++;
66
- } else tokens.push("_");
67
- } else if (c === "%" || c === "_") tokens.push(`\\${c}`);
68
- else tokens.push(c);
64
+ } else tokens.push("?");
65
+ } else tokens.push(c);
69
66
  }
70
- if (!end) tokens.push("%");
67
+ if (!end) tokens.push("*");
71
68
  let out = "";
72
69
  let prev = "";
73
70
  for (const t of tokens) {
74
- if (t === "%" && prev === "%") continue;
71
+ if (t === "*" && prev === "*") continue;
75
72
  out += t;
76
73
  prev = t;
77
74
  }
@@ -206,15 +203,15 @@ var SqliteStore = class {
206
203
  // --- commit: transaction + optimistic concurrency ---
207
204
  async commit(stream, msgs, meta, expectedVersion) {
208
205
  const tx = await this.client.transaction("write");
206
+ let current_version = -1;
209
207
  try {
210
208
  const version_row = await tx.execute({
211
209
  sql: "SELECT COALESCE(MAX(version), -1) as v FROM events WHERE stream = ?",
212
210
  args: [stream]
213
211
  });
214
- const current_version = Number(version_row.rows[0].v);
212
+ current_version = Number(version_row.rows[0].v);
215
213
  if (typeof expectedVersion === "number" && current_version !== expectedVersion) {
216
- const { ConcurrencyError } = await import("@rotorsoft/act");
217
- throw new ConcurrencyError(
214
+ throw new import_act.ConcurrencyError(
218
215
  stream,
219
216
  current_version,
220
217
  msgs,
@@ -254,7 +251,15 @@ var SqliteStore = class {
254
251
  return committed;
255
252
  } catch (e) {
256
253
  await tx.rollback();
257
- throw e;
254
+ if (e instanceof import_act.ConcurrencyError) throw e;
255
+ if (is_unique_violation(e))
256
+ throw new import_act.ConcurrencyError(
257
+ stream,
258
+ current_version,
259
+ msgs,
260
+ expectedVersion ?? -1
261
+ );
262
+ throw new import_act.StoreError("commit", { cause: e });
258
263
  }
259
264
  }
260
265
  // --- query: read-only, no transaction needed ---
@@ -266,11 +271,11 @@ var SqliteStore = class {
266
271
  sql += " AND stream = ?";
267
272
  args.push(query.stream);
268
273
  } else {
269
- sql += " AND stream LIKE ? ESCAPE '\\'";
270
- args.push(streamPatternToLike(query.stream));
274
+ sql += " AND stream GLOB ?";
275
+ args.push(streamPatternToGlob(query.stream));
271
276
  }
272
277
  }
273
- if (query?.names) {
278
+ if (query?.names !== void 0) {
274
279
  sql += ` AND name IN (${query.names.map(() => "?").join(",")})`;
275
280
  args.push(...query.names);
276
281
  }
@@ -281,7 +286,7 @@ var SqliteStore = class {
281
286
  if (query?.after !== void 0) {
282
287
  sql += " AND id > ?";
283
288
  args.push(query.after);
284
- } else if (query?.with_snaps && query.stream_exact && query.stream) {
289
+ } else if (query?.with_snaps && query.stream_exact && query.stream && query.created_before === void 0 && query.created_after === void 0) {
285
290
  sql += " AND id >= (SELECT COALESCE(MAX(id), -1) FROM events WHERE stream = ? AND name = '__snapshot__')";
286
291
  args.push(query.stream);
287
292
  }
@@ -316,8 +321,8 @@ var SqliteStore = class {
316
321
  version: Number(row.version),
317
322
  created: new Date(row.created),
318
323
  name: row.name,
319
- data: JSON.parse(row.data),
320
- meta: JSON.parse(row.meta),
324
+ data: parse_json(row.data),
325
+ meta: parse_json(row.meta),
321
326
  pii: pii_value
322
327
  })
323
328
  );
@@ -332,7 +337,7 @@ var SqliteStore = class {
332
337
  async subscribe(streams) {
333
338
  for (const { source } of streams) {
334
339
  if (source !== void 0 && !(0, import_act.is_literal_source)(source))
335
- streamPatternToLike(source);
340
+ streamPatternToGlob(source);
336
341
  }
337
342
  const tx = await this.client.transaction("write");
338
343
  try {
@@ -398,8 +403,8 @@ var SqliteStore = class {
398
403
  sql: `SELECT 1 FROM events WHERE id > ? AND name != '__snapshot__' AND stream = ? LIMIT 1`,
399
404
  args: [at, source]
400
405
  }) : await tx.execute({
401
- sql: `SELECT 1 FROM events WHERE id > ? AND name != '__snapshot__' AND stream LIKE ? ESCAPE '\\' LIMIT 1`,
402
- args: [at, streamPatternToLike(source)]
406
+ sql: `SELECT 1 FROM events WHERE id > ? AND name != '__snapshot__' AND stream GLOB ? LIMIT 1`,
407
+ args: [at, streamPatternToGlob(source)]
403
408
  });
404
409
  has_events = check.rows.length > 0;
405
410
  } else {
@@ -419,7 +424,14 @@ var SqliteStore = class {
419
424
  });
420
425
  }
421
426
  }
422
- const lag = candidates.slice(0, lagging).map((c) => ({ ...c, lagging: true }));
427
+ const fair = lagging >= 2 ? Math.max(1, Math.floor(lagging / 4)) : 0;
428
+ const priority_slice = candidates.slice(0, lagging - fair);
429
+ const picked = new Set(priority_slice.map((c) => c.stream));
430
+ const fair_slice = [...candidates].sort((a, b) => a.at - b.at).filter((c) => !picked.has(c.stream)).slice(0, fair);
431
+ const lag = [...priority_slice, ...fair_slice].map((c) => ({
432
+ ...c,
433
+ lagging: true
434
+ }));
423
435
  const lead = [...candidates].sort((a, b) => b.at - a.at).slice(0, leading).map((c) => ({ ...c, lagging: false }));
424
436
  const seen = /* @__PURE__ */ new Set();
425
437
  const combined = [...lag, ...lead].filter((p) => {
@@ -540,8 +552,8 @@ var SqliteStore = class {
540
552
  conditions.push("stream = ?");
541
553
  args.push(filter.stream);
542
554
  } else {
543
- conditions.push("stream LIKE ? ESCAPE '\\'");
544
- args.push(streamPatternToLike(filter.stream));
555
+ conditions.push("stream GLOB ?");
556
+ args.push(streamPatternToGlob(filter.stream));
545
557
  }
546
558
  }
547
559
  if (filter.source !== void 0) {
@@ -550,8 +562,8 @@ var SqliteStore = class {
550
562
  conditions.push("source = ?");
551
563
  args.push(filter.source);
552
564
  } else {
553
- conditions.push("source LIKE ? ESCAPE '\\'");
554
- args.push(streamPatternToLike(filter.source));
565
+ conditions.push("source GLOB ?");
566
+ args.push(streamPatternToGlob(filter.source));
555
567
  }
556
568
  }
557
569
  if (filter.blocked !== void 0) {
@@ -640,8 +652,8 @@ var SqliteStore = class {
640
652
  sql += " AND stream = ?";
641
653
  args.push(query.stream);
642
654
  } else {
643
- sql += " AND stream LIKE ? ESCAPE '\\'";
644
- args.push(streamPatternToLike(query.stream));
655
+ sql += " AND stream GLOB ?";
656
+ args.push(streamPatternToGlob(query.stream));
645
657
  }
646
658
  }
647
659
  if (query?.source !== void 0) {
@@ -650,8 +662,8 @@ var SqliteStore = class {
650
662
  sql += " AND source = ?";
651
663
  args.push(query.source);
652
664
  } else {
653
- sql += " AND source LIKE ? ESCAPE '\\'";
654
- args.push(streamPatternToLike(query.source));
665
+ sql += " AND source GLOB ?";
666
+ args.push(streamPatternToGlob(query.source));
655
667
  }
656
668
  }
657
669
  if (query?.blocked !== void 0) {
@@ -740,8 +752,8 @@ var SqliteStore = class {
740
752
  where.push(`e.stream = ?`);
741
753
  args.push(input.stream);
742
754
  } else {
743
- where.push(`e.stream LIKE ? ESCAPE '\\'`);
744
- args.push(streamPatternToLike(input.stream));
755
+ where.push(`e.stream GLOB ?`);
756
+ args.push(streamPatternToGlob(input.stream));
745
757
  }
746
758
  }
747
759
  if (exclude.length) {
@@ -810,8 +822,8 @@ var SqliteStore = class {
810
822
  stream: row.stream,
811
823
  version: Number(row.version),
812
824
  name: row.name,
813
- data: JSON.parse(row.data),
814
- meta: JSON.parse(row.meta),
825
+ data: parse_json(row.data),
826
+ meta: parse_json(row.meta),
815
827
  created: new Date(row.created),
816
828
  pii: await this._parse_pii_from_read(row.pii)
817
829
  });
@@ -883,8 +895,8 @@ var SqliteStore = class {
883
895
  stream,
884
896
  version: Number(version),
885
897
  name,
886
- data: JSON.parse(data),
887
- meta: JSON.parse(meta),
898
+ data: parse_json(data),
899
+ meta: parse_json(meta),
888
900
  created: new Date(created),
889
901
  pii: await this._parse_pii_from_read(pii)
890
902
  });
@@ -965,8 +977,8 @@ var SqliteStore = class {
965
977
  version: Number(row.version),
966
978
  created: new Date(row.created),
967
979
  name: row.name,
968
- data: JSON.parse(row.data),
969
- meta: JSON.parse(row.meta)
980
+ data: parse_json(row.data),
981
+ meta: parse_json(row.meta)
970
982
  },
971
983
  before
972
984
  });
@@ -1086,6 +1098,6 @@ var SqliteStore = class {
1086
1098
  // Annotate the CommonJS export names for ESM import in node:
1087
1099
  0 && (module.exports = {
1088
1100
  SqliteStore,
1089
- streamPatternToLike
1101
+ streamPatternToGlob
1090
1102
  });
1091
1103
  //# sourceMappingURL=index.cjs.map