@superhero/eventflow-db 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +401 -0
  2. package/config.js +30 -0
  3. package/index.js +662 -0
  4. package/index.test.js +266 -0
  5. package/package.json +34 -0
  6. package/sql/event/delete-by-id.sql +3 -0
  7. package/sql/event/delete-by-pid-domain.sql +4 -0
  8. package/sql/event/persist.sql +3 -0
  9. package/sql/event/read-by-id.sql +3 -0
  10. package/sql/event/read-by-pid-domain.sql +4 -0
  11. package/sql/event/schema.sql +19 -0
  12. package/sql/event_cpid/delete.sql +4 -0
  13. package/sql/event_cpid/persist.sql +3 -0
  14. package/sql/event_cpid/read-by-cpid-domain.sql +6 -0
  15. package/sql/event_cpid/read-by-event_id.sql +3 -0
  16. package/sql/event_cpid/schema.sql +12 -0
  17. package/sql/event_eid/delete.sql +4 -0
  18. package/sql/event_eid/persist.sql +3 -0
  19. package/sql/event_eid/read-by-eid-domain.sql +6 -0
  20. package/sql/event_eid/read-by-eid.sql +5 -0
  21. package/sql/event_eid/read-by-event_id.sql +3 -0
  22. package/sql/event_eid/schema.sql +12 -0
  23. package/sql/event_published/persist.sql +3 -0
  24. package/sql/event_published/schema.sql +23 -0
  25. package/sql/event_published/update-to-consumed-by-hub.sql +5 -0
  26. package/sql/event_published/update-to-consumed-by-spoke.sql +5 -0
  27. package/sql/event_published/update-to-failed.sql +3 -0
  28. package/sql/event_published/update-to-orphan.sql +3 -0
  29. package/sql/event_published/update-to-success.sql +3 -0
  30. package/sql/event_scheduled/persist.sql +3 -0
  31. package/sql/event_scheduled/read.sql +4 -0
  32. package/sql/event_scheduled/schema.sql +20 -0
  33. package/sql/event_scheduled/update-executed.sql +3 -0
  34. package/sql/event_scheduled/update-failed.sql +3 -0
  35. package/sql/event_scheduled/update-success.sql +3 -0
  36. package/sql/hub/persist.sql +3 -0
  37. package/sql/hub/read-online-hubs.sql +3 -0
  38. package/sql/hub/schema.sql +16 -0
  39. package/sql/hub/update-to-quit.sql +3 -0
  40. package/sql/log/archive.sql +5 -0
  41. package/sql/log/persist.sql +3 -0
  42. package/sql/log/schema.sql +14 -0
package/index.js ADDED
@@ -0,0 +1,662 @@
1
+
2
+ import Gateway from '@superhero/db'
3
+ import mysql2 from 'mysql2'
4
+ import AdapterFactory from '@superhero/db/adapter/mysql/factory.js'
5
+ import path from 'node:path'
6
+ import { fileURLToPath } from 'node:url'
7
+
8
+ export function locate(locator)
9
+ {
10
+ const
11
+ config = locator('@superhero/config').find('eventflow/db', {}),
12
+ adapterFactory = new AdapterFactory(),
13
+ adapter = adapterFactory.create(mysql2, config),
14
+ filePath = fileURLToPath(path.join(path.dirname(import.meta.url), 'sql')),
15
+ fileSuffix = '.sql',
16
+ gateway = new Gateway(adapter, filePath, fileSuffix)
17
+
18
+ return new DB(gateway)
19
+ }
20
+
21
+ /**
22
+ * @memberof Eventflow
23
+ */
24
+ export default class DB
25
+ {
26
+ constructor(gateway)
27
+ {
28
+ this.gateway = gateway
29
+ }
30
+
31
+ async destroy()
32
+ {
33
+ await this.gateway.close()
34
+ }
35
+
36
+ async createTableEventPublished()
37
+ {
38
+ try
39
+ {
40
+ await this.gateway.query('event_published/schema')
41
+ }
42
+ catch(reason)
43
+ {
44
+ const error = new Error('could not create table event_published')
45
+ error.code = 'E_EVENTFLOW_DB_CREATE_TABLE_EVENT_PUBLISHED'
46
+ error.cause = reason
47
+ throw error
48
+ }
49
+ }
50
+
51
+ async createTableEventCpid()
52
+ {
53
+ try
54
+ {
55
+ await this.gateway.query('event_cpid/schema')
56
+ }
57
+ catch(reason)
58
+ {
59
+ const error = new Error('could not create table event_cpid')
60
+ error.code = 'E_EVENTFLOW_DB_CREATE_TABLE_EVENT_CPID'
61
+ error.cause = reason
62
+ throw error
63
+ }
64
+ }
65
+
66
+ async createTableEventEid()
67
+ {
68
+ try
69
+ {
70
+ await this.gateway.query('event_eid/schema')
71
+ }
72
+ catch(reason)
73
+ {
74
+ const error = new Error('could not create table event_eid')
75
+ error.code = 'E_EVENTFLOW_DB_CREATE_TABLE_EVENT_EID'
76
+ error.cause = reason
77
+ throw error
78
+ }
79
+ }
80
+
81
+ async createTableEventScheduled()
82
+ {
83
+ try
84
+ {
85
+ await this.gateway.query('event_scheduled/schema')
86
+ }
87
+ catch(reason)
88
+ {
89
+ const error = new Error('could not create table event_schedule')
90
+ error.code = 'E_EVENTFLOW_DB_CREATE_TABLE_EVENT_SCHEDULED'
91
+ error.cause = reason
92
+ throw error
93
+ }
94
+ }
95
+
96
+ async createTableEvent()
97
+ {
98
+ try
99
+ {
100
+ await this.gateway.query('event/schema')
101
+ }
102
+ catch(reason)
103
+ {
104
+ const error = new Error('could not create table event')
105
+ error.code = 'E_EVENTFLOW_DB_CREATE_TABLE_EVENT'
106
+ error.cause = reason
107
+ throw error
108
+ }
109
+ }
110
+
111
+ async createTableLog()
112
+ {
113
+ try
114
+ {
115
+ await this.gateway.query('log/schema')
116
+ }
117
+ catch(reason)
118
+ {
119
+ const error = new Error('could not create table log')
120
+ error.code = 'E_EVENTFLOW_DB_CREATE_TABLE_LOG'
121
+ error.cause = reason
122
+ throw error
123
+ }
124
+ }
125
+
126
+ async createTableHub()
127
+ {
128
+ try
129
+ {
130
+ await this.gateway.query('hub/schema')
131
+ }
132
+ catch(reason)
133
+ {
134
+ const error = new Error('could not create table hub')
135
+ error.code = 'E_EVENTFLOW_DB_CREATE_TABLE_HUB'
136
+ error.cause = reason
137
+ throw error
138
+ }
139
+ }
140
+
141
+ async setupTableSchemas()
142
+ {
143
+ await this.createTableHub()
144
+ await this.createTableEvent()
145
+ await this.createTableEventCpid()
146
+ await this.createTableEventEid()
147
+ await this.createTableEventPublished()
148
+ await this.createTableEventScheduled()
149
+ await this.createTableLog()
150
+ }
151
+
152
+ #generateEventId()
153
+ {
154
+ return Date.now().toString(36) + '-' + Math.random().toString(36).slice(2)
155
+ }
156
+
157
+ async persistEvent(event)
158
+ {
159
+ try
160
+ {
161
+ const
162
+ id = event.id ?? this.#generateEventId(),
163
+ data = JSON.stringify(event.data ?? {})
164
+
165
+ await this.gateway.query('event/persist', [{ ...event, id, data }])
166
+
167
+ return id
168
+ }
169
+ catch(reason)
170
+ {
171
+ const error = new Error('could not persist event')
172
+ error.code = 'E_EVENTFLOW_DB_EVENT_PERSIST'
173
+ error.cause = reason
174
+ error.event = event
175
+ throw error
176
+ }
177
+ }
178
+
179
+ async deleteEvent(id)
180
+ {
181
+ try
182
+ {
183
+ const result = await this.gateway.query('event/delete-by-id', [ id ])
184
+ return result.affectedRows > 0
185
+ }
186
+ catch(reason)
187
+ {
188
+ const error = new Error(`could not delete event by id: ${id}`)
189
+ error.code = 'E_EVENTFLOW_DB_EVENT_DELETE'
190
+ error.cause = reason
191
+ throw error
192
+ }
193
+ }
194
+
195
+ async deleteEventByDomainAndPid(domain, pid)
196
+ {
197
+ try
198
+ {
199
+ const result = await this.gateway.query('event/delete-by-pid-domain', [ pid, domain ])
200
+ return result.affectedRows > 0
201
+ }
202
+ catch(reason)
203
+ {
204
+ const error = new Error(`could not delete event by pid ${pid} in domain ${domain}`)
205
+ error.code = 'E_EVENTFLOW_DB_EVENT_DELETE_BY_PID'
206
+ error.cause = reason
207
+ throw error
208
+ }
209
+ }
210
+
211
+ async readEvent(id)
212
+ {
213
+ let result
214
+
215
+ try
216
+ {
217
+ result = await this.gateway.query('event/read-by-id', [ id ])
218
+ }
219
+ catch(reason)
220
+ {
221
+ const error = new Error(`could not read event by id: ${id}`)
222
+ error.code = 'E_EVENTFLOW_DB_EVENT_READ'
223
+ error.cause = reason
224
+ throw error
225
+ }
226
+
227
+ if(result.length === 0)
228
+ {
229
+ const error = new Error(`event not found by id: ${id}`)
230
+ error.code = 'E_EVENTFLOW_DB_EVENT_NOT_FOUND'
231
+ throw error
232
+ }
233
+
234
+ const event = result[0]
235
+ return event
236
+ }
237
+
238
+ async readEventsByDomainAndPid(domain, pid)
239
+ {
240
+ let result
241
+
242
+ try
243
+ {
244
+ result = await this.gateway.query('event/read-by-pid-domain', [ pid, domain ])
245
+ }
246
+ catch(reason)
247
+ {
248
+ const error = new Error(`could not read event by pid: ${pid} and domain: ${domain}`)
249
+ error.code = 'E_EVENTFLOW_DB_EVENT_READ_BY_PID'
250
+ error.cause = reason
251
+ throw error
252
+ }
253
+
254
+ return result
255
+ }
256
+
257
+ async persistEventCpid(event_id, cpid)
258
+ {
259
+ try
260
+ {
261
+ const result = await this.gateway.query('event_cpid/persist', [ event_id, cpid ])
262
+ return result.affectedRows > 0
263
+ }
264
+ catch(reason)
265
+ {
266
+ const error = new Error(`Could not persist event (${event_id}) and cpid (${cpid}) association`)
267
+ error.code = 'E_EVENTFLOW_DB_EVENT_CPID_PERSIST'
268
+ error.cause = reason
269
+ throw error
270
+ }
271
+ }
272
+
273
+ async deleteEventCpid(event_id, cpid)
274
+ {
275
+ try
276
+ {
277
+ const result = await this.gateway.query('event_cpid/delete', [ event_id, cpid ])
278
+ return result.affectedRows > 0
279
+ }
280
+ catch(reason)
281
+ {
282
+ const error = new Error(`Could not delete event (${event_id}) and cpid (${cpid}) association`)
283
+ error.code = 'E_EVENTFLOW_DB_EVENT_CPID_DELETE'
284
+ error.cause = reason
285
+ throw error
286
+ }
287
+ }
288
+
289
+ async readEventCpidByEventId(id)
290
+ {
291
+ let result
292
+
293
+ try
294
+ {
295
+ result = await this.gateway.query('event_cpid/read-by-event_id', [ id ])
296
+ }
297
+ catch(reason)
298
+ {
299
+ const error = new Error(`could not read cpid by event id: ${id}`)
300
+ error.code = 'E_EVENTFLOW_DB_EVENT_CPID_READ_BY_EVENT_ID'
301
+ error.cause = reason
302
+ throw error
303
+ }
304
+
305
+ return result.map((row) => row.cpid)
306
+ }
307
+
308
+ async readEventsByDomainAndCpid(domain, cpid)
309
+ {
310
+ try
311
+ {
312
+ return await this.gateway.query('event_cpid/read-by-cpid-domain', [ cpid, domain ])
313
+ }
314
+ catch(reason)
315
+ {
316
+ const error = new Error(`could not read events by domain: ${domain} and cpid: ${cpid}`)
317
+ error.code = 'E_EVENTFLOW_DB_EVENT_BY_DOMAIN_AND_CPID_READ'
318
+ error.cause = reason
319
+ throw error
320
+ }
321
+ }
322
+
323
+ async persistEventEid(event_id, eid)
324
+ {
325
+ try
326
+ {
327
+ const result = await this.gateway.query('event_eid/persist', [ event_id, eid ])
328
+ return result.affectedRows > 0
329
+ }
330
+ catch(reason)
331
+ {
332
+ const error = new Error(`could not persist event (${event_id}) and eid (${eid}) association`)
333
+ error.code = 'E_EVENTFLOW_DB_EVENT_EID_PERSIST'
334
+ error.cause = reason
335
+ throw error
336
+ }
337
+ }
338
+
339
+ async deleteEventEid(event_id, eid)
340
+ {
341
+ try
342
+ {
343
+ const result = await this.gateway.query('event_eid/delete', [ event_id, eid ])
344
+ return result.affectedRows > 0
345
+ }
346
+ catch(reason)
347
+ {
348
+ const error = new Error(`could not persist event (${event_id}) and eid (${eid}) association`)
349
+ error.code = 'E_EVENTFLOW_DB_EVENT_EID_DELETE'
350
+ error.cause = reason
351
+ throw error
352
+ }
353
+ }
354
+
355
+ async readEventEidByEventId(id)
356
+ {
357
+ let result
358
+
359
+ try
360
+ {
361
+ result = await this.gateway.query('event_eid/read-by-event_id', [ id ])
362
+ }
363
+ catch(reason)
364
+ {
365
+ const error = new Error(`could not read eid by event id: ${id}`)
366
+ error.code = 'E_EVENTFLOW_DB_EVENT_EID_READ_BY_EVENT_ID'
367
+ error.cause = reason
368
+ throw error
369
+ }
370
+
371
+ return result.map((row) => row.eid)
372
+ }
373
+
374
+ async readEventsByEid(eid)
375
+ {
376
+ try
377
+ {
378
+ return await this.gateway.query('event_eid/read-by-eid', [ eid ])
379
+ }
380
+ catch(reason)
381
+ {
382
+ const error = new Error(`could not read event by eid: ${eid}`)
383
+ error.code = 'E_EVENTFLOW_DB_EVENTS_READ_BY_EID'
384
+ error.cause = reason
385
+ throw error
386
+ }
387
+ }
388
+
389
+ async readEventsByDomainAndEid(domain, eid)
390
+ {
391
+ try
392
+ {
393
+ return await this.gateway.query('event_eid/read-by-eid-domain', [ eid, domain ])
394
+ }
395
+ catch(reason)
396
+ {
397
+ const error = new Error(`could not read events by domain: ${domain} eid: ${eid}`)
398
+ error.code = 'E_EVENTFLOW_DB_EVENTS_READ_BY_DOMAIN_AND_EID'
399
+ error.cause = reason
400
+ throw error
401
+ }
402
+ }
403
+
404
+ async persistEventPublished(publishedEvent)
405
+ {
406
+ try
407
+ {
408
+ const result = await this.gateway.query('event_published/persist', [ publishedEvent ])
409
+ return result.affectedRows > 0
410
+ }
411
+ catch(reason)
412
+ {
413
+ const error = new Error('could not persist event published')
414
+ error.code = 'E_EVENTFLOW_DB_EVENT_PUBLISHED_PERSIST'
415
+ error.cause = reason
416
+ error.publishedEvent = publishedEvent
417
+ throw error
418
+ }
419
+ }
420
+
421
+ async updateEventPublishedToConsumedByHub(id, hub)
422
+ {
423
+ try
424
+ {
425
+ const result = await this.gateway.query('event_published/update-to-consumed-by-hub', [ hub, id ])
426
+ return result.affectedRows > 0
427
+ }
428
+ catch(reason)
429
+ {
430
+ const error = new Error(`could not update published event: ${id} to consumed by hub: ${hub}`)
431
+ error.code = 'E_EVENTFLOW_DB_EVENT_PUBLISHED_CREATE'
432
+ error.cause = reason
433
+ throw error
434
+ }
435
+ }
436
+
437
+ async updateEventPublishedToConsumedBySpoke(id, spoke)
438
+ {
439
+ try
440
+ {
441
+ const result = await this.gateway.query('event_published/update-to-consumed-by-spoke', [ spoke, id ])
442
+ return result.affectedRows > 0
443
+ }
444
+ catch(reason)
445
+ {
446
+ const error = new Error(`could not update published event: ${id} to consumed by spoke: ${spoke}`)
447
+ error.code = 'E_EVENTFLOW_DB_EVENT_PUBLISHED_CREATE'
448
+ error.cause = reason
449
+ throw error
450
+ }
451
+ }
452
+
453
+ async updateEventPublishedToOrphan(id)
454
+ {
455
+ try
456
+ {
457
+ const result = await this.gateway.query('event_published/update-to-orphan', [ id ])
458
+ return result.affectedRows > 0
459
+ }
460
+ catch(reason)
461
+ {
462
+ const error = new Error(`could not update published event: ${id} to orphan`)
463
+ error.code = 'E_EVENTFLOW_DB_EVENT_PUBLISHED_UPDATE_ORPHAN'
464
+ error.cause = reason
465
+ throw error
466
+ }
467
+ }
468
+
469
+ async updateEventPublishedToSuccess(id)
470
+ {
471
+ try
472
+ {
473
+ const result = await this.gateway.query('event_published/update-to-success', [ id ])
474
+ return result.affectedRows > 0
475
+ }
476
+ catch(reason)
477
+ {
478
+ const error = new Error(`could not update published event: ${id} to success`)
479
+ error.code = 'E_EVENTFLOW_DB_EVENT_PUBLISHED_UPDATE_SUCCESS'
480
+ error.cause = reason
481
+ throw error
482
+ }
483
+ }
484
+
485
+ async updateEventPublishedToFailed(id)
486
+ {
487
+ try
488
+ {
489
+ const result = await this.gateway.query('event_published/update-to-failed', [ id ])
490
+ return result.affectedRows > 0
491
+ }
492
+ catch(reason)
493
+ {
494
+ const error = new Error(`could not update published event: ${id} to failed`)
495
+ error.code = 'E_EVENTFLOW_DB_EVENT_PUBLISHED_UPDATE_FAILED'
496
+ error.cause = reason
497
+ throw error
498
+ }
499
+ }
500
+
501
+ async persistEventScheduled(scheduledEvent)
502
+ {
503
+ try
504
+ {
505
+ const result = await this.gateway.query('event_scheduled/persist', [ scheduledEvent ])
506
+ return result.affectedRows > 0
507
+ }
508
+ catch(reason)
509
+ {
510
+ const error = new Error(`could not persist the scheduled event`)
511
+ error.code = 'E_EVENTFLOW_DB_SCHEDULED_EVENT_PERSIST'
512
+ error.cause = reason
513
+ error.scheduledEvent = scheduledEvent
514
+ throw error
515
+ }
516
+ }
517
+
518
+ async readEventsScheduled()
519
+ {
520
+ try
521
+ {
522
+ return await this.gateway.query('event_scheduled/read')
523
+ }
524
+ catch(reason)
525
+ {
526
+ const error = new Error('could not read scheduled events')
527
+ error.code = 'E_EVENTFLOW_DB_SCHEDULED_EVENT_READ'
528
+ error.cause = reason
529
+ throw error
530
+ }
531
+ }
532
+
533
+ async updateEventScheduledExecuted(id)
534
+ {
535
+ try
536
+ {
537
+ const result = await this.gateway.query('event_scheduled/update-executed', [ id ])
538
+ return result.affectedRows > 0
539
+ }
540
+ catch(reason)
541
+ {
542
+ const error = new Error(`could not update the scheduled event: ${id} as executed`)
543
+ error.code = 'E_EVENTFLOW_DB_SCHEDULED_EVENT_UPDATE_EXECUTED'
544
+ error.cause = reason
545
+ throw error
546
+ }
547
+ }
548
+
549
+ async updateEventScheduledSuccess(id)
550
+ {
551
+ try
552
+ {
553
+ const result = await this.gateway.query('event_scheduled/update-success', [ id ])
554
+ return result.affectedRows > 0
555
+ }
556
+ catch(reason)
557
+ {
558
+ const error = new Error(`could not update the scheduled event: ${id} as successful`)
559
+ error.code = 'E_EVENTFLOW_DB_SCHEDULED_EVENT_UPDATE_SUCCESS'
560
+ error.cause = reason
561
+ throw error
562
+ }
563
+ }
564
+
565
+ async updateEventScheduledFailed(id)
566
+ {
567
+ try
568
+ {
569
+ const result = await this.gateway.query('event_scheduled/update-failed', [ id ])
570
+ return result.affectedRows > 0
571
+ }
572
+ catch(reason)
573
+ {
574
+ const error = new Error(`could not update the scheduled event: ${id} as failed`)
575
+ error.code = 'E_EVENTFLOW_DB_SCHEDULED_EVENT_UPDATE_FAILED'
576
+ error.cause = reason
577
+ throw error
578
+ }
579
+ }
580
+
581
+ async persistHub(hub)
582
+ {
583
+ try
584
+ {
585
+ const result = await this.gateway.query('hub/persist', [ hub ])
586
+ return result.affectedRows > 0
587
+ }
588
+ catch(reason)
589
+ {
590
+ const error = new Error('could not persist hub')
591
+ error.code = 'E_EVENTFLOW_DB_HUB_PERSIST'
592
+ error.cause = reason
593
+ error.hub = hub
594
+ throw error
595
+ }
596
+ }
597
+
598
+ async readOnlineHubs()
599
+ {
600
+ try
601
+ {
602
+ return await this.gateway.query('hub/read-online-hubs')
603
+ }
604
+ catch(reason)
605
+ {
606
+ const error = new Error('could not read online hubs')
607
+ error.code = 'E_EVENTFLOW_DB_HUBS_READ'
608
+ error.cause = reason
609
+ throw error
610
+ }
611
+ }
612
+
613
+ async updateHubToQuit(hub)
614
+ {
615
+ try
616
+ {
617
+ const result = await this.gateway.query('hub/update-to-quit', [ hub ])
618
+ return result.affectedRows > 0
619
+ }
620
+ catch(reason)
621
+ {
622
+ const error = new Error(`could not update hub: ${hub} to quit`)
623
+ error.code = 'E_EVENTFLOW_DB_HUB_UPDATE_TO_QUIT'
624
+ error.cause = reason
625
+ throw error
626
+ }
627
+ }
628
+
629
+ async persistLog(log)
630
+ {
631
+ try
632
+ {
633
+ log.error = JSON.stringify(log.error ?? {})
634
+ await this.gateway.query('log/persist', [ log ])
635
+ }
636
+ catch(reason)
637
+ {
638
+ const error = new Error('could not persist log')
639
+ error.code = 'E_EVENTFLOW_DB_LOG_PERSIST'
640
+ error.cause = reason
641
+ error.log = log
642
+ throw error
643
+ }
644
+ }
645
+
646
+ async archiveLog(date)
647
+ {
648
+ date = (date ? new Date(date) : new Date()).toJSON().slice(0, 10)
649
+ try
650
+ {
651
+ const partition = date.replace(/-/g, '')
652
+ await this.gateway.query('log/archive', [ partition, date ])
653
+ }
654
+ catch(reason)
655
+ {
656
+ const error = new Error(`could not archive log for date: ${date}`)
657
+ error.code = 'E_EVENTFLOW_DB_LOG_ARCHIVE'
658
+ error.cause = reason
659
+ throw error
660
+ }
661
+ }
662
+ }