@ocoda/event-sourcing-mariadb 2.1.4 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,37 @@
1
1
  # @ocoda/event-sourcing-mariadb
2
2
 
3
+ ## 3.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#526](https://github.com/ocoda/event-sourcing/pull/526) [`b93acfa`](https://github.com/ocoda/event-sourcing/commit/b93acfaea457a6ee1e7cb2b345bd9f5ca8cb695d) Thanks [@drieshooghe](https://github.com/drieshooghe)! - Harden the MariaDB and MongoDB event and snapshot stores.
8
+
9
+ MariaDB:
10
+
11
+ - Reads no longer hide failures. A missing table, a dropped connection or an unregistered event used to end the stream silently and return a truncated history. The original error is now thrown to the consumer. Applications that relied on reading a not-yet-created pool returning nothing must create it with `ensureCollection()` first.
12
+ - Stopping a read early (`break` or an error in the consumer) now discards the rest of the result set and releases the connection. Before, this could leave the connection stuck and eventually exhaust the pool.
13
+ - A concurrent append that loses the race on the primary key now throws `EventStoreVersionConflictException` / `SnapshotStoreVersionConflictException` instead of `EventStorePersistenceException` / `SnapshotStorePersistenceException`.
14
+ - Table names are quoted with the connector's `escapeId`, so pool names with special characters are handled safely.
15
+
16
+ MongoDB:
17
+
18
+ - Cursors are now closed when a read ends early or fails, instead of staying open on the server until they time out.
19
+ - Appends no longer look up the collection on every write. Collections that are known to exist (created through `ensureCollection()` or found once) are remembered per store instance. Unknown pools are still rejected with the same exception and are checked against the server on every attempt. If you drop a collection while a store instance is running, call `ensureCollection()` again before appending to it: otherwise MongoDB re-creates it on the next write without its unique indexes.
20
+ - A concurrent append that loses the race on the `(streamId, version)` unique index now throws `EventStoreVersionConflictException` / `SnapshotStoreVersionConflictException` instead of `EventStorePersistenceException` / `SnapshotStorePersistenceException`. Events of the losing append that were already inserted are removed again.
21
+ - The batches yielded by the read methods are no longer emptied after the consumer resumes, so consumers can safely keep a reference to a batch.
22
+
23
+ - Updated dependencies [[`c2f0b47`](https://github.com/ocoda/event-sourcing/commit/c2f0b479ad295d0c92b1cf3c522bac23424c8c81)]:
24
+ - @ocoda/event-sourcing@3.0.1
25
+
26
+ ## 3.0.0
27
+
28
+ ### Patch Changes
29
+
30
+ - [#474](https://github.com/ocoda/event-sourcing/pull/474) [`7a14fea`](https://github.com/ocoda/event-sourcing/commit/7a14feab663e0d0f323b017127e2771aae6b9183) Thanks [@drieshooghe](https://github.com/drieshooghe)! - Expand shared E2E coverage, align integration test structure, and add core bus edge-case tests.
31
+
32
+ - Updated dependencies [[`6290979`](https://github.com/ocoda/event-sourcing/commit/6290979d9727a1edbede492c19a330ddef5ba736), [`7a14fea`](https://github.com/ocoda/event-sourcing/commit/7a14feab663e0d0f323b017127e2771aae6b9183)]:
33
+ - @ocoda/event-sourcing@3.0.0
34
+
3
35
  ## 2.1.4
4
36
 
5
37
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -26,6 +26,10 @@ declare class MariaDBEventStore extends EventStore<MariaDBEventStoreConfig> {
26
26
  getEnvelope({ streamId }: EventStream, version: number, pool?: IEventPool): Promise<EventEnvelope>;
27
27
  getEnvelopes({ streamId }: EventStream, filter?: IEventFilter): AsyncGenerator<EventEnvelope[]>;
28
28
  getAllEnvelopes(filter: IAllEventsFilter): AsyncGenerator<EventEnvelope[]>;
29
+ /**
30
+ * Best effort lookup of the latest version of a stream, used to report a conflict.
31
+ */
32
+ private getLatestVersion;
29
33
  }
30
34
 
31
35
  interface MariaDBEventStoreConfig extends EventStoreConfig, PoolConfig {
@@ -60,6 +64,10 @@ declare class MariaDBSnapshotStore extends SnapshotStore<MariaDBSnapshotStoreCon
60
64
  getLastEnvelopesForAggregate<A extends AggregateRoot>(aggregate: Type<A>, filter?: ILatestSnapshotFilter): AsyncGenerator<SnapshotEnvelope<A>[]>;
61
65
  getManyLastSnapshotEnvelopes<A extends AggregateRoot>(streams: SnapshotStream[], pool?: ISnapshotPool): Promise<Map<SnapshotStream, SnapshotEnvelope<A>>>;
62
66
  private getLastStreamEntities;
67
+ /**
68
+ * Best effort lookup of the latest snapshot version of a stream, used to report a conflict.
69
+ */
70
+ private getLatestVersion;
63
71
  }
64
72
 
65
73
  interface MariaDBSnapshotStoreConfig extends SnapshotStoreConfig, PoolConfig {
package/dist/index.js CHANGED
@@ -3,6 +3,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
4
4
  var __hasOwnProp = Object.prototype.hasOwnProperty;
5
5
  var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : Symbol.for("Symbol." + name);
6
+ var __typeError = (msg) => {
7
+ throw TypeError(msg);
8
+ };
6
9
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
7
10
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
8
11
  var __export = (target, all) => {
@@ -54,6 +57,34 @@ var __asyncGenerator = (__this, __arguments, generator) => {
54
57
  }, method = (k) => it[k] = (x) => new Promise((yes, no) => resume(k, x, yes, no)), it = {};
55
58
  return generator = generator.apply(__this, __arguments), it[__knownSymbol("asyncIterator")] = () => it, method("next"), method("throw"), method("return"), it;
56
59
  };
60
+ var __yieldStar = (value) => {
61
+ var obj = value[__knownSymbol("asyncIterator")], isAwait = false, method, it = {};
62
+ if (obj == null) {
63
+ obj = value[__knownSymbol("iterator")]();
64
+ method = (k) => it[k] = (x) => obj[k](x);
65
+ } else {
66
+ obj = obj.call(value);
67
+ method = (k) => it[k] = (v) => {
68
+ if (isAwait) {
69
+ isAwait = false;
70
+ if (k === "throw") throw v;
71
+ return v;
72
+ }
73
+ isAwait = true;
74
+ return {
75
+ done: false,
76
+ value: new __await(new Promise((resolve) => {
77
+ var x = obj[k](v);
78
+ if (!(x instanceof Object)) __typeError("Object expected");
79
+ resolve(x);
80
+ }), 1)
81
+ };
82
+ };
83
+ }
84
+ return it[__knownSymbol("iterator")] = () => it, method("next"), "throw" in obj ? method("throw") : it.throw = (x) => {
85
+ throw x;
86
+ }, "return" in obj && method("return"), it;
87
+ };
57
88
  var __forAwait = (obj, it, method) => (it = obj[__knownSymbol("asyncIterator")]) ? it.call(obj) : (obj = obj[__knownSymbol("iterator")](), it = {}, method = (key, fn) => (fn = obj[key]) && (it[key] = (arg) => new Promise((yes, no, done) => (arg = fn.call(obj, arg), done = arg.done, Promise.resolve(arg.value).then((value) => yes({ value, done }), no)))), method("next"), method("return"), it);
58
89
 
59
90
  // lib/index.ts
@@ -67,6 +98,34 @@ module.exports = __toCommonJS(index_exports);
67
98
  // lib/mariadb.event-store.ts
68
99
  var import_event_sourcing = require("@ocoda/event-sourcing");
69
100
  var import_mariadb = require("mariadb");
101
+
102
+ // lib/mariadb.utils.ts
103
+ var ER_DUP_ENTRY = 1062;
104
+ var isDuplicateEntryError = /* @__PURE__ */ __name((error) => {
105
+ const { errno, code } = error != null ? error : {};
106
+ return errno === ER_DUP_ENTRY || code === "ER_DUP_ENTRY";
107
+ }, "isDuplicateEntryError");
108
+ function streamRows(pool, sql, params) {
109
+ return __asyncGenerator(this, null, function* () {
110
+ var _a;
111
+ const connection = yield new __await(pool.getConnection());
112
+ let stream;
113
+ try {
114
+ stream = connection.queryStream(sql, params);
115
+ stream.on("error", () => void 0);
116
+ yield* __yieldStar(stream);
117
+ } finally {
118
+ if (stream) {
119
+ (_a = stream.close) == null ? void 0 : _a.call(stream);
120
+ stream.destroy();
121
+ }
122
+ yield new __await(connection.release());
123
+ }
124
+ });
125
+ }
126
+ __name(streamRows, "streamRows");
127
+
128
+ // lib/mariadb.event-store.ts
70
129
  var _MariaDBEventStore = class _MariaDBEventStore extends import_event_sourcing.EventStore {
71
130
  constructor() {
72
131
  super(...arguments);
@@ -88,7 +147,7 @@ var _MariaDBEventStore = class _MariaDBEventStore extends import_event_sourcing.
88
147
  return __async(this, null, function* () {
89
148
  const collection = import_event_sourcing.EventCollection.get(pool);
90
149
  try {
91
- yield this.pool.query(`CREATE TABLE IF NOT EXISTS \`${collection}\` (
150
+ yield this.pool.query(`CREATE TABLE IF NOT EXISTS ${this.pool.escapeId(collection)} (
92
151
  stream_id VARCHAR(120) NOT NULL,
93
152
  version INT NOT NULL,
94
153
  event VARCHAR(80) NOT NULL,
@@ -110,45 +169,35 @@ var _MariaDBEventStore = class _MariaDBEventStore extends import_event_sourcing.
110
169
  }
111
170
  listCollections(filter) {
112
171
  return __asyncGenerator(this, null, function* () {
113
- const connection = this.pool.getConnection();
114
172
  const batch = (filter == null ? void 0 : filter.batch) || import_event_sourcing.DEFAULT_BATCH_SIZE;
115
173
  const query = "SELECT TABLE_NAME FROM information_schema.tables WHERE BINARY table_name LIKE '%events'";
116
- const client = yield new __await(connection);
117
- const stream = client.queryStream(query);
174
+ let batchedCollections = [];
118
175
  try {
119
- let batchedCollections = [];
120
- try {
121
- for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
122
- const { TABLE_NAME } = temp.value;
123
- batchedCollections.push(TABLE_NAME);
124
- if (batchedCollections.length === batch) {
125
- yield batchedCollections;
126
- batchedCollections = [];
127
- }
128
- }
129
- } catch (temp) {
130
- error = [temp];
131
- } finally {
132
- try {
133
- more && (temp = iter.return) && (yield new __await(temp.call(iter)));
134
- } finally {
135
- if (error)
136
- throw error[0];
176
+ for (var iter = __forAwait(streamRows(this.pool, query)), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
177
+ const { TABLE_NAME } = temp.value;
178
+ batchedCollections.push(TABLE_NAME);
179
+ if (batchedCollections.length === batch) {
180
+ yield batchedCollections;
181
+ batchedCollections = [];
137
182
  }
138
183
  }
139
- if (batchedCollections.length > 0) {
140
- yield batchedCollections;
141
- }
142
- } catch (e) {
143
- stream.destroy();
184
+ } catch (temp) {
185
+ error = [temp];
144
186
  } finally {
145
- yield new __await(client.release());
187
+ try {
188
+ more && (temp = iter.return) && (yield new __await(temp.call(iter)));
189
+ } finally {
190
+ if (error)
191
+ throw error[0];
192
+ }
193
+ }
194
+ if (batchedCollections.length > 0) {
195
+ yield batchedCollections;
146
196
  }
147
197
  });
148
198
  }
149
199
  getEvents(_0, _1) {
150
200
  return __asyncGenerator(this, arguments, function* ({ streamId }, filter) {
151
- const connection = this.pool.getConnection();
152
201
  const collection = import_event_sourcing.EventCollection.get(filter == null ? void 0 : filter.pool);
153
202
  const fromVersion = filter == null ? void 0 : filter.fromVersion;
154
203
  const direction = (filter == null ? void 0 : filter.direction) || import_event_sourcing.StreamReadingDirection.FORWARD;
@@ -156,7 +205,7 @@ var _MariaDBEventStore = class _MariaDBEventStore extends import_event_sourcing.
156
205
  const batch = (filter == null ? void 0 : filter.batch) || import_event_sourcing.DEFAULT_BATCH_SIZE;
157
206
  const query = `
158
207
  SELECT event, payload
159
- FROM \`${collection}\`
208
+ FROM ${this.pool.escapeId(collection)}
160
209
  WHERE stream_id = ?
161
210
  ${fromVersion ? "AND version >= ?" : ""}
162
211
  ORDER BY version ${direction === import_event_sourcing.StreamReadingDirection.FORWARD ? "ASC" : "DESC"}
@@ -170,43 +219,35 @@ var _MariaDBEventStore = class _MariaDBEventStore extends import_event_sourcing.
170
219
  streamId,
171
220
  limit
172
221
  ];
173
- const client = yield new __await(connection);
174
- const stream = client.queryStream(query, params);
222
+ let batchedEvents = [];
175
223
  try {
176
- let batchedEvents = [];
177
- try {
178
- for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
179
- const { event, payload } = temp.value;
180
- batchedEvents.push(this.eventMap.deserializeEvent(event, payload));
181
- if (batchedEvents.length === batch) {
182
- yield batchedEvents;
183
- batchedEvents = [];
184
- }
185
- }
186
- } catch (temp) {
187
- error = [temp];
188
- } finally {
189
- try {
190
- more && (temp = iter.return) && (yield new __await(temp.call(iter)));
191
- } finally {
192
- if (error)
193
- throw error[0];
224
+ for (var iter = __forAwait(streamRows(this.pool, query, params)), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
225
+ const { event, payload } = temp.value;
226
+ batchedEvents.push(this.eventMap.deserializeEvent(event, payload));
227
+ if (batchedEvents.length === batch) {
228
+ yield batchedEvents;
229
+ batchedEvents = [];
194
230
  }
195
231
  }
196
- if (batchedEvents.length > 0) {
197
- yield batchedEvents;
198
- }
199
- } catch (e) {
200
- stream.destroy();
232
+ } catch (temp) {
233
+ error = [temp];
201
234
  } finally {
202
- yield new __await(client.release());
235
+ try {
236
+ more && (temp = iter.return) && (yield new __await(temp.call(iter)));
237
+ } finally {
238
+ if (error)
239
+ throw error[0];
240
+ }
241
+ }
242
+ if (batchedEvents.length > 0) {
243
+ yield batchedEvents;
203
244
  }
204
245
  });
205
246
  }
206
247
  getEvent(_0, _1, _2) {
207
248
  return __async(this, arguments, function* ({ streamId }, version, pool) {
208
249
  const collection = import_event_sourcing.EventCollection.get(pool);
209
- const [entity] = yield this.pool.query(`SELECT event, payload FROM \`${collection}\` WHERE stream_id = ? AND version = ?`, [
250
+ const [entity] = yield this.pool.query(`SELECT event, payload FROM ${this.pool.escapeId(collection)} WHERE stream_id = ? AND version = ?`, [
210
251
  streamId,
211
252
  version
212
253
  ]);
@@ -220,11 +261,13 @@ var _MariaDBEventStore = class _MariaDBEventStore extends import_event_sourcing.
220
261
  return __async(this, null, function* () {
221
262
  const connection = yield this.pool.getConnection();
222
263
  const collection = import_event_sourcing.EventCollection.get(pool);
264
+ let currentVersion = 0;
223
265
  try {
224
- const [currentVersionResult] = yield connection.query(`SELECT MAX(version) as version FROM \`${collection}\` WHERE stream_id = ?`, [
266
+ const table = connection.escapeId(collection);
267
+ const [currentVersionResult] = yield connection.query(`SELECT MAX(version) as version FROM ${table} WHERE stream_id = ?`, [
225
268
  stream.streamId
226
269
  ]);
227
- const currentVersion = (currentVersionResult == null ? void 0 : currentVersionResult.version) || 0;
270
+ currentVersion = (currentVersionResult == null ? void 0 : currentVersionResult.version) || 0;
228
271
  if (aggregateVersion <= currentVersion) {
229
272
  throw new import_event_sourcing.EventStoreVersionConflictException(stream, aggregateVersion, currentVersion);
230
273
  }
@@ -246,7 +289,7 @@ var _MariaDBEventStore = class _MariaDBEventStore extends import_event_sourcing.
246
289
  envelopes.push(envelope);
247
290
  }
248
291
  yield connection.beginTransaction();
249
- yield connection.batch(`INSERT INTO \`${collection}\` VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, envelopes.map(({ event, payload, metadata }) => {
292
+ yield connection.batch(`INSERT INTO ${table} VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, envelopes.map(({ event, payload, metadata }) => {
250
293
  var _a, _b;
251
294
  return [
252
295
  stream.streamId,
@@ -264,15 +307,17 @@ var _MariaDBEventStore = class _MariaDBEventStore extends import_event_sourcing.
264
307
  yield connection.commit();
265
308
  return envelopes;
266
309
  } catch (error) {
267
- yield connection.rollback();
268
- switch (error.constructor) {
269
- case import_event_sourcing.EventStoreVersionConflictException:
270
- throw error;
271
- default:
272
- throw new import_event_sourcing.EventStorePersistenceException(collection, error);
310
+ yield connection.rollback().catch(() => void 0);
311
+ if (error instanceof import_event_sourcing.EventStoreVersionConflictException) {
312
+ throw error;
313
+ }
314
+ if (isDuplicateEntryError(error)) {
315
+ const latestVersion = yield this.getLatestVersion(collection, stream, connection, currentVersion);
316
+ throw new import_event_sourcing.EventStoreVersionConflictException(stream, aggregateVersion, latestVersion, error);
273
317
  }
318
+ throw new import_event_sourcing.EventStorePersistenceException(collection, error);
274
319
  } finally {
275
- connection.release();
320
+ yield connection.release();
276
321
  }
277
322
  });
278
323
  }
@@ -280,7 +325,7 @@ var _MariaDBEventStore = class _MariaDBEventStore extends import_event_sourcing.
280
325
  return __async(this, arguments, function* ({ streamId }, version, pool) {
281
326
  var _a, _b;
282
327
  const collection = import_event_sourcing.EventCollection.get(pool);
283
- const [entity] = yield this.pool.query(`SELECT event, payload, event_id, aggregate_id, version, occurred_on, correlation_id, causation_id FROM \`${collection}\` WHERE stream_id = ? AND version = ?`, [
328
+ const [entity] = yield this.pool.query(`SELECT event, payload, event_id, aggregate_id, version, occurred_on, correlation_id, causation_id FROM ${this.pool.escapeId(collection)} WHERE stream_id = ? AND version = ?`, [
284
329
  streamId,
285
330
  version
286
331
  ]);
@@ -299,7 +344,6 @@ var _MariaDBEventStore = class _MariaDBEventStore extends import_event_sourcing.
299
344
  }
300
345
  getEnvelopes(_0, _1) {
301
346
  return __asyncGenerator(this, arguments, function* ({ streamId }, filter) {
302
- const connection = this.pool.getConnection();
303
347
  const collection = import_event_sourcing.EventCollection.get(filter == null ? void 0 : filter.pool);
304
348
  const fromVersion = filter == null ? void 0 : filter.fromVersion;
305
349
  const direction = (filter == null ? void 0 : filter.direction) || import_event_sourcing.StreamReadingDirection.FORWARD;
@@ -307,7 +351,7 @@ var _MariaDBEventStore = class _MariaDBEventStore extends import_event_sourcing.
307
351
  const batch = (filter == null ? void 0 : filter.batch) || import_event_sourcing.DEFAULT_BATCH_SIZE;
308
352
  const query = `
309
353
  SELECT event, payload, event_id, aggregate_id, version, occurred_on, correlation_id, causation_id
310
- FROM \`${collection}\`
354
+ FROM ${this.pool.escapeId(collection)}
311
355
  WHERE stream_id = ?
312
356
  ${fromVersion ? "AND version >= ?" : ""}
313
357
  ORDER BY version ${direction === import_event_sourcing.StreamReadingDirection.FORWARD ? "ASC" : "DESC"}
@@ -321,98 +365,96 @@ var _MariaDBEventStore = class _MariaDBEventStore extends import_event_sourcing.
321
365
  streamId,
322
366
  limit
323
367
  ];
324
- const client = yield new __await(connection);
325
- const stream = client.queryStream(query, params);
368
+ let batchedEvents = [];
326
369
  try {
327
- let batchedEvents = [];
328
- try {
329
- for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
330
- const { event, payload, event_id, aggregate_id, version, occurred_on, correlation_id, causation_id } = temp.value;
331
- batchedEvents.push(import_event_sourcing.EventEnvelope.from(event, payload, {
332
- eventId: import_event_sourcing.EventId.from(event_id),
333
- aggregateId: aggregate_id,
334
- version,
335
- occurredOn: occurred_on,
336
- correlationId: correlation_id != null ? correlation_id : void 0,
337
- causationId: causation_id != null ? causation_id : void 0
338
- }));
339
- if (batchedEvents.length === batch) {
340
- yield batchedEvents;
341
- batchedEvents = [];
342
- }
343
- }
344
- } catch (temp) {
345
- error = [temp];
346
- } finally {
347
- try {
348
- more && (temp = iter.return) && (yield new __await(temp.call(iter)));
349
- } finally {
350
- if (error)
351
- throw error[0];
370
+ for (var iter = __forAwait(streamRows(this.pool, query, params)), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
371
+ const { event, payload, event_id, aggregate_id, version, occurred_on, correlation_id, causation_id } = temp.value;
372
+ batchedEvents.push(import_event_sourcing.EventEnvelope.from(event, payload, {
373
+ eventId: import_event_sourcing.EventId.from(event_id),
374
+ aggregateId: aggregate_id,
375
+ version,
376
+ occurredOn: occurred_on,
377
+ correlationId: correlation_id != null ? correlation_id : void 0,
378
+ causationId: causation_id != null ? causation_id : void 0
379
+ }));
380
+ if (batchedEvents.length === batch) {
381
+ yield batchedEvents;
382
+ batchedEvents = [];
352
383
  }
353
384
  }
354
- if (batchedEvents.length > 0) {
355
- yield batchedEvents;
356
- }
357
- } catch (e) {
358
- stream.destroy();
385
+ } catch (temp) {
386
+ error = [temp];
359
387
  } finally {
360
- yield new __await(client.release());
388
+ try {
389
+ more && (temp = iter.return) && (yield new __await(temp.call(iter)));
390
+ } finally {
391
+ if (error)
392
+ throw error[0];
393
+ }
394
+ }
395
+ if (batchedEvents.length > 0) {
396
+ yield batchedEvents;
361
397
  }
362
398
  });
363
399
  }
364
400
  getAllEnvelopes(filter) {
365
401
  return __asyncGenerator(this, null, function* () {
366
- const connection = this.pool.getConnection();
367
402
  const collection = import_event_sourcing.EventCollection.get(filter == null ? void 0 : filter.pool);
368
403
  const yearMonths = this.getYearMonthRange(filter.since, filter.until);
369
404
  const batch = (filter == null ? void 0 : filter.batch) || import_event_sourcing.DEFAULT_BATCH_SIZE;
370
405
  const query = `
371
406
  SELECT event, payload, event_id, aggregate_id, version, occurred_on, correlation_id, causation_id
372
- FROM \`${collection}\`
407
+ FROM ${this.pool.escapeId(collection)}
373
408
  WHERE event_date IN (?)
374
409
  ORDER BY event_date ASC, event_id ASC
375
410
  `;
376
411
  const params = [
377
412
  yearMonths
378
413
  ];
379
- const client = yield new __await(connection);
380
- const stream = client.queryStream(query, params);
414
+ let batchedEvents = [];
381
415
  try {
382
- let batchedEvents = [];
383
- try {
384
- for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
385
- const { event, payload, event_id, aggregate_id, version, occurred_on, correlation_id, causation_id } = temp.value;
386
- batchedEvents.push(import_event_sourcing.EventEnvelope.from(event, payload, {
387
- eventId: import_event_sourcing.EventId.from(event_id),
388
- aggregateId: aggregate_id,
389
- version,
390
- occurredOn: occurred_on,
391
- correlationId: correlation_id != null ? correlation_id : void 0,
392
- causationId: causation_id != null ? causation_id : void 0
393
- }));
394
- if (batchedEvents.length === batch) {
395
- yield batchedEvents;
396
- batchedEvents = [];
397
- }
398
- }
399
- } catch (temp) {
400
- error = [temp];
401
- } finally {
402
- try {
403
- more && (temp = iter.return) && (yield new __await(temp.call(iter)));
404
- } finally {
405
- if (error)
406
- throw error[0];
416
+ for (var iter = __forAwait(streamRows(this.pool, query, params)), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
417
+ const { event, payload, event_id, aggregate_id, version, occurred_on, correlation_id, causation_id } = temp.value;
418
+ batchedEvents.push(import_event_sourcing.EventEnvelope.from(event, payload, {
419
+ eventId: import_event_sourcing.EventId.from(event_id),
420
+ aggregateId: aggregate_id,
421
+ version,
422
+ occurredOn: occurred_on,
423
+ correlationId: correlation_id != null ? correlation_id : void 0,
424
+ causationId: causation_id != null ? causation_id : void 0
425
+ }));
426
+ if (batchedEvents.length === batch) {
427
+ yield batchedEvents;
428
+ batchedEvents = [];
407
429
  }
408
430
  }
409
- if (batchedEvents.length > 0) {
410
- yield batchedEvents;
431
+ } catch (temp) {
432
+ error = [temp];
433
+ } finally {
434
+ try {
435
+ more && (temp = iter.return) && (yield new __await(temp.call(iter)));
436
+ } finally {
437
+ if (error)
438
+ throw error[0];
411
439
  }
440
+ }
441
+ if (batchedEvents.length > 0) {
442
+ yield batchedEvents;
443
+ }
444
+ });
445
+ }
446
+ /**
447
+ * Best effort lookup of the latest version of a stream, used to report a conflict.
448
+ */
449
+ getLatestVersion(_0, _1, _2, _3) {
450
+ return __async(this, arguments, function* (collection, { streamId }, connection, fallback) {
451
+ try {
452
+ const [result] = yield connection.query(`SELECT MAX(version) as version FROM ${connection.escapeId(collection)} WHERE stream_id = ?`, [
453
+ streamId
454
+ ]);
455
+ return (result == null ? void 0 : result.version) || fallback;
412
456
  } catch (e) {
413
- stream.destroy();
414
- } finally {
415
- yield new __await(client.release());
457
+ return fallback;
416
458
  }
417
459
  });
418
460
  }
@@ -422,7 +464,7 @@ var MariaDBEventStore = _MariaDBEventStore;
422
464
 
423
465
  // lib/mariadb.snapshot-store.ts
424
466
  var import_event_sourcing2 = require("@ocoda/event-sourcing");
425
- var import_mariadb2 = require("mariadb");
467
+ var import_mariadb3 = require("mariadb");
426
468
  var _MariaDBSnapshotStore = class _MariaDBSnapshotStore extends import_event_sourcing2.SnapshotStore {
427
469
  constructor() {
428
470
  super(...arguments);
@@ -431,7 +473,7 @@ var _MariaDBSnapshotStore = class _MariaDBSnapshotStore extends import_event_sou
431
473
  connect() {
432
474
  return __async(this, null, function* () {
433
475
  this.logger.log("Starting store");
434
- this.pool = (0, import_mariadb2.createPool)(this.options);
476
+ this.pool = (0, import_mariadb3.createPool)(this.options);
435
477
  });
436
478
  }
437
479
  disconnect() {
@@ -444,7 +486,7 @@ var _MariaDBSnapshotStore = class _MariaDBSnapshotStore extends import_event_sou
444
486
  return __async(this, null, function* () {
445
487
  const collection = import_event_sourcing2.SnapshotCollection.get(pool);
446
488
  try {
447
- yield this.pool.query(`CREATE TABLE IF NOT EXISTS \`${collection}\` (
489
+ yield this.pool.query(`CREATE TABLE IF NOT EXISTS ${this.pool.escapeId(collection)} (
448
490
  stream_id VARCHAR(90) NOT NULL,
449
491
  version INT NOT NULL,
450
492
  payload JSON NOT NULL,
@@ -464,45 +506,35 @@ var _MariaDBSnapshotStore = class _MariaDBSnapshotStore extends import_event_sou
464
506
  }
465
507
  listCollections(filter) {
466
508
  return __asyncGenerator(this, null, function* () {
467
- const connection = this.pool.getConnection();
468
509
  const batch = (filter == null ? void 0 : filter.batch) || import_event_sourcing2.DEFAULT_BATCH_SIZE;
469
510
  const query = "SELECT TABLE_NAME FROM information_schema.tables WHERE BINARY table_name LIKE '%snapshots'";
470
- const client = yield new __await(connection);
471
- const stream = client.queryStream(query);
511
+ let batchedCollections = [];
472
512
  try {
473
- let batchedCollections = [];
474
- try {
475
- for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
476
- const { TABLE_NAME } = temp.value;
477
- batchedCollections.push(TABLE_NAME);
478
- if (batchedCollections.length === batch) {
479
- yield batchedCollections;
480
- batchedCollections = [];
481
- }
482
- }
483
- } catch (temp) {
484
- error = [temp];
485
- } finally {
486
- try {
487
- more && (temp = iter.return) && (yield new __await(temp.call(iter)));
488
- } finally {
489
- if (error)
490
- throw error[0];
513
+ for (var iter = __forAwait(streamRows(this.pool, query)), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
514
+ const { TABLE_NAME } = temp.value;
515
+ batchedCollections.push(TABLE_NAME);
516
+ if (batchedCollections.length === batch) {
517
+ yield batchedCollections;
518
+ batchedCollections = [];
491
519
  }
492
520
  }
493
- if (batchedCollections.length > 0) {
494
- yield batchedCollections;
495
- }
496
- } catch (e) {
497
- stream.destroy();
521
+ } catch (temp) {
522
+ error = [temp];
498
523
  } finally {
499
- yield new __await(client.release());
524
+ try {
525
+ more && (temp = iter.return) && (yield new __await(temp.call(iter)));
526
+ } finally {
527
+ if (error)
528
+ throw error[0];
529
+ }
530
+ }
531
+ if (batchedCollections.length > 0) {
532
+ yield batchedCollections;
500
533
  }
501
534
  });
502
535
  }
503
536
  getSnapshots(_0, _1) {
504
537
  return __asyncGenerator(this, arguments, function* ({ streamId }, filter) {
505
- const connection = this.pool.getConnection();
506
538
  const collection = import_event_sourcing2.SnapshotCollection.get(filter == null ? void 0 : filter.pool);
507
539
  const fromVersion = filter == null ? void 0 : filter.fromVersion;
508
540
  const direction = (filter == null ? void 0 : filter.direction) || import_event_sourcing2.StreamReadingDirection.FORWARD;
@@ -510,7 +542,7 @@ var _MariaDBSnapshotStore = class _MariaDBSnapshotStore extends import_event_sou
510
542
  const batch = (filter == null ? void 0 : filter.batch) || import_event_sourcing2.DEFAULT_BATCH_SIZE;
511
543
  const query = `
512
544
  SELECT payload
513
- FROM \`${collection}\`
545
+ FROM ${this.pool.escapeId(collection)}
514
546
  WHERE stream_id = ?
515
547
  ${fromVersion ? "AND version >= ?" : ""}
516
548
  ORDER BY version ${direction === import_event_sourcing2.StreamReadingDirection.FORWARD ? "ASC" : "DESC"}
@@ -524,43 +556,35 @@ var _MariaDBSnapshotStore = class _MariaDBSnapshotStore extends import_event_sou
524
556
  streamId,
525
557
  limit
526
558
  ];
527
- const client = yield new __await(connection);
528
- const stream = client.queryStream(query, params);
559
+ let batchedEvents = [];
529
560
  try {
530
- let batchedEvents = [];
531
- try {
532
- for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
533
- const { payload } = temp.value;
534
- batchedEvents.push(payload);
535
- if (batchedEvents.length === batch) {
536
- yield batchedEvents;
537
- batchedEvents = [];
538
- }
561
+ for (var iter = __forAwait(streamRows(this.pool, query, params)), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
562
+ const { payload } = temp.value;
563
+ batchedEvents.push(payload);
564
+ if (batchedEvents.length === batch) {
565
+ yield batchedEvents;
566
+ batchedEvents = [];
539
567
  }
540
- } catch (temp) {
541
- error = [temp];
542
- } finally {
543
- try {
544
- more && (temp = iter.return) && (yield new __await(temp.call(iter)));
545
- } finally {
546
- if (error)
547
- throw error[0];
548
- }
549
- }
550
- if (batchedEvents.length > 0) {
551
- yield batchedEvents;
552
568
  }
553
- } catch (e) {
554
- stream.destroy();
569
+ } catch (temp) {
570
+ error = [temp];
555
571
  } finally {
556
- yield new __await(client.release());
572
+ try {
573
+ more && (temp = iter.return) && (yield new __await(temp.call(iter)));
574
+ } finally {
575
+ if (error)
576
+ throw error[0];
577
+ }
578
+ }
579
+ if (batchedEvents.length > 0) {
580
+ yield batchedEvents;
557
581
  }
558
582
  });
559
583
  }
560
584
  getSnapshot(_0, _1, _2) {
561
585
  return __async(this, arguments, function* ({ streamId }, version, pool) {
562
586
  const collection = import_event_sourcing2.SnapshotCollection.get(pool);
563
- const [entity] = yield this.pool.query(`SELECT payload FROM \`${collection}\` WHERE stream_id = ? AND version = ?`, [
587
+ const [entity] = yield this.pool.query(`SELECT payload FROM ${this.pool.escapeId(collection)} WHERE stream_id = ? AND version = ?`, [
564
588
  streamId,
565
589
  version
566
590
  ]);
@@ -572,9 +596,12 @@ var _MariaDBSnapshotStore = class _MariaDBSnapshotStore extends import_event_sou
572
596
  }
573
597
  appendSnapshot(stream, aggregateVersion, snapshot, pool) {
574
598
  return __async(this, null, function* () {
599
+ var _a;
575
600
  const connection = yield this.pool.getConnection();
576
601
  const collection = import_event_sourcing2.SnapshotCollection.get(pool);
602
+ let latestVersion = 0;
577
603
  try {
604
+ const table = connection.escapeId(collection);
578
605
  const envelope = import_event_sourcing2.SnapshotEnvelope.create(snapshot, {
579
606
  aggregateId: stream.aggregateId,
580
607
  version: aggregateVersion
@@ -585,17 +612,18 @@ var _MariaDBSnapshotStore = class _MariaDBSnapshotStore extends import_event_sou
585
612
  "stream_id",
586
613
  "version"
587
614
  ], connection);
615
+ latestVersion = (_a = lastStreamEntity == null ? void 0 : lastStreamEntity.version) != null ? _a : 0;
588
616
  if (aggregateVersion <= (lastStreamEntity == null ? void 0 : lastStreamEntity.version)) {
589
617
  throw new import_event_sourcing2.SnapshotStoreVersionConflictException(stream, aggregateVersion, lastStreamEntity.version);
590
618
  }
591
619
  yield connection.beginTransaction();
592
620
  if (lastStreamEntity) {
593
- yield connection.query(`UPDATE \`${collection}\` SET latest = null WHERE stream_id = ? AND version = ?`, [
621
+ yield connection.query(`UPDATE ${table} SET latest = null WHERE stream_id = ? AND version = ?`, [
594
622
  lastStreamEntity.stream_id,
595
623
  lastStreamEntity.version
596
624
  ]);
597
625
  }
598
- yield connection.query(`INSERT INTO \`${collection}\` VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [
626
+ yield connection.query(`INSERT INTO ${table} VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [
599
627
  stream.streamId,
600
628
  envelope.metadata.version,
601
629
  JSON.stringify(envelope.payload),
@@ -608,15 +636,17 @@ var _MariaDBSnapshotStore = class _MariaDBSnapshotStore extends import_event_sou
608
636
  yield connection.commit();
609
637
  return envelope;
610
638
  } catch (error) {
611
- yield connection.rollback();
612
- switch (error.constructor) {
613
- case import_event_sourcing2.SnapshotStoreVersionConflictException:
614
- throw error;
615
- default:
616
- throw new import_event_sourcing2.SnapshotStorePersistenceException(collection, error);
639
+ yield connection.rollback().catch(() => void 0);
640
+ if (error instanceof import_event_sourcing2.SnapshotStoreVersionConflictException) {
641
+ throw error;
642
+ }
643
+ if (isDuplicateEntryError(error)) {
644
+ latestVersion = yield this.getLatestVersion(collection, stream, connection, latestVersion);
645
+ throw new import_event_sourcing2.SnapshotStoreVersionConflictException(stream, aggregateVersion, latestVersion, error);
617
646
  }
647
+ throw new import_event_sourcing2.SnapshotStorePersistenceException(collection, error);
618
648
  } finally {
619
- connection.release();
649
+ yield connection.release();
620
650
  }
621
651
  });
622
652
  }
@@ -673,7 +703,6 @@ var _MariaDBSnapshotStore = class _MariaDBSnapshotStore extends import_event_sou
673
703
  }
674
704
  getEnvelopes(_0, _1) {
675
705
  return __asyncGenerator(this, arguments, function* ({ streamId }, filter) {
676
- const connection = this.pool.getConnection();
677
706
  const collection = import_event_sourcing2.SnapshotCollection.get(filter == null ? void 0 : filter.pool);
678
707
  const fromVersion = filter == null ? void 0 : filter.fromVersion;
679
708
  const direction = (filter == null ? void 0 : filter.direction) || import_event_sourcing2.StreamReadingDirection.FORWARD;
@@ -681,7 +710,7 @@ var _MariaDBSnapshotStore = class _MariaDBSnapshotStore extends import_event_sou
681
710
  const batch = (filter == null ? void 0 : filter.batch) || import_event_sourcing2.DEFAULT_BATCH_SIZE;
682
711
  const query = `
683
712
  SELECT payload, aggregate_id, registered_on, snapshot_id, version
684
- FROM \`${collection}\`
713
+ FROM ${this.pool.escapeId(collection)}
685
714
  WHERE stream_id = ?
686
715
  ${fromVersion ? "AND version >= ?" : ""}
687
716
  ORDER BY version ${direction === import_event_sourcing2.StreamReadingDirection.FORWARD ? "ASC" : "DESC"}
@@ -695,48 +724,40 @@ var _MariaDBSnapshotStore = class _MariaDBSnapshotStore extends import_event_sou
695
724
  streamId,
696
725
  limit
697
726
  ];
698
- const client = yield new __await(connection);
699
- const stream = client.queryStream(query, params);
727
+ let batchedSnapshots = [];
700
728
  try {
701
- let batchedSnapshots = [];
702
- try {
703
- for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
704
- const { payload, aggregate_id, registered_on, snapshot_id, version } = temp.value;
705
- batchedSnapshots.push(import_event_sourcing2.SnapshotEnvelope.from(payload, {
706
- aggregateId: aggregate_id,
707
- registeredOn: registered_on,
708
- snapshotId: snapshot_id,
709
- version
710
- }));
711
- if (batchedSnapshots.length === batch) {
712
- yield batchedSnapshots;
713
- batchedSnapshots = [];
714
- }
715
- }
716
- } catch (temp) {
717
- error = [temp];
718
- } finally {
719
- try {
720
- more && (temp = iter.return) && (yield new __await(temp.call(iter)));
721
- } finally {
722
- if (error)
723
- throw error[0];
729
+ for (var iter = __forAwait(streamRows(this.pool, query, params)), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
730
+ const { payload, aggregate_id, registered_on, snapshot_id, version } = temp.value;
731
+ batchedSnapshots.push(import_event_sourcing2.SnapshotEnvelope.from(payload, {
732
+ aggregateId: aggregate_id,
733
+ registeredOn: registered_on,
734
+ snapshotId: snapshot_id,
735
+ version
736
+ }));
737
+ if (batchedSnapshots.length === batch) {
738
+ yield batchedSnapshots;
739
+ batchedSnapshots = [];
724
740
  }
725
741
  }
726
- if (batchedSnapshots.length > 0) {
727
- yield batchedSnapshots;
728
- }
729
- } catch (e) {
730
- stream.destroy();
742
+ } catch (temp) {
743
+ error = [temp];
731
744
  } finally {
732
- yield new __await(client.release());
745
+ try {
746
+ more && (temp = iter.return) && (yield new __await(temp.call(iter)));
747
+ } finally {
748
+ if (error)
749
+ throw error[0];
750
+ }
751
+ }
752
+ if (batchedSnapshots.length > 0) {
753
+ yield batchedSnapshots;
733
754
  }
734
755
  });
735
756
  }
736
757
  getEnvelope(_0, _1, _2) {
737
758
  return __async(this, arguments, function* ({ streamId }, version, pool) {
738
759
  const collection = import_event_sourcing2.SnapshotCollection.get(pool);
739
- const [entity] = yield this.pool.query(`SELECT payload, aggregate_id, registered_on, snapshot_id, version FROM \`${collection}\` WHERE stream_id = ? AND version = ?`, [
760
+ const [entity] = yield this.pool.query(`SELECT payload, aggregate_id, registered_on, snapshot_id, version FROM ${this.pool.escapeId(collection)} WHERE stream_id = ? AND version = ?`, [
740
761
  streamId,
741
762
  version
742
763
  ]);
@@ -753,7 +774,6 @@ var _MariaDBSnapshotStore = class _MariaDBSnapshotStore extends import_event_sou
753
774
  }
754
775
  getLastEnvelopesForAggregate(aggregate, filter) {
755
776
  return __asyncGenerator(this, null, function* () {
756
- const connection = this.pool.getConnection();
757
777
  const collection = import_event_sourcing2.SnapshotCollection.get(filter == null ? void 0 : filter.pool);
758
778
  const { streamName } = (0, import_event_sourcing2.getAggregateMetadata)(aggregate);
759
779
  const aggregateId = filter == null ? void 0 : filter.aggregateId;
@@ -761,7 +781,7 @@ var _MariaDBSnapshotStore = class _MariaDBSnapshotStore extends import_event_sou
761
781
  const batch = (filter == null ? void 0 : filter.batch) || import_event_sourcing2.DEFAULT_BATCH_SIZE;
762
782
  const query = `
763
783
  SELECT payload, aggregate_id, registered_on, snapshot_id, version
764
- FROM \`${collection}\`
784
+ FROM ${this.pool.escapeId(collection)}
765
785
  WHERE aggregate_name = ?
766
786
  AND ${aggregateId ? "latest >= ?" : "latest LIKE 'latest%'"}
767
787
  LIMIT ?
@@ -774,41 +794,33 @@ var _MariaDBSnapshotStore = class _MariaDBSnapshotStore extends import_event_sou
774
794
  streamName,
775
795
  limit
776
796
  ];
777
- const client = yield new __await(connection);
778
- const stream = client.queryStream(query, params);
797
+ let batchedSnapshots = [];
779
798
  try {
780
- let batchedSnapshots = [];
781
- try {
782
- for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
783
- const { payload, aggregate_id, registered_on, snapshot_id, version } = temp.value;
784
- batchedSnapshots.push(import_event_sourcing2.SnapshotEnvelope.from(payload, {
785
- aggregateId: aggregate_id,
786
- registeredOn: registered_on,
787
- snapshotId: snapshot_id,
788
- version
789
- }));
790
- if (batchedSnapshots.length === batch) {
791
- yield batchedSnapshots;
792
- batchedSnapshots = [];
793
- }
794
- }
795
- } catch (temp) {
796
- error = [temp];
797
- } finally {
798
- try {
799
- more && (temp = iter.return) && (yield new __await(temp.call(iter)));
800
- } finally {
801
- if (error)
802
- throw error[0];
799
+ for (var iter = __forAwait(streamRows(this.pool, query, params)), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
800
+ const { payload, aggregate_id, registered_on, snapshot_id, version } = temp.value;
801
+ batchedSnapshots.push(import_event_sourcing2.SnapshotEnvelope.from(payload, {
802
+ aggregateId: aggregate_id,
803
+ registeredOn: registered_on,
804
+ snapshotId: snapshot_id,
805
+ version
806
+ }));
807
+ if (batchedSnapshots.length === batch) {
808
+ yield batchedSnapshots;
809
+ batchedSnapshots = [];
803
810
  }
804
811
  }
805
- if (batchedSnapshots.length > 0) {
806
- yield batchedSnapshots;
807
- }
808
- } catch (e) {
809
- stream.destroy();
812
+ } catch (temp) {
813
+ error = [temp];
810
814
  } finally {
811
- yield new __await(client.release());
815
+ try {
816
+ more && (temp = iter.return) && (yield new __await(temp.call(iter)));
817
+ } finally {
818
+ if (error)
819
+ throw error[0];
820
+ }
821
+ }
822
+ if (batchedSnapshots.length > 0) {
823
+ yield batchedSnapshots;
812
824
  }
813
825
  });
814
826
  }
@@ -841,13 +853,28 @@ var _MariaDBSnapshotStore = class _MariaDBSnapshotStore extends import_event_sou
841
853
  return __async(this, null, function* () {
842
854
  const latestIds = streams.map(({ streamId }) => `latest#${streamId}`);
843
855
  return (connection || this.pool).query(`SELECT ${fields.join(", ")}
844
- FROM \`${collection}\`
856
+ FROM ${this.pool.escapeId(collection)}
845
857
  WHERE latest IN (?)
846
858
  `, [
847
859
  latestIds
848
860
  ]);
849
861
  });
850
862
  }
863
+ /**
864
+ * Best effort lookup of the latest snapshot version of a stream, used to report a conflict.
865
+ */
866
+ getLatestVersion(_0, _1, _2, _3) {
867
+ return __async(this, arguments, function* (collection, { streamId }, connection, fallback) {
868
+ try {
869
+ const [result] = yield connection.query(`SELECT MAX(version) as version FROM ${connection.escapeId(collection)} WHERE stream_id = ?`, [
870
+ streamId
871
+ ]);
872
+ return (result == null ? void 0 : result.version) || fallback;
873
+ } catch (e) {
874
+ return fallback;
875
+ }
876
+ });
877
+ }
851
878
  };
852
879
  __name(_MariaDBSnapshotStore, "MariaDBSnapshotStore");
853
880
  var MariaDBSnapshotStore = _MariaDBSnapshotStore;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ocoda/event-sourcing-mariadb",
3
- "version": "2.1.4",
3
+ "version": "3.0.1",
4
4
  "description": "NestJS Event Sourcing Library (@mariadb)",
5
5
  "author": "Dries Hooghe <dries@drieshooghe.com>",
6
6
  "license": "MIT",
@@ -13,32 +13,32 @@
13
13
  "node": ">= 20.0.0"
14
14
  },
15
15
  "dependencies": {
16
- "mariadb": "^3.4.2"
16
+ "mariadb": "^3.4.5"
17
17
  },
18
18
  "peerDependencies": {
19
19
  "@nestjs/core": "^11.0.0",
20
20
  "reflect-metadata": "^0.2.0",
21
21
  "rxjs": "^7.2.0",
22
- "@ocoda/event-sourcing": "2.1.4"
22
+ "@ocoda/event-sourcing": "3.0.1"
23
23
  },
24
24
  "devDependencies": {
25
25
  "@biomejs/biome": "1.9.4",
26
- "@faker-js/faker": "^9.8.0",
27
- "@nestjs/common": "11.1.3",
28
- "@nestjs/core": "11.1.3",
29
- "@nestjs/platform-express": "11.1.3",
30
- "@nestjs/testing": "11.1.3",
31
- "@swc-node/register": "^1.10.10",
32
- "@swc/core": "1.12.5",
33
- "@swc/jest": "0.2.38",
26
+ "@faker-js/faker": "^10.2.0",
27
+ "@nestjs/common": "11.1.6",
28
+ "@nestjs/core": "11.1.6",
29
+ "@nestjs/platform-express": "11.1.6",
30
+ "@nestjs/testing": "11.1.6",
31
+ "@swc-node/register": "^1.11.1",
32
+ "@swc/core": "1.13.5",
33
+ "@swc/jest": "0.2.39",
34
34
  "@types/jest": "30.0.0",
35
35
  "@types/node": "20.17.6",
36
- "jest": "30.0.2",
37
- "jest-mock": "30.0.2",
36
+ "jest": "30.1.3",
37
+ "jest-mock": "30.0.5",
38
38
  "reflect-metadata": "0.2.2",
39
39
  "rxjs": "7.8.2",
40
40
  "tsup": "^8.5.0",
41
- "typescript": "5.8.3",
41
+ "typescript": "5.9.2",
42
42
  "@ocoda/event-sourcing-config": "1.0.0",
43
43
  "@ocoda/event-sourcing-testing": "1.0.0"
44
44
  },
@@ -50,7 +50,8 @@
50
50
  "scripts": {
51
51
  "build": "rm -rf dist && tsup lib/index.ts --format cjs --dts",
52
52
  "test": "jest --config jest.config.js",
53
- "test:cov": "jest --config jest.config.js --coverage --collectCoverageFrom=lib/**/*.ts",
53
+ "test:cov": "jest --config jest.config.js --coverage",
54
+ "test:cov:check": "jest --config jest.config.js --coverage --coverageThreshold='{'\"global\"':{'\"lines\"':90}}'",
54
55
  "ci": "biome ci",
55
56
  "format": "biome format --write",
56
57
  "lint": "biome check --write"