@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.
- package/README.md +401 -0
- package/config.js +30 -0
- package/index.js +662 -0
- package/index.test.js +266 -0
- package/package.json +34 -0
- package/sql/event/delete-by-id.sql +3 -0
- package/sql/event/delete-by-pid-domain.sql +4 -0
- package/sql/event/persist.sql +3 -0
- package/sql/event/read-by-id.sql +3 -0
- package/sql/event/read-by-pid-domain.sql +4 -0
- package/sql/event/schema.sql +19 -0
- package/sql/event_cpid/delete.sql +4 -0
- package/sql/event_cpid/persist.sql +3 -0
- package/sql/event_cpid/read-by-cpid-domain.sql +6 -0
- package/sql/event_cpid/read-by-event_id.sql +3 -0
- package/sql/event_cpid/schema.sql +12 -0
- package/sql/event_eid/delete.sql +4 -0
- package/sql/event_eid/persist.sql +3 -0
- package/sql/event_eid/read-by-eid-domain.sql +6 -0
- package/sql/event_eid/read-by-eid.sql +5 -0
- package/sql/event_eid/read-by-event_id.sql +3 -0
- package/sql/event_eid/schema.sql +12 -0
- package/sql/event_published/persist.sql +3 -0
- package/sql/event_published/schema.sql +23 -0
- package/sql/event_published/update-to-consumed-by-hub.sql +5 -0
- package/sql/event_published/update-to-consumed-by-spoke.sql +5 -0
- package/sql/event_published/update-to-failed.sql +3 -0
- package/sql/event_published/update-to-orphan.sql +3 -0
- package/sql/event_published/update-to-success.sql +3 -0
- package/sql/event_scheduled/persist.sql +3 -0
- package/sql/event_scheduled/read.sql +4 -0
- package/sql/event_scheduled/schema.sql +20 -0
- package/sql/event_scheduled/update-executed.sql +3 -0
- package/sql/event_scheduled/update-failed.sql +3 -0
- package/sql/event_scheduled/update-success.sql +3 -0
- package/sql/hub/persist.sql +3 -0
- package/sql/hub/read-online-hubs.sql +3 -0
- package/sql/hub/schema.sql +16 -0
- package/sql/hub/update-to-quit.sql +3 -0
- package/sql/log/archive.sql +5 -0
- package/sql/log/persist.sql +3 -0
- 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
|
+
}
|