@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/README.md ADDED
@@ -0,0 +1,401 @@
1
+ # @superhero/eventflow-db
2
+
3
+ `@superhero/eventflow-db` is a Node.js library providing common persistent logic for the Eventflow ecosystem. It abstracts database interactions and ensures a standardized way of managing event-related data in the event-driven architecture of Eventflow.
4
+
5
+ ## Features
6
+
7
+ - Simplified table schema management for the Eventflow components.
8
+ - Supports creating, reading, updating and deleting events and their associations.
9
+ - Supports database interactions for scheduled and published events.
10
+ - Integrates with `@superhero/db` for file management of SQL queries, and `mysql2` as the database driver.
11
+ - Error declarations with descriptive error messages and error codes.
12
+
13
+ ## Installation
14
+
15
+ > [!NOTE]
16
+ > This module is only expected to be a dependency to `@superhero/eventflow-hub` and `@superhero/eventflow-spoke` as a common library.
17
+
18
+ ```sh
19
+ npm install @superhero/eventflow-db
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ ### Initialize the Database Component
25
+
26
+ The library uses a locator pattern to retrieve dependencies and set up configurations.
27
+
28
+ ```javascript
29
+ import Config from '@superhero/config'
30
+ import Locator from '@superhero/locator'
31
+ import { locate } from '@superhero/eventflow-db'
32
+
33
+ const config = new Config()
34
+ await config.add('@superhero/eventflow-db')
35
+
36
+ const locator = new Locator()
37
+ locator.set('@superhero/config', config)
38
+
39
+ const db = locate(locator)
40
+ ```
41
+
42
+ ### Table Schema Setup
43
+
44
+ Use the `setupTableSchemas` method to ensure all required tables are created:
45
+
46
+ ```javascript
47
+ await db.setupTableSchemas()
48
+ ```
49
+
50
+ ### Persisting Events
51
+
52
+ You can persist an event and let the library generate a unique ID if one is not provided:
53
+
54
+ ```javascript
55
+ const event =
56
+ {
57
+ domain : 'example',
58
+ pid : 'process-id',
59
+ name : 'event-name',
60
+ data : { key: 'value' },
61
+ }
62
+
63
+ const eventId = await db.persistEvent(event)
64
+ console.log(`Event persisted with ID: ${eventId}`)
65
+ ```
66
+
67
+ ### Reading Events
68
+
69
+ #### By ID
70
+
71
+ ```javascript
72
+ const event = await db.readEvent(eventId)
73
+ console.log('Event:', event)
74
+ ```
75
+
76
+ #### By Domain and Process ID
77
+
78
+ ```javascript
79
+ const events = await db.readEventsByDomainAndPid('example', 'process-id')
80
+ console.log('Events:', events)
81
+ ```
82
+
83
+ ### Scheduling Events
84
+
85
+ ```javascript
86
+ const scheduledEvent =
87
+ {
88
+ event_id : eventId,
89
+ scheduled : new Date(),
90
+ }
91
+
92
+ await db.persistEventScheduled(scheduledEvent)
93
+
94
+ const scheduledEvents = await db.readEventsScheduled()
95
+ console.log('Scheduled Events:', scheduledEvents)
96
+ ```
97
+
98
+ ### Publishing Events
99
+
100
+ ```javascript
101
+ const publishedEvent =
102
+ {
103
+ event_id : eventId,
104
+ publisher : 'publisher-id',
105
+ }
106
+
107
+ await db.persistEventPublished(publishedEvent)
108
+ await db.updateEventPublishedToSuccess(eventId)
109
+ ```
110
+
111
+ ### Logging
112
+
113
+ ```javascript
114
+ const log =
115
+ {
116
+ agent : 'hub-id',
117
+ message : 'Test log message',
118
+ error : { message: 'Error details' },
119
+ };
120
+
121
+ await db.persistLog(log)
122
+ ```
123
+
124
+ ### Managing Hubs
125
+
126
+ #### Persisting a Hub
127
+
128
+ ```javascript
129
+ const hub =
130
+ {
131
+ id : 'hub-id',
132
+ external_ip : '127.0.0.1',
133
+ external_port : 50001,
134
+ internal_ip : '127.0.0.1',
135
+ internal_port : 50001,
136
+ }
137
+
138
+ await db.persistHub(hub)
139
+ ```
140
+
141
+ #### Reading Online Hubs
142
+
143
+ ```javascript
144
+ const hubs = await db.readOnlineHubs()
145
+ console.log('Online Hubs:', hubs)
146
+ ```
147
+
148
+ ## Table Schemas
149
+
150
+ Below are the database schemas used in this component:
151
+
152
+ ### Event Table
153
+
154
+ ```sql
155
+ CREATE TABLE IF NOT EXISTS event
156
+ (
157
+ id VARCHAR(64) NOT NULL,
158
+ timestamp DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
159
+ domain VARCHAR(64) NOT NULL,
160
+ rid VARCHAR(64) NULL,
161
+ pid VARCHAR(64) NOT NULL,
162
+ name VARCHAR(64) NOT NULL,
163
+ data JSON NOT NULL,
164
+
165
+ PRIMARY KEY (id),
166
+ FOREIGN KEY (rid) REFERENCES event (id) ON DELETE SET NULL,
167
+
168
+ INDEX idx_rid (rid),
169
+ INDEX idx_name (name, timestamp),
170
+ INDEX idx_domain (domain, timestamp),
171
+ INDEX idx_domain_pid (domain, pid, timestamp)
172
+ )
173
+ ENGINE=InnoDB
174
+ ```
175
+
176
+ ### Associated Event CPID Table
177
+
178
+ ```sql
179
+ CREATE TABLE IF NOT EXISTS event_cpid
180
+ (
181
+ event_id VARCHAR(64) NOT NULL,
182
+ cpid VARCHAR(64) NOT NULL,
183
+
184
+ PRIMARY KEY (event_id, cpid),
185
+ FOREIGN KEY (event_id) REFERENCES event (id)
186
+ ON UPDATE CASCADE
187
+ ON DELETE CASCADE,
188
+ INDEX idx_cpid (cpid)
189
+ )
190
+ ENGINE=InnoDB
191
+ ```
192
+
193
+ ### Associated Event EID Table
194
+
195
+ ```sql
196
+ CREATE TABLE IF NOT EXISTS event_eid
197
+ (
198
+ event_id VARCHAR(64) NOT NULL,
199
+ eid VARCHAR(64) NOT NULL,
200
+
201
+ PRIMARY KEY (event_id, eid),
202
+ FOREIGN KEY (event_id) REFERENCES event (id)
203
+ ON UPDATE CASCADE
204
+ ON DELETE CASCADE,
205
+ INDEX idx_eid (eid)
206
+ )
207
+ ENGINE=InnoDB
208
+ ```
209
+
210
+ ### Event Published Table
211
+
212
+ ```sql
213
+ CREATE TABLE IF NOT EXISTS event_published
214
+ (
215
+ event_id VARCHAR(64) NOT NULL,
216
+ published DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP(),
217
+ publisher VARCHAR(64) NOT NULL,
218
+ consumer VARCHAR(64) NULL,
219
+ hub VARCHAR(64) NULL,
220
+ consumed_hub DATETIME NULL,
221
+ consumed_spoke DATETIME NULL,
222
+ success DATETIME NULL,
223
+ failed DATETIME NULL,
224
+ orphan DATETIME NULL,
225
+
226
+ PRIMARY KEY (event_id),
227
+ FOREIGN KEY (hub) REFERENCES hub (id),
228
+ FOREIGN KEY (event_id) REFERENCES event (id)
229
+ ON UPDATE CASCADE
230
+ ON DELETE CASCADE,
231
+ INDEX idx_published (published),
232
+ INDEX idx_consumed_hub (consumed_hub),
233
+ INDEX idx_consumed_spoke (consumed_spoke)
234
+ )
235
+ ENGINE=InnoDB
236
+ ```
237
+
238
+ ### Event Scheduled Table
239
+
240
+ ```sql
241
+ CREATE TABLE IF NOT EXISTS event_scheduled
242
+ (
243
+ event_id VARCHAR(64) NOT NULL,
244
+ timestamp DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP(),
245
+ scheduled DATETIME NOT NULL,
246
+ executed DATETIME NULL,
247
+ success DATETIME NULL,
248
+ failed DATETIME NULL,
249
+
250
+ PRIMARY KEY (event_id),
251
+ FOREIGN KEY (event_id) REFERENCES event (id)
252
+ ON UPDATE CASCADE
253
+ ON DELETE CASCADE,
254
+ INDEX idx_timestamp (timestamp),
255
+ INDEX idx_scheduled (scheduled),
256
+ INDEX idx_executed (executed),
257
+ INDEX idx_success (success),
258
+ INDEX idx_failed (failed)
259
+ )
260
+ ENGINE=InnoDB
261
+ ```
262
+
263
+ ### Hub Table
264
+
265
+ ```sql
266
+ CREATE TABLE IF NOT EXISTS hub
267
+ (
268
+ id VARCHAR(64) NOT NULL,
269
+ timestamp DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP(),
270
+ external_ip VARCHAR(16) NOT NULL,
271
+ external_port SMALLINT UNSIGNED NOT NULL,
272
+ internal_ip VARCHAR(16) NOT NULL,
273
+ internal_port SMALLINT UNSIGNED NOT NULL,
274
+ quit DATETIME NULL,
275
+
276
+ PRIMARY KEY (id),
277
+ INDEX idx_timestamp (timestamp),
278
+ INDEX idx_external_ip_port (external_ip, external_port),
279
+ INDEX idx_internal_ip_port (internal_ip, internal_port)
280
+ )
281
+ ENGINE=InnoDB
282
+ ```
283
+
284
+ ### Log Table
285
+
286
+ ```sql
287
+ CREATE TABLE IF NOT EXISTS log
288
+ (
289
+ timestamp DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
290
+ agent VARCHAR(64) NOT NULL,
291
+ message TEXT NOT NULL,
292
+ error JSON NOT NULL,
293
+ INDEX idx_timestamp (timestamp),
294
+ INDEX idx_agent (agent)
295
+ )
296
+ ENGINE=InnoDB
297
+ PARTITION BY RANGE (TO_DAYS(timestamp))
298
+ (
299
+ PARTITION p_hot VALUES LESS THAN MAXVALUE
300
+ )
301
+ ```
302
+
303
+ ## Development
304
+
305
+ ### Build the Environment
306
+
307
+ The `build` script launches a MySQL container for testing:
308
+
309
+ ```sh
310
+ npm run build
311
+ ```
312
+
313
+ ## Running Tests
314
+
315
+ The library includes a test suite using `node:test`. Run tests using:
316
+
317
+ ```bash
318
+ npm test
319
+ ```
320
+
321
+ ### Test Coverage
322
+
323
+ ```
324
+ ▶ @superhero/eventflow-db
325
+ ▶ Setup table schemas
326
+ ▶ Persist a hub
327
+ ✔ Read online hubs (5.587373ms)
328
+
329
+ ▶ Persisting an event should generate an ID if not provided
330
+ ✔ Read an event by id should return the same data as when persisted the event (4.480859ms)
331
+
332
+ ▶ Schedule a persisted event
333
+ ✔ Read all scheduled events (5.224091ms)
334
+ ✔ Update scheduled event as executed (5.74482ms)
335
+ ✔ Update scheduled event as success (5.297828ms)
336
+ ✔ Update scheduled event as failed (6.276729ms)
337
+ ✔ Schedule a persisted event (29.417902ms)
338
+
339
+ ▶ Publish a persisted event
340
+ ✔ Update published event to consumed by hub (7.16767ms)
341
+ ✔ Update published event to consumed by spoke (6.096988ms)
342
+ ✔ Update published event to success (6.491936ms)
343
+ ✔ Update published event to failed (7.925911ms)
344
+ ✔ Update published event to orphan (4.379269ms)
345
+ ✔ Publish a persisted event (38.916677ms)
346
+
347
+ ▶ Persist event cpid association
348
+ ✔ Read events by domain and cpid (3.532181ms)
349
+ ✔ Read associated cpid by event id (4.202583ms)
350
+ ✔ Delete associated cpid by event id (7.538617ms)
351
+ ✔ Read deleted associated cpid by event id returns empty (2.465462ms)
352
+ ✔ Persist event cpid association (25.886055ms)
353
+
354
+ ▶ Persist event eid association
355
+ ✔ Read events by eid (3.706348ms)
356
+ ✔ Read events by domain and eid (4.862519ms)
357
+ ✔ Read associated eid by event id (3.864714ms)
358
+ ✔ Delete associated eid by event id (3.806146ms)
359
+ ✔ Read deleted associated eid by event id returns empty (3.217061ms)
360
+ ✔ Persist event eid association (24.547606ms)
361
+
362
+ ▶ Delete event
363
+ ✔ Reading a deleted event rejects (2.195439ms)
364
+ ✔ Delete event (9.437439ms)
365
+
366
+ ▶ By domain and pid
367
+ ✔ Read event by domain and pid (3.467037ms)
368
+ ✔ Delete event by domain and pid (5.735279ms)
369
+ ✔ Read empty eventlog by domain and pid (2.678678ms)
370
+ ✔ By domain and pid (17.088958ms)
371
+ ✔ Persisting an event should generate an ID if not provided (158.031614ms)
372
+
373
+ ✔ Persist log (5.5136ms)
374
+ ✔ Update hub to quit (7.367751ms)
375
+ ✔ Persist a hub (182.853588ms)
376
+ ✔ Reading a non existing event should reject with an error (2.51415ms)
377
+ ✔ Setup table schemas (250.260079ms)
378
+ ✔ @superhero/eventflow-db (251.7368ms)
379
+
380
+ tests 36
381
+ suites 1
382
+ pass 36
383
+
384
+ ----------------------------------------------------------------
385
+ file | line % | branch % | funcs % | uncovered lines
386
+ ----------------------------------------------------------------
387
+ config.js | 100.00 | 100.00 | 100.00 |
388
+ index.js | 100.00 | 96.51 | 100.00 |
389
+ index.test.js | 100.00 | 100.00 | 100.00 |
390
+ ----------------------------------------------------------------
391
+ all files | 100.00 | 97.62 | 100.00 |
392
+ ----------------------------------------------------------------
393
+ ```
394
+
395
+ ## License
396
+
397
+ This project is licensed under the MIT License.
398
+
399
+ ## Contributing
400
+
401
+ Feel free to submit issues or pull requests for improvements or additional features.
package/config.js ADDED
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @memberof Eventflow.DB
3
+ */
4
+ export default
5
+ {
6
+ core:
7
+ {
8
+ locator:
9
+ {
10
+ 'eventflow/db' : '.'
11
+ }
12
+ },
13
+ eventflow:
14
+ {
15
+ db:
16
+ {
17
+ debug : process.env.EVENTFLOW_MYSQL_DEBUG ?? false,
18
+ insecureAuth : process.env.EVENTFLOW_MYSQL_INSECURE_AUTH ?? false,
19
+ connectionLimit : process.env.EVENTFLOW_MYSQL_CONNECTION_LIMIT ?? '5',
20
+ flags : process.env.EVENTFLOW_MYSQL_FLAGS ?? '',
21
+ charset : process.env.EVENTFLOW_MYSQL_CHARSET ?? 'UTF8_GENERAL_CI',
22
+ timezone : process.env.EVENTFLOW_MYSQL_TIMEZONE ?? 'Z',
23
+ host : process.env.EVENTFLOW_MYSQL_HOST ?? 'localhost',
24
+ port : process.env.EVENTFLOW_MYSQL_PORT ?? '3306',
25
+ user : process.env.EVENTFLOW_MYSQL_USER ?? 'root',
26
+ password : process.env.EVENTFLOW_MYSQL_PASS ?? 'root',
27
+ database : process.env.EVENTFLOW_MYSQL_DB ?? 'eventflow',
28
+ }
29
+ }
30
+ }