@rotorsoft/act-sqlite 1.17.0 → 1.19.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.
@@ -1,4 +1,4 @@
1
- import type { BlockedLease, Committed, EventMeta, Lease, Message, Query, QueryStatsOptions, QueryStreams, QueryStreamsResult, Schemas, Store, StreamFilter, StreamPosition, StreamStats, SubscribeInput } from "@rotorsoft/act";
1
+ import type { BlockedLease, Committed, EventMeta, Lease, Message, Query, QueryStatsOptions, QueryStreams, QueryStreamsResult, Schemas, Store, StreamFilter, StreamPosition, StreamStats, SubscribeInput, SubscribeResult } from "@rotorsoft/act";
2
2
  import { type Encryption } from "@rotorsoft/act-crypto";
3
3
  /**
4
4
  * SQLite store configuration
@@ -159,11 +159,11 @@ export declare class SqliteStore implements Store {
159
159
  dispose(): Promise<void>;
160
160
  commit<E extends Schemas>(stream: string, msgs: Message<E, keyof E>[], meta: EventMeta, expectedVersion?: number): Promise<Committed<E, keyof E>[]>;
161
161
  query<E extends Schemas>(callback: (event: Committed<E, keyof E>) => void, query?: Query): Promise<number>;
162
- subscribe(streams: SubscribeInput[], correlated_at?: number): Promise<{
163
- subscribed: number;
164
- watermark: number;
165
- correlated_at: number;
166
- }>;
162
+ subscribe(streams: SubscribeInput[], correlated_at?: number, correlator?: {
163
+ key: string;
164
+ by: string;
165
+ millis: number;
166
+ }): Promise<SubscribeResult>;
167
167
  claim(lagging: number, leading: number, by: string, millis: number, lane?: string): Promise<Lease[]>;
168
168
  ack(leases: Lease[]): Promise<Lease[]>;
169
169
  block(leases: BlockedLease[]): Promise<BlockedLease[]>;
@@ -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
@@ -215,14 +215,38 @@ var SqliteStore = class {
215
215
  SET correlated_at = (SELECT COALESCE(MAX(id), -1) FROM events)
216
216
  WHERE correlated_at IS NULL`
217
217
  );
218
- await this.client.execute(`
219
- CREATE TABLE IF NOT EXISTS correlated (
220
- id INTEGER PRIMARY KEY CHECK (id = 0),
221
- at INTEGER NOT NULL DEFAULT -1
222
- )
223
- `);
218
+ const correlated_columns = await this.client.execute(
219
+ "PRAGMA table_info(correlated)"
220
+ );
221
+ const legacy = correlated_columns.rows.some((r) => r.name === "id");
222
+ if (legacy) {
223
+ await this.client.execute(`
224
+ CREATE TABLE IF NOT EXISTS correlated_keyed (
225
+ key TEXT PRIMARY KEY,
226
+ at INTEGER NOT NULL DEFAULT -1,
227
+ leased_by TEXT,
228
+ leased_until INTEGER
229
+ )
230
+ `);
231
+ await this.client.execute(
232
+ "INSERT OR IGNORE INTO correlated_keyed (key, at) SELECT '', at FROM correlated WHERE id = 0"
233
+ );
234
+ await this.client.execute("DROP TABLE correlated");
235
+ await this.client.execute(
236
+ "ALTER TABLE correlated_keyed RENAME TO correlated"
237
+ );
238
+ } else {
239
+ await this.client.execute(`
240
+ CREATE TABLE IF NOT EXISTS correlated (
241
+ key TEXT PRIMARY KEY,
242
+ at INTEGER NOT NULL DEFAULT -1,
243
+ leased_by TEXT,
244
+ leased_until INTEGER
245
+ )
246
+ `);
247
+ }
224
248
  await this.client.execute(
225
- "INSERT OR IGNORE INTO correlated (id) VALUES (0)"
249
+ "INSERT OR IGNORE INTO correlated (key) VALUES ('')"
226
250
  );
227
251
  await this.client.execute(
228
252
  "CREATE INDEX IF NOT EXISTS idx_streams_claim ON streams(blocked, priority DESC, at)"
@@ -380,7 +404,7 @@ var SqliteStore = class {
380
404
  // plus a UPDATE pass to keep the *max* priority across reactions
381
405
  // targeting the same stream (ACT-102). Operator overrides go
382
406
  // through `prioritize()` instead.
383
- async subscribe(streams, correlated_at) {
407
+ async subscribe(streams, correlated_at, correlator) {
384
408
  for (const { source } of streams) {
385
409
  if (source !== void 0 && !(0, import_act.is_literal_source)(source))
386
410
  streamPatternToGlob(source);
@@ -420,19 +444,64 @@ var SqliteStore = class {
420
444
  const wm = await tx.execute(
421
445
  "SELECT COALESCE(MAX(at), -1) as w FROM streams"
422
446
  );
423
- if (correlated_at !== void 0)
447
+ let correlating;
448
+ if (correlator) {
449
+ const now = Date.now();
450
+ const taken = await tx.execute({
451
+ sql: `INSERT INTO correlated (key, at, leased_by, leased_until)
452
+ SELECT ?,
453
+ MAX(COALESCE(?, -1),
454
+ COALESCE((SELECT at FROM correlated WHERE key = ''), -1)),
455
+ ?, ?
456
+ ON CONFLICT (key) DO UPDATE
457
+ SET at = MAX(correlated.at, COALESCE(?, -1)),
458
+ leased_by = excluded.leased_by,
459
+ leased_until = excluded.leased_until
460
+ WHERE correlated.leased_until IS NULL
461
+ OR correlated.leased_until < ?
462
+ OR correlated.leased_by = excluded.leased_by`,
463
+ args: [
464
+ correlator.key,
465
+ correlated_at ?? null,
466
+ correlator.by,
467
+ // `millis <= 0` releases outright rather than setting an expiry a
468
+ // hair in the future, which would still refuse a successor asking
469
+ // in the same instant.
470
+ correlator.millis > 0 ? now + correlator.millis : null,
471
+ correlated_at ?? null,
472
+ now
473
+ ]
474
+ });
475
+ correlating = taken.rowsAffected > 0;
476
+ if (!correlating && correlated_at !== void 0)
477
+ await tx.execute({
478
+ sql: "UPDATE correlated SET at = MAX(at, ?) WHERE key = ?",
479
+ args: [correlated_at, correlator.key]
480
+ });
481
+ if (correlated_at !== void 0)
482
+ await tx.execute({
483
+ sql: "UPDATE correlated SET at = MAX(at, ?) WHERE key = ''",
484
+ args: [correlated_at]
485
+ });
486
+ } else if (correlated_at !== void 0)
424
487
  await tx.execute({
425
- sql: "UPDATE correlated SET at = MAX(at, ?) WHERE id = 0",
488
+ sql: "UPDATE correlated SET at = MAX(at, ?) WHERE key = ''",
426
489
  args: [correlated_at]
427
490
  });
428
- const cp = await tx.execute("SELECT at FROM correlated WHERE id = 0");
491
+ const cp = await tx.execute({
492
+ sql: "SELECT at FROM correlated WHERE key = ?",
493
+ args: [correlator?.key ?? ""]
494
+ });
429
495
  await tx.commit();
430
496
  return {
431
497
  subscribed,
432
498
  watermark: Number(wm.rows[0].w),
433
- // `seed()` always inserts the singleton row, so this read cannot
434
- // come back empty — no defensive fallback to leave untested.
435
- correlated_at: Number(cp.rows[0].at)
499
+ // `seed()` always inserts the shared row, and a correlator's row is
500
+ // created by the upsert above — or already existed, which is why the
501
+ // lease was refused. Either way this read cannot come back empty, so
502
+ // there is no defensive fallback to leave untested.
503
+ correlated_at: Number(cp.rows[0].at),
504
+ ...correlating === void 0 ? {} : { correlating }
436
505
  };
437
506
  } catch (e) {
438
507
  await tx.rollback();
@@ -1086,11 +1155,6 @@ var SqliteStore = class {
1086
1155
  sql: "DELETE FROM events WHERE stream = ?",
1087
1156
  args: [stream]
1088
1157
  });
1089
- if (snapshot === void 0)
1090
- await tx.execute({
1091
- sql: "DELETE FROM streams WHERE stream = ?",
1092
- args: [stream]
1093
- });
1094
1158
  const event_name = snapshot !== void 0 ? "__snapshot__" : "__tombstone__";
1095
1159
  const event_meta = meta ?? { correlation: "", causation: {} };
1096
1160
  const now = (/* @__PURE__ */ new Date()).toISOString();