@photon-grove/evt 0.1.1 → 0.1.2

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.
Files changed (65) hide show
  1. package/README.md +39 -4
  2. package/dist/aggregate.d.ts +26 -0
  3. package/dist/aggregate.d.ts.map +1 -1
  4. package/dist/aggregate.js.map +1 -1
  5. package/dist/dynamodb/index.d.ts +1 -0
  6. package/dist/dynamodb/index.d.ts.map +1 -1
  7. package/dist/dynamodb/index.js +1 -0
  8. package/dist/dynamodb/index.js.map +1 -1
  9. package/dist/dynamodb/repository.d.ts.map +1 -1
  10. package/dist/dynamodb/repository.js +24 -7
  11. package/dist/dynamodb/repository.js.map +1 -1
  12. package/dist/dynamodb/requests.d.ts +5 -2
  13. package/dist/dynamodb/requests.d.ts.map +1 -1
  14. package/dist/dynamodb/requests.js +19 -4
  15. package/dist/dynamodb/requests.js.map +1 -1
  16. package/dist/dynamodb/views.d.ts +18 -0
  17. package/dist/dynamodb/views.d.ts.map +1 -0
  18. package/dist/dynamodb/views.js +56 -0
  19. package/dist/dynamodb/views.js.map +1 -0
  20. package/dist/errors.d.ts +14 -1
  21. package/dist/errors.d.ts.map +1 -1
  22. package/dist/errors.js +15 -0
  23. package/dist/errors.js.map +1 -1
  24. package/dist/index.d.ts +3 -3
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +1 -1
  27. package/dist/index.js.map +1 -1
  28. package/dist/postgres/client.d.ts +32 -0
  29. package/dist/postgres/client.d.ts.map +1 -0
  30. package/dist/postgres/client.js +4 -0
  31. package/dist/postgres/client.js.map +1 -0
  32. package/dist/postgres/index.d.ts +4 -0
  33. package/dist/postgres/index.d.ts.map +1 -0
  34. package/dist/postgres/index.js +6 -0
  35. package/dist/postgres/index.js.map +1 -0
  36. package/dist/postgres/repository.d.ts +55 -0
  37. package/dist/postgres/repository.d.ts.map +1 -0
  38. package/dist/postgres/repository.js +527 -0
  39. package/dist/postgres/repository.js.map +1 -0
  40. package/dist/postgres/schema.d.ts +81 -0
  41. package/dist/postgres/schema.d.ts.map +1 -0
  42. package/dist/postgres/schema.js +233 -0
  43. package/dist/postgres/schema.js.map +1 -0
  44. package/dist/repository.d.ts +26 -6
  45. package/dist/repository.d.ts.map +1 -1
  46. package/dist/repository.js +21 -5
  47. package/dist/repository.js.map +1 -1
  48. package/dist/store.d.ts +4 -2
  49. package/dist/store.d.ts.map +1 -1
  50. package/dist/store.js +31 -6
  51. package/dist/store.js.map +1 -1
  52. package/package.json +5 -1
  53. package/src/aggregate.ts +28 -0
  54. package/src/dynamodb/index.ts +1 -0
  55. package/src/dynamodb/repository.ts +29 -6
  56. package/src/dynamodb/requests.ts +24 -4
  57. package/src/dynamodb/views.ts +67 -0
  58. package/src/errors.ts +23 -0
  59. package/src/index.ts +4 -0
  60. package/src/postgres/client.ts +37 -0
  61. package/src/postgres/index.ts +23 -0
  62. package/src/postgres/repository.ts +773 -0
  63. package/src/postgres/schema.ts +286 -0
  64. package/src/repository.ts +52 -7
  65. package/src/store.ts +58 -8
@@ -0,0 +1,527 @@
1
+ // The PostgreSQL repository: events in one table keyed by (entity_id, sequence), snapshots in a
2
+ // second keyed by entity_id, and the engine rows (the feature marker, the rebuild fence, the
3
+ // stream heads) in tables derived from the events table's name (storage format, "PostgreSQL").
4
+ // Every commit is one READ COMMITTED transaction that runs the statements Go and Rust run, in
5
+ // their order: the entity lock, the feature-marker check under its shared lock, the rebuild-lock
6
+ // assertion under its own, the head statement, the event inserts, then the snapshot upsert.
7
+ //
8
+ // Each statement of a transaction needs the one before it, so they await in loops on purpose.
9
+ /* oxlint-disable no-await-in-loop */
10
+ import { CompactionUncoveredError, ConflictError, EvtError, HistoryDependentProjectionError, RebuildInProgressError, SequenceGapError, StreamHeadDriftError, StreamHeadsNotMigratedError, TransientError, } from '../errors.js';
11
+ import { checkSupported, checkWritable, declaresStreamHeads, decodeManifest, encodeManifest, withStreamHeads, } from '../features.js';
12
+ import { int64Argument } from '../fields.js';
13
+ import { decodeMetadata, emptyMetadata, encodeMetadata } from '../metadata.js';
14
+ import { checkBudget, checkNotReserved, commitSizes, validateCommit, } from '../repository.js';
15
+ import { ENGINE_LOCK_EXCLUSIVE, ENGINE_LOCK_SHARED, ENTITY_LOCK, SCHEMA_LOCK, featuresLockKey, featuresTable, pgTables, rebuildGenerationTable, rebuildLockKey, rebuildLockTable, schemaDdl, streamHeadsTable, } from './schema.js';
16
+ /** The backend name a projector group for the PostgreSQL repository would carry. */
17
+ export const POSTGRES_BACKEND = 'postgres';
18
+ // The event columns every read selects, each as text, so no driver parses a stored value.
19
+ const EVENT_COLUMNS = 'event_id, sequence::text AS sequence, event_type, version::text AS version, entity_id, ' +
20
+ "entity_type, encode(payload, 'hex') AS payload, metadata::text AS metadata";
21
+ // SQLSTATEs for which PostgreSQL rolled the transaction back and a retry may not hit again: a
22
+ // serialization failure and a detected deadlock.
23
+ const TRANSIENT_STATES = new Set(['40001', '40P01']);
24
+ /**
25
+ * A {@link Repository} on PostgreSQL, through any client shaped like `pg`'s `Pool`
26
+ * ({@link PgClient}).
27
+ *
28
+ * Run {@link PgRepository.ensureSchema} once before the first write. A writer initializes a fresh
29
+ * store itself on its first write, as Go's and Rust's do: the check is two `EXISTS` probes under
30
+ * the lock it takes anyway. {@link PgRepository.initialize} is for a deploy step that treats every
31
+ * backend alike.
32
+ *
33
+ * The repository validates the store's feature manifest at its first write and caches the version
34
+ * it validated. Every commit and snapshot write reads the manifest again under a shared lock that
35
+ * no declaration can take while the write is open, and validates it again when it changed.
36
+ */
37
+ export class PgRepository {
38
+ #client;
39
+ #tables;
40
+ // The manifest version this writer validated, or null until it validates.
41
+ #validated = null;
42
+ // Whether the rebuild-lock table exists, which a commit's assertion probes for until it does.
43
+ #rebuildReady = false;
44
+ /**
45
+ * Takes the client and the table names, which must be plain identifiers that fit their limits
46
+ * ({@link pgTables}), or the constructor fails with `invalidArgument`.
47
+ */
48
+ constructor(client, options = {}) {
49
+ this.#client = client;
50
+ this.#tables = pgTables(options.eventsTable, options.snapshotsTable);
51
+ }
52
+ /** The tables this repository reads and writes, folded to lower case. */
53
+ get tables() {
54
+ return this.#tables;
55
+ }
56
+ /**
57
+ * Creates the event log's tables if they don't exist, with the DDL Go and Rust run
58
+ * ({@link schemaDdl}), under the schema lock they take. Safe to call on every start.
59
+ */
60
+ async ensureSchema(options) {
61
+ await this.#transaction(options, async (run) => {
62
+ await run(SCHEMA_LOCK, [this.#tables.events]);
63
+ for (const statement of statements(schemaDdl(this.#tables))) {
64
+ await run(statement);
65
+ }
66
+ });
67
+ }
68
+ /**
69
+ * Declares stream-heads on a store whose events and snapshots tables are empty, under the
70
+ * manifest's exclusive lock, and resolves `true` when this call declared it. A store that
71
+ * already declares it is left alone. Run {@link PgRepository.ensureSchema} first.
72
+ */
73
+ async initialize(options) {
74
+ try {
75
+ return await this.#transaction(options, async (run) => {
76
+ await run(ENGINE_LOCK_EXCLUSIVE, [featuresLockKey(this.#tables)]);
77
+ const manifest = await this.#readManifest(run);
78
+ checkSupported(manifest);
79
+ if (declaresStreamHeads(manifest)) {
80
+ return false;
81
+ }
82
+ const { events, snapshots } = this.#tables;
83
+ const populated = await run(`SELECT 1 WHERE EXISTS (SELECT 1 FROM ${events}) OR EXISTS (SELECT 1 FROM ${snapshots})`);
84
+ if (populated.length > 0) {
85
+ throw new StreamHeadsNotMigratedError();
86
+ }
87
+ await this.#writeManifest(run, manifest, withStreamHeads(manifest));
88
+ return true;
89
+ });
90
+ }
91
+ finally {
92
+ // A declaration moved the version: the next write reads it again.
93
+ this.#validated = null;
94
+ }
95
+ }
96
+ async commit(commit, options) {
97
+ options?.signal?.throwIfAborted();
98
+ validateCommit(commit);
99
+ checkNotReserved(commit.entityId);
100
+ if (commit.events.length === 0) {
101
+ return;
102
+ }
103
+ for (const group of commit.projections ?? []) {
104
+ if (group.backend !== POSTGRES_BACKEND || group.operations.length > 0) {
105
+ throw new EvtError('invalidCommit', `invalid commit: a PostgreSQL repository can't write a ${group.backend} projector group`);
106
+ }
107
+ }
108
+ // Every backend budgets a commit the same way, so an oversized one fails before any request.
109
+ checkBudget(commitSizes(commit, () => undefined));
110
+ await this.#ensureStreamHeads(options);
111
+ const { entityId, events } = commit;
112
+ const first = events[0].sequence;
113
+ const last = events.at(-1).sequence;
114
+ await this.#transaction(options, async (run) => {
115
+ await run(ENTITY_LOCK, [entityId]);
116
+ await this.#checkManifest(run);
117
+ await this.#assertNoRebuildLock(run);
118
+ if (!(await this.#moveHead(run, entityId, events[0].entityType, first, last))) {
119
+ throw await this.#probe(run, entityId, first);
120
+ }
121
+ for (const event of events) {
122
+ if (!(await this.#insertEvent(run, event))) {
123
+ // The head statement passed and the row exists: an event sits above the head. The
124
+ // entity lock rules out a racing writer.
125
+ throw drift(entityId, first - 1n, await this.#derivedHead(run, entityId));
126
+ }
127
+ }
128
+ const snapshot = commit.snapshot;
129
+ if (snapshot) {
130
+ const rows = await run(`SELECT sequence::text AS sequence FROM ${this.#tables.snapshots} WHERE entity_id = $1`, [entityId]);
131
+ const stored = rows[0] === undefined ? null : BigInt(text(rows[0], 'sequence'));
132
+ if (stored === null && snapshot.sequence !== 1n) {
133
+ throw new ConflictError(entityId, `snapshot sequence ${snapshot.sequence} has no stored predecessor`);
134
+ }
135
+ if (stored !== null && snapshot.sequence !== stored + 1n) {
136
+ throw new ConflictError(entityId, `snapshot sequence moved: stored ${stored}, commit writes ${snapshot.sequence}`);
137
+ }
138
+ await this.#upsertSnapshot(run, { ...snapshot, entityId, eventSequence: last });
139
+ }
140
+ });
141
+ }
142
+ async events(entityId, options) {
143
+ options?.signal?.throwIfAborted();
144
+ const rows = await this.#read(`SELECT ${EVENT_COLUMNS} FROM ${this.#tables.events} WHERE entity_id = $1 ` +
145
+ 'ORDER BY sequence ASC', [entityId]);
146
+ return rows.map(eventFromRow);
147
+ }
148
+ async eventsAfter(entityId, after, options) {
149
+ options?.signal?.throwIfAborted();
150
+ int64Argument(after, 'after');
151
+ const rows = await this.#read(`SELECT ${EVENT_COLUMNS} FROM ${this.#tables.events} ` +
152
+ 'WHERE entity_id = $1 AND sequence > $2::bigint ORDER BY sequence ASC', [entityId, after.toString()]);
153
+ return rows.map(eventFromRow);
154
+ }
155
+ async latest(entityId, n, options) {
156
+ options?.signal?.throwIfAborted();
157
+ if (!Number.isSafeInteger(n) || n < 1) {
158
+ throw new EvtError('invalidArgument', `latest(n) requires a whole number of at least one event: got n = ${n}`);
159
+ }
160
+ const rows = await this.#read(`SELECT ${EVENT_COLUMNS} FROM ${this.#tables.events} WHERE entity_id = $1 ` +
161
+ 'ORDER BY sequence DESC LIMIT $2::bigint', [entityId, n.toString()]);
162
+ return rows.map(eventFromRow);
163
+ }
164
+ async snapshot(entityId, options) {
165
+ options?.signal?.throwIfAborted();
166
+ const rows = await this.#read('SELECT entity_type, entity_id, sequence::text AS sequence, ' +
167
+ "event_sequence::text AS event_sequence, encode(payload, 'hex') AS payload " +
168
+ `FROM ${this.#tables.snapshots} WHERE entity_id = $1`, [entityId]);
169
+ return rows[0] === undefined ? null : snapshotFromRow(rows[0]);
170
+ }
171
+ async putSnapshot(snapshot, options) {
172
+ options?.signal?.throwIfAborted();
173
+ checkNotReserved(snapshot.entityId);
174
+ int64Argument(snapshot.sequence, 'snapshot.sequence');
175
+ const eventSequence = int64Argument(snapshot.eventSequence, 'snapshot.eventSequence');
176
+ await this.#ensureStreamHeads(options);
177
+ return this.#transaction(options, async (run) => {
178
+ const { entityId } = snapshot;
179
+ await run(ENTITY_LOCK, [entityId]);
180
+ await this.#checkManifest(run);
181
+ // The head must cover the snapshot. A snapshot of an empty stream needs no head. The entity
182
+ // lock holds the head steady.
183
+ const head = await this.#storedHead(run, entityId);
184
+ if (eventSequence > 0n && head < eventSequence) {
185
+ const derived = await this.#derivedHead(run, entityId);
186
+ throw drift(entityId, head, derived > eventSequence ? derived : eventSequence);
187
+ }
188
+ return this.#upsertSnapshot(run, snapshot);
189
+ });
190
+ }
191
+ async compactBelow(entityId, through, options) {
192
+ options?.signal?.throwIfAborted();
193
+ checkNotReserved(entityId);
194
+ if (int64Argument(through, 'through') < 1n) {
195
+ return 0;
196
+ }
197
+ // One transaction under the manifest's shared lock, held through the delete, so no
198
+ // declaration lands between the check and the delete it authorizes. It never declares
199
+ // stream-heads, and never touches the head.
200
+ return this.#transaction(options, async (run) => {
201
+ await run(ENGINE_LOCK_SHARED, [featuresLockKey(this.#tables)]);
202
+ const manifest = await this.#readManifest(run);
203
+ checkWritable(manifest);
204
+ const rows = await run('SELECT entity_type, event_sequence::text AS event_sequence ' +
205
+ `FROM ${this.#tables.snapshots} WHERE entity_id = $1`, [entityId]);
206
+ const covered = rows[0] === undefined ? null : BigInt(text(rows[0], 'event_sequence'));
207
+ if (covered === null || covered < through) {
208
+ throw new CompactionUncoveredError(entityId, through, covered);
209
+ }
210
+ const entityType = text(rows[0], 'entity_type');
211
+ if (manifest.historyDependent.includes(entityType)) {
212
+ throw new HistoryDependentProjectionError(entityType, entityId);
213
+ }
214
+ const deleted = await run(`WITH deleted AS (DELETE FROM ${this.#tables.events} ` +
215
+ 'WHERE entity_id = $1 AND sequence >= 1 AND sequence <= $2::bigint RETURNING 1) ' +
216
+ 'SELECT count(*)::text AS deleted FROM deleted', [entityId, through.toString()]);
217
+ return Number(text(deleted[0], 'deleted'));
218
+ });
219
+ }
220
+ // Makes sure the store is ready for this writer's first write: it declares stream-heads. A
221
+ // writer initializes a store whose manifest lacks it, which refuses one that holds data. It runs
222
+ // before the write's transaction, which holds the shared lock a declaration would wait for.
223
+ async #ensureStreamHeads(options) {
224
+ if (this.#validated !== null) {
225
+ return;
226
+ }
227
+ const manifest = await this.#readManifest((statement, values) => this.#read(statement, values));
228
+ checkSupported(manifest);
229
+ if (!declaresStreamHeads(manifest)) {
230
+ await this.initialize(options);
231
+ }
232
+ }
233
+ // The commit-time marker check, under the manifest's shared lock held to COMMIT, so a
234
+ // declaration can't slip between the check and the write. A manifest that changed since this
235
+ // writer validated it is validated again.
236
+ async #checkManifest(run) {
237
+ await run(ENGINE_LOCK_SHARED, [featuresLockKey(this.#tables)]);
238
+ const manifest = await this.#readManifest(run);
239
+ if (manifest !== null && manifest.version === this.#validated) {
240
+ return;
241
+ }
242
+ this.#validated = null;
243
+ checkWritable(manifest);
244
+ this.#validated = manifest.version;
245
+ }
246
+ // The commit-time rebuild-lock assertion, under the rebuild fence's shared lock held to COMMIT:
247
+ // a lock row, an expired one included, or an odd generation refuses the commit. A schema older
248
+ // than the fence has no lock table, and nobody can have taken the lock.
249
+ async #assertNoRebuildLock(run) {
250
+ await run(ENGINE_LOCK_SHARED, [rebuildLockKey(this.#tables)]);
251
+ const lock = rebuildLockTable(this.#tables);
252
+ if (!this.#rebuildReady) {
253
+ if ((await run('SELECT 1 WHERE to_regclass($1) IS NOT NULL', [lock])).length === 0) {
254
+ return;
255
+ }
256
+ this.#rebuildReady = true;
257
+ }
258
+ const generation = rebuildGenerationTable(this.#tables);
259
+ const held = await run(`SELECT 1 WHERE EXISTS (SELECT 1 FROM ${lock} WHERE id = 0) ` +
260
+ `OR EXISTS (SELECT 1 FROM ${generation} WHERE id = 0 AND value % 2 <> 0)`);
261
+ if (held.length > 0) {
262
+ throw new RebuildInProgressError();
263
+ }
264
+ }
265
+ // The stream's head statement: a create inserts its head row, an append moves it from the
266
+ // sequence before the commit's first. It passes when it wrote one row.
267
+ async #moveHead(run, entityId, entityType, first, last) {
268
+ const heads = streamHeadsTable(this.#tables);
269
+ const rows = first <= 1n
270
+ ? await run(`INSERT INTO ${heads} (entity_id, entity_type, head) VALUES ($1, $2, $3::bigint) ` +
271
+ 'ON CONFLICT (entity_id) DO NOTHING RETURNING 1', [entityId, entityType, last.toString()])
272
+ : await run(`UPDATE ${heads} SET head = $3::bigint WHERE entity_id = $1 AND head = $2::bigint ` +
273
+ 'RETURNING 1', [entityId, (first - 1n).toString(), last.toString()]);
274
+ return rows.length === 1;
275
+ }
276
+ // Classifies a failed head statement under the stream's lock, as Go and Rust do: a stored head
277
+ // below the head the log derives is drift, an equal one leaves a gap or a conflict, and one
278
+ // above it is drift unless deriving again catches up with it.
279
+ async #probe(run, entityId, first) {
280
+ const derived = await this.#derivedHead(run, entityId);
281
+ const stored = await this.#storedHead(run, entityId);
282
+ if (stored < derived) {
283
+ return drift(entityId, stored, derived);
284
+ }
285
+ if (stored > derived) {
286
+ const again = await this.#derivedHead(run, entityId);
287
+ return again < stored ? drift(entityId, stored, again) : conflict(entityId);
288
+ }
289
+ if (stored < first - 1n) {
290
+ return new SequenceGapError(entityId, stored, first);
291
+ }
292
+ return conflict(entityId);
293
+ }
294
+ // The stream's stored head, 0 when it has no head row.
295
+ async #storedHead(run, entityId) {
296
+ const rows = await run(`SELECT head::text AS head FROM ${streamHeadsTable(this.#tables)} WHERE entity_id = $1`, [entityId]);
297
+ return rows[0] === undefined ? 0n : BigInt(text(rows[0], 'head'));
298
+ }
299
+ // The head the stream's log derives: the higher of its last event and its snapshot's event
300
+ // sequence.
301
+ async #derivedHead(run, entityId) {
302
+ const { events, snapshots } = this.#tables;
303
+ const rows = await run('SELECT GREATEST(' +
304
+ `COALESCE((SELECT MAX(sequence) FROM ${events} WHERE entity_id = $1), 0), ` +
305
+ `COALESCE((SELECT MAX(event_sequence) FROM ${snapshots} WHERE entity_id = $1), 0)` +
306
+ ')::text AS head', [entityId]);
307
+ return BigInt(text(rows[0], 'head'));
308
+ }
309
+ // Inserts one event row, and reports whether it was written: false when its sequence exists.
310
+ async #insertEvent(run, event) {
311
+ const rows = await run(`INSERT INTO ${this.#tables.events} ` +
312
+ '(entity_id, sequence, event_id, event_type, version, entity_type, payload, metadata) ' +
313
+ "VALUES ($1, $2::bigint, $3, $4, $5::bigint, $6, decode($7, 'hex'), $8::text::jsonb) " +
314
+ 'ON CONFLICT (entity_id, sequence) DO NOTHING RETURNING 1', [
315
+ event.entityId,
316
+ event.sequence.toString(),
317
+ event.id,
318
+ event.type,
319
+ event.version.toString(),
320
+ event.entityType,
321
+ hex(event.payload),
322
+ encodeMetadata(event.metadata),
323
+ ]);
324
+ return rows.length === 1;
325
+ }
326
+ // Writes a snapshot unless a newer one is stored, and reports whether it wrote.
327
+ async #upsertSnapshot(run, snapshot) {
328
+ const table = this.#tables.snapshots;
329
+ const rows = await run(`INSERT INTO ${table} ` +
330
+ '(entity_id, entity_type, sequence, event_sequence, payload, updated_at) ' +
331
+ "VALUES ($1, $2, $3::bigint, $4::bigint, decode($5, 'hex'), now()) " +
332
+ 'ON CONFLICT (entity_id) DO UPDATE SET entity_type = EXCLUDED.entity_type, ' +
333
+ 'sequence = EXCLUDED.sequence, event_sequence = EXCLUDED.event_sequence, ' +
334
+ 'payload = EXCLUDED.payload, updated_at = now() ' +
335
+ `WHERE EXCLUDED.event_sequence >= ${table}.event_sequence RETURNING 1`, [
336
+ snapshot.entityId,
337
+ snapshot.entityType,
338
+ snapshot.sequence.toString(),
339
+ snapshot.eventSequence.toString(),
340
+ hex(snapshot.payload),
341
+ ]);
342
+ return rows.length === 1;
343
+ }
344
+ // The manifest row, or null when the store has none. A store older than the marker has no
345
+ // marker table: the probe doesn't name it, since a failed statement would abort the transaction.
346
+ async #readManifest(run) {
347
+ const table = featuresTable(this.#tables);
348
+ if ((await run('SELECT 1 WHERE to_regclass($1) IS NOT NULL', [table])).length === 0) {
349
+ return null;
350
+ }
351
+ const rows = await run('SELECT version::text AS version, features, history_dependent, retention ' +
352
+ `FROM ${table} WHERE id = 0`);
353
+ const row = rows[0];
354
+ if (row === undefined) {
355
+ return null;
356
+ }
357
+ return decodeManifest(BigInt(text(row, 'version')), {
358
+ features: text(row, 'features'),
359
+ historyDependent: text(row, 'history_dependent'),
360
+ retention: text(row, 'retention'),
361
+ });
362
+ }
363
+ // Writes the next manifest over the stored one, which the caller read under the exclusive lock.
364
+ async #writeManifest(run, stored, next) {
365
+ const table = featuresTable(this.#tables);
366
+ const texts = encodeManifest(next);
367
+ const { features, historyDependent, retention } = texts;
368
+ const values = [next.version.toString(), features, historyDependent, retention];
369
+ const rows = stored === null
370
+ ? await run(`INSERT INTO ${table} (id, version, features, history_dependent, retention) ` +
371
+ 'VALUES (0, $1::bigint, $2, $3, $4) RETURNING 1', values)
372
+ : await run(`UPDATE ${table} SET version = $1::bigint, features = $2, history_dependent = $3, ` +
373
+ 'retention = $4 WHERE id = 0 AND version = $5::bigint RETURNING 1', [...values, stored.version.toString()]);
374
+ if (rows.length !== 1) {
375
+ // Impossible while the exclusive lock is held: refuse rather than guess.
376
+ throw new EvtError('invalidRecord', 'the feature manifest moved during its declaration despite the exclusive lock');
377
+ }
378
+ }
379
+ // One statement outside a transaction.
380
+ async #read(statement, values) {
381
+ const client = this.#client;
382
+ if (client.connect !== undefined) {
383
+ return rowsOf(await client.query(statement, values));
384
+ }
385
+ return serialize(client, async () => rowsOf(await client.query(statement, values)));
386
+ }
387
+ // Runs `work` in one READ COMMITTED transaction on a connection of its own, and commits it. A
388
+ // failure, an abort included, rolls it back. A serialization failure or a deadlock is transient.
389
+ async #transaction(options, work) {
390
+ const signal = options?.signal;
391
+ signal?.throwIfAborted();
392
+ const client = this.#client;
393
+ if (client.connect === undefined) {
394
+ return serialize(client, () => inTransaction(client, signal, work));
395
+ }
396
+ const connection = await client.connect();
397
+ if (typeof connection?.query !== 'function' || typeof connection.release !== 'function') {
398
+ if (typeof connection?.release === 'function') {
399
+ connection.release();
400
+ }
401
+ throw new EvtError('invalidArgument', "the PostgreSQL client's connect() lent no connection: pass a pool, such as pg's Pool");
402
+ }
403
+ let broken;
404
+ try {
405
+ return await inTransaction(connection, signal, work, (error) => {
406
+ broken = error;
407
+ });
408
+ }
409
+ finally {
410
+ connection.release(broken);
411
+ }
412
+ }
413
+ }
414
+ // The operations queued on each single-connection client, shared by every repository on it: two
415
+ // transactions on one session would share its locks, and one's ROLLBACK would undo the other.
416
+ const queues = new WeakMap();
417
+ // Runs `task` on a single-connection client after every task queued on it before.
418
+ function serialize(client, task) {
419
+ const result = (queues.get(client) ?? Promise.resolve()).then(task, task);
420
+ queues.set(client, result.catch(() => undefined));
421
+ return result;
422
+ }
423
+ // One transaction on one connection. `broken` hears of a connection that failed to roll back.
424
+ async function inTransaction(connection, signal, work, broken) {
425
+ const run = async (statement, values) => {
426
+ signal?.throwIfAborted();
427
+ return rowsOf(await connection.query(statement, values));
428
+ };
429
+ let result;
430
+ try {
431
+ await connection.query('START TRANSACTION ISOLATION LEVEL READ COMMITTED');
432
+ result = await work(run);
433
+ signal?.throwIfAborted();
434
+ await connection.query('COMMIT');
435
+ }
436
+ catch (error) {
437
+ try {
438
+ await connection.query('ROLLBACK');
439
+ }
440
+ catch (rollback) {
441
+ broken?.(rollback instanceof Error ? rollback : new Error(String(rollback)));
442
+ }
443
+ throw transient(error);
444
+ }
445
+ // An abort while the COMMIT was in flight rejects too, though the commit may have applied, as
446
+ // CallOptions promises: there is nothing left to roll back.
447
+ signal?.throwIfAborted();
448
+ return result;
449
+ }
450
+ // A driver error PostgreSQL raised for a rollback a retry may not hit again, as a TransientError.
451
+ function transient(error) {
452
+ const code = typeof error === 'object' && error !== null ? error.code : null;
453
+ if (typeof code === 'string' && TRANSIENT_STATES.has(code)) {
454
+ return new TransientError(`PostgreSQL rolled the transaction back (${code})`, { cause: error });
455
+ }
456
+ return error;
457
+ }
458
+ // The statements of a DDL script, one at a time, since a driver's extended protocol runs one per
459
+ // call. Each ends at a semicolon that ends its line and comes before a blank line, a CREATE, a DO
460
+ // or the end, which no statement inside the DO block's body is followed by.
461
+ function statements(ddl) {
462
+ return ddl
463
+ .split(/;\n(?=\n|CREATE |DO |$)/)
464
+ .map((statement) => statement.trim())
465
+ .filter((statement) => statement !== '');
466
+ }
467
+ function rowsOf(result) {
468
+ const rows = result?.rows;
469
+ if (!Array.isArray(rows)) {
470
+ throw new EvtError('invalidRecord', 'the PostgreSQL client returned a result without rows');
471
+ }
472
+ return rows;
473
+ }
474
+ // A text column of a row.
475
+ function text(row, column) {
476
+ const value = row[column];
477
+ if (typeof value !== 'string') {
478
+ throw new EvtError('invalidRecord', `the PostgreSQL row has no text column ${column}`);
479
+ }
480
+ return value;
481
+ }
482
+ function eventFromRow(row) {
483
+ const metadata = text(row, 'metadata');
484
+ return {
485
+ id: text(row, 'event_id'),
486
+ sequence: BigInt(text(row, 'sequence')),
487
+ type: text(row, 'event_type'),
488
+ version: Number(text(row, 'version')),
489
+ entityId: text(row, 'entity_id'),
490
+ entityType: text(row, 'entity_type'),
491
+ payload: unhex(text(row, 'payload')),
492
+ // A row Go wrote with null metadata reads as the default, as Go and Rust read it.
493
+ metadata: metadata.trim() === '' || metadata === 'null' ? emptyMetadata() : decodeMetadata(metadata),
494
+ };
495
+ }
496
+ function snapshotFromRow(row) {
497
+ return {
498
+ entityType: text(row, 'entity_type'),
499
+ entityId: text(row, 'entity_id'),
500
+ sequence: BigInt(text(row, 'sequence')),
501
+ eventSequence: BigInt(text(row, 'event_sequence')),
502
+ payload: unhex(text(row, 'payload')),
503
+ };
504
+ }
505
+ // Bytes as lowercase hex, which decode(…, 'hex') reads. A null payload is stored empty.
506
+ function hex(bytes) {
507
+ let out = '';
508
+ for (const byte of bytes ?? []) {
509
+ out += byte.toString(16).padStart(2, '0');
510
+ }
511
+ return out;
512
+ }
513
+ function unhex(digits) {
514
+ const bytes = new Uint8Array(digits.length / 2);
515
+ for (let i = 0; i < bytes.length; i++) {
516
+ bytes[i] = Number.parseInt(digits.slice(2 * i, 2 * i + 2), 16);
517
+ }
518
+ return bytes;
519
+ }
520
+ function conflict(entityId) {
521
+ return new ConflictError(entityId, 'conditional check failed: the sequence or snapshot changed since it was read');
522
+ }
523
+ // A stored head of 0 is an absent head.
524
+ function drift(entityId, stored, derived) {
525
+ return new StreamHeadDriftError(entityId, stored > 0n ? stored : null, derived);
526
+ }
527
+ //# sourceMappingURL=repository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repository.js","sourceRoot":"","sources":["../../src/postgres/repository.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,81 @@
1
+ /** The default events table. */
2
+ export declare const DEFAULT_EVENTS_TABLE = "evt_events";
3
+ /** The default snapshots table. */
4
+ export declare const DEFAULT_SNAPSHOTS_TABLE = "evt_snapshots";
5
+ /**
6
+ * The infix the engine relations derive from the events table name with, such as
7
+ * `evt_events__evt_features`. A configured table name may not contain it, in any case, so one
8
+ * log's tables can never equal another log's derived relation.
9
+ */
10
+ export declare const RESERVED_INFIX = "__evt_";
11
+ /**
12
+ * The longest events table name, in bytes. Its longest derived relation,
13
+ * `{events}__evt_rebuild_generation_pkey`, then fills PostgreSQL's 63-byte identifier limit.
14
+ */
15
+ export declare const MAX_EVENTS_TABLE_NAME_BYTES: number;
16
+ /** The longest snapshots table name, in bytes, which leaves room for its `_pkey` index. */
17
+ export declare const MAX_SNAPSHOTS_TABLE_NAME_BYTES: number;
18
+ declare const validated: unique symbol;
19
+ /**
20
+ * An event log's two configured tables, validated and folded to lower case. Only
21
+ * {@link pgTables} makes one.
22
+ */
23
+ export interface PgTables {
24
+ readonly events: string;
25
+ readonly snapshots: string;
26
+ readonly [validated]: true;
27
+ }
28
+ /**
29
+ * Validates an event log's table names and folds them to lower case, as PostgreSQL folds unquoted
30
+ * identifiers. Each must be a plain identifier that isn't a reserved keyword, within its length
31
+ * limit, without the {@link RESERVED_INFIX}, and no two relations the schema creates may share a
32
+ * name. A name that breaks a rule fails with `invalidArgument`, as Go and Rust refuse it at
33
+ * construction.
34
+ */
35
+ export declare function pgTables(events?: string, snapshots?: string): PgTables;
36
+ /** The command-outcomes table: `evt_events` yields `evt_events__evt_command_outcomes`. */
37
+ export declare function outcomesTable(tables: PgTables): string;
38
+ /** The feature-marker table: `evt_events` yields `evt_events__evt_features`. */
39
+ export declare function featuresTable(tables: PgTables): string;
40
+ /** The rebuild-lock table: `evt_events` yields `evt_events__evt_rebuild_lock`. */
41
+ export declare function rebuildLockTable(tables: PgTables): string;
42
+ /** The rebuild-generation table: `evt_events` yields `evt_events__evt_rebuild_generation`. */
43
+ export declare function rebuildGenerationTable(tables: PgTables): string;
44
+ /** The stream-heads table: `evt_events` yields `evt_events__evt_stream_heads`. */
45
+ export declare function streamHeadsTable(tables: PgTables): string;
46
+ /** The entity-type index of the events table: `evt_events__evt_entity_type_idx`. */
47
+ export declare function entityTypeIndex(tables: PgTables): string;
48
+ /**
49
+ * The idempotent DDL of an event log, byte for byte the DDL Go's `EnsureSchema` and Rust's
50
+ * `ensure_schema` run: the events and snapshots tables, the entity-type index (dropping its
51
+ * pre-v0.9 name), and the command-outcome, feature-marker, rebuild-fence and stream-heads tables.
52
+ * Run it inside one transaction, after {@link SCHEMA_LOCK} with the events table name, as Go and
53
+ * Rust do.
54
+ */
55
+ export declare function schemaDdl(tables: PgTables): string;
56
+ /**
57
+ * Serializes schema changes across processes, in every language: `IF NOT EXISTS` alone can still
58
+ * race in PostgreSQL's catalogs. `$1` is the events table name.
59
+ */
60
+ export declare const SCHEMA_LOCK = "SELECT pg_advisory_xact_lock(1702261762, hashtext($1))";
61
+ /**
62
+ * The per-entity transaction lock every commit and snapshot write takes, `$1` being the entity
63
+ * ID. Go and Rust run this exact statement, so writers in every language exclude each other.
64
+ */
65
+ export declare const ENTITY_LOCK = "SELECT pg_advisory_xact_lock(1702261760, hashtext($1))";
66
+ /**
67
+ * The shared engine-row lock a commit takes and holds to `COMMIT`, `$1` being a key from
68
+ * {@link featuresLockKey} or {@link rebuildLockKey}. Commits don't serialize against each other.
69
+ */
70
+ export declare const ENGINE_LOCK_SHARED = "SELECT pg_advisory_xact_lock_shared(1702261761, hashtext($1))";
71
+ /**
72
+ * The exclusive engine-row lock a declaration or a rebuild lifecycle step takes for its short
73
+ * transaction, so it never slips between a commit's check and its `COMMIT`.
74
+ */
75
+ export declare const ENGINE_LOCK_EXCLUSIVE = "SELECT pg_advisory_xact_lock(1702261761, hashtext($1))";
76
+ /** The feature marker's engine-row lock key: `{events}:features`. */
77
+ export declare function featuresLockKey(tables: PgTables): string;
78
+ /** The rebuild fence's engine-row lock key: `{events}:rebuild`. */
79
+ export declare function rebuildLockKey(tables: PgTables): string;
80
+ export {};
81
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/postgres/schema.ts"],"names":[],"mappings":"AAMA,gCAAgC;AAChC,eAAO,MAAM,oBAAoB,eAAe,CAAA;AAEhD,mCAAmC;AACnC,eAAO,MAAM,uBAAuB,kBAAkB,CAAA;AAEtD;;;;GAIG;AACH,eAAO,MAAM,cAAc,WAAW,CAAA;AAEtC;;;GAGG;AACH,eAAO,MAAM,2BAA2B,QAA8C,CAAA;AAEtF,2FAA2F;AAC3F,eAAO,MAAM,8BAA8B,QAAsB,CAAA;AAGjE,OAAO,CAAC,MAAM,SAAS,EAAE,OAAO,MAAM,CAAA;AAEtC;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,CAAC,SAAS,CAAC,EAAE,IAAI,CAAA;CAC3B;AAkBD;;;;;;GAMG;AACH,wBAAgB,QAAQ,CACtB,MAAM,GAAE,MAA6B,EACrC,SAAS,GAAE,MAAgC,GAC1C,QAAQ,CA0BV;AAED,0FAA0F;AAC1F,wBAAgB,aAAa,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,CAEtD;AAED,gFAAgF;AAChF,wBAAgB,aAAa,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,CAEtD;AAED,kFAAkF;AAClF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,CAEzD;AAED,8FAA8F;AAC9F,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,CAE/D;AAED,kFAAkF;AAClF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,CAEzD;AAED,oFAAoF;AACpF,wBAAgB,eAAe,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,CAExD;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,CA6ElD;AAED;;;GAGG;AACH,eAAO,MAAM,WAAW,2DAA2D,CAAA;AAEnF;;;GAGG;AACH,eAAO,MAAM,WAAW,2DAA2D,CAAA;AAEnF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,kEAAkE,CAAA;AAEjG;;;GAGG;AACH,eAAO,MAAM,qBAAqB,2DAA2D,CAAA;AAE7F,qEAAqE;AACrE,wBAAgB,eAAe,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,CAExD;AAED,mEAAmE;AACnE,wBAAgB,cAAc,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,CAEvD"}