@event-driven-io/emmett-postgresql 0.18.0 → 0.19.0-alpha.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.
package/dist/index.cjs ADDED
@@ -0,0 +1,363 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var _dumbo = require('@event-driven-io/dumbo');require('commander');var G=(e=>(e.NOT_A_NONEMPTY_STRING="NOT_A_NONEMPTY_STRING",e.NOT_A_POSITIVE_NUMBER="NOT_A_POSITIVE_NUMBER",e.NOT_AN_UNSIGNED_BIGINT="NOT_AN_UNSIGNED_BIGINT",e))(G||{}),W=e=>typeof e=="number"&&e===e,z=e=>typeof e=="string";var U=e=>typeof e=="function"&&e.prototype&&e.prototype.constructor===e,H=class k extends Error{constructor(t){let n=t&&typeof t=="object"&&"errorCode"in t?t.errorCode:W(t)?t:500,o=t&&typeof t=="object"&&"message"in t?t.message:z(t)?t:`Error with status code '${n}' ocurred during Emmett processing`;super(o),this.errorCode=n,Object.setPrototypeOf(this,k.prototype)}},q=class Y extends H{constructor(t,n,o){super({errorCode:412,message:_nullishCoalesce(o, () => (`Expected version ${n.toString()} does not match current ${_optionalChain([t, 'optionalAccess', _2 => _2.toString, 'call', _3 => _3()])}`))}),this.current=t,this.expected=n,Object.setPrototypeOf(this,Y.prototype)}};var _uuid = require('uuid');var _asyncretry = require('async-retry'); var _asyncretry2 = _interopRequireDefault(_asyncretry);var _webstreamspolyfill = require('web-streams-polyfill');var D="STREAM_EXISTS",x="STREAM_DOES_NOT_EXIST",O="NO_CONCURRENCY_CHECK";var $=class J extends q{constructor(t,n){super(_optionalChain([t, 'optionalAccess', _4 => _4.toString, 'call', _5 => _5()]),_optionalChain([n, 'optionalAccess', _6 => _6.toString, 'call', _7 => _7()])),Object.setPrototypeOf(this,J.prototype)}};var K=(e,t,n)=>({type:e,data:t,metadata:n});var Z=e=>e;var Pe=class extends Error{constructor(e){super(`Cannot parse! ${e}`)}},P={stringify:(e,t)=>JSON.stringify(_optionalChain([t, 'optionalAccess', _8 => _8.map])?t.map(e):e,(n,o)=>typeof o=="bigint"?o.toString():o),parse:(e,t)=>{let n=JSON.parse(e,_optionalChain([t, 'optionalAccess', _9 => _9.reviver]));if(_optionalChain([t, 'optionalAccess', _10 => _10.typeCheck])&&!_optionalChain([t, 'optionalAccess', _11 => _11.typeCheck, 'call', _12 => _12(n)]))throw new Pe(e);return _optionalChain([t, 'optionalAccess', _13 => _13.map])?t.map(n):n}};var u=(e,t)=>{if(he(e))return e.equals(t);if(Array.isArray(e))return Array.isArray(t)&&e.length===t.length&&e.every((a,s)=>u(a,t[s]));if(typeof e!="object"||typeof t!="object"||e===null||t===null)return e===t;if(Array.isArray(t))return!1;let n=Object.keys(e),o=Object.keys(t);if(n.length!==o.length||!n.every(a=>o.includes(a)))return!1;for(let a in e)if(!(e[a]instanceof Function&&t[a]instanceof Function)&&!u(e[a],t[a]))return!1;return!0},he=e=>e&&typeof e=="object"&&"equals"in e&&typeof e.equals=="function";var y=class extends Error{constructor(e){super(e)}};var ee=e=>{throw new y(_nullishCoalesce(e, () => ("That should not ever happened, right?")))};var te=(e,t,n)=>{if(!u(e,t))throw new y(_nullishCoalesce(n, () => (`subObj:
2
+ ${P.stringify(t)}
3
+ is not equal to
4
+ ${P.stringify(e)}`)))};function T(e,t){if(!e)throw new y(_nullishCoalesce(t, () => ("Condition is false")))}function Ie(e,t){if(!e)throw new y(_nullishCoalesce(t, () => ("Condition is not truthy")))}function S(e,t,n){if(e!==t)throw new y(`${_nullishCoalesce(n, () => ("Objects are not equal"))}:
5
+ Expected: ${P.stringify(e)}
6
+ Actual:${P.stringify(t)}`)}function ne(e,t,n){if(e===t)throw new y(_nullishCoalesce(n, () => (`Objects are equal: ${P.stringify(e)}`)))}function j(e){ne(e,null),Ie(e)}var R=e=>({isEmpty:()=>S(e.length,0),isNotEmpty:()=>ne(e.length,0),hasSize:t=>S(e.length,t),containsElements:(...t)=>{T(t.every(n=>t.some(o=>u(n,o))))},containsExactlyInAnyOrder:(...t)=>{S(e.length,t.length),T(e.every(n=>t.some(o=>u(n,o))))},containsExactlyInAnyOrderElementsOf:t=>{S(e.length,t.length),T(e.every(n=>t.some(o=>u(n,o))))},containsExactlyElementsOf:t=>{S(e.length,t.length);for(let n=0;n<e.length;n++)T(u(e[n],t[n]))},containsExactly:t=>{S(e.length,1),T(u(e[0],t))},contains:t=>{T(e.some(n=>u(n,t)))},containsOnlyOnceElementsOf:t=>{T(t.map(n=>e.filter(o=>u(o,n)).length).filter(n=>n===1).length===t.length)},containsAnyOf:(...t)=>{T(e.some(n=>t.some(o=>u(n,o))))},allMatch:t=>{T(e.every(t))},anyMatches:t=>{T(e.some(t))},allMatchAsync:async t=>{for(let n of e)T(await t(n))}});require('pg');var _pongo = require('@event-driven-io/pongo');var A=(e,t)=>{let{pool:n,connectionString:o,inDatabase:a,inCollection:s}=t;return n.withConnection(async p=>{let m=_pongo.pongoClient.call(void 0, o,{connectionOptions:{connection:p}});try{let l=m.db(a).collection(s);return e(l)}finally{await m.close()}})},oe=e=>{let{_id:t,...n}=e;return n},Ne=(e,t)=>("_id"in t&&S(t._id,e._id,`Document ids are not matching! Expected: ${t._id}, actual: ${e._id}`),te(oe(e),oe(t))),Re= exports.documentExists =(e,t)=>n=>A(async o=>{let a=await o.findOne("withId"in t?{_id:t.withId}:t.matchingFilter);j(a),Ne(a,e)},{...t,...n}),Ae= exports.documentsAreTheSame =(e,t)=>n=>A(async o=>{let a=await o.find("withId"in t?{_id:t.withId}:t.matchingFilter);S(e.length,a.length,"Different Documents Count than expected");for(let s=0;s<e.length;s++)R(a).contains(e[s])},{...t,...n}),Le= exports.documentsMatchingHaveCount =(e,t)=>n=>A(async o=>{let a=await o.find("withId"in t?{_id:t.withId}:t.matchingFilter);S(e,a.length,"Different Documents Count than expected")},{...t,...n}),ae= exports.documentMatchingExists =e=>t=>A(async n=>{let o=await n.find("withId"in e?{_id:e.withId}:e.matchingFilter);R(o).isNotEmpty()},{...e,...t}),re= exports.documentDoesNotExist =e=>t=>A(async n=>{let o=await n.findOne("withId"in e?{_id:e.withId}:e.matchingFilter);j(o)},{...e,...t}),Pt= exports.expectPongoDocuments ={fromCollection:e=>({withId:t=>({toBeEqual:n=>Re(n,{withId:t,inCollection:e}),toExist:()=>ae({withId:t,inCollection:e}),notToExist:()=>re({withId:t,inCollection:e})}),matching:t=>({toBeTheSame:n=>Ae(n,{matchingFilter:t,inCollection:e}),toHaveCount:n=>Le(n,{matchingFilter:t,inCollection:e}),toExist:()=>ae({matchingFilter:t,inCollection:e}),notToExist:()=>re({matchingFilter:t,inCollection:e})})})};var xe=({handle:e,canHandle:t})=>Q({canHandle:t,handle:async(n,o)=>{let{connectionString:a,client:s}=o,p=_pongo.pongoClient.call(void 0, a,{connectionOptions:{client:s}});await e(n,{...o,pongo:p})}}),Ce= exports.pongoMultiStreamProjection =e=>{let{collectionName:t,getDocumentId:n,canHandle:o}=e;return xe({handle:async(a,{pongo:s})=>{let p=s.db().collection(t);for(let m of a)await p.handle(n(m),async l=>"initialState"in e?await e.evolve(_nullishCoalesce(l, () => (e.initialState())),m):await e.evolve(l,m))},canHandle:o})},Rt= exports.pongoSingleStreamProjection =e=>Ce({...e,getDocumentId:t=>t.metadata.streamName});var Ft={for:e=>{{let{projection:t,...n}=e,{connectionString:o}=n;return a=>({when:(s,p)=>{let m=[],l=async c=>{let E=0n,d=_nullishCoalesce(_optionalChain([p, 'optionalAccess', _14 => _14.numberOfTimes]), () => (1));for(let _ of[...a,...Array.from({length:d}).flatMap(()=>s)])m.push({..._,metadata:{globalPosition:++E,streamPosition:E,streamName:`test-${_uuid.v4.call(void 0, )}`,eventId:_uuid.v4.call(void 0, ),..._nullishCoalesce(_.metadata, () => ({}))}});await c.withTransaction(_=>C({events:m,projections:[t],connection:{connectionString:o,transaction:_}}))};return{then:async(c,E)=>{let d=_dumbo.dumbo.call(void 0, n);try{await l(d);let _=await c({pool:d,connectionString:o});_!==void 0&&_===!1&&ee(_nullishCoalesce(E, () => ("Projection specification didn't match the criteria")))}finally{await d.close()}},thenThrows:async(...c)=>{let E=_dumbo.dumbo.call(void 0, n);try{throw await l(E),new y("Handler did not fail as expected")}catch(d){if(d instanceof y)throw d;if(c.length===0)return;if(!U(c[0])){T(c[0](d),`Error didn't match the error condition: ${_optionalChain([d, 'optionalAccess', _15 => _15.toString, 'call', _16 => _16()])}`);return}T(d instanceof c[0],`Caught error is not an instance of the expected type: ${_optionalChain([d, 'optionalAccess', _17 => _17.toString, 'call', _18 => _18()])}`),c[1]&&T(c[1](d),`Error didn't match the error condition: ${_optionalChain([d, 'optionalAccess', _19 => _19.toString, 'call', _20 => _20()])}`)}finally{await E.close()}}}}})}}},we= exports.eventInStream =(e,t)=>({...t,metadata:{..._nullishCoalesce(t.metadata, () => ({})),streamName:_nullishCoalesce(_optionalChain([t, 'access', _21 => _21.metadata, 'optionalAccess', _22 => _22.streamName]), () => (e))}}),be= exports.eventsInStream =(e,t)=>t.map(n=>we(e,n)),Ut= exports.newEventsInStream =be,Me= exports.assertSQLQueryResultMatches =(e,t)=>async({pool:{execute:n}})=>{let o=await n.query(e);R(t).containsExactlyInAnyOrder(...o.rows)},$t= exports.expectSQL ={query:e=>({resultRows:{toBeTheSame:t=>Me(e,t)}})};var C=async e=>{let{projections:t,events:n,connection:{transaction:o,connectionString:a}}=e,s=n.map(l=>l.type),p=t.filter(l=>l.canHandle.some(c=>s.includes(c))),m=await o.connection.open();for(let l of p)await l.handle(n,{connectionString:a,client:m,transaction:o,execute:o.execute})},Q= exports.postgreSQLProjection =e=>Z(e),Fe= exports.postgreSQLRawBatchSQLProjection =(e,...t)=>Q({canHandle:t,handle:async(n,o)=>{let a=await e(n,o);await o.execute.batchCommand(a)}}),Xt= exports.postgreSQLRawSQLProjection =(e,...t)=>Fe(async(n,o)=>{let a=[];for(let s of n)a.push(await e(s,o));return a},...t);var w="emt",v= exports.globalTag ="global",N= exports.defaultTag ="emt:default",zt= exports.globalNames ={module:`${w}:module:${v}`,tenant:`${w}:tenant:${v}`},b={partition:{name:"partition"},isArchived:{name:"is_archived"}},i= exports.streamsTable ={name:`${w}_streams`,columns:{partition:b.partition,isArchived:b.isArchived}},r= exports.eventsTable ={name:`${w}_events`,columns:{partition:b.partition,isArchived:b.isArchived}};var ce=_dumbo.rawSql.call(void 0, `CREATE OR REPLACE FUNCTION emt_append_event(
7
+ v_event_ids text[],
8
+ v_events_data jsonb[],
9
+ v_events_metadata jsonb[],
10
+ v_event_schema_versions text[],
11
+ v_event_types text[],
12
+ v_stream_id text,
13
+ v_stream_type text,
14
+ v_expected_stream_position bigint DEFAULT NULL,
15
+ v_partition text DEFAULT emt_sanitize_name('default_partition')
16
+ ) RETURNS TABLE (
17
+ success boolean,
18
+ next_stream_position bigint,
19
+ last_global_position bigint,
20
+ transaction_id xid8
21
+ ) LANGUAGE plpgsql
22
+ AS $$
23
+ DECLARE
24
+ v_next_stream_position bigint;
25
+ v_position bigint;
26
+ v_updated_rows int;
27
+ v_transaction_id xid8;
28
+ v_last_global_position bigint;
29
+ BEGIN
30
+ IF v_expected_stream_position IS NULL THEN
31
+ SELECT COALESCE(max(stream_position), 0) INTO v_expected_stream_position
32
+ FROM ${i.name}
33
+ WHERE stream_id = v_stream_id AND partition = v_partition;
34
+ END IF;
35
+
36
+ v_next_stream_position := v_expected_stream_position + array_upper(v_events_data, 1);
37
+ v_transaction_id := pg_current_xact_id();
38
+
39
+ WITH ev AS (
40
+ SELECT row_number() OVER () + v_expected_stream_position AS stream_position,
41
+ event_data,
42
+ event_metadata,
43
+ schema_version,
44
+ event_id,
45
+ event_type
46
+ FROM (
47
+ SELECT *
48
+ FROM
49
+ unnest(v_event_ids, v_events_data, v_events_metadata, v_event_schema_versions, v_event_types)
50
+ AS event(event_id, event_data, event_metadata, schema_version, event_type)
51
+ ) AS event
52
+ ),
53
+ all_events_insert AS (
54
+ INSERT INTO ${r.name}
55
+ (stream_id, stream_position, partition, event_data, event_metadata, event_schema_version, event_type, event_id, transaction_id)
56
+ SELECT
57
+ v_stream_id, ev.stream_position, v_partition, ev.event_data, ev.event_metadata, ev.schema_version, ev.event_type, ev.event_id, v_transaction_id
58
+ FROM ev
59
+ RETURNING global_position
60
+ )
61
+ SELECT
62
+ max(global_position) INTO v_last_global_position
63
+ FROM
64
+ all_events_insert;
65
+
66
+
67
+ IF v_expected_stream_position = 0 THEN
68
+ INSERT INTO ${i.name}
69
+ (stream_id, stream_position, partition, stream_type, stream_metadata, is_archived)
70
+ VALUES
71
+ (v_stream_id, v_next_stream_position, v_partition, v_stream_type, '{}', FALSE);
72
+ ELSE
73
+ UPDATE ${i.name} as s
74
+ SET stream_position = v_next_stream_position
75
+ WHERE stream_id = v_stream_id AND stream_position = v_expected_stream_position AND partition = v_partition AND is_archived = FALSE;
76
+
77
+ get diagnostics v_updated_rows = row_count;
78
+
79
+ IF v_updated_rows = 0 THEN
80
+ RETURN QUERY SELECT FALSE, NULL::bigint, NULL::bigint, NULL::xid8;
81
+ RETURN;
82
+ END IF;
83
+ END IF;
84
+
85
+ RETURN QUERY SELECT TRUE, v_next_stream_position, v_last_global_position, v_transaction_id;
86
+ END;
87
+ $$;
88
+ `),me= exports.appendToStream =(e,t,n,o,a)=>e.withTransaction(async s=>{let{execute:p}=s;if(o.length===0)return{success:!1,result:{success:!1}};let m;try{let _=Qe(_optionalChain([a, 'optionalAccess', _23 => _23.expectedStreamVersion])),h=o.map((I,f)=>({...I,metadata:{streamName:t,eventId:_uuid.v4.call(void 0, ),streamPosition:BigInt(f),...I.metadata}}));m=await Xe(p,t,n,h,{expectedStreamVersion:_}),_optionalChain([a, 'optionalAccess', _24 => _24.preCommitHook])&&await a.preCommitHook(h,{transaction:s})}catch(_){if(!Be(_))throw _;m={success:!1,last_global_position:null,next_stream_position:null,transaction_id:null}}let{success:l,next_stream_position:c,last_global_position:E,transaction_id:d}=m;return{success:l,result:l&&c&&E&&d?{success:!0,nextStreamPosition:BigInt(c),lastGlobalPosition:BigInt(E),transactionId:d}:{success:!1}}}),Qe=e=>e===void 0||e===O||e==x||e==D?null:e,Be=e=>e instanceof Error&&"code"in e&&e.code==="23505",Xe=(e,t,n,o,a)=>_dumbo.single.call(void 0, e.command(_dumbo.sql.call(void 0, `SELECT * FROM emt_append_event(
89
+ ARRAY[%s]::text[],
90
+ ARRAY[%s]::jsonb[],
91
+ ARRAY[%s]::jsonb[],
92
+ ARRAY[%s]::text[],
93
+ ARRAY[%s]::text[],
94
+ %L::text,
95
+ %L::text,
96
+ %s::bigint,
97
+ %L::text
98
+ )`,o.map(s=>_dumbo.sql.call(void 0, "%L",s.metadata.eventId)).join(","),o.map(s=>_dumbo.sql.call(void 0, "%L",P.stringify(s.data))).join(","),o.map(s=>_dumbo.sql.call(void 0, "%L",P.stringify(_nullishCoalesce(s.metadata, () => ({}))))).join(","),o.map(()=>"'1'").join(","),o.map(s=>_dumbo.sql.call(void 0, "%L",s.type)).join(","),t,n,_nullishCoalesce(_optionalChain([a, 'optionalAccess', _25 => _25.expectedStreamVersion]), () => ("NULL")),_nullishCoalesce(_optionalChain([a, 'optionalAccess', _26 => _26.partition]), () => (N)))));var de=_dumbo.rawSql.call(void 0, `CREATE TABLE IF NOT EXISTS ${i.name}(
99
+ stream_id TEXT NOT NULL,
100
+ stream_position BIGINT NOT NULL,
101
+ partition TEXT NOT NULL DEFAULT '${v}__${v}',
102
+ stream_type TEXT NOT NULL,
103
+ stream_metadata JSONB NOT NULL,
104
+ is_archived BOOLEAN NOT NULL DEFAULT FALSE,
105
+ PRIMARY KEY (stream_id, stream_position, partition, is_archived),
106
+ UNIQUE (stream_id, partition, is_archived)
107
+ ) PARTITION BY LIST (partition);`),le= exports.eventsTableSQL =_dumbo.rawSql.call(void 0, `
108
+ CREATE SEQUENCE IF NOT EXISTS emt_global_event_position;
109
+
110
+ CREATE TABLE IF NOT EXISTS ${r.name}(
111
+ stream_id TEXT NOT NULL,
112
+ stream_position BIGINT NOT NULL,
113
+ partition TEXT NOT NULL DEFAULT '${v}',
114
+ event_data JSONB NOT NULL,
115
+ event_metadata JSONB NOT NULL,
116
+ event_schema_version TEXT NOT NULL,
117
+ event_type TEXT NOT NULL,
118
+ event_id TEXT NOT NULL,
119
+ is_archived BOOLEAN NOT NULL DEFAULT FALSE,
120
+ global_position BIGINT DEFAULT nextval('emt_global_event_position'),
121
+ transaction_id XID8 NOT NULL,
122
+ created TIMESTAMPTZ NOT NULL DEFAULT now(),
123
+ PRIMARY KEY (stream_id, stream_position, partition, is_archived)
124
+ ) PARTITION BY LIST (partition);`),Ee= exports.subscriptionsTableSQL =_dumbo.rawSql.call(void 0, `
125
+ CREATE TABLE IF NOT EXISTS emt_subscriptions(
126
+ subscription_id TEXT NOT NULL PRIMARY KEY,
127
+ version INT NOT NULL DEFAULT 1,
128
+ module TEXT NULL,
129
+ tenant TEXT NULL,
130
+ last_processed_position BIGINT NOT NULL,
131
+ last_processed_transaction_id BIGINT NOT NULL
132
+ );
133
+ `),pe= exports.sanitizeNameSQL =_dumbo.rawSql.call(void 0, `CREATE OR REPLACE FUNCTION emt_sanitize_name(input_name TEXT) RETURNS TEXT AS $$
134
+ BEGIN
135
+ RETURN REGEXP_REPLACE(input_name, '[^a-zA-Z0-9_]', '_', 'g');
136
+ END;
137
+ $$ LANGUAGE plpgsql;`),_e= exports.addTablePartitions =_dumbo.rawSql.call(void 0, `
138
+ CREATE OR REPLACE FUNCTION emt_add_table_partition(tableName TEXT, partition_name TEXT) RETURNS void AS $$
139
+ DECLARE
140
+ v_main_partiton_name TEXT;
141
+ v_active_partiton_name TEXT;
142
+ v_archived_partiton_name TEXT;
143
+ BEGIN
144
+ v_main_partiton_name := emt_sanitize_name(tableName || '_' || partition_name);
145
+ v_active_partiton_name := emt_sanitize_name(v_main_partiton_name || '_active');
146
+ v_archived_partiton_name := emt_sanitize_name(v_main_partiton_name || '_archived');
147
+
148
+ -- create default events partition
149
+ EXECUTE format('
150
+ CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
151
+ FOR VALUES IN (%L) PARTITION BY LIST (is_archived);',
152
+ v_main_partiton_name, tableName, partition_name
153
+ );
154
+
155
+ -- create default streams partition
156
+ EXECUTE format('
157
+ CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
158
+ FOR VALUES IN (%L) PARTITION BY LIST (is_archived);',
159
+ v_main_partiton_name, tableName, partition_name
160
+ );
161
+
162
+ EXECUTE format('
163
+ CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
164
+ FOR VALUES IN (FALSE);',
165
+ v_active_partiton_name, v_main_partiton_name
166
+ );
167
+
168
+ EXECUTE format('
169
+ CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
170
+ FOR VALUES IN (TRUE);',
171
+ v_archived_partiton_name, v_main_partiton_name
172
+ );
173
+ END;
174
+ $$ LANGUAGE plpgsql;`),ve= exports.addEventsPartitions =_dumbo.rawSql.call(void 0, `
175
+ CREATE OR REPLACE FUNCTION emt_add_partition(partition_name TEXT) RETURNS void AS $$
176
+ BEGIN
177
+ PERFORM emt_add_table_partition('${r.name}', partition_name);
178
+ PERFORM emt_add_table_partition('${i.name}', partition_name);
179
+ END;
180
+ $$ LANGUAGE plpgsql;`),Te= exports.addModuleSQL =_dumbo.rawSql.call(void 0, `
181
+ CREATE OR REPLACE FUNCTION add_module(new_module TEXT) RETURNS void AS $$
182
+ BEGIN
183
+ -- For ${r.name} table
184
+ EXECUTE format('
185
+ CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
186
+ FOR VALUES IN (emt_sanitize_name(%L || ''__'' || %L)) PARTITION BY LIST (is_archived);',
187
+ emt_sanitize_name('${r.name}_' || new_module || '__' || '${v}'), '${r.name}', new_module, '${v}'
188
+ );
189
+
190
+ EXECUTE format('
191
+ CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I
192
+ FOR VALUES IN (FALSE);',
193
+ emt_sanitize_name('${r.name}_' || new_module || '__' || '${v}' || '_active'), emt_sanitize_name('${r.name}_' || new_module || '__' || '${v}')
194
+ );
195
+
196
+ EXECUTE format('
197
+ CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I
198
+ FOR VALUES IN (TRUE);',
199
+ emt_sanitize_name('${r.name}_' || new_module || '__' || '${v}' || '_archived'), emt_sanitize_name('${r.name}_' || new_module || '__' || '${v}')
200
+ );
201
+
202
+ -- For ${i.name} table
203
+ EXECUTE format('
204
+ CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
205
+ FOR VALUES IN (emt_sanitize_name(%L || ''__'' || %L)) PARTITION BY LIST (is_archived);',
206
+ emt_sanitize_name('${i.name}_' || new_module || '__' || '${v}'), '${i.name}', new_module, '${v}'
207
+ );
208
+
209
+ EXECUTE format('
210
+ CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I
211
+ FOR VALUES IN (FALSE);',
212
+ emt_sanitize_name('${i.name}_' || new_module || '__' || '${v}' || '_active'), emt_sanitize_name('${i.name}_' || new_module || '__' || '${v}')
213
+ );
214
+
215
+ EXECUTE format('
216
+ CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I
217
+ FOR VALUES IN (TRUE);',
218
+ emt_sanitize_name('${i.name}_' || new_module || '__' || '${v}' || '_archived'), emt_sanitize_name('${i.name}_' || new_module || '__' || '${v}')
219
+ );
220
+ END;
221
+ $$ LANGUAGE plpgsql;
222
+ `),ue= exports.addTenantSQL =_dumbo.rawSql.call(void 0, `
223
+ CREATE OR REPLACE FUNCTION add_tenant(new_module TEXT, new_tenant TEXT) RETURNS void AS $$
224
+ BEGIN
225
+ -- For ${r.name} table
226
+ EXECUTE format('
227
+ CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
228
+ FOR VALUES IN (emt_sanitize_name(''%s__%s'')) PARTITION BY LIST (is_archived);',
229
+ emt_sanitize_name('${r.name}_' || new_module || '__' || new_tenant), '${r.name}', new_module, new_tenant
230
+ );
231
+
232
+ EXECUTE format('
233
+ CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I
234
+ FOR VALUES IN (FALSE);',
235
+ emt_sanitize_name('${r.name}_' || new_module || '__' || new_tenant || '_active'), emt_sanitize_name('${r.name}_' || new_module || '__' || new_tenant)
236
+ );
237
+
238
+ EXECUTE format('
239
+ CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I
240
+ FOR VALUES IN (TRUE);',
241
+ emt_sanitize_name('${r.name}_' || new_module || '__' || new_tenant || '_archived'), emt_sanitize_name('${r.name}_' || new_module || '__' || new_tenant)
242
+ );
243
+
244
+ -- For ${i.name} table
245
+ EXECUTE format('
246
+ CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
247
+ FOR VALUES IN (emt_sanitize_name(''%s__%s'')) PARTITION BY LIST (is_archived);',
248
+ emt_sanitize_name('${i.name}_' || new_module || '__' || new_tenant), '${i.name}', new_module, new_tenant
249
+ );
250
+
251
+ EXECUTE format('
252
+ CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I
253
+ FOR VALUES IN (FALSE);',
254
+ emt_sanitize_name('${i.name}_' || new_module || '__' || new_tenant || '_active'), emt_sanitize_name('${i.name}_' || new_module || '__' || new_tenant)
255
+ );
256
+
257
+ EXECUTE format('
258
+ CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I
259
+ FOR VALUES IN (TRUE);',
260
+ emt_sanitize_name('${i.name}_' || new_module || '__' || new_tenant || '_archived'), emt_sanitize_name('${i.name}_' || new_module || '__' || new_tenant)
261
+ );
262
+ END;
263
+ $$ LANGUAGE plpgsql;
264
+ `),ge= exports.addModuleForAllTenantsSQL =_dumbo.rawSql.call(void 0, `
265
+ CREATE OR REPLACE FUNCTION add_module_for_all_tenants(new_module TEXT) RETURNS void AS $$
266
+ DECLARE
267
+ tenant_record RECORD;
268
+ BEGIN
269
+ PERFORM add_module(new_module);
270
+
271
+ FOR tenant_record IN SELECT DISTINCT tenant FROM ${r.name}
272
+ LOOP
273
+ -- For ${r.name} table
274
+ EXECUTE format('
275
+ CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
276
+ FOR VALUES IN (emt_sanitize_name(''%s__%s'')) PARTITION BY LIST (is_archived);',
277
+ emt_sanitize_name('${r.name}_' || new_module || '__' || tenant_record.tenant), '${r.name}', new_module, tenant_record.tenant
278
+ );
279
+
280
+ EXECUTE format('
281
+ CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I
282
+ FOR VALUES IN (FALSE);',
283
+ emt_sanitize_name('${r.name}_' || new_module || '__' || tenant_record.tenant || '_active'), emt_sanitize_name('${r.name}_' || new_module || '__' || tenant_record.tenant)
284
+ );
285
+
286
+ EXECUTE format('
287
+ CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I
288
+ FOR VALUES IN (TRUE);',
289
+ emt_sanitize_name('${r.name}_' || new_module || '__' || tenant_record.tenant || '_archived'), emt_sanitize_name('${r.name}_' || new_module || '__' || tenant_record.tenant)
290
+ );
291
+
292
+ -- For ${i.name} table
293
+ EXECUTE format('
294
+ CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
295
+ FOR VALUES IN (emt_sanitize_name(''%s__%s'')) PARTITION BY LIST (is_archived);',
296
+ emt_sanitize_name('${i.name}_' || new_module || '__' || tenant_record.tenant), '${i.name}', new_module, tenant_record.tenant
297
+ );
298
+
299
+ EXECUTE format('
300
+ CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I
301
+ FOR VALUES IN (FALSE);',
302
+ emt_sanitize_name('${i.name}_' || new_module || '__' || tenant_record.tenant || '_active'), emt_sanitize_name('${i.name}_' || new_module || '__' || tenant_record.tenant)
303
+ );
304
+
305
+ EXECUTE format('
306
+ CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I
307
+ FOR VALUES IN (TRUE);',
308
+ emt_sanitize_name('${i.name}_' || new_module || '__' || tenant_record.tenant || '_archived'), emt_sanitize_name('${i.name}_' || new_module || '__' || tenant_record.tenant)
309
+ );
310
+ END LOOP;
311
+ END;
312
+ $$ LANGUAGE plpgsql;
313
+ `),Se= exports.addTenantForAllModulesSQL =_dumbo.rawSql.call(void 0, `
314
+ CREATE OR REPLACE FUNCTION add_tenant_for_all_modules(new_tenant TEXT) RETURNS void AS $$
315
+ DECLARE
316
+ module_record RECORD;
317
+ BEGIN
318
+ FOR module_record IN SELECT DISTINCT partitionname FROM pg_partman.part_config WHERE parent_table = '${r.name}'
319
+ LOOP
320
+ -- For ${r.name} table
321
+ EXECUTE format('
322
+ CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
323
+ FOR VALUES IN (emt_sanitize_name(''%s__%s'')) PARTITION BY LIST (is_archived);',
324
+ emt_sanitize_name('${r.name}_' || module_record.partitionname || '__' || new_tenant), '${r.name}', module_record.partitionname, new_tenant
325
+ );
326
+
327
+ EXECUTE format('
328
+ CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I
329
+ FOR VALUES IN (FALSE);',
330
+ emt_sanitize_name('${r.name}_' || module_record.partitionname || '__' || new_tenant || '_active'), emt_sanitize_name('${r.name}_' || module_record.partitionname || '__' || new_tenant)
331
+ );
332
+
333
+ EXECUTE format('
334
+ CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I
335
+ FOR VALUES IN (TRUE);',
336
+ emt_sanitize_name('${r.name}_' || module_record.partitionname || '__' || new_tenant || '_archived'), emt_sanitize_name('${r.name}_' || module_record.partitionname || '__' || new_tenant)
337
+ );
338
+
339
+ -- For ${i.name} table
340
+ EXECUTE format('
341
+ CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
342
+ FOR VALUES IN (emt_sanitize_name(''%s__%s'')) PARTITION BY LIST (is_archived);',
343
+ emt_sanitize_name('${i.name}_' || module_record.partitionname || '__' || new_tenant), '${i.name}', module_record.partitionname, new_tenant
344
+ );
345
+
346
+ EXECUTE format('
347
+ CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I
348
+ FOR VALUES IN (FALSE);',
349
+ emt_sanitize_name('${i.name}_' || module_record.partitionname || '__' || new_tenant || '_active'), emt_sanitize_name('${i.name}_' || module_record.partitionname || '__' || new_tenant)
350
+ );
351
+
352
+ EXECUTE format('
353
+ CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I
354
+ FOR VALUES IN (TRUE);',
355
+ emt_sanitize_name('${i.name}_' || module_record.partitionname || '__' || new_tenant || '_archived'), emt_sanitize_name('${i.name}_' || module_record.partitionname || '__' || new_tenant)
356
+ );
357
+ END LOOP;
358
+ END;
359
+ $$ LANGUAGE plpgsql;
360
+ `),ye= exports.addDefaultPartition =_dumbo.rawSql.call(void 0, `SELECT emt_add_partition('${N}');`);var fe=async(e,t,n)=>{let o=n&&"from"in n?`AND stream_position >= ${n.from}`:"",a=Number(n&&"to"in n?n.to:n&&"maxCount"in n&&n.maxCount?n.from+n.maxCount:NaN),s=isNaN(a)?"":`AND stream_position <= ${a}`,p=await _dumbo.mapRows.call(void 0, e.query(_dumbo.sql.call(void 0, `SELECT stream_id, stream_position, global_position, event_data, event_metadata, event_schema_version, event_type, event_id
361
+ FROM ${r.name}
362
+ WHERE stream_id = %L AND partition = %L AND is_archived = FALSE ${o} ${s}`,t,_nullishCoalesce(_optionalChain([n, 'optionalAccess', _27 => _27.partition]), () => (N)))),m=>{let l=K(m.event_type,m.event_data,m.event_metadata);return{...l,metadata:{...l.metadata,eventId:m.event_id,streamName:t,streamPosition:BigInt(m.stream_position),globalPosition:BigInt(m.global_position)}}});return p.length>0?{currentStreamVersion:p[p.length-1].metadata.streamPosition,events:p}:null};var M=[de,le,Ee,pe,_e,ve,Te,ue,ge,Se,ce,ye],B= exports.createEventStoreSchema =async e=>{await e.withTransaction(({execute:t})=>t.batchCommand(M))};var ze={projections:[],schema:{autoMigration:"CreateOrUpdate"}},He= exports.getPostgreSQLEventStore =(e,t=ze)=>{let n={connectionString:e,...t.connectionOptions?t.connectionOptions:{}},o="dumbo"in n?n.dumbo:_dumbo.dumbo.call(void 0, n),a,s=_optionalChain([t, 'access', _28 => _28.schema, 'optionalAccess', _29 => _29.autoMigration])===void 0||_optionalChain([t, 'access', _30 => _30.schema, 'optionalAccess', _31 => _31.autoMigration])!=="None",p=()=>s?(a||(a=B(o)),a):Promise.resolve(),m=(_nullishCoalesce(t.projections, () => ([]))).filter(({type:c})=>c==="inline").map(({projection:c})=>c),l=m.length>0?(c,{transaction:E})=>C({projections:m,connection:{connectionString:e,transaction:E},events:c}):void 0;return{schema:{sql:()=>M.join(""),print:()=>console.log(M.join("")),migrate:async()=>{await(a=B(o))}},async aggregateStream(c,E){let{evolve:d,initialState:_,read:h}=E,I=_optionalChain([h, 'optionalAccess', _32 => _32.expectedStreamVersion]),f=_(),F=await this.readStream(c,E.read);if(F===null)return null;let X=F.currentStreamVersion;qe(X,I);for(let V of F.events)V&&(f=d(f,V));return{currentStreamVersion:X,state:f}},readStream:async(c,E)=>(await p(),fe(o.execute,c,E)),appendToStream:async(c,E,d)=>{await p();let[_,...h]=c.split("-"),I=_&&h.length>0?_:"emt:unknown",f=await me(o,c,I,E,{...d,preCommitHook:l});if(!f.success)throw new $(-1n,_nullishCoalesce(_optionalChain([d, 'optionalAccess', _33 => _33.expectedStreamVersion]), () => (O)));return{nextExpectedStreamVersion:f.nextStreamPosition}},close:()=>o.close(),async withSession(c){return await o.withConnection(async E=>{let d={...t,connectionOptions:{connection:E}},_=He(e,d);return c({eventStore:_,close:()=>Promise.resolve()})})}}},ke=(e,t)=>t===O?!0:t==x?e===void 0:t==D?e!==void 0:e===t,qe=(e,t)=>{if(t??=O,!ke(e,t))throw new $(e,t)};exports.PostgreSQLProjectionSpec = Ft; exports.addDefaultPartition = ye; exports.addEventsPartitions = ve; exports.addModuleForAllTenantsSQL = ge; exports.addModuleSQL = Te; exports.addTablePartitions = _e; exports.addTenantForAllModulesSQL = Se; exports.addTenantSQL = ue; exports.appendEventsSQL = ce; exports.appendToStream = me; exports.assertSQLQueryResultMatches = Me; exports.createEventStoreSchema = B; exports.defaultPostgreSQLOptions = ze; exports.defaultTag = N; exports.documentDoesNotExist = re; exports.documentExists = Re; exports.documentMatchingExists = ae; exports.documentsAreTheSame = Ae; exports.documentsMatchingHaveCount = Le; exports.emmettPrefix = w; exports.eventInStream = we; exports.eventsInStream = be; exports.eventsTable = r; exports.eventsTableSQL = le; exports.expectPongoDocuments = Pt; exports.expectSQL = $t; exports.getPostgreSQLEventStore = He; exports.globalNames = zt; exports.globalTag = v; exports.handleProjections = C; exports.newEventsInStream = Ut; exports.pongoMultiStreamProjection = Ce; exports.pongoProjection = xe; exports.pongoSingleStreamProjection = Rt; exports.postgreSQLProjection = Q; exports.postgreSQLRawBatchSQLProjection = Fe; exports.postgreSQLRawSQLProjection = Xt; exports.readStream = fe; exports.sanitizeNameSQL = pe; exports.schemaSQL = M; exports.streamsTable = i; exports.streamsTableSQL = de; exports.subscriptionsTableSQL = Ee;
363
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/eventStore/postgreSQLEventStore.ts","../../emmett/src/config/plugins/index.ts","../../emmett/src/validation/index.ts","../../emmett/src/errors/index.ts","../../emmett/src/testing/assertions.ts","/home/runner/work/emmett/emmett/src/packages/emmett-postgresql/dist/index.cjs","../src/eventStore/schema/appendToStream.ts","../src/eventStore/schema/tables.ts","../src/eventStore/schema/readStream.ts"],"names":["ValidationErrors","isNumber","val","isString","isErrorConstructor","expect","EmmettError","_EmmettError","options","errorCode","message","ConcurrencyError","_ConcurrencyError","current","expected","a","streamType"],"mappings":"AAAA,g0BAOO,qBCP+B,ICEpBA,CAAAA,CAAAA,CAAAA,CAAAA,EAAAA,CAChBA,CAAAA,CAAA,qBAAA,CAAwB,uBAAA,CACxBA,CAAAA,CAAA,qBAAA,CAAwB,uBAAA,CACxBA,CAAAA,CAAA,sBAAA,CAAyB,wBAAA,CAHTA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,EAAA,CAAA,CAAA,CAAA,CAMLC,CAAAA,CAAYC,CAAAA,EACvB,OAAOA,CAAAA,EAAQ,QAAA,EAAYA,CAAAA,GAAQA,CAAAA,CAExBC,CAAAA,CAAYD,CAAAA,EACvB,OAAOA,CAAAA,EAAQ,QAAA,CCLV,IAAME,CAAAA,CAEXC,CAAAA,EAIE,OAAOA,CAAAA,EAAW,UAAA,EAClBA,CAAAA,CAAO,SAAA,EAEPA,CAAAA,CAAO,SAAA,CAAU,WAAA,GAAgBA,CAAAA,CAIxBC,CAAAA,CAAN,MAAMC,EAAAA,QAAoB,KAAM,CAC9B,WAEP,CACEC,CAAAA,CACA,CACA,IAAMC,CAAAA,CACJD,CAAAA,EAAW,OAAOA,CAAAA,EAAY,QAAA,EAAY,WAAA,GAAeA,CAAAA,CACrDA,CAAAA,CAAQ,SAAA,CACRP,CAAAA,CAASO,CAAO,CAAA,CACdA,CAAAA,CACA,GAAA,CACFE,CAAAA,CACJF,CAAAA,EAAW,OAAOA,CAAAA,EAAY,QAAA,EAAY,SAAA,GAAaA,CAAAA,CACnDA,CAAAA,CAAQ,OAAA,CACRL,CAAAA,CAASK,CAAO,CAAA,CACdA,CAAAA,CACA,CAAA,wBAAA,EAA2BC,CAAS,CAAA,kCAAA,CAAA,CAE5C,KAAA,CAAMC,CAAO,CAAA,CACb,IAAA,CAAK,SAAA,CAAYD,CAAAA,CAGjB,MAAA,CAAO,cAAA,CAAe,IAAA,CAAMF,CAAAA,CAAY,SAAS,CACnD,CACF,CAAA,CAEaI,CAAAA,CAAN,MAAMC,EAAAA,QAAyBN,CAAY,CAChD,WAAA,CACSO,CAAAA,CACAC,CAAAA,CACPJ,CAAAA,CACA,CACA,KAAA,CAAM,CACJ,SAAA,CAAW,GAAA,CACX,OAAA,kBACEA,CAAAA,SACA,CAAA,iBAAA,EAAoBI,CAAAA,CAAS,QAAA,CAAS,CAAC,CAAA,wBAAA,kBAA2BD,CAAAA,6BAAS,QAAA,mBAAS,GAAC,CAAA,GAAA;ACkB3C;ACzEyvB;AD2HhwB;AAA8C,UAAA;AA+IzBE,OAAAA;AEtP9D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA0BgC,eAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsBM,sBAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAcC,sBAAA;AAAA;AAAA;AAAA;AAAA;AAKL,iBAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgJlCC,EAAAA;AAUM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AC/OyC,eAAA;AAAA;AAAA;AAG4C,oEAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAU3F,kCAAA;AAAA;AAAA;AAG6C,6BAAA;AAAA;AAAA;AAGqC,yEAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAelF,kCAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaA;AAAA;AAAA;AAAA;AAQA,wBAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyCA,sBAAA;AAAA;AAAA;AAGuD,uCAAA;AACC,uCAAA;AAAA;AAMxD,sBAAA;AAAA;AAAA;AAGiC,iBAAA;AAAA;AAAA;AAAA;AAI6G,iCAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAM4C,iCAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAME,iCAAA;AAAA;AAAA;AAG1J,iBAAA;AAAA;AAAA;AAAA;AAI8G,iCAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAM4C,iCAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAME,iCAAA;AAAA;AAAA;AAAA;AAQ9L,IAAA;AAAA;AAAA;AAG+B,eAAA;AAAA;AAAA;AAAA;AAI6E,+BAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAM+B,+BAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAME,+BAAA;AAAA;AAAA;AAG7G,eAAA;AAAA;AAAA;AAAA;AAI8E,+BAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAM+B,+BAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAME,+BAAA;AAAA;AAAA;AAAA;AAQ/I,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOyE,yDAAA;AAAA;AAEtC,mBAAA;AAAA;AAAA;AAAA;AAIuF,mCAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAM+B,mCAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAME,mCAAA;AAAA;AAAA;AAGvH,mBAAA;AAAA;AAAA;AAAA;AAIwF,mCAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAM+B,mCAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAME,mCAAA;AAAA;AAAA;AAAA;AAAA;AAS7J,EAAA;AAAA;AAAA;AAAA;AAAA;AAK6H,6GAAA;AAAA;AAE1F,mBAAA;AAAA;AAAA;AAAA;AAI8F,mCAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAM+B,mCAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAME,mCAAA;AAAA;AAAA;AAG9H,mBAAA;AAAA;AAAA;AAAA;AAI+F,mCAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAM+B,mCAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAME,mCAAA;AAAA;AAAA;AAAA;AAAA;AChP5J,EAAA;AACwB,gBAAA;AR8FU,2EAAA","file":"/home/runner/work/emmett/emmett/src/packages/emmett-postgresql/dist/index.cjs","sourcesContent":["import {\n dumbo,\n type MigrationStyle,\n type NodePostgresClientConnection,\n type NodePostgresConnector,\n type NodePostgresPool,\n type NodePostgresPoolClientConnection,\n} from '@event-driven-io/dumbo';\nimport {\n ExpectedVersionConflictError,\n NO_CONCURRENCY_CHECK,\n STREAM_DOES_NOT_EXIST,\n STREAM_EXISTS,\n type AggregateStreamOptions,\n type AggregateStreamResult,\n type AppendToStreamOptions,\n type AppendToStreamResult,\n type DefaultStreamVersionType,\n type Event,\n type EventStore,\n type EventStoreSession,\n type EventStoreSessionFactory,\n type ExpectedStreamVersion,\n type ProjectionRegistration,\n type ReadEventMetadataWithGlobalPosition,\n type ReadStreamOptions,\n type ReadStreamResult,\n} from '@event-driven-io/emmett';\nimport pg from 'pg';\nimport {\n handleProjections,\n type PostgreSQLProjectionHandlerContext,\n} from './projections';\nimport {\n appendToStream,\n createEventStoreSchema,\n readStream,\n schemaSQL,\n type AppendToStreamPreCommitHook,\n} from './schema';\n\nexport interface PostgresEventStore\n extends EventStore<\n DefaultStreamVersionType,\n ReadEventMetadataWithGlobalPosition\n >,\n EventStoreSessionFactory<PostgresEventStore, DefaultStreamVersionType> {\n close(): Promise<void>;\n schema: {\n sql(): string;\n print(): void;\n migrate(): Promise<void>;\n };\n}\n\ntype PostgresEventStorePooledOptions =\n | {\n connector?: NodePostgresConnector;\n connectionString?: string;\n database?: string;\n pooled: true;\n pool: pg.Pool;\n }\n | {\n connector?: NodePostgresConnector;\n connectionString?: string;\n database?: string;\n pool: pg.Pool;\n }\n | {\n connector?: NodePostgresConnector;\n connectionString?: string;\n database?: string;\n pooled: true;\n }\n | {\n connector?: NodePostgresConnector;\n connectionString?: string;\n database?: string;\n };\n\ntype PostgresEventStoreNotPooledOptions =\n | {\n connector?: NodePostgresConnector;\n connectionString?: string;\n database?: string;\n pooled: false;\n client: pg.Client;\n }\n | {\n connector?: NodePostgresConnector;\n connectionString?: string;\n database?: string;\n client: pg.Client;\n }\n | {\n connector?: NodePostgresConnector;\n connectionString?: string;\n database?: string;\n pooled: false;\n }\n | {\n connector?: NodePostgresConnector;\n connectionString?: string;\n database?: string;\n connection:\n | NodePostgresPoolClientConnection\n | NodePostgresClientConnection;\n pooled?: false;\n }\n | {\n connector?: NodePostgresConnector;\n connectionString?: string;\n database?: string;\n dumbo: NodePostgresPool;\n pooled?: false;\n };\n\nexport type PostgresEventStoreConnectionOptions =\n | PostgresEventStorePooledOptions\n | PostgresEventStoreNotPooledOptions;\n\nexport type PostgresEventStoreOptions = {\n projections?: ProjectionRegistration<\n 'inline',\n PostgreSQLProjectionHandlerContext\n >[];\n schema?: { autoMigration?: MigrationStyle };\n connectionOptions?: PostgresEventStoreConnectionOptions;\n};\n\nexport const defaultPostgreSQLOptions: PostgresEventStoreOptions = {\n projections: [],\n schema: { autoMigration: 'CreateOrUpdate' },\n};\n\nexport const getPostgreSQLEventStore = (\n connectionString: string,\n options: PostgresEventStoreOptions = defaultPostgreSQLOptions,\n): PostgresEventStore => {\n const poolOptions = {\n connectionString,\n ...(options.connectionOptions ? options.connectionOptions : {}),\n };\n const pool = 'dumbo' in poolOptions ? poolOptions.dumbo : dumbo(poolOptions);\n let migrateSchema: Promise<void>;\n\n const autoGenerateSchema =\n options.schema?.autoMigration === undefined ||\n options.schema?.autoMigration !== 'None';\n\n const ensureSchemaExists = () => {\n if (!autoGenerateSchema) return Promise.resolve();\n\n if (!migrateSchema) {\n migrateSchema = createEventStoreSchema(pool);\n }\n return migrateSchema;\n };\n\n const inlineProjections = (options.projections ?? [])\n .filter(({ type }) => type === 'inline')\n .map(({ projection }) => projection);\n\n const preCommitHook: AppendToStreamPreCommitHook | undefined =\n inlineProjections.length > 0\n ? (events, { transaction }) =>\n handleProjections({\n projections: inlineProjections,\n connection: {\n connectionString,\n transaction,\n },\n events,\n })\n : undefined;\n\n return {\n schema: {\n sql: () => schemaSQL.join(''),\n print: () => console.log(schemaSQL.join('')),\n migrate: async () => {\n await (migrateSchema = createEventStoreSchema(pool));\n },\n },\n async aggregateStream<State, EventType extends Event>(\n streamName: string,\n options: AggregateStreamOptions<State, EventType>,\n ): Promise<AggregateStreamResult<State> | null> {\n const { evolve, initialState, read } = options;\n\n const expectedStreamVersion = read?.expectedStreamVersion;\n\n let state = initialState();\n\n const result = await this.readStream<EventType>(streamName, options.read);\n\n if (result === null) return null;\n\n const currentStreamVersion = result.currentStreamVersion;\n\n assertExpectedVersionMatchesCurrent(\n currentStreamVersion,\n expectedStreamVersion,\n );\n\n for (const event of result.events) {\n if (!event) continue;\n\n state = evolve(state, event);\n }\n\n return {\n currentStreamVersion: currentStreamVersion,\n state,\n };\n },\n\n readStream: async <EventType extends Event>(\n streamName: string,\n options?: ReadStreamOptions,\n ): Promise<\n ReadStreamResult<\n EventType,\n DefaultStreamVersionType,\n ReadEventMetadataWithGlobalPosition\n >\n > => {\n await ensureSchemaExists();\n return readStream<EventType>(pool.execute, streamName, options);\n },\n\n appendToStream: async <EventType extends Event>(\n streamName: string,\n events: EventType[],\n options?: AppendToStreamOptions,\n ): Promise<AppendToStreamResult> => {\n await ensureSchemaExists();\n // TODO: This has to be smarter when we introduce urn-based resolution\n const [firstPart, ...rest] = streamName.split('-');\n\n const streamType =\n firstPart && rest.length > 0 ? firstPart : 'emt:unknown';\n\n const appendResult = await appendToStream(\n pool,\n streamName,\n streamType,\n events,\n {\n ...options,\n preCommitHook,\n },\n );\n\n if (!appendResult.success)\n throw new ExpectedVersionConflictError<bigint>(\n -1n, //TODO: Return actual version in case of error\n options?.expectedStreamVersion ?? NO_CONCURRENCY_CHECK,\n );\n\n return { nextExpectedStreamVersion: appendResult.nextStreamPosition };\n },\n close: () => pool.close(),\n\n async withSession<T = unknown>(\n callback: (\n session: EventStoreSession<\n PostgresEventStore,\n DefaultStreamVersionType\n >,\n ) => Promise<T>,\n ): Promise<T> {\n return await pool.withConnection(async (connection) => {\n const storeOptions: PostgresEventStoreOptions = {\n ...options,\n connectionOptions: {\n connection,\n },\n };\n\n const eventStore = getPostgreSQLEventStore(\n connectionString,\n storeOptions,\n );\n\n return callback({\n eventStore,\n close: () => Promise.resolve(),\n });\n });\n },\n };\n};\n\nconst matchesExpectedVersion = (\n current: bigint | undefined,\n expected: ExpectedStreamVersion,\n): boolean => {\n if (expected === NO_CONCURRENCY_CHECK) return true;\n\n if (expected == STREAM_DOES_NOT_EXIST) return current === undefined;\n\n if (expected == STREAM_EXISTS) return current !== undefined;\n\n return current === expected;\n};\n\nconst assertExpectedVersionMatchesCurrent = (\n current: bigint | undefined,\n expected: ExpectedStreamVersion | undefined,\n): void => {\n expected ??= NO_CONCURRENCY_CHECK;\n\n if (!matchesExpectedVersion(current, expected))\n throw new ExpectedVersionConflictError(current, expected);\n};\n","import { Command as CliCommand } from 'commander';\n\nexport type EmmettPluginConfig =\n | {\n name: string;\n register: EmmettPluginRegistration[];\n }\n | string;\n\nexport type EmmettPluginType = 'cli';\n\nexport type EmmettCliPluginRegistration = { pluginType: 'cli'; path?: string };\n\nexport type EmmettPluginRegistration = EmmettCliPluginRegistration;\n\nexport type EmmettCliPlugin = {\n pluginType: 'cli';\n name: string;\n registerCommands: (program: CliCommand) => Promise<void> | void;\n};\n\nexport type EmmettPlugin = EmmettCliPlugin;\n\nexport const isPluginConfig = (\n plugin: Partial<EmmettPluginConfig> | string | undefined,\n): plugin is EmmettPluginConfig =>\n plugin !== undefined &&\n (typeof plugin === 'string' ||\n ('name' in plugin &&\n plugin.name !== undefined &&\n typeof plugin.name === 'string'));\n","import { ValidationError } from '../errors';\n\nexport const enum ValidationErrors {\n NOT_A_NONEMPTY_STRING = 'NOT_A_NONEMPTY_STRING',\n NOT_A_POSITIVE_NUMBER = 'NOT_A_POSITIVE_NUMBER',\n NOT_AN_UNSIGNED_BIGINT = 'NOT_AN_UNSIGNED_BIGINT',\n}\n\nexport const isNumber = (val: unknown): val is number =>\n typeof val === 'number' && val === val;\n\nexport const isString = (val: unknown): val is string =>\n typeof val === 'string';\n\nexport const assertNotEmptyString = (value: unknown): string => {\n if (!isString(value) || value.length === 0) {\n throw new ValidationError(ValidationErrors.NOT_A_NONEMPTY_STRING);\n }\n return value;\n};\n\nexport const assertPositiveNumber = (value: unknown): number => {\n if (!isNumber(value) || value <= 0) {\n throw new ValidationError(ValidationErrors.NOT_A_POSITIVE_NUMBER);\n }\n return value;\n};\n\nexport const assertUnsignedBigInt = (value: string): bigint => {\n const number = BigInt(value);\n if (number < 0) {\n throw new ValidationError(ValidationErrors.NOT_AN_UNSIGNED_BIGINT);\n }\n return number;\n};\n\nexport * from './dates';\n","import { isNumber, isString } from '../validation';\n\nexport type ErrorConstructor<ErrorType extends Error> = new (\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ...args: any[]\n) => ErrorType;\n\nexport const isErrorConstructor = <ErrorType extends Error>(\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n expect: Function,\n): expect is ErrorConstructor<ErrorType> => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return (\n typeof expect === 'function' &&\n expect.prototype &&\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n expect.prototype.constructor === expect\n );\n};\n\nexport class EmmettError extends Error {\n public errorCode: number;\n\n constructor(\n options?: { errorCode: number; message?: string } | string | number,\n ) {\n const errorCode =\n options && typeof options === 'object' && 'errorCode' in options\n ? options.errorCode\n : isNumber(options)\n ? options\n : 500;\n const message =\n options && typeof options === 'object' && 'message' in options\n ? options.message\n : isString(options)\n ? options\n : `Error with status code '${errorCode}' ocurred during Emmett processing`;\n\n super(message);\n this.errorCode = errorCode;\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, EmmettError.prototype);\n }\n}\n\nexport class ConcurrencyError extends EmmettError {\n constructor(\n public current: string | undefined,\n public expected: string,\n message?: string,\n ) {\n super({\n errorCode: 412,\n message:\n message ??\n `Expected version ${expected.toString()} does not match current ${current?.toString()}`,\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, ConcurrencyError.prototype);\n }\n}\n\nexport class ValidationError extends EmmettError {\n constructor(message?: string) {\n super({\n errorCode: 400,\n message: message ?? `Validation Error ocurred during Emmett processing`,\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, ValidationError.prototype);\n }\n}\n\nexport class IllegalStateError extends EmmettError {\n constructor(message?: string) {\n super({\n errorCode: 403,\n message: message ?? `Illegal State ocurred during Emmett processing`,\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, IllegalStateError.prototype);\n }\n}\n\nexport class NotFoundError extends EmmettError {\n constructor(options?: { id: string; type: string; message?: string }) {\n super({\n errorCode: 404,\n message:\n options?.message ??\n (options?.id\n ? options.type\n ? `${options.type} with ${options.id} was not found during Emmett processing`\n : `State with ${options.id} was not found during Emmett processing`\n : options?.type\n ? `${options.type} was not found during Emmett processing`\n : 'State was not found during Emmett processing'),\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, NotFoundError.prototype);\n }\n}\n","import { JSONParser } from '../serialization';\nimport type { DefaultRecord } from '../typing';\nimport { deepEquals } from '../utils';\n\nexport class AssertionError extends Error {\n constructor(message: string) {\n super(message);\n }\n}\nexport const isSubset = (superObj: unknown, subObj: unknown): boolean => {\n const sup = superObj as DefaultRecord;\n const sub = subObj as DefaultRecord;\n\n assertOk(sup);\n assertOk(sub);\n\n return Object.keys(sub).every((ele: string) => {\n if (typeof sub[ele] == 'object') {\n return isSubset(sup[ele], sub[ele]);\n }\n return sub[ele] === sup[ele];\n });\n};\n\nexport const assertFails = (message?: string) => {\n throw new AssertionError(message ?? 'That should not ever happened, right?');\n};\n\nexport const assertThrowsAsync = async <TError extends Error>(\n fun: () => Promise<void>,\n errorCheck?: (error: Error) => boolean,\n): Promise<TError> => {\n try {\n await fun();\n throw new AssertionError(\"Function didn't throw expected error\");\n } catch (error) {\n const typedError = error as TError;\n if (errorCheck) assertTrue(errorCheck(typedError));\n return typedError;\n }\n};\n\nexport const assertThrows = <TError extends Error>(\n fun: () => void,\n errorCheck?: (error: Error) => boolean,\n): TError => {\n try {\n fun();\n throw new AssertionError(\"Function didn't throw expected error\");\n } catch (error) {\n const typedError = error as TError;\n if (errorCheck) assertTrue(errorCheck(typedError));\n return typedError;\n }\n};\nexport const assertMatches = (\n actual: unknown,\n expected: unknown,\n message?: string,\n) => {\n if (!isSubset(actual, expected))\n throw new AssertionError(\n message ??\n `subObj:\\n${JSONParser.stringify(expected)}\\nis not subset of\\n${JSONParser.stringify(actual)}`,\n );\n};\n\nexport const assertDeepEqual = <T = unknown>(\n actual: T,\n expected: T,\n message?: string,\n) => {\n if (!deepEquals(actual, expected))\n throw new AssertionError(\n message ??\n `subObj:\\n${JSONParser.stringify(expected)}\\nis not equal to\\n${JSONParser.stringify(actual)}`,\n );\n};\n\nexport const assertNotDeepEqual = <T = unknown>(\n actual: T,\n expected: T,\n message?: string,\n) => {\n if (deepEquals(actual, expected))\n throw new AssertionError(\n message ??\n `subObj:\\n${JSONParser.stringify(expected)}\\nis equals to\\n${JSONParser.stringify(actual)}`,\n );\n};\n\nexport const assertThat = <T>(item: T) => {\n return {\n isEqualTo: (other: T) => assertTrue(deepEquals(item, other)),\n };\n};\n\nexport function assertFalse(\n condition: boolean,\n message?: string,\n): asserts condition is false {\n if (condition) throw new AssertionError(message ?? `Condition is false`);\n}\n\nexport function assertTrue(\n condition: boolean,\n message?: string,\n): asserts condition is true {\n if (!condition) throw new AssertionError(message ?? `Condition is false`);\n}\n\nexport function assertOk<T>(\n obj: T | null | undefined,\n message?: string,\n): asserts obj is T {\n if (!obj) throw new AssertionError(message ?? `Condition is not truthy`);\n}\n\nexport function assertEqual<T>(\n expected: T | null | undefined,\n actual: T | null | undefined,\n message?: string,\n): void {\n if (expected !== actual)\n throw new AssertionError(\n `${message ?? 'Objects are not equal'}:\\nExpected: ${JSONParser.stringify(expected)}\\nActual:${JSONParser.stringify(actual)}`,\n );\n}\n\nexport function assertNotEqual<T>(\n obj: T | null | undefined,\n other: T | null | undefined,\n message?: string,\n): void {\n if (obj === other)\n throw new AssertionError(\n message ?? `Objects are equal: ${JSONParser.stringify(obj)}`,\n );\n}\n\nexport function assertIsNotNull<T extends object | bigint>(\n result: T | null,\n): asserts result is T {\n assertNotEqual(result, null);\n assertOk(result);\n}\n\nexport function assertIsNull<T extends object>(\n result: T | null,\n): asserts result is null {\n assertEqual(result, null);\n}\n\ntype Call = {\n arguments: unknown[];\n result: unknown;\n target: unknown;\n this: unknown;\n};\n\nexport type ArgumentMatcher = (arg: unknown) => boolean;\n\nexport const argValue =\n <T>(value: T): ArgumentMatcher =>\n (arg) =>\n deepEquals(arg, value);\n\nexport const argMatches =\n <T>(matches: (arg: T) => boolean): ArgumentMatcher =>\n (arg) =>\n matches(arg as T);\n\n// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\nexport type MockedFunction = Function & { mock?: { calls: Call[] } };\n\nexport function verifyThat(fn: MockedFunction) {\n return {\n calledTimes: (times: number) => {\n assertEqual(fn.mock?.calls?.length, times);\n },\n notCalled: () => {\n assertEqual(fn?.mock?.calls?.length, 0);\n },\n called: () => {\n assertTrue(\n fn.mock?.calls.length !== undefined && fn.mock.calls.length > 0,\n );\n },\n calledWith: (...args: unknown[]) => {\n assertTrue(\n fn.mock?.calls.length !== undefined &&\n fn.mock.calls.length >= 1 &&\n fn.mock.calls.some((call) => deepEquals(call.arguments, args)),\n );\n },\n calledOnceWith: (...args: unknown[]) => {\n assertTrue(\n fn.mock?.calls.length !== undefined &&\n fn.mock.calls.length === 1 &&\n fn.mock.calls.some((call) => deepEquals(call.arguments, args)),\n );\n },\n calledWithArgumentMatching: (...matches: ArgumentMatcher[]) => {\n assertTrue(\n fn.mock?.calls.length !== undefined && fn.mock.calls.length >= 1,\n );\n assertTrue(\n fn.mock?.calls.length !== undefined &&\n fn.mock.calls.length >= 1 &&\n fn.mock.calls.some(\n (call) =>\n call.arguments &&\n call.arguments.length >= matches.length &&\n matches.every((match, index) => match(call.arguments[index])),\n ),\n );\n },\n notCalledWithArgumentMatching: (...matches: ArgumentMatcher[]) => {\n assertFalse(\n fn.mock?.calls.length !== undefined &&\n fn.mock.calls.length >= 1 &&\n fn.mock.calls[0]!.arguments &&\n fn.mock.calls[0]!.arguments.length >= matches.length &&\n matches.every((match, index) =>\n match(fn.mock!.calls[0]!.arguments[index]),\n ),\n );\n },\n };\n}\n\nexport const assertThatArray = <T>(array: T[]) => {\n return {\n isEmpty: () => assertEqual(array.length, 0),\n isNotEmpty: () => assertNotEqual(array.length, 0),\n hasSize: (length: number) => assertEqual(array.length, length),\n containsElements: (...other: T[]) => {\n assertTrue(other.every((ts) => other.some((o) => deepEquals(ts, o))));\n },\n containsExactlyInAnyOrder: (...other: T[]) => {\n assertEqual(array.length, other.length);\n assertTrue(array.every((ts) => other.some((o) => deepEquals(ts, o))));\n },\n containsExactlyInAnyOrderElementsOf: (other: T[]) => {\n assertEqual(array.length, other.length);\n assertTrue(array.every((ts) => other.some((o) => deepEquals(ts, o))));\n },\n containsExactlyElementsOf: (other: T[]) => {\n assertEqual(array.length, other.length);\n for (let i = 0; i < array.length; i++) {\n assertTrue(deepEquals(array[i], other[i]));\n }\n },\n containsExactly: (elem: T) => {\n assertEqual(array.length, 1);\n assertTrue(deepEquals(array[0], elem));\n },\n contains: (elem: T) => {\n assertTrue(array.some((a) => deepEquals(a, elem)));\n },\n containsOnlyOnceElementsOf: (other: T[]) => {\n assertTrue(\n other\n .map((o) => array.filter((a) => deepEquals(a, o)).length)\n .filter((a) => a === 1).length === other.length,\n );\n },\n containsAnyOf: (...other: T[]) => {\n assertTrue(array.some((a) => other.some((o) => deepEquals(a, o))));\n },\n allMatch: (matches: (item: T) => boolean) => {\n assertTrue(array.every(matches));\n },\n anyMatches: (matches: (item: T) => boolean) => {\n assertTrue(array.some(matches));\n },\n allMatchAsync: async (\n matches: (item: T) => Promise<boolean>,\n ): Promise<void> => {\n for (const item of array) {\n assertTrue(await matches(item));\n }\n },\n };\n};\n",null,"import {\n rawSql,\n single,\n sql,\n type NodePostgresPool,\n type NodePostgresTransaction,\n type SQLExecutor,\n} from '@event-driven-io/dumbo';\nimport {\n JSONParser,\n NO_CONCURRENCY_CHECK,\n STREAM_DOES_NOT_EXIST,\n STREAM_EXISTS,\n type AppendToStreamOptions,\n type Event,\n type ExpectedStreamVersion,\n type ReadEvent,\n} from '@event-driven-io/emmett';\nimport { v4 as uuid } from 'uuid';\nimport { defaultTag, eventsTable, streamsTable } from './typing';\n\nexport const appendEventsSQL = rawSql(\n `CREATE OR REPLACE FUNCTION emt_append_event(\n v_event_ids text[],\n v_events_data jsonb[],\n v_events_metadata jsonb[],\n v_event_schema_versions text[],\n v_event_types text[],\n v_stream_id text,\n v_stream_type text,\n v_expected_stream_position bigint DEFAULT NULL,\n v_partition text DEFAULT emt_sanitize_name('default_partition')\n ) RETURNS TABLE (\n success boolean,\n next_stream_position bigint,\n last_global_position bigint,\n transaction_id xid8\n ) LANGUAGE plpgsql\n AS $$\n DECLARE\n v_next_stream_position bigint;\n v_position bigint;\n v_updated_rows int;\n v_transaction_id xid8;\n v_last_global_position bigint;\n BEGIN\n IF v_expected_stream_position IS NULL THEN\n SELECT COALESCE(max(stream_position), 0) INTO v_expected_stream_position\n FROM ${streamsTable.name}\n WHERE stream_id = v_stream_id AND partition = v_partition;\n END IF;\n\n v_next_stream_position := v_expected_stream_position + array_upper(v_events_data, 1);\n v_transaction_id := pg_current_xact_id();\n\n WITH ev AS (\n SELECT row_number() OVER () + v_expected_stream_position AS stream_position, \n event_data, \n event_metadata, \n schema_version, \n event_id, \n event_type\n FROM (\n SELECT *\n FROM \n unnest(v_event_ids, v_events_data, v_events_metadata, v_event_schema_versions, v_event_types) \n AS event(event_id, event_data, event_metadata, schema_version, event_type)\n ) AS event\n ),\n all_events_insert AS (\n INSERT INTO ${eventsTable.name}\n (stream_id, stream_position, partition, event_data, event_metadata, event_schema_version, event_type, event_id, transaction_id)\n SELECT \n v_stream_id, ev.stream_position, v_partition, ev.event_data, ev.event_metadata, ev.schema_version, ev.event_type, ev.event_id, v_transaction_id\n FROM ev\n RETURNING global_position\n )\n SELECT \n max(global_position) INTO v_last_global_position \n FROM \n all_events_insert;\n\n\n IF v_expected_stream_position = 0 THEN\n INSERT INTO ${streamsTable.name}\n (stream_id, stream_position, partition, stream_type, stream_metadata, is_archived)\n VALUES\n (v_stream_id, v_next_stream_position, v_partition, v_stream_type, '{}', FALSE);\n ELSE\n UPDATE ${streamsTable.name} as s \n SET stream_position = v_next_stream_position\n WHERE stream_id = v_stream_id AND stream_position = v_expected_stream_position AND partition = v_partition AND is_archived = FALSE;\n\n get diagnostics v_updated_rows = row_count;\n\n IF v_updated_rows = 0 THEN\n RETURN QUERY SELECT FALSE, NULL::bigint, NULL::bigint, NULL::xid8;\n RETURN;\n END IF;\n END IF;\n\n RETURN QUERY SELECT TRUE, v_next_stream_position, v_last_global_position, v_transaction_id;\n END;\n $$;\n `,\n);\n\ntype AppendEventResult =\n | {\n success: true;\n nextStreamPosition: bigint;\n lastGlobalPosition: bigint;\n transactionId: string;\n }\n | { success: false };\n\nexport type AppendToStreamPreCommitHook = (\n events: ReadEvent[],\n context: {\n transaction: NodePostgresTransaction;\n },\n) => Promise<void>;\n\nexport const appendToStream = (\n pool: NodePostgresPool,\n streamName: string,\n streamType: string,\n events: Event[],\n options?: AppendToStreamOptions & {\n partition?: string;\n preCommitHook?: AppendToStreamPreCommitHook;\n },\n): Promise<AppendEventResult> =>\n pool.withTransaction<AppendEventResult>(async (transaction) => {\n const { execute } = transaction;\n\n if (events.length === 0)\n return { success: false, result: { success: false } };\n\n let appendResult: AppendEventSqlResult;\n\n try {\n const expectedStreamVersion = toExpectedVersion(\n options?.expectedStreamVersion,\n );\n\n const eventsToAppend: ReadEvent[] = events.map((e, i) => ({\n ...e,\n metadata: {\n streamName,\n eventId: uuid(),\n streamPosition: BigInt(i),\n ...e.metadata,\n },\n }));\n\n // TODO: return global positions from append raw and other generated data\n appendResult = await appendEventsRaw(\n execute,\n streamName,\n streamType,\n eventsToAppend,\n {\n expectedStreamVersion,\n },\n );\n\n if (options?.preCommitHook)\n await options.preCommitHook(eventsToAppend, { transaction });\n } catch (error) {\n if (!isOptimisticConcurrencyError(error)) throw error;\n\n appendResult = {\n success: false,\n last_global_position: null,\n next_stream_position: null,\n transaction_id: null,\n };\n }\n\n const {\n success,\n next_stream_position,\n last_global_position,\n transaction_id,\n } = appendResult;\n\n return {\n success,\n result:\n success &&\n next_stream_position &&\n last_global_position &&\n transaction_id\n ? {\n success: true,\n nextStreamPosition: BigInt(next_stream_position),\n lastGlobalPosition: BigInt(last_global_position),\n transactionId: transaction_id,\n }\n : { success: false },\n };\n });\n\nconst toExpectedVersion = (\n expected: ExpectedStreamVersion | undefined,\n): bigint | null => {\n if (expected === undefined) return null;\n\n if (expected === NO_CONCURRENCY_CHECK) return null;\n\n // TODO: this needs to be fixed\n if (expected == STREAM_DOES_NOT_EXIST) return null;\n\n // TODO: this needs to be fixed\n if (expected == STREAM_EXISTS) return null;\n\n return expected as bigint;\n};\n\nconst isOptimisticConcurrencyError = (error: unknown): boolean =>\n error instanceof Error && 'code' in error && error.code === '23505';\n\ntype AppendEventSqlResult = {\n success: boolean;\n next_stream_position: string | null;\n last_global_position: string | null;\n transaction_id: string | null | undefined;\n};\n\nconst appendEventsRaw = (\n execute: SQLExecutor,\n streamId: string,\n streamType: string,\n events: ReadEvent[],\n options?: {\n expectedStreamVersion: bigint | null;\n partition?: string;\n },\n): Promise<AppendEventSqlResult> =>\n single(\n execute.command<AppendEventSqlResult>(\n sql(\n `SELECT * FROM emt_append_event(\n ARRAY[%s]::text[],\n ARRAY[%s]::jsonb[],\n ARRAY[%s]::jsonb[],\n ARRAY[%s]::text[],\n ARRAY[%s]::text[],\n %L::text,\n %L::text,\n %s::bigint,\n %L::text\n )`,\n events.map((e) => sql('%L', e.metadata.eventId)).join(','),\n events.map((e) => sql('%L', JSONParser.stringify(e.data))).join(','),\n events\n .map((e) => sql('%L', JSONParser.stringify(e.metadata ?? {})))\n .join(','),\n events.map(() => `'1'`).join(','),\n events.map((e) => sql('%L', e.type)).join(','),\n streamId,\n streamType,\n options?.expectedStreamVersion ?? 'NULL',\n options?.partition ?? defaultTag,\n ),\n ),\n );\n","import { rawSql } from '@event-driven-io/dumbo';\nimport { defaultTag, eventsTable, globalTag, streamsTable } from './typing';\n\nexport const streamsTableSQL = rawSql(\n `CREATE TABLE IF NOT EXISTS ${streamsTable.name}(\n stream_id TEXT NOT NULL,\n stream_position BIGINT NOT NULL,\n partition TEXT NOT NULL DEFAULT '${globalTag}__${globalTag}',\n stream_type TEXT NOT NULL,\n stream_metadata JSONB NOT NULL,\n is_archived BOOLEAN NOT NULL DEFAULT FALSE,\n PRIMARY KEY (stream_id, stream_position, partition, is_archived),\n UNIQUE (stream_id, partition, is_archived)\n ) PARTITION BY LIST (partition);`,\n);\n\nexport const eventsTableSQL = rawSql(\n `\n CREATE SEQUENCE IF NOT EXISTS emt_global_event_position;\n\n CREATE TABLE IF NOT EXISTS ${eventsTable.name}(\n stream_id TEXT NOT NULL,\n stream_position BIGINT NOT NULL,\n partition TEXT NOT NULL DEFAULT '${globalTag}',\n event_data JSONB NOT NULL,\n event_metadata JSONB NOT NULL,\n event_schema_version TEXT NOT NULL,\n event_type TEXT NOT NULL,\n event_id TEXT NOT NULL,\n is_archived BOOLEAN NOT NULL DEFAULT FALSE,\n global_position BIGINT DEFAULT nextval('emt_global_event_position'),\n transaction_id XID8 NOT NULL,\n created TIMESTAMPTZ NOT NULL DEFAULT now(),\n PRIMARY KEY (stream_id, stream_position, partition, is_archived)\n ) PARTITION BY LIST (partition);`,\n);\n\nexport const subscriptionsTableSQL = rawSql(\n `\n CREATE TABLE IF NOT EXISTS emt_subscriptions(\n subscription_id TEXT NOT NULL PRIMARY KEY,\n version INT NOT NULL DEFAULT 1,\n module TEXT NULL,\n tenant TEXT NULL,\n last_processed_position BIGINT NOT NULL,\n last_processed_transaction_id BIGINT NOT NULL\n );\n`,\n);\n\nexport const sanitizeNameSQL = rawSql(\n `CREATE OR REPLACE FUNCTION emt_sanitize_name(input_name TEXT) RETURNS TEXT AS $$\n BEGIN\n RETURN REGEXP_REPLACE(input_name, '[^a-zA-Z0-9_]', '_', 'g');\n END;\n $$ LANGUAGE plpgsql;`,\n);\n\nexport const addTablePartitions = rawSql(\n `\n CREATE OR REPLACE FUNCTION emt_add_table_partition(tableName TEXT, partition_name TEXT) RETURNS void AS $$\n DECLARE\n v_main_partiton_name TEXT;\n v_active_partiton_name TEXT;\n v_archived_partiton_name TEXT;\n BEGIN \n v_main_partiton_name := emt_sanitize_name(tableName || '_' || partition_name);\n v_active_partiton_name := emt_sanitize_name(v_main_partiton_name || '_active');\n v_archived_partiton_name := emt_sanitize_name(v_main_partiton_name || '_archived');\n\n -- create default events partition\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (%L) PARTITION BY LIST (is_archived);',\n v_main_partiton_name, tableName, partition_name\n );\n\n -- create default streams partition\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (%L) PARTITION BY LIST (is_archived);',\n v_main_partiton_name, tableName, partition_name\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (FALSE);',\n v_active_partiton_name, v_main_partiton_name\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (TRUE);',\n v_archived_partiton_name, v_main_partiton_name\n );\n END;\n $$ LANGUAGE plpgsql;`,\n);\n\nexport const addEventsPartitions = rawSql(\n `\n CREATE OR REPLACE FUNCTION emt_add_partition(partition_name TEXT) RETURNS void AS $$\n BEGIN \n PERFORM emt_add_table_partition('${eventsTable.name}', partition_name);\n PERFORM emt_add_table_partition('${streamsTable.name}', partition_name);\n END;\n $$ LANGUAGE plpgsql;`,\n);\n\nexport const addModuleSQL = rawSql(\n `\n CREATE OR REPLACE FUNCTION add_module(new_module TEXT) RETURNS void AS $$\n BEGIN\n -- For ${eventsTable.name} table\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (emt_sanitize_name(%L || ''__'' || %L)) PARTITION BY LIST (is_archived);',\n emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || '${globalTag}'), '${eventsTable.name}', new_module, '${globalTag}'\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I\n FOR VALUES IN (FALSE);',\n emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || '${globalTag}' || '_active'), emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || '${globalTag}')\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I\n FOR VALUES IN (TRUE);',\n emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || '${globalTag}' || '_archived'), emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || '${globalTag}')\n );\n \n -- For ${streamsTable.name} table\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (emt_sanitize_name(%L || ''__'' || %L)) PARTITION BY LIST (is_archived);',\n emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || '${globalTag}'), '${streamsTable.name}', new_module, '${globalTag}'\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I\n FOR VALUES IN (FALSE);',\n emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || '${globalTag}' || '_active'), emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || '${globalTag}')\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I\n FOR VALUES IN (TRUE);',\n emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || '${globalTag}' || '_archived'), emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || '${globalTag}')\n );\n END;\n $$ LANGUAGE plpgsql;\n `,\n);\n\nexport const addTenantSQL = rawSql(\n `\n CREATE OR REPLACE FUNCTION add_tenant(new_module TEXT, new_tenant TEXT) RETURNS void AS $$\n BEGIN\n -- For ${eventsTable.name} table\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (emt_sanitize_name(''%s__%s'')) PARTITION BY LIST (is_archived);',\n emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || new_tenant), '${eventsTable.name}', new_module, new_tenant\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I\n FOR VALUES IN (FALSE);',\n emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || new_tenant || '_active'), emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || new_tenant)\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I\n FOR VALUES IN (TRUE);',\n emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || new_tenant || '_archived'), emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || new_tenant)\n );\n \n -- For ${streamsTable.name} table\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (emt_sanitize_name(''%s__%s'')) PARTITION BY LIST (is_archived);',\n emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || new_tenant), '${streamsTable.name}', new_module, new_tenant\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I\n FOR VALUES IN (FALSE);',\n emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || new_tenant || '_active'), emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || new_tenant)\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I\n FOR VALUES IN (TRUE);',\n emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || new_tenant || '_archived'), emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || new_tenant)\n );\n END;\n $$ LANGUAGE plpgsql;\n `,\n);\n\nexport const addModuleForAllTenantsSQL = rawSql(\n `\n CREATE OR REPLACE FUNCTION add_module_for_all_tenants(new_module TEXT) RETURNS void AS $$\n DECLARE\n tenant_record RECORD;\n BEGIN\n PERFORM add_module(new_module);\n \n FOR tenant_record IN SELECT DISTINCT tenant FROM ${eventsTable.name}\n LOOP\n -- For ${eventsTable.name} table\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (emt_sanitize_name(''%s__%s'')) PARTITION BY LIST (is_archived);',\n emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || tenant_record.tenant), '${eventsTable.name}', new_module, tenant_record.tenant\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I\n FOR VALUES IN (FALSE);',\n emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || tenant_record.tenant || '_active'), emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || tenant_record.tenant)\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I\n FOR VALUES IN (TRUE);',\n emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || tenant_record.tenant || '_archived'), emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || tenant_record.tenant)\n );\n \n -- For ${streamsTable.name} table\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (emt_sanitize_name(''%s__%s'')) PARTITION BY LIST (is_archived);',\n emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || tenant_record.tenant), '${streamsTable.name}', new_module, tenant_record.tenant\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I\n FOR VALUES IN (FALSE);',\n emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || tenant_record.tenant || '_active'), emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || tenant_record.tenant)\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I\n FOR VALUES IN (TRUE);',\n emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || tenant_record.tenant || '_archived'), emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || tenant_record.tenant)\n );\n END LOOP;\n END;\n $$ LANGUAGE plpgsql;\n `,\n);\n\nexport const addTenantForAllModulesSQL = rawSql(\n `\n CREATE OR REPLACE FUNCTION add_tenant_for_all_modules(new_tenant TEXT) RETURNS void AS $$\n DECLARE\n module_record RECORD;\n BEGIN\n FOR module_record IN SELECT DISTINCT partitionname FROM pg_partman.part_config WHERE parent_table = '${eventsTable.name}'\n LOOP\n -- For ${eventsTable.name} table\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (emt_sanitize_name(''%s__%s'')) PARTITION BY LIST (is_archived);',\n emt_sanitize_name('${eventsTable.name}_' || module_record.partitionname || '__' || new_tenant), '${eventsTable.name}', module_record.partitionname, new_tenant\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I\n FOR VALUES IN (FALSE);',\n emt_sanitize_name('${eventsTable.name}_' || module_record.partitionname || '__' || new_tenant || '_active'), emt_sanitize_name('${eventsTable.name}_' || module_record.partitionname || '__' || new_tenant)\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I\n FOR VALUES IN (TRUE);',\n emt_sanitize_name('${eventsTable.name}_' || module_record.partitionname || '__' || new_tenant || '_archived'), emt_sanitize_name('${eventsTable.name}_' || module_record.partitionname || '__' || new_tenant)\n );\n \n -- For ${streamsTable.name} table\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (emt_sanitize_name(''%s__%s'')) PARTITION BY LIST (is_archived);',\n emt_sanitize_name('${streamsTable.name}_' || module_record.partitionname || '__' || new_tenant), '${streamsTable.name}', module_record.partitionname, new_tenant\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I\n FOR VALUES IN (FALSE);',\n emt_sanitize_name('${streamsTable.name}_' || module_record.partitionname || '__' || new_tenant || '_active'), emt_sanitize_name('${streamsTable.name}_' || module_record.partitionname || '__' || new_tenant)\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I\n FOR VALUES IN (TRUE);',\n emt_sanitize_name('${streamsTable.name}_' || module_record.partitionname || '__' || new_tenant || '_archived'), emt_sanitize_name('${streamsTable.name}_' || module_record.partitionname || '__' || new_tenant)\n );\n END LOOP;\n END;\n $$ LANGUAGE plpgsql;\n `,\n);\n\nexport const addDefaultPartition = rawSql(\n `SELECT emt_add_partition('${defaultTag}');`,\n);\n","import { mapRows, sql, type SQLExecutor } from '@event-driven-io/dumbo';\nimport {\n event,\n type DefaultStreamVersionType,\n type Event,\n type EventDataOf,\n type EventMetaDataOf,\n type EventTypeOf,\n type ReadEvent,\n type ReadEventMetadataWithGlobalPosition,\n type ReadStreamOptions,\n type ReadStreamResult,\n} from '@event-driven-io/emmett';\nimport { defaultTag, eventsTable } from './typing';\n\ntype ReadStreamSqlResult<EventType extends Event> = {\n stream_position: string;\n event_data: EventDataOf<EventType>;\n event_metadata: EventMetaDataOf<EventType>;\n event_schema_version: string;\n event_type: EventTypeOf<EventType>;\n event_id: string;\n global_position: string;\n transaction_id: string;\n created: string;\n};\n\nexport const readStream = async <EventType extends Event>(\n execute: SQLExecutor,\n streamId: string,\n options?: ReadStreamOptions & { partition?: string },\n): Promise<\n ReadStreamResult<\n EventType,\n DefaultStreamVersionType,\n ReadEventMetadataWithGlobalPosition\n >\n> => {\n const fromCondition: string =\n options && 'from' in options\n ? `AND stream_position >= ${options.from}`\n : '';\n\n const to = Number(\n options && 'to' in options\n ? options.to\n : options && 'maxCount' in options && options.maxCount\n ? options.from + options.maxCount\n : NaN,\n );\n\n const toCondition = !isNaN(to) ? `AND stream_position <= ${to}` : '';\n\n const events: ReadEvent<EventType, ReadEventMetadataWithGlobalPosition>[] =\n await mapRows(\n execute.query<ReadStreamSqlResult<EventType>>(\n sql(\n `SELECT stream_id, stream_position, global_position, event_data, event_metadata, event_schema_version, event_type, event_id\n FROM ${eventsTable.name}\n WHERE stream_id = %L AND partition = %L AND is_archived = FALSE ${fromCondition} ${toCondition}`,\n streamId,\n options?.partition ?? defaultTag,\n ),\n ),\n (row) => {\n const rawEvent = event<EventType>(\n row.event_type,\n row.event_data,\n row.event_metadata,\n ) as EventType;\n\n return {\n ...rawEvent,\n metadata: {\n ...rawEvent.metadata,\n eventId: row.event_id,\n streamName: streamId,\n streamPosition: BigInt(row.stream_position),\n globalPosition: BigInt(row.global_position),\n },\n };\n },\n );\n\n return events.length > 0\n ? {\n currentStreamVersion:\n events[events.length - 1]!.metadata.streamPosition,\n events,\n }\n : null;\n};\n"]}
@@ -1,5 +1,5 @@
1
1
  import * as _event_driven_io_dumbo from '@event-driven-io/dumbo';
2
- import { Dumbo, DumboOptions, QueryResultRow, SQL, NodePostgresClient, SQLExecutor, NodePostgresTransaction, NodePostgresConnector, NodePostgresPoolClientConnection, NodePostgresClientConnection, NodePostgresPool } from '@event-driven-io/dumbo';
2
+ import { Dumbo, DumboOptions, QueryResultRow, SQL, NodePostgresClient, SQLExecutor, NodePostgresTransaction, MigrationStyle, NodePostgresConnector, NodePostgresPoolClientConnection, NodePostgresClientConnection, NodePostgresPool } from '@event-driven-io/dumbo';
3
3
  import { Event, EventMetaDataOf, ReadEventMetadataWithGlobalPosition, ReadEvent, CanHandle, ThenThrows, ReadEventMetadata, ProjectionHandler, TypedProjectionDefinition, EventStore, DefaultStreamVersionType, EventStoreSessionFactory, ProjectionRegistration, AppendToStreamOptions, ReadStreamOptions, ReadStreamResult } from '@event-driven-io/emmett';
4
4
  import pg from 'pg';
5
5
  import { PongoDocument, WithId, PongoFilter, PongoClient } from '@event-driven-io/pongo';
@@ -224,15 +224,11 @@ type PostgresEventStoreNotPooledOptions = {
224
224
  dumbo: NodePostgresPool;
225
225
  pooled?: false;
226
226
  };
227
- declare enum SchemaMigration {
228
- None = "None",
229
- CreateOrUpdate = "CreateOrUpdate"
230
- }
231
227
  type PostgresEventStoreConnectionOptions = PostgresEventStorePooledOptions | PostgresEventStoreNotPooledOptions;
232
228
  type PostgresEventStoreOptions = {
233
229
  projections?: ProjectionRegistration<'inline', PostgreSQLProjectionHandlerContext>[];
234
230
  schema?: {
235
- autoMigration?: SchemaMigration;
231
+ autoMigration?: MigrationStyle;
236
232
  };
237
233
  connectionOptions?: PostgresEventStoreConnectionOptions;
238
234
  };
@@ -305,4 +301,4 @@ declare const eventsTable: {
305
301
  declare const schemaSQL: SQL[];
306
302
  declare const createEventStoreSchema: (pool: NodePostgresPool) => Promise<void>;
307
303
 
308
- export { type AppendToStreamPreCommitHook, type PongoAssertOptions, type PongoDocumentEvolve, type PongoMultiStreamProjectionOptions, type PongoProjectionHandlerContext, type PongoProjectionOptions, type PongoSingleStreamProjectionOptions, type PongoWithNotNullDocumentEvolve, type PongoWithNullableDocumentEvolve, type PostgreSQLProjectionAssert, type PostgreSQLProjectionDefinition, type PostgreSQLProjectionHandler, type PostgreSQLProjectionHandlerContext, PostgreSQLProjectionSpec, type PostgreSQLProjectionSpecEvent, type PostgreSQLProjectionSpecOptions, type PostgreSQLProjectionSpecWhenOptions, type PostgresEventStore, type PostgresEventStoreConnectionOptions, type PostgresEventStoreOptions, type ProjectionHandlerOptions, SchemaMigration, addDefaultPartition, addEventsPartitions, addModuleForAllTenantsSQL, addModuleSQL, addTablePartitions, addTenantForAllModulesSQL, addTenantSQL, appendEventsSQL, appendToStream, assertSQLQueryResultMatches, createEventStoreSchema, defaultPostgreSQLOptions, defaultTag, documentDoesNotExist, documentExists, documentMatchingExists, documentsAreTheSame, documentsMatchingHaveCount, emmettPrefix, eventInStream, eventsInStream, eventsTable, eventsTableSQL, expectPongoDocuments, expectSQL, getPostgreSQLEventStore, globalNames, globalTag, handleProjections, newEventsInStream, pongoMultiStreamProjection, pongoProjection, pongoSingleStreamProjection, postgreSQLProjection, postgreSQLRawBatchSQLProjection, postgreSQLRawSQLProjection, readStream, sanitizeNameSQL, schemaSQL, streamsTable, streamsTableSQL, subscriptionsTableSQL };
304
+ export { type AppendToStreamPreCommitHook, type PongoAssertOptions, type PongoDocumentEvolve, type PongoMultiStreamProjectionOptions, type PongoProjectionHandlerContext, type PongoProjectionOptions, type PongoSingleStreamProjectionOptions, type PongoWithNotNullDocumentEvolve, type PongoWithNullableDocumentEvolve, type PostgreSQLProjectionAssert, type PostgreSQLProjectionDefinition, type PostgreSQLProjectionHandler, type PostgreSQLProjectionHandlerContext, PostgreSQLProjectionSpec, type PostgreSQLProjectionSpecEvent, type PostgreSQLProjectionSpecOptions, type PostgreSQLProjectionSpecWhenOptions, type PostgresEventStore, type PostgresEventStoreConnectionOptions, type PostgresEventStoreOptions, type ProjectionHandlerOptions, addDefaultPartition, addEventsPartitions, addModuleForAllTenantsSQL, addModuleSQL, addTablePartitions, addTenantForAllModulesSQL, addTenantSQL, appendEventsSQL, appendToStream, assertSQLQueryResultMatches, createEventStoreSchema, defaultPostgreSQLOptions, defaultTag, documentDoesNotExist, documentExists, documentMatchingExists, documentsAreTheSame, documentsMatchingHaveCount, emmettPrefix, eventInStream, eventsInStream, eventsTable, eventsTableSQL, expectPongoDocuments, expectSQL, getPostgreSQLEventStore, globalNames, globalTag, handleProjections, newEventsInStream, pongoMultiStreamProjection, pongoProjection, pongoSingleStreamProjection, postgreSQLProjection, postgreSQLRawBatchSQLProjection, postgreSQLRawSQLProjection, readStream, sanitizeNameSQL, schemaSQL, streamsTable, streamsTableSQL, subscriptionsTableSQL };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _event_driven_io_dumbo from '@event-driven-io/dumbo';
2
- import { Dumbo, DumboOptions, QueryResultRow, SQL, NodePostgresClient, SQLExecutor, NodePostgresTransaction, NodePostgresConnector, NodePostgresPoolClientConnection, NodePostgresClientConnection, NodePostgresPool } from '@event-driven-io/dumbo';
2
+ import { Dumbo, DumboOptions, QueryResultRow, SQL, NodePostgresClient, SQLExecutor, NodePostgresTransaction, MigrationStyle, NodePostgresConnector, NodePostgresPoolClientConnection, NodePostgresClientConnection, NodePostgresPool } from '@event-driven-io/dumbo';
3
3
  import { Event, EventMetaDataOf, ReadEventMetadataWithGlobalPosition, ReadEvent, CanHandle, ThenThrows, ReadEventMetadata, ProjectionHandler, TypedProjectionDefinition, EventStore, DefaultStreamVersionType, EventStoreSessionFactory, ProjectionRegistration, AppendToStreamOptions, ReadStreamOptions, ReadStreamResult } from '@event-driven-io/emmett';
4
4
  import pg from 'pg';
5
5
  import { PongoDocument, WithId, PongoFilter, PongoClient } from '@event-driven-io/pongo';
@@ -224,15 +224,11 @@ type PostgresEventStoreNotPooledOptions = {
224
224
  dumbo: NodePostgresPool;
225
225
  pooled?: false;
226
226
  };
227
- declare enum SchemaMigration {
228
- None = "None",
229
- CreateOrUpdate = "CreateOrUpdate"
230
- }
231
227
  type PostgresEventStoreConnectionOptions = PostgresEventStorePooledOptions | PostgresEventStoreNotPooledOptions;
232
228
  type PostgresEventStoreOptions = {
233
229
  projections?: ProjectionRegistration<'inline', PostgreSQLProjectionHandlerContext>[];
234
230
  schema?: {
235
- autoMigration?: SchemaMigration;
231
+ autoMigration?: MigrationStyle;
236
232
  };
237
233
  connectionOptions?: PostgresEventStoreConnectionOptions;
238
234
  };
@@ -305,4 +301,4 @@ declare const eventsTable: {
305
301
  declare const schemaSQL: SQL[];
306
302
  declare const createEventStoreSchema: (pool: NodePostgresPool) => Promise<void>;
307
303
 
308
- export { type AppendToStreamPreCommitHook, type PongoAssertOptions, type PongoDocumentEvolve, type PongoMultiStreamProjectionOptions, type PongoProjectionHandlerContext, type PongoProjectionOptions, type PongoSingleStreamProjectionOptions, type PongoWithNotNullDocumentEvolve, type PongoWithNullableDocumentEvolve, type PostgreSQLProjectionAssert, type PostgreSQLProjectionDefinition, type PostgreSQLProjectionHandler, type PostgreSQLProjectionHandlerContext, PostgreSQLProjectionSpec, type PostgreSQLProjectionSpecEvent, type PostgreSQLProjectionSpecOptions, type PostgreSQLProjectionSpecWhenOptions, type PostgresEventStore, type PostgresEventStoreConnectionOptions, type PostgresEventStoreOptions, type ProjectionHandlerOptions, SchemaMigration, addDefaultPartition, addEventsPartitions, addModuleForAllTenantsSQL, addModuleSQL, addTablePartitions, addTenantForAllModulesSQL, addTenantSQL, appendEventsSQL, appendToStream, assertSQLQueryResultMatches, createEventStoreSchema, defaultPostgreSQLOptions, defaultTag, documentDoesNotExist, documentExists, documentMatchingExists, documentsAreTheSame, documentsMatchingHaveCount, emmettPrefix, eventInStream, eventsInStream, eventsTable, eventsTableSQL, expectPongoDocuments, expectSQL, getPostgreSQLEventStore, globalNames, globalTag, handleProjections, newEventsInStream, pongoMultiStreamProjection, pongoProjection, pongoSingleStreamProjection, postgreSQLProjection, postgreSQLRawBatchSQLProjection, postgreSQLRawSQLProjection, readStream, sanitizeNameSQL, schemaSQL, streamsTable, streamsTableSQL, subscriptionsTableSQL };
304
+ export { type AppendToStreamPreCommitHook, type PongoAssertOptions, type PongoDocumentEvolve, type PongoMultiStreamProjectionOptions, type PongoProjectionHandlerContext, type PongoProjectionOptions, type PongoSingleStreamProjectionOptions, type PongoWithNotNullDocumentEvolve, type PongoWithNullableDocumentEvolve, type PostgreSQLProjectionAssert, type PostgreSQLProjectionDefinition, type PostgreSQLProjectionHandler, type PostgreSQLProjectionHandlerContext, PostgreSQLProjectionSpec, type PostgreSQLProjectionSpecEvent, type PostgreSQLProjectionSpecOptions, type PostgreSQLProjectionSpecWhenOptions, type PostgresEventStore, type PostgresEventStoreConnectionOptions, type PostgresEventStoreOptions, type ProjectionHandlerOptions, addDefaultPartition, addEventsPartitions, addModuleForAllTenantsSQL, addModuleSQL, addTablePartitions, addTenantForAllModulesSQL, addTenantSQL, appendEventsSQL, appendToStream, assertSQLQueryResultMatches, createEventStoreSchema, defaultPostgreSQLOptions, defaultTag, documentDoesNotExist, documentExists, documentMatchingExists, documentsAreTheSame, documentsMatchingHaveCount, emmettPrefix, eventInStream, eventsInStream, eventsTable, eventsTableSQL, expectPongoDocuments, expectSQL, getPostgreSQLEventStore, globalNames, globalTag, handleProjections, newEventsInStream, pongoMultiStreamProjection, pongoProjection, pongoSingleStreamProjection, postgreSQLProjection, postgreSQLRawBatchSQLProjection, postgreSQLRawSQLProjection, readStream, sanitizeNameSQL, schemaSQL, streamsTable, streamsTableSQL, subscriptionsTableSQL };