@photon-grove/evt 0.1.1 → 0.2.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.
- package/README.md +51 -4
- package/dist/aggregate.d.ts +26 -0
- package/dist/aggregate.d.ts.map +1 -1
- package/dist/aggregate.js.map +1 -1
- package/dist/dynamodb/head.d.ts +6 -0
- package/dist/dynamodb/head.d.ts.map +1 -1
- package/dist/dynamodb/head.js +11 -0
- package/dist/dynamodb/head.js.map +1 -1
- package/dist/dynamodb/index.d.ts +2 -1
- package/dist/dynamodb/index.d.ts.map +1 -1
- package/dist/dynamodb/index.js +2 -1
- package/dist/dynamodb/index.js.map +1 -1
- package/dist/dynamodb/repository.d.ts +9 -2
- package/dist/dynamodb/repository.d.ts.map +1 -1
- package/dist/dynamodb/repository.js +123 -27
- package/dist/dynamodb/repository.js.map +1 -1
- package/dist/dynamodb/requests.d.ts +37 -3
- package/dist/dynamodb/requests.d.ts.map +1 -1
- package/dist/dynamodb/requests.js +67 -9
- package/dist/dynamodb/requests.js.map +1 -1
- package/dist/dynamodb/views.d.ts +18 -0
- package/dist/dynamodb/views.d.ts.map +1 -0
- package/dist/dynamodb/views.js +56 -0
- package/dist/dynamodb/views.js.map +1 -0
- package/dist/errors.d.ts +51 -4
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +60 -4
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/memory/repository.d.ts +3 -2
- package/dist/memory/repository.d.ts.map +1 -1
- package/dist/memory/repository.js +78 -29
- package/dist/memory/repository.js.map +1 -1
- package/dist/postgres/client.d.ts +32 -0
- package/dist/postgres/client.d.ts.map +1 -0
- package/dist/postgres/client.js +4 -0
- package/dist/postgres/client.js.map +1 -0
- package/dist/postgres/index.d.ts +4 -0
- package/dist/postgres/index.d.ts.map +1 -0
- package/dist/postgres/index.js +6 -0
- package/dist/postgres/index.js.map +1 -0
- package/dist/postgres/repository.d.ts +62 -0
- package/dist/postgres/repository.d.ts.map +1 -0
- package/dist/postgres/repository.js +598 -0
- package/dist/postgres/repository.js.map +1 -0
- package/dist/postgres/schema.d.ts +81 -0
- package/dist/postgres/schema.d.ts.map +1 -0
- package/dist/postgres/schema.js +249 -0
- package/dist/postgres/schema.js.map +1 -0
- package/dist/repository.d.ts +101 -6
- package/dist/repository.d.ts.map +1 -1
- package/dist/repository.js +108 -6
- package/dist/repository.js.map +1 -1
- package/dist/staging.d.ts +28 -0
- package/dist/staging.d.ts.map +1 -0
- package/dist/staging.js +89 -0
- package/dist/staging.js.map +1 -0
- package/dist/store.d.ts +15 -3
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +38 -54
- package/dist/store.js.map +1 -1
- package/dist/transaction.d.ts +113 -0
- package/dist/transaction.d.ts.map +1 -0
- package/dist/transaction.js +207 -0
- package/dist/transaction.js.map +1 -0
- package/package.json +5 -1
- package/src/aggregate.ts +28 -0
- package/src/dynamodb/head.ts +15 -0
- package/src/dynamodb/index.ts +2 -0
- package/src/dynamodb/repository.ts +177 -33
- package/src/dynamodb/requests.ts +114 -10
- package/src/dynamodb/views.ts +67 -0
- package/src/errors.ts +86 -4
- package/src/index.ts +19 -6
- package/src/memory/repository.ts +93 -32
- package/src/postgres/client.ts +37 -0
- package/src/postgres/index.ts +23 -0
- package/src/postgres/repository.ts +858 -0
- package/src/postgres/schema.ts +302 -0
- package/src/repository.ts +220 -8
- package/src/staging.ts +138 -0
- package/src/store.ts +66 -65
- package/src/transaction.ts +322 -0
|
@@ -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,CA6FlD;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"}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
// The PostgreSQL layout of an event log, independent of any driver (storage format, "PostgreSQL"):
|
|
2
|
+
// the table names a store is configured with, the engine relations derived from them, and the
|
|
3
|
+
// idempotent DDL that Go's EnsureSchema and Rust's ensure_schema run.
|
|
4
|
+
import { EvtError } from '../errors.js';
|
|
5
|
+
/** The default events table. */
|
|
6
|
+
export const DEFAULT_EVENTS_TABLE = 'evt_events';
|
|
7
|
+
/** The default snapshots table. */
|
|
8
|
+
export const DEFAULT_SNAPSHOTS_TABLE = 'evt_snapshots';
|
|
9
|
+
/**
|
|
10
|
+
* The infix the engine relations derive from the events table name with, such as
|
|
11
|
+
* `evt_events__evt_features`. A configured table name may not contain it, in any case, so one
|
|
12
|
+
* log's tables can never equal another log's derived relation.
|
|
13
|
+
*/
|
|
14
|
+
export const RESERVED_INFIX = '__evt_';
|
|
15
|
+
/**
|
|
16
|
+
* The longest events table name, in bytes. Its longest derived relation,
|
|
17
|
+
* `{events}__evt_rebuild_generation_pkey`, then fills PostgreSQL's 63-byte identifier limit.
|
|
18
|
+
*/
|
|
19
|
+
export const MAX_EVENTS_TABLE_NAME_BYTES = 63 - '__evt_rebuild_generation_pkey'.length;
|
|
20
|
+
/** The longest snapshots table name, in bytes, which leaves room for its `_pkey` index. */
|
|
21
|
+
export const MAX_SNAPSHOTS_TABLE_NAME_BYTES = 63 - '_pkey'.length;
|
|
22
|
+
const IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
23
|
+
// PostgreSQL's reserved keywords (pg_get_keywords() categories R and T), which can't be unquoted
|
|
24
|
+
// table names. The same list as Go's and Rust's.
|
|
25
|
+
const RESERVED_KEYWORDS = new Set(`all analyse analyze and any array as asc asymmetric authorization binary both case cast check
|
|
26
|
+
collate collation column concurrently constraint create cross current_catalog current_date
|
|
27
|
+
current_role current_schema current_time current_timestamp current_user default deferrable desc
|
|
28
|
+
distinct do else end except false fetch for foreign freeze from full grant group having ilike in
|
|
29
|
+
initially inner intersect into is isnull join lateral leading left like limit localtime
|
|
30
|
+
localtimestamp natural not notnull null offset on only or order outer overlaps placing primary
|
|
31
|
+
references returning right select session_user similar some symmetric system_user table
|
|
32
|
+
tablesample then to trailing true union unique user using variadic verbose when where window
|
|
33
|
+
with`.split(/\s+/));
|
|
34
|
+
/**
|
|
35
|
+
* Validates an event log's table names and folds them to lower case, as PostgreSQL folds unquoted
|
|
36
|
+
* identifiers. Each must be a plain identifier that isn't a reserved keyword, within its length
|
|
37
|
+
* limit, without the {@link RESERVED_INFIX}, and no two relations the schema creates may share a
|
|
38
|
+
* name. A name that breaks a rule fails with `invalidArgument`, as Go and Rust refuse it at
|
|
39
|
+
* construction.
|
|
40
|
+
*/
|
|
41
|
+
export function pgTables(events = DEFAULT_EVENTS_TABLE, snapshots = DEFAULT_SNAPSHOTS_TABLE) {
|
|
42
|
+
for (const [name, limit] of [
|
|
43
|
+
[events, MAX_EVENTS_TABLE_NAME_BYTES],
|
|
44
|
+
[snapshots, MAX_SNAPSHOTS_TABLE_NAME_BYTES],
|
|
45
|
+
]) {
|
|
46
|
+
if (!validIdentifier(name, limit)) {
|
|
47
|
+
throw invalidConfig(`invalid table name ${JSON.stringify(name)}`);
|
|
48
|
+
}
|
|
49
|
+
if (name.toLowerCase().includes(RESERVED_INFIX)) {
|
|
50
|
+
throw invalidConfig(`table name ${JSON.stringify(name)} must not contain the reserved infix ` +
|
|
51
|
+
JSON.stringify(RESERVED_INFIX));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const tables = { events: events.toLowerCase(), snapshots: snapshots.toLowerCase() };
|
|
55
|
+
const shared = sharedRelation(tables);
|
|
56
|
+
if (shared !== null) {
|
|
57
|
+
throw invalidConfig(`tables ${JSON.stringify(events)} and ${JSON.stringify(snapshots)} would both use the ` +
|
|
58
|
+
`name ${JSON.stringify(shared)}`);
|
|
59
|
+
}
|
|
60
|
+
return tables;
|
|
61
|
+
}
|
|
62
|
+
/** The command-outcomes table: `evt_events` yields `evt_events__evt_command_outcomes`. */
|
|
63
|
+
export function outcomesTable(tables) {
|
|
64
|
+
return derived(tables.events, 'command_outcomes');
|
|
65
|
+
}
|
|
66
|
+
/** The feature-marker table: `evt_events` yields `evt_events__evt_features`. */
|
|
67
|
+
export function featuresTable(tables) {
|
|
68
|
+
return derived(tables.events, 'features');
|
|
69
|
+
}
|
|
70
|
+
/** The rebuild-lock table: `evt_events` yields `evt_events__evt_rebuild_lock`. */
|
|
71
|
+
export function rebuildLockTable(tables) {
|
|
72
|
+
return derived(tables.events, 'rebuild_lock');
|
|
73
|
+
}
|
|
74
|
+
/** The rebuild-generation table: `evt_events` yields `evt_events__evt_rebuild_generation`. */
|
|
75
|
+
export function rebuildGenerationTable(tables) {
|
|
76
|
+
return derived(tables.events, 'rebuild_generation');
|
|
77
|
+
}
|
|
78
|
+
/** The stream-heads table: `evt_events` yields `evt_events__evt_stream_heads`. */
|
|
79
|
+
export function streamHeadsTable(tables) {
|
|
80
|
+
return derived(tables.events, 'stream_heads');
|
|
81
|
+
}
|
|
82
|
+
/** The entity-type index of the events table: `evt_events__evt_entity_type_idx`. */
|
|
83
|
+
export function entityTypeIndex(tables) {
|
|
84
|
+
return derived(tables.events, 'entity_type_idx');
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* The idempotent DDL of an event log, byte for byte the DDL Go's `EnsureSchema` and Rust's
|
|
88
|
+
* `ensure_schema` run: the events and snapshots tables, the entity-type index (dropping its
|
|
89
|
+
* pre-v0.9 name), and the command-outcome, feature-marker, rebuild-fence and stream-heads tables.
|
|
90
|
+
* Run it inside one transaction, after {@link SCHEMA_LOCK} with the events table name, as Go and
|
|
91
|
+
* Rust do.
|
|
92
|
+
*/
|
|
93
|
+
export function schemaDdl(tables) {
|
|
94
|
+
const { events, snapshots } = tables;
|
|
95
|
+
return `
|
|
96
|
+
CREATE TABLE IF NOT EXISTS ${events} (
|
|
97
|
+
entity_id text NOT NULL,
|
|
98
|
+
sequence bigint NOT NULL,
|
|
99
|
+
event_id text NOT NULL,
|
|
100
|
+
event_type text NOT NULL,
|
|
101
|
+
version bigint NOT NULL,
|
|
102
|
+
entity_type text NOT NULL,
|
|
103
|
+
payload bytea NOT NULL,
|
|
104
|
+
metadata jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
105
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
106
|
+
PRIMARY KEY (entity_id, sequence)
|
|
107
|
+
);
|
|
108
|
+
CREATE INDEX IF NOT EXISTS ${entityTypeIndex(tables)} ON ${events} (entity_type);
|
|
109
|
+
DO $$
|
|
110
|
+
BEGIN
|
|
111
|
+
IF EXISTS (
|
|
112
|
+
SELECT 1 FROM pg_index
|
|
113
|
+
WHERE indexrelid = to_regclass('${events}_entity_type_idx')
|
|
114
|
+
AND indrelid = '${events}'::regclass
|
|
115
|
+
) THEN
|
|
116
|
+
DROP INDEX ${events}_entity_type_idx;
|
|
117
|
+
END IF;
|
|
118
|
+
END $$;
|
|
119
|
+
|
|
120
|
+
CREATE TABLE IF NOT EXISTS ${snapshots} (
|
|
121
|
+
entity_id text PRIMARY KEY,
|
|
122
|
+
entity_type text NOT NULL,
|
|
123
|
+
sequence bigint NOT NULL,
|
|
124
|
+
event_sequence bigint NOT NULL,
|
|
125
|
+
payload bytea NOT NULL,
|
|
126
|
+
updated_at timestamptz NOT NULL DEFAULT now()
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
CREATE TABLE IF NOT EXISTS ${outcomesTable(tables)} (
|
|
130
|
+
command_id text PRIMARY KEY,
|
|
131
|
+
status text NOT NULL CHECK (status IN ('accepted', 'rejected')),
|
|
132
|
+
digest text NOT NULL,
|
|
133
|
+
response bytea,
|
|
134
|
+
events jsonb NOT NULL DEFAULT '[]'::jsonb,
|
|
135
|
+
rejection jsonb,
|
|
136
|
+
code text,
|
|
137
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
138
|
+
command_type text,
|
|
139
|
+
targets jsonb,
|
|
140
|
+
principal text,
|
|
141
|
+
CHECK ((status = 'rejected' AND rejection IS NOT NULL AND code IS NOT NULL)
|
|
142
|
+
OR (status = 'accepted' AND rejection IS NULL AND code IS NULL))
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
DO $$
|
|
146
|
+
BEGIN
|
|
147
|
+
IF (SELECT count(*) FROM pg_attribute
|
|
148
|
+
WHERE attrelid = '${outcomesTable(tables)}'::regclass
|
|
149
|
+
AND attname IN ('command_type', 'targets', 'principal')
|
|
150
|
+
AND NOT attisdropped) < 3 THEN
|
|
151
|
+
ALTER TABLE ${outcomesTable(tables)}
|
|
152
|
+
ADD COLUMN IF NOT EXISTS command_type text,
|
|
153
|
+
ADD COLUMN IF NOT EXISTS targets jsonb,
|
|
154
|
+
ADD COLUMN IF NOT EXISTS principal text;
|
|
155
|
+
END IF;
|
|
156
|
+
END $$;
|
|
157
|
+
|
|
158
|
+
CREATE TABLE IF NOT EXISTS ${featuresTable(tables)} (
|
|
159
|
+
id integer PRIMARY KEY,
|
|
160
|
+
version bigint NOT NULL,
|
|
161
|
+
features text NOT NULL,
|
|
162
|
+
history_dependent text NOT NULL DEFAULT '[]',
|
|
163
|
+
retention text NOT NULL DEFAULT '[]'
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
CREATE TABLE IF NOT EXISTS ${rebuildLockTable(tables)} (
|
|
167
|
+
id integer PRIMARY KEY,
|
|
168
|
+
owner text NOT NULL,
|
|
169
|
+
generation bigint NOT NULL,
|
|
170
|
+
lease_expires_at timestamptz NOT NULL
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
CREATE TABLE IF NOT EXISTS ${rebuildGenerationTable(tables)} (
|
|
174
|
+
id integer PRIMARY KEY,
|
|
175
|
+
value bigint NOT NULL,
|
|
176
|
+
force_released boolean NOT NULL DEFAULT false
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
CREATE TABLE IF NOT EXISTS ${streamHeadsTable(tables)} (
|
|
180
|
+
entity_id text PRIMARY KEY,
|
|
181
|
+
entity_type text NOT NULL,
|
|
182
|
+
head bigint NOT NULL CHECK (head >= 1)
|
|
183
|
+
);
|
|
184
|
+
`;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Serializes schema changes across processes, in every language: `IF NOT EXISTS` alone can still
|
|
188
|
+
* race in PostgreSQL's catalogs. `$1` is the events table name.
|
|
189
|
+
*/
|
|
190
|
+
export const SCHEMA_LOCK = 'SELECT pg_advisory_xact_lock(1702261762, hashtext($1))';
|
|
191
|
+
/**
|
|
192
|
+
* The per-entity transaction lock every commit and snapshot write takes, `$1` being the entity
|
|
193
|
+
* ID. Go and Rust run this exact statement, so writers in every language exclude each other.
|
|
194
|
+
*/
|
|
195
|
+
export const ENTITY_LOCK = 'SELECT pg_advisory_xact_lock(1702261760, hashtext($1))';
|
|
196
|
+
/**
|
|
197
|
+
* The shared engine-row lock a commit takes and holds to `COMMIT`, `$1` being a key from
|
|
198
|
+
* {@link featuresLockKey} or {@link rebuildLockKey}. Commits don't serialize against each other.
|
|
199
|
+
*/
|
|
200
|
+
export const ENGINE_LOCK_SHARED = 'SELECT pg_advisory_xact_lock_shared(1702261761, hashtext($1))';
|
|
201
|
+
/**
|
|
202
|
+
* The exclusive engine-row lock a declaration or a rebuild lifecycle step takes for its short
|
|
203
|
+
* transaction, so it never slips between a commit's check and its `COMMIT`.
|
|
204
|
+
*/
|
|
205
|
+
export const ENGINE_LOCK_EXCLUSIVE = 'SELECT pg_advisory_xact_lock(1702261761, hashtext($1))';
|
|
206
|
+
/** The feature marker's engine-row lock key: `{events}:features`. */
|
|
207
|
+
export function featuresLockKey(tables) {
|
|
208
|
+
return `${tables.events}:features`;
|
|
209
|
+
}
|
|
210
|
+
/** The rebuild fence's engine-row lock key: `{events}:rebuild`. */
|
|
211
|
+
export function rebuildLockKey(tables) {
|
|
212
|
+
return `${tables.events}:rebuild`;
|
|
213
|
+
}
|
|
214
|
+
function derived(events, suffix) {
|
|
215
|
+
return `${events}${RESERVED_INFIX}${suffix}`;
|
|
216
|
+
}
|
|
217
|
+
// A valid identifier is ASCII, so its length is its byte count and folding it changes only A-Z.
|
|
218
|
+
// The type check refuses a non-string passed from JavaScript, which the pattern would coerce.
|
|
219
|
+
function validIdentifier(name, limit) {
|
|
220
|
+
return (typeof name === 'string' &&
|
|
221
|
+
name.length <= limit &&
|
|
222
|
+
IDENTIFIER.test(name) &&
|
|
223
|
+
!RESERVED_KEYWORDS.has(name.toLowerCase()));
|
|
224
|
+
}
|
|
225
|
+
// A name two relations of the schema would share, or null, with the names already folded to lower
|
|
226
|
+
// case. CREATE TABLE IF NOT EXISTS would otherwise skip a table whose name an index already took.
|
|
227
|
+
function sharedRelation(tables) {
|
|
228
|
+
const { events, snapshots } = tables;
|
|
229
|
+
const derivedTables = [
|
|
230
|
+
outcomesTable(tables),
|
|
231
|
+
featuresTable(tables),
|
|
232
|
+
rebuildLockTable(tables),
|
|
233
|
+
rebuildGenerationTable(tables),
|
|
234
|
+
streamHeadsTable(tables),
|
|
235
|
+
];
|
|
236
|
+
const relations = [
|
|
237
|
+
events,
|
|
238
|
+
`${events}_pkey`,
|
|
239
|
+
entityTypeIndex(tables),
|
|
240
|
+
...derivedTables.flatMap((table) => [table, `${table}_pkey`]),
|
|
241
|
+
snapshots,
|
|
242
|
+
`${snapshots}_pkey`,
|
|
243
|
+
];
|
|
244
|
+
return relations.find((relation, index) => relations.indexOf(relation) !== index) ?? null;
|
|
245
|
+
}
|
|
246
|
+
function invalidConfig(message) {
|
|
247
|
+
return new EvtError('invalidArgument', `postgres: ${message}`);
|
|
248
|
+
}
|
|
249
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/postgres/schema.ts"],"names":[],"mappings":"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"}
|
package/dist/repository.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { EvtError, type FenceProvenance } from './errors.js';
|
|
1
2
|
import { type SerializedEvent, type SerializedSnapshot } from './event.js';
|
|
2
3
|
/** A snapshot to write with a commit. Its event sequence is the commit's last event. */
|
|
3
4
|
export interface NewSnapshot {
|
|
@@ -7,9 +8,23 @@ export interface NewSnapshot {
|
|
|
7
8
|
/** The aggregate state after the commit's events. */
|
|
8
9
|
payload: Uint8Array;
|
|
9
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* Operations a projector adds to a commit, for the backend it names to write in the commit's own
|
|
13
|
+
* transaction (Go's transaction groups). The DynamoDB repository writes `dynamodb` groups, whose
|
|
14
|
+
* operations are `TransactWriteItems` actions. The in-memory repository budgets every group and
|
|
15
|
+
* writes none, as Go's does, so code with projectors runs on it unchanged.
|
|
16
|
+
*/
|
|
17
|
+
export interface ProjectorGroup {
|
|
18
|
+
/** The backend whose transaction carries the operations, such as `dynamodb`. */
|
|
19
|
+
readonly backend: string;
|
|
20
|
+
/** The operations, in the order they're written. */
|
|
21
|
+
readonly operations: readonly unknown[];
|
|
22
|
+
/** Each operation's size in the commit budget, as DynamoDB counts it. */
|
|
23
|
+
readonly sizes: readonly number[];
|
|
24
|
+
}
|
|
10
25
|
/**
|
|
11
26
|
* Everything a repository writes atomically for one command. A commit with no events is a no-op,
|
|
12
|
-
* and its snapshot is ignored.
|
|
27
|
+
* and its snapshot is ignored, unless it carries projector operations: then it's refused.
|
|
13
28
|
*/
|
|
14
29
|
export interface Commit {
|
|
15
30
|
/** The stream the events are appended to. */
|
|
@@ -18,6 +33,8 @@ export interface Commit {
|
|
|
18
33
|
events: SerializedEvent[];
|
|
19
34
|
/** The snapshot to write, when the commit reaches a snapshot boundary. */
|
|
20
35
|
snapshot?: NewSnapshot | null | undefined;
|
|
36
|
+
/** The operations the aggregate's projectors add, written first, in order. */
|
|
37
|
+
projections?: readonly ProjectorGroup[] | null | undefined;
|
|
21
38
|
}
|
|
22
39
|
/** Options every repository call takes. */
|
|
23
40
|
export interface CallOptions {
|
|
@@ -41,7 +58,9 @@ export interface CallOptions {
|
|
|
41
58
|
* {@link StreamHeadDriftError}, ranked above a gap and any other conflict;
|
|
42
59
|
* - refuse a commit's snapshot whose sequence isn't the stored snapshot's plus one (1 with none
|
|
43
60
|
* stored) with a {@link ConflictError};
|
|
44
|
-
* - write a commit's events, head and snapshot atomically, or nothing
|
|
61
|
+
* - write a commit's events, head and snapshot atomically, or nothing, with the projector
|
|
62
|
+
* operations it writes (a backend writes only its own groups), and refuse projector operations
|
|
63
|
+
* without events with a {@link ProjectorOnlyCommitError};
|
|
45
64
|
* - refuse an entity ID in a reserved namespace on every write path, before any request;
|
|
46
65
|
* - refuse every write (a commit, a snapshot write, compaction) to a store whose feature manifest
|
|
47
66
|
* declares a pair this package doesn't model, with an {@link UnsupportedFeatureError}, and to
|
|
@@ -99,6 +118,74 @@ export interface StoreInitializer {
|
|
|
99
118
|
*/
|
|
100
119
|
initialize(options?: CallOptions): Promise<boolean>;
|
|
101
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* A stream a transaction read but doesn't write, whose head must not move before it commits (ADR
|
|
123
|
+
* 0007): the fence passes while the stream's stored head still equals `head`.
|
|
124
|
+
*/
|
|
125
|
+
export interface ReadFence {
|
|
126
|
+
entityId: string;
|
|
127
|
+
/** The stream's entity type, which a fence on a retained type is refused for. */
|
|
128
|
+
entityType: string;
|
|
129
|
+
/** The head the transaction observed: 0 for a stream with no events. */
|
|
130
|
+
head: bigint;
|
|
131
|
+
/** Whether the engine read the head itself, or the caller stamped it. */
|
|
132
|
+
provenance: FenceProvenance;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Everything one transaction writes atomically: the streams it appends to, and fences on the
|
|
136
|
+
* streams it read. A fence on a stream the transaction also writes is dropped, since that stream's
|
|
137
|
+
* head update already conditions on the head it read. A transaction that writes nothing and fences
|
|
138
|
+
* nothing is a no-op.
|
|
139
|
+
*/
|
|
140
|
+
export interface TransactionCommit {
|
|
141
|
+
/** The streams written, each a {@link Commit}, at most one per stream. */
|
|
142
|
+
streams: readonly Commit[];
|
|
143
|
+
/** The streams read but not written, at most one fence per stream. */
|
|
144
|
+
fences?: readonly ReadFence[] | null | undefined;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* A repository that commits several streams atomically, with read fences (ADR 0004). A
|
|
148
|
+
* transaction is refused as a commit is, and also:
|
|
149
|
+
*
|
|
150
|
+
* - with `invalidCommit` when it writes a stream twice, fences a stream twice, fences at a head
|
|
151
|
+
* below 0 or at the largest int64, or carries a snapshot for a stream it writes no events to;
|
|
152
|
+
* - with a {@link RetentionConflictError} when it fences an entity type with retention: by the
|
|
153
|
+
* repository's own configuration before any request, and by the store's manifest after the
|
|
154
|
+
* manifest's other refusals, but always before the rebuild lock's;
|
|
155
|
+
* - with a {@link FenceConflictError} when a fenced stream's head moved, unless the stream
|
|
156
|
+
* drifted, ranked after every drift and gap of the transaction, in transaction order.
|
|
157
|
+
*/
|
|
158
|
+
export interface TransactionalRepository extends Repository {
|
|
159
|
+
/** Appends to every stream and checks every fence atomically. */
|
|
160
|
+
commitTransaction(transaction: TransactionCommit, options?: CallOptions): Promise<void>;
|
|
161
|
+
}
|
|
162
|
+
/** A transaction as the backends write it. */
|
|
163
|
+
export interface NormalizedTransaction {
|
|
164
|
+
/** The streams it writes events to, sorted by entity ID bytes, without their projections. */
|
|
165
|
+
readonly streams: readonly Commit[];
|
|
166
|
+
/** Its fences on the streams it doesn't write, sorted the same way. */
|
|
167
|
+
readonly fences: readonly ReadFence[];
|
|
168
|
+
/** The written streams' projector groups, in the order the streams were declared. */
|
|
169
|
+
readonly projections: readonly ProjectorGroup[];
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Validates a transaction and puts it in the order every backend writes it: the written streams,
|
|
173
|
+
* then the fences, each sorted by entity ID bytes, the order that pins a DynamoDB transaction and
|
|
174
|
+
* PostgreSQL's locks. The projector groups keep the order the streams were declared in. Streams
|
|
175
|
+
* without events are dropped, and so are the fences on streams that write events, whose head
|
|
176
|
+
* updates condition on the head they read. A fence on a stream listed without events stays.
|
|
177
|
+
*/
|
|
178
|
+
export declare function normalizeTransaction(transaction: TransactionCommit): NormalizedTransaction;
|
|
179
|
+
/**
|
|
180
|
+
* Refuses a transaction that fences a retained entity type, by the store's manifest or the
|
|
181
|
+
* repository's own configuration.
|
|
182
|
+
*/
|
|
183
|
+
export declare function checkFenceRetention(transaction: NormalizedTransaction, retained: (entityType: string) => boolean): void;
|
|
184
|
+
/**
|
|
185
|
+
* The error a failed transaction reports from the failures of its streams and fences, given in
|
|
186
|
+
* transaction order: the first drift, else the first gap, else the first of the rest.
|
|
187
|
+
*/
|
|
188
|
+
export declare function rankFailures(failures: readonly EvtError[]): EvtError | undefined;
|
|
102
189
|
/** The most actions one commit may carry, DynamoDB's transaction limit. */
|
|
103
190
|
export declare const MAX_COMMIT_ACTIONS = 100;
|
|
104
191
|
/** The most bytes one commit may carry, summed over its actions: 95% of DynamoDB's 4 MB. */
|
|
@@ -113,16 +200,24 @@ export declare function checkNotReserved(entityId: string): void;
|
|
|
113
200
|
* Checks that a commit's events can be stored as written: each belongs to the commit's entity and
|
|
114
201
|
* has the ID `{entityId}:{sequence}`, they share one entity type, the first sequence is at least
|
|
115
202
|
* 1, and the sequences are contiguous. A snapshot must have the events' entity type and a
|
|
116
|
-
* sequence of at least 1
|
|
203
|
+
* sequence of at least 1, and each projector group a size per operation. A commit with no events
|
|
204
|
+
* is valid, and its snapshot isn't checked, but its projector operations are refused.
|
|
117
205
|
*/
|
|
118
206
|
export declare function validateCommit(commit: Commit): void;
|
|
119
207
|
/**
|
|
120
208
|
* The size of each action a commit's transaction carries, in order: the feature-marker and
|
|
121
|
-
* rebuild-lock checks, then the stream's head update, its event puts,
|
|
122
|
-
* it writes one. `ttl` gives the expiry an entity type's items carry, if
|
|
123
|
-
* backend budgets a commit by these sizes, so an oversized commit fails the
|
|
209
|
+
* rebuild-lock checks, the projector operations, then the stream's head update, its event puts,
|
|
210
|
+
* and its snapshot put when it writes one. `ttl` gives the expiry an entity type's items carry, if
|
|
211
|
+
* it's retained. Every backend budgets a commit by these sizes, so an oversized commit fails the
|
|
212
|
+
* same way on each.
|
|
124
213
|
*/
|
|
125
214
|
export declare function commitSizes(commit: Commit, ttl: (entityType: string) => number | undefined): number[];
|
|
215
|
+
/**
|
|
216
|
+
* The size of each action a transaction carries: the two control checks, every stream's projector
|
|
217
|
+
* operations, every written stream's head update, event puts and snapshot put, then a check on
|
|
218
|
+
* every fenced stream's head. Every backend budgets a transaction by these sizes.
|
|
219
|
+
*/
|
|
220
|
+
export declare function transactionSizes(transaction: NormalizedTransaction, ttl: (entityType: string) => number | undefined): number[];
|
|
126
221
|
/**
|
|
127
222
|
* Refuses a commit whose actions are over the budget: more than {@link MAX_COMMIT_ACTIONS}, more
|
|
128
223
|
* than {@link MAX_COMMIT_BYTES} in all, or one over {@link MAX_COMMIT_ITEM_BYTES}.
|
package/dist/repository.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../src/repository.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../src/repository.ts"],"names":[],"mappings":"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"}
|