@rotorsoft/act-sqlite 1.22.7 → 2.0.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, SubscribeResult } from "@rotorsoft/act";
1
+ import type { Append, BlockedLease, Committed, EventMeta, Lease, 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
@@ -141,7 +141,7 @@ export declare class SqliteStore implements Store {
141
141
  private _begin;
142
142
  private _tx;
143
143
  dispose(): Promise<void>;
144
- commit<E extends Schemas>(stream: string, msgs: Message<E, keyof E>[], meta: EventMeta, expectedVersion?: number): Promise<Committed<E, keyof E>[]>;
144
+ commit<E extends Schemas>(appends: readonly Append<E>[], meta: EventMeta): Promise<Committed<E, keyof E>[]>;
145
145
  query<E extends Schemas>(callback: (event: Committed<E, keyof E>) => void, query?: Query): Promise<number>;
146
146
  subscribe(streams: SubscribeInput[], correlated_at?: number, correlator?: {
147
147
  key: string;
@@ -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
@@ -257,8 +257,9 @@ var SqliteStore = class {
257
257
  // while a write transaction is open on it: a second one fails at once
258
258
  // (`TRANSACTION_ACTIVE` in memory, `SQLITE_BUSY` on a file) instead of
259
259
  // waiting. So every statement and every transaction takes its turn here.
260
- // A turn covers only the database work, never a caller's callback, so a
261
- // callback that writes to the store can't wait on itself.
260
+ // A turn covers only the database work, so a `query` callback that writes to
261
+ // the store can't wait on itself. `restore` is the exception: its driver runs
262
+ // inside the turn, because the whole restore is one transaction.
262
263
  _turn = Promise.resolve();
263
264
  _serial(work) {
264
265
  const run = this._turn.then(work);
@@ -292,53 +293,63 @@ var SqliteStore = class {
292
293
  async dispose() {
293
294
  await this._serial(async () => this.client.close());
294
295
  }
295
- // --- commit: transaction + optimistic concurrency ---
296
- async commit(stream, msgs, meta, expectedVersion) {
296
+ // --- commit: one transaction across every append ---
297
+ async commit(appends, meta) {
298
+ (0, import_act.check_appends)(appends);
299
+ if (!appends.length) return [];
297
300
  return this._serial(async () => {
298
301
  const tx = await this._begin("commit");
299
- let current_version = -1;
302
+ let appending = appends[0];
303
+ let head = -1;
300
304
  try {
301
- const version_row = await tx.execute({
302
- sql: "SELECT COALESCE(MAX(version), -1) as v FROM events WHERE stream = ?",
303
- args: [stream]
304
- });
305
- current_version = Number(version_row.rows[0].v);
306
- if (typeof expectedVersion === "number" && current_version !== expectedVersion) {
307
- throw new import_act.ConcurrencyError(
308
- stream,
309
- current_version,
310
- msgs,
311
- expectedVersion
312
- );
305
+ const heads = /* @__PURE__ */ new Map();
306
+ for (const { stream, msgs, expectedVersion } of appends) {
307
+ const row = await tx.execute({
308
+ sql: "SELECT COALESCE(MAX(version), -1) as v FROM events WHERE stream = ?",
309
+ args: [stream]
310
+ });
311
+ const current = Number(row.rows[0].v);
312
+ if (typeof expectedVersion === "number" && current !== expectedVersion)
313
+ throw new import_act.ConcurrencyError(
314
+ stream,
315
+ current,
316
+ msgs,
317
+ expectedVersion
318
+ );
319
+ heads.set(stream, current);
313
320
  }
314
321
  const now = (/* @__PURE__ */ new Date()).toISOString();
315
322
  const committed = [];
316
- let version = current_version + 1;
317
- for (const { name, data, pii } of msgs) {
318
- const pii_for_write = await this._stringify_pii_for_write(pii);
319
- const result = await tx.execute({
320
- sql: "INSERT INTO events (stream, version, name, data, meta, created, pii) VALUES (?, ?, ?, ?, ?, ?, ?)",
321
- args: [
322
- stream,
323
+ for (const append of appends) {
324
+ appending = append;
325
+ head = heads.get(append.stream);
326
+ let version = head + 1;
327
+ for (const { name, data, pii } of append.msgs) {
328
+ const pii_for_write = await this._stringify_pii_for_write(pii);
329
+ const result = await tx.execute({
330
+ sql: "INSERT INTO events (stream, version, name, data, meta, created, pii) VALUES (?, ?, ?, ?, ?, ?, ?)",
331
+ args: [
332
+ append.stream,
333
+ version,
334
+ name,
335
+ JSON.stringify(data),
336
+ JSON.stringify(meta),
337
+ now,
338
+ pii_for_write
339
+ ]
340
+ });
341
+ committed.push({
342
+ id: Number(result.lastInsertRowid),
343
+ stream: append.stream,
323
344
  version,
345
+ created: new Date(now),
324
346
  name,
325
- JSON.stringify(data),
326
- JSON.stringify(meta),
327
- now,
328
- pii_for_write
329
- ]
330
- });
331
- committed.push({
332
- id: Number(result.lastInsertRowid),
333
- stream,
334
- version,
335
- created: new Date(now),
336
- name,
337
- data,
338
- meta,
339
- ...pii == null ? {} : { pii }
340
- });
341
- version++;
347
+ data,
348
+ meta,
349
+ ...pii == null ? {} : { pii }
350
+ });
351
+ version++;
352
+ }
342
353
  }
343
354
  await tx.commit();
344
355
  return committed;
@@ -347,10 +358,10 @@ var SqliteStore = class {
347
358
  if (e instanceof import_act.ConcurrencyError) throw e;
348
359
  if (is_unique_violation(e))
349
360
  throw new import_act.ConcurrencyError(
350
- stream,
351
- current_version,
352
- msgs,
353
- expectedVersion ?? -1
361
+ appending.stream,
362
+ head,
363
+ appending.msgs,
364
+ appending.expectedVersion ?? -1
354
365
  );
355
366
  throw new import_act.StoreError("commit", { cause: e });
356
367
  }
@@ -423,8 +434,8 @@ var SqliteStore = class {
423
434
  // targeting the same stream. Operator overrides go
424
435
  // through `prioritize()` instead.
425
436
  async subscribe(streams, correlated_at, correlator) {
426
- for (const { source } of streams) {
427
- if (source !== void 0 && !(0, import_act.is_literal_source)(source))
437
+ for (const { stream, source } of streams) {
438
+ if (source !== void 0 && !(0, import_act.is_literal_source)(source, stream))
428
439
  streamPatternToGlob(source);
429
440
  }
430
441
  return this._tx("subscribe", async (tx) => {
@@ -558,7 +569,7 @@ var SqliteStore = class {
558
569
  priority: Number(row.priority),
559
570
  lane: row.lane
560
571
  })).sort((a, b) => b.priority - a.priority || a.at - b.at);
561
- const fair = lagging >= 2 ? Math.max(1, Math.floor(lagging / 4)) : 0;
572
+ const fair = (0, import_act.fair_slots)(lagging);
562
573
  const priority_slice = candidates.slice(0, lagging - fair);
563
574
  const picked = new Set(priority_slice.map((c) => c.stream));
564
575
  const fair_slice = [...candidates].sort((a, b) => a.at - b.at).filter((c) => !picked.has(c.stream)).slice(0, fair);
@@ -765,7 +776,7 @@ var SqliteStore = class {
765
776
  }
766
777
  // --- query_streams: read-only introspection with filters ---
767
778
  async query_streams(callback, query) {
768
- const limit = query?.limit ?? 100;
779
+ const limit = query?.limit ?? import_act.DEFAULT_QUERY_STREAMS_LIMIT;
769
780
  const { clause, args } = this._filter_clause(query ?? {});
770
781
  let sql = `SELECT stream, source, at, retry, blocked, error, leased_by, leased_until, priority, lane, deferred_at, correlated_at FROM streams WHERE ${clause}`;
771
782
  if (query?.after !== void 0) {
@@ -1080,6 +1091,8 @@ var SqliteStore = class {
1080
1091
  * new sequence is dense from 1. `created` is preserved verbatim
1081
1092
  * from the source.
1082
1093
  */
1094
+ // The driver runs inside this store's turn, so it must read from another
1095
+ // store: a call on this one would wait for the restore to end, forever.
1083
1096
  async restore(driver) {
1084
1097
  return this._serial(async () => {
1085
1098
  const tx = await this._begin("restore");