@rotorsoft/act-sqlite 1.18.0 → 1.19.1
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/.tsbuildinfo +1 -1
- package/dist/@types/sqlite-store.d.ts +6 -6
- package/dist/@types/sqlite-store.d.ts.map +1 -1
- package/dist/index.cjs +85 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +85 -21
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
|
@@ -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
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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":"AACA,OAAO,KAAK,EACV,YAAY,EACZ,SAAS,EACT,SAAS,EACT,KAAK,EACL,OAAO,EACP,KAAK,EACL,iBAAiB,EACjB,YAAY,EACZ,kBAAkB,EAClB,OAAO,EACP,KAAK,EACL,YAAY,EACZ,cAAc,EACd,WAAW,EACX,cAAc,
|
|
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
|
@@ -46,7 +46,7 @@ var resolve_url = (url) => {
|
|
|
46
46
|
);
|
|
47
47
|
return is_in_memory_url(url) ? SHARED_MEMORY_URL : url;
|
|
48
48
|
};
|
|
49
|
-
var parse_json = (raw) => JSON.parse(raw
|
|
49
|
+
var parse_json = (raw) => JSON.parse(raw);
|
|
50
50
|
var SQLITE_CONSTRAINT_UNIQUE = 2067;
|
|
51
51
|
var is_unique_violation = (e) => {
|
|
52
52
|
const err = e;
|
|
@@ -131,11 +131,7 @@ var SqliteStore = class {
|
|
|
131
131
|
if (raw == null) return null;
|
|
132
132
|
const parsed = parse_json(raw);
|
|
133
133
|
if (this._resolve_pii_key && typeof parsed === "string") {
|
|
134
|
-
return await (0, import_act_crypto.decrypt)(
|
|
135
|
-
parsed,
|
|
136
|
-
this._resolve_pii_key,
|
|
137
|
-
import_act.dateReviver
|
|
138
|
-
);
|
|
134
|
+
return await (0, import_act_crypto.decrypt)(parsed, this._resolve_pii_key);
|
|
139
135
|
}
|
|
140
136
|
return parsed;
|
|
141
137
|
}
|
|
@@ -215,14 +211,38 @@ var SqliteStore = class {
|
|
|
215
211
|
SET correlated_at = (SELECT COALESCE(MAX(id), -1) FROM events)
|
|
216
212
|
WHERE correlated_at IS NULL`
|
|
217
213
|
);
|
|
218
|
-
await this.client.execute(
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
214
|
+
const correlated_columns = await this.client.execute(
|
|
215
|
+
"PRAGMA table_info(correlated)"
|
|
216
|
+
);
|
|
217
|
+
const legacy = correlated_columns.rows.some((r) => r.name === "id");
|
|
218
|
+
if (legacy) {
|
|
219
|
+
await this.client.execute(`
|
|
220
|
+
CREATE TABLE IF NOT EXISTS correlated_keyed (
|
|
221
|
+
key TEXT PRIMARY KEY,
|
|
222
|
+
at INTEGER NOT NULL DEFAULT -1,
|
|
223
|
+
leased_by TEXT,
|
|
224
|
+
leased_until INTEGER
|
|
225
|
+
)
|
|
226
|
+
`);
|
|
227
|
+
await this.client.execute(
|
|
228
|
+
"INSERT OR IGNORE INTO correlated_keyed (key, at) SELECT '', at FROM correlated WHERE id = 0"
|
|
229
|
+
);
|
|
230
|
+
await this.client.execute("DROP TABLE correlated");
|
|
231
|
+
await this.client.execute(
|
|
232
|
+
"ALTER TABLE correlated_keyed RENAME TO correlated"
|
|
233
|
+
);
|
|
234
|
+
} else {
|
|
235
|
+
await this.client.execute(`
|
|
236
|
+
CREATE TABLE IF NOT EXISTS correlated (
|
|
237
|
+
key TEXT PRIMARY KEY,
|
|
238
|
+
at INTEGER NOT NULL DEFAULT -1,
|
|
239
|
+
leased_by TEXT,
|
|
240
|
+
leased_until INTEGER
|
|
241
|
+
)
|
|
242
|
+
`);
|
|
243
|
+
}
|
|
224
244
|
await this.client.execute(
|
|
225
|
-
"INSERT OR IGNORE INTO correlated (
|
|
245
|
+
"INSERT OR IGNORE INTO correlated (key) VALUES ('')"
|
|
226
246
|
);
|
|
227
247
|
await this.client.execute(
|
|
228
248
|
"CREATE INDEX IF NOT EXISTS idx_streams_claim ON streams(blocked, priority DESC, at)"
|
|
@@ -380,7 +400,7 @@ var SqliteStore = class {
|
|
|
380
400
|
// plus a UPDATE pass to keep the *max* priority across reactions
|
|
381
401
|
// targeting the same stream (ACT-102). Operator overrides go
|
|
382
402
|
// through `prioritize()` instead.
|
|
383
|
-
async subscribe(streams, correlated_at) {
|
|
403
|
+
async subscribe(streams, correlated_at, correlator) {
|
|
384
404
|
for (const { source } of streams) {
|
|
385
405
|
if (source !== void 0 && !(0, import_act.is_literal_source)(source))
|
|
386
406
|
streamPatternToGlob(source);
|
|
@@ -420,19 +440,64 @@ var SqliteStore = class {
|
|
|
420
440
|
const wm = await tx.execute(
|
|
421
441
|
"SELECT COALESCE(MAX(at), -1) as w FROM streams"
|
|
422
442
|
);
|
|
423
|
-
|
|
443
|
+
let correlating;
|
|
444
|
+
if (correlator) {
|
|
445
|
+
const now = Date.now();
|
|
446
|
+
const taken = await tx.execute({
|
|
447
|
+
sql: `INSERT INTO correlated (key, at, leased_by, leased_until)
|
|
448
|
+
SELECT ?,
|
|
449
|
+
MAX(COALESCE(?, -1),
|
|
450
|
+
COALESCE((SELECT at FROM correlated WHERE key = ''), -1)),
|
|
451
|
+
?, ?
|
|
452
|
+
ON CONFLICT (key) DO UPDATE
|
|
453
|
+
SET at = MAX(correlated.at, COALESCE(?, -1)),
|
|
454
|
+
leased_by = excluded.leased_by,
|
|
455
|
+
leased_until = excluded.leased_until
|
|
456
|
+
WHERE correlated.leased_until IS NULL
|
|
457
|
+
OR correlated.leased_until < ?
|
|
458
|
+
OR correlated.leased_by = excluded.leased_by`,
|
|
459
|
+
args: [
|
|
460
|
+
correlator.key,
|
|
461
|
+
correlated_at ?? null,
|
|
462
|
+
correlator.by,
|
|
463
|
+
// `millis <= 0` releases outright rather than setting an expiry a
|
|
464
|
+
// hair in the future, which would still refuse a successor asking
|
|
465
|
+
// in the same instant.
|
|
466
|
+
correlator.millis > 0 ? now + correlator.millis : null,
|
|
467
|
+
correlated_at ?? null,
|
|
468
|
+
now
|
|
469
|
+
]
|
|
470
|
+
});
|
|
471
|
+
correlating = taken.rowsAffected > 0;
|
|
472
|
+
if (!correlating && correlated_at !== void 0)
|
|
473
|
+
await tx.execute({
|
|
474
|
+
sql: "UPDATE correlated SET at = MAX(at, ?) WHERE key = ?",
|
|
475
|
+
args: [correlated_at, correlator.key]
|
|
476
|
+
});
|
|
477
|
+
if (correlated_at !== void 0)
|
|
478
|
+
await tx.execute({
|
|
479
|
+
sql: "UPDATE correlated SET at = MAX(at, ?) WHERE key = ''",
|
|
480
|
+
args: [correlated_at]
|
|
481
|
+
});
|
|
482
|
+
} else if (correlated_at !== void 0)
|
|
424
483
|
await tx.execute({
|
|
425
|
-
sql: "UPDATE correlated SET at = MAX(at, ?) WHERE
|
|
484
|
+
sql: "UPDATE correlated SET at = MAX(at, ?) WHERE key = ''",
|
|
426
485
|
args: [correlated_at]
|
|
427
486
|
});
|
|
428
|
-
const cp = await tx.execute(
|
|
487
|
+
const cp = await tx.execute({
|
|
488
|
+
sql: "SELECT at FROM correlated WHERE key = ?",
|
|
489
|
+
args: [correlator?.key ?? ""]
|
|
490
|
+
});
|
|
429
491
|
await tx.commit();
|
|
430
492
|
return {
|
|
431
493
|
subscribed,
|
|
432
494
|
watermark: Number(wm.rows[0].w),
|
|
433
|
-
// `seed()` always inserts the
|
|
434
|
-
//
|
|
435
|
-
|
|
495
|
+
// `seed()` always inserts the shared row, and a correlator's row is
|
|
496
|
+
// created by the upsert above — or already existed, which is why the
|
|
497
|
+
// lease was refused. Either way this read cannot come back empty, so
|
|
498
|
+
// there is no defensive fallback to leave untested.
|
|
499
|
+
correlated_at: Number(cp.rows[0].at),
|
|
500
|
+
...correlating === void 0 ? {} : { correlating }
|
|
436
501
|
};
|
|
437
502
|
} catch (e) {
|
|
438
503
|
await tx.rollback();
|