node-cqrs 1.2.0-beta.0 → 1.3.0-alpha.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/CHANGELOG.md +13 -0
- package/README.md +29 -9
- package/dist/cjs/postgresql/AbstractPostgresqlAccessor.js +83 -0
- package/dist/cjs/postgresql/AbstractPostgresqlAccessor.js.map +1 -0
- package/dist/cjs/postgresql/AbstractPostgresqlObjectProjection.js +36 -0
- package/dist/cjs/postgresql/AbstractPostgresqlObjectProjection.js.map +1 -0
- package/dist/cjs/postgresql/AbstractPostgresqlView.js +53 -0
- package/dist/cjs/postgresql/AbstractPostgresqlView.js.map +1 -0
- package/dist/cjs/postgresql/IContainer.js +3 -0
- package/dist/cjs/postgresql/IContainer.js.map +1 -0
- package/dist/cjs/postgresql/PostgresqlConnection.js +3 -0
- package/dist/cjs/postgresql/PostgresqlConnection.js.map +1 -0
- package/dist/cjs/postgresql/PostgresqlEventLocker.js +127 -0
- package/dist/cjs/postgresql/PostgresqlEventLocker.js.map +1 -0
- package/dist/cjs/postgresql/PostgresqlEventStorage.js +315 -0
- package/dist/cjs/postgresql/PostgresqlEventStorage.js.map +1 -0
- package/dist/cjs/postgresql/PostgresqlObjectStorage.js +137 -0
- package/dist/cjs/postgresql/PostgresqlObjectStorage.js.map +1 -0
- package/dist/cjs/postgresql/PostgresqlObjectView.js +46 -0
- package/dist/cjs/postgresql/PostgresqlObjectView.js.map +1 -0
- package/dist/cjs/postgresql/PostgresqlProjectionDataParams.js +3 -0
- package/dist/cjs/postgresql/PostgresqlProjectionDataParams.js.map +1 -0
- package/dist/cjs/postgresql/PostgresqlViewLocker.js +151 -0
- package/dist/cjs/postgresql/PostgresqlViewLocker.js.map +1 -0
- package/dist/cjs/postgresql/index.js +29 -0
- package/dist/cjs/postgresql/index.js.map +1 -0
- package/dist/cjs/postgresql/utils/getEventId.js +14 -0
- package/dist/cjs/postgresql/utils/getEventId.js.map +1 -0
- package/dist/cjs/postgresql/utils/index.js +19 -0
- package/dist/cjs/postgresql/utils/index.js.map +1 -0
- package/dist/cjs/postgresql/utils/quoteIdentifier.js +14 -0
- package/dist/cjs/postgresql/utils/quoteIdentifier.js.map +1 -0
- package/dist/cjs/sqlite/SqliteEventStorage.js +66 -36
- package/dist/cjs/sqlite/SqliteEventStorage.js.map +1 -1
- package/dist/esm/postgresql/AbstractPostgresqlAccessor.js +79 -0
- package/dist/esm/postgresql/AbstractPostgresqlAccessor.js.map +1 -0
- package/dist/esm/postgresql/AbstractPostgresqlObjectProjection.js +32 -0
- package/dist/esm/postgresql/AbstractPostgresqlObjectProjection.js.map +1 -0
- package/dist/esm/postgresql/AbstractPostgresqlView.js +49 -0
- package/dist/esm/postgresql/AbstractPostgresqlView.js.map +1 -0
- package/dist/esm/postgresql/IContainer.js +2 -0
- package/dist/esm/postgresql/IContainer.js.map +1 -0
- package/dist/esm/postgresql/PostgresqlConnection.js +2 -0
- package/dist/esm/postgresql/PostgresqlConnection.js.map +1 -0
- package/dist/esm/postgresql/PostgresqlEventLocker.js +123 -0
- package/dist/esm/postgresql/PostgresqlEventLocker.js.map +1 -0
- package/dist/esm/postgresql/PostgresqlEventStorage.js +311 -0
- package/dist/esm/postgresql/PostgresqlEventStorage.js.map +1 -0
- package/dist/esm/postgresql/PostgresqlObjectStorage.js +133 -0
- package/dist/esm/postgresql/PostgresqlObjectStorage.js.map +1 -0
- package/dist/esm/postgresql/PostgresqlObjectView.js +42 -0
- package/dist/esm/postgresql/PostgresqlObjectView.js.map +1 -0
- package/dist/esm/postgresql/PostgresqlProjectionDataParams.js +2 -0
- package/dist/esm/postgresql/PostgresqlProjectionDataParams.js.map +1 -0
- package/dist/esm/postgresql/PostgresqlViewLocker.js +147 -0
- package/dist/esm/postgresql/PostgresqlViewLocker.js.map +1 -0
- package/dist/esm/postgresql/index.js +13 -0
- package/dist/esm/postgresql/index.js.map +1 -0
- package/dist/esm/postgresql/utils/getEventId.js +10 -0
- package/dist/esm/postgresql/utils/getEventId.js.map +1 -0
- package/dist/esm/postgresql/utils/index.js +3 -0
- package/dist/esm/postgresql/utils/index.js.map +1 -0
- package/dist/esm/postgresql/utils/quoteIdentifier.js +11 -0
- package/dist/esm/postgresql/utils/quoteIdentifier.js.map +1 -0
- package/dist/esm/sqlite/SqliteEventStorage.js +66 -36
- package/dist/esm/sqlite/SqliteEventStorage.js.map +1 -1
- package/dist/types/postgresql/AbstractPostgresqlAccessor.d.ts +29 -0
- package/dist/types/postgresql/AbstractPostgresqlObjectProjection.d.ts +12 -0
- package/dist/types/postgresql/AbstractPostgresqlView.d.ts +23 -0
- package/dist/types/postgresql/IContainer.d.ts +12 -0
- package/dist/types/postgresql/PostgresqlConnection.d.ts +7 -0
- package/dist/types/postgresql/PostgresqlEventLocker.d.ts +39 -0
- package/dist/types/postgresql/PostgresqlEventStorage.d.ts +23 -0
- package/dist/types/postgresql/PostgresqlObjectStorage.d.ts +29 -0
- package/dist/types/postgresql/PostgresqlObjectView.d.ts +19 -0
- package/dist/types/postgresql/PostgresqlProjectionDataParams.d.ts +14 -0
- package/dist/types/postgresql/PostgresqlViewLocker.d.ts +41 -0
- package/dist/types/postgresql/index.d.ts +12 -0
- package/dist/types/postgresql/utils/getEventId.d.ts +5 -0
- package/dist/types/postgresql/utils/index.d.ts +2 -0
- package/dist/types/postgresql/utils/quoteIdentifier.d.ts +1 -0
- package/package.json +20 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
# [1.3.0-alpha.0](https://github.com/snatalenko/node-cqrs/compare/v1.2.0-beta.0...v1.3.0-alpha.0) (2026-06-17)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* PostgreSQL event storage ([a567da2](https://github.com/snatalenko/node-cqrs/commit/a567da2597f30013c201d9c2e7c22e94b5abf429))
|
|
7
|
+
* PostgreSQL projection views ([6ac7301](https://github.com/snatalenko/node-cqrs/commit/6ac73012a187de5755b5f9a646d2e816397e143d))
|
|
8
|
+
|
|
9
|
+
### Performance Improvements
|
|
10
|
+
|
|
11
|
+
* Aggregate SQLite saga origins in event queries ([491310e](https://github.com/snatalenko/node-cqrs/commit/491310ecc7263a1f6833ad08fc9b8340f8d434a1))
|
|
12
|
+
|
|
13
|
+
|
|
1
14
|
# [1.2.0-beta.0](https://github.com/snatalenko/node-cqrs/compare/v1.1.0...v1.2.0-beta.0) (2026-06-17)
|
|
2
15
|
|
|
3
16
|
|
package/README.md
CHANGED
|
@@ -34,6 +34,7 @@ The core is infrastructure-agnostic, but the heavy lifting for common stacks is
|
|
|
34
34
|
- `node-cqrs/mongodb` – Distributed event storage and persistent projection views for multi-process deployments.
|
|
35
35
|
- `node-cqrs/rabbitmq` – Robust, distributed command and event bus.
|
|
36
36
|
- `node-cqrs/redis` – Redis-backed persistent projection views for distributed deployments.
|
|
37
|
+
- `node-cqrs/postgresql` – PostgreSQL-backed event storage and persistent views for custom relational read models.
|
|
37
38
|
|
|
38
39
|
## Table of Contents
|
|
39
40
|
|
|
@@ -417,14 +418,15 @@ All modules below implement the same interfaces - pick what fits your deployment
|
|
|
417
418
|
|
|
418
419
|
### Capability Matrix
|
|
419
420
|
|
|
420
|
-
| Module | Event storage | Object view storage | Projection wiring /
|
|
421
|
-
| ------------------- | -------------------------------------------------- | ----------------------------------------------------------------------------------- |
|
|
422
|
-
| `node-cqrs` | `InMemoryEventStorage`, `InMemorySnapshotStorage` | `InMemoryView
|
|
423
|
-
| `node-cqrs/sqlite` | `SqliteEventStorage` | `SqliteObjectView`, `SqliteObjectStorage`, `
|
|
424
|
-
| `node-cqrs/mongodb` | `MongoEventStorage` | `MongoObjectView`, `MongoObjectStorage`, `
|
|
425
|
-
| `node-cqrs/redis` | - | `RedisView`, `RedisObjectStorage`, `RedisViewLocker`, `RedisEventLocker`
|
|
426
|
-
| `node-cqrs/
|
|
427
|
-
| `node-cqrs/
|
|
421
|
+
| Module | Event storage | Object view storage | Projection wiring / lifecycle | Message buses |
|
|
422
|
+
| ------------------- | -------------------------------------------------- | ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | ------------------------------------------------- |
|
|
423
|
+
| `node-cqrs` | `InMemoryEventStorage`, `InMemorySnapshotStorage` | `InMemoryView` | `AbstractProjection`, `InMemoryLock` | `InMemoryMessageBus` |
|
|
424
|
+
| `node-cqrs/sqlite` | `SqliteEventStorage` | `SqliteObjectView`, `SqliteObjectStorage`, `AbstractSqliteObjectProjection` | `AbstractSqliteView`, `SqliteViewLocker`, `SqliteEventLocker` | - |
|
|
425
|
+
| `node-cqrs/mongodb` | `MongoEventStorage` | `MongoObjectView`, `MongoObjectStorage`, `AbstractMongoObjectProjection` | `AbstractMongoView`, `MongoViewLocker`, `MongoEventLocker` | - |
|
|
426
|
+
| `node-cqrs/redis` | - | `RedisView`, `RedisObjectStorage`, `AbstractRedisProjection` | `RedisViewLocker`, `RedisEventLocker` | - |
|
|
427
|
+
| `node-cqrs/postgresql` | `PostgresqlEventStorage` | `PostgresqlObjectView`, `PostgresqlObjectStorage`, `AbstractPostgresqlObjectProjection` | `AbstractPostgresqlView`, `PostgresqlViewLocker`, `PostgresqlEventLocker` | - |
|
|
428
|
+
| `node-cqrs/rabbitmq` | - | - | - | `RabbitMqGateway`, `RabbitMqCommandBus`, `RabbitMqEventBus` |
|
|
429
|
+
| `node-cqrs/workers` | - | - | `AbstractWorkerProjection`, `WorkerProxyProjection` | - |
|
|
428
430
|
|
|
429
431
|
### Event Storage
|
|
430
432
|
|
|
@@ -435,11 +437,12 @@ Where aggregate events are persisted and replayed from.
|
|
|
435
437
|
| `InMemoryEventStorage` | `node-cqrs` | - | Dev/test only; data lost on restart ([example](examples/user-domain-ts/index.ts)) |
|
|
436
438
|
| `SqliteEventStorage` | `node-cqrs/sqlite` | `better-sqlite3` | Embedded, single-process ([example](examples/sqlite/index.ts)) |
|
|
437
439
|
| `MongoEventStorage` | `node-cqrs/mongodb` | `mongodb` | Distributed, multi-process ([example](examples/mongodb-eventstore/index.ts)) |
|
|
440
|
+
| `PostgresqlEventStorage` | `node-cqrs/postgresql` | `pg` | Distributed, multi-process ([example](examples/postgresql/index.ts)) |
|
|
438
441
|
|
|
439
442
|
### Read Model
|
|
440
443
|
|
|
441
444
|
Where projections store and query their read-side state.
|
|
442
|
-
|
|
445
|
+
Persistent view backends are built from the following layers. Not every backend implements every layer.
|
|
443
446
|
|
|
444
447
|
| Layer | Purpose |
|
|
445
448
|
| ------------------- | ------------------------------------------------------------------------------------------------ |
|
|
@@ -498,6 +501,22 @@ See [src/mongodb](src/mongodb) for additional documentation, and [examples/mongo
|
|
|
498
501
|
|
|
499
502
|
See [src/redis](src/redis) for additional documentation, and [examples/redis](examples/redis/index.ts) for runnable projection examples.
|
|
500
503
|
|
|
504
|
+
#### PostgreSQL (`node-cqrs/postgresql`, peer dep: `pg`)
|
|
505
|
+
|
|
506
|
+
> **Experimental** - not yet validated in production. APIs may change in minor versions.
|
|
507
|
+
|
|
508
|
+
| Class | Role |
|
|
509
|
+
| ------------------------- | ------------------------------------------------------------------------------------- |
|
|
510
|
+
| `PostgresqlEventStorage` | Transactional PostgreSQL event storage with saga refs and optimistic concurrency |
|
|
511
|
+
| `PostgresqlObjectStorage` | Key/value object storage backed by PostgreSQL `jsonb` rows |
|
|
512
|
+
| `PostgresqlViewLocker` | Prevents concurrent schema-migration rebuilds; auto-prolongs lock via token + TTL row |
|
|
513
|
+
| `PostgresqlEventLocker` | Event deduplication and last-event checkpoint |
|
|
514
|
+
| `PostgresqlObjectView` | Composite view combining object storage, view locking, and event checkpointing |
|
|
515
|
+
| `AbstractPostgresqlObjectProjection` | Base projection wired to `PostgresqlObjectView` |
|
|
516
|
+
| `AbstractPostgresqlView` | Base class for custom relational PostgreSQL views with view and event locks embedded |
|
|
517
|
+
|
|
518
|
+
See [src/postgresql](src/postgresql) for additional documentation, and [examples/postgresql](examples/postgresql/index.ts) for a runnable projection example.
|
|
519
|
+
|
|
501
520
|
### Message Buses
|
|
502
521
|
|
|
503
522
|
How commands and events move between producers and consumers.
|
|
@@ -543,6 +562,7 @@ See [examples/telemetry/index.ts](examples/telemetry/index.ts) for a full workin
|
|
|
543
562
|
- [examples/workers-projection](examples/workers-projection) - worker thread projection
|
|
544
563
|
- [examples/mongodb-eventstore](examples/mongodb-eventstore/index.ts) - MongoDB event storage with DI container and manual wiring
|
|
545
564
|
- [examples/mongodb-views](examples/mongodb-views/index.ts) - MongoDB-backed projection views with object storage and locking
|
|
565
|
+
- [examples/postgresql](examples/postgresql/index.ts) - PostgreSQL-backed event storage and projection view
|
|
546
566
|
- [examples/telemetry](examples/telemetry/index.ts) - OpenTelemetry tracing with multiple exporters
|
|
547
567
|
|
|
548
568
|
TS examples can be run with NodeJS 24+ without transpiling.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AbstractPostgresqlAccessor = void 0;
|
|
4
|
+
const node_async_hooks_1 = require("node:async_hooks");
|
|
5
|
+
const index_ts_1 = require("../utils/index.js");
|
|
6
|
+
const transactionConnectionStorage = new node_async_hooks_1.AsyncLocalStorage();
|
|
7
|
+
/**
|
|
8
|
+
* Abstract base class for accessing a PostgreSQL connection.
|
|
9
|
+
*
|
|
10
|
+
* Manages the connection lifecycle, ensuring initialization via `assertConnection`.
|
|
11
|
+
* Supports providing a query-capable connection directly or a factory function for lazy initialization.
|
|
12
|
+
*
|
|
13
|
+
* Subclasses must implement the `initialize` method for specific setup tasks.
|
|
14
|
+
*/
|
|
15
|
+
class AbstractPostgresqlAccessor {
|
|
16
|
+
db;
|
|
17
|
+
#dbFactory;
|
|
18
|
+
#initLocker = new index_ts_1.Lock();
|
|
19
|
+
#initialized = false;
|
|
20
|
+
constructor(c) {
|
|
21
|
+
if (!c.viewModelPostgresqlDb && !c.viewModelPostgresqlDbFactory)
|
|
22
|
+
throw new TypeError('either viewModelPostgresqlDb or viewModelPostgresqlDbFactory argument required');
|
|
23
|
+
this.db = c.viewModelPostgresqlDb;
|
|
24
|
+
this.#dbFactory = c.viewModelPostgresqlDbFactory;
|
|
25
|
+
}
|
|
26
|
+
get connection() {
|
|
27
|
+
return transactionConnectionStorage.getStore() ?? this.db;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Ensures that the PostgreSQL connection is initialized.
|
|
31
|
+
* Uses a lock to prevent race conditions during concurrent initialization attempts.
|
|
32
|
+
* If the connection is not already set, it creates one using the provided factory
|
|
33
|
+
* and then calls the `initialize` method.
|
|
34
|
+
*
|
|
35
|
+
* This method is idempotent and safe to call multiple times.
|
|
36
|
+
*/
|
|
37
|
+
async assertConnection() {
|
|
38
|
+
if (this.#initialized)
|
|
39
|
+
return;
|
|
40
|
+
try {
|
|
41
|
+
await this.#initLocker.acquire();
|
|
42
|
+
if (this.#initialized)
|
|
43
|
+
return;
|
|
44
|
+
if (!this.db)
|
|
45
|
+
this.db = await this.#dbFactory();
|
|
46
|
+
await this.initialize(this.db);
|
|
47
|
+
this.#initialized = true;
|
|
48
|
+
}
|
|
49
|
+
finally {
|
|
50
|
+
this.#initLocker.release();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async runInTransaction(callback) {
|
|
54
|
+
await this.assertConnection();
|
|
55
|
+
if (transactionConnectionStorage.getStore())
|
|
56
|
+
return callback();
|
|
57
|
+
const transactionConnection = await this.getTransactionConnection();
|
|
58
|
+
await transactionConnection.query('BEGIN');
|
|
59
|
+
try {
|
|
60
|
+
const result = await transactionConnectionStorage.run(transactionConnection, callback);
|
|
61
|
+
await transactionConnection.query('COMMIT');
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
await transactionConnection.query('ROLLBACK');
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
if ('release' in transactionConnection)
|
|
70
|
+
transactionConnection.release();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
async getTransactionConnection() {
|
|
74
|
+
if (AbstractPostgresqlAccessor.isConnectionPool(this.db))
|
|
75
|
+
return this.db.connect();
|
|
76
|
+
return this.db;
|
|
77
|
+
}
|
|
78
|
+
static isConnectionPool(db) {
|
|
79
|
+
return typeof db?.connect === 'function';
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
exports.AbstractPostgresqlAccessor = AbstractPostgresqlAccessor;
|
|
83
|
+
//# sourceMappingURL=AbstractPostgresqlAccessor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AbstractPostgresqlAccessor.js","sourceRoot":"","sources":["../../../src/postgresql/AbstractPostgresqlAccessor.ts"],"names":[],"mappings":";;;AACA,uDAAqD;AACrD,gDAAyC;AAWzC,MAAM,4BAA4B,GAAG,IAAI,oCAAiB,EAAwB,CAAC;AAEnF;;;;;;;GAOG;AACH,MAAsB,0BAA0B;IAErC,EAAE,CAAmC;IACtC,UAAU,CAA2E;IACrF,WAAW,GAAG,IAAI,eAAI,EAAE,CAAC;IAClC,YAAY,GAAG,KAAK,CAAC;IAErB,YAAY,CAAsF;QACjG,IAAI,CAAC,CAAC,CAAC,qBAAqB,IAAI,CAAC,CAAC,CAAC,4BAA4B;YAC9D,MAAM,IAAI,SAAS,CAAC,gFAAgF,CAAC,CAAC;QAEvG,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,qBAAqB,CAAC;QAClC,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,4BAA4B,CAAC;IAClD,CAAC;IAID,IAAc,UAAU;QACvB,OAAO,4BAA4B,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC,EAAG,CAAC;IAC5D,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,gBAAgB;QACrB,IAAI,IAAI,CAAC,YAAY;YACpB,OAAO;QAER,IAAI,CAAC;YACJ,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;YACjC,IAAI,IAAI,CAAC,YAAY;gBACpB,OAAO;YAER,IAAI,CAAC,IAAI,CAAC,EAAE;gBACX,IAAI,CAAC,EAAE,GAAG,MAAM,IAAI,CAAC,UAAW,EAAE,CAAC;YAEpC,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAE/B,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QAC1B,CAAC;gBACO,CAAC;YACR,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;QAC5B,CAAC;IACF,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAI,QAA8B;QACvD,MAAM,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAE9B,IAAI,4BAA4B,CAAC,QAAQ,EAAE;YAC1C,OAAO,QAAQ,EAAE,CAAC;QAEnB,MAAM,qBAAqB,GAAG,MAAM,IAAI,CAAC,wBAAwB,EAAE,CAAC;QAEpE,MAAM,qBAAqB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC3C,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,MAAM,4BAA4B,CAAC,GAAG,CAAC,qBAAqB,EAAE,QAAQ,CAAC,CAAC;YACvF,MAAM,qBAAqB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAC5C,OAAO,MAAM,CAAC;QACf,CAAC;QACD,OAAO,KAAK,EAAE,CAAC;YACd,MAAM,qBAAqB,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YAC9C,MAAM,KAAK,CAAC;QACb,CAAC;gBACO,CAAC;YACR,IAAI,SAAS,IAAI,qBAAqB;gBACrC,qBAAqB,CAAC,OAAO,EAAE,CAAC;QAClC,CAAC;IACF,CAAC;IAEO,KAAK,CAAC,wBAAwB;QACrC,IAAI,0BAA0B,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;YACvD,OAAO,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC;QAE1B,OAAO,IAAI,CAAC,EAAG,CAAC;IACjB,CAAC;IAEO,MAAM,CAAC,gBAAgB,CAAC,EAAoC;QACnE,OAAO,OAAQ,EAA2C,EAAE,OAAO,KAAK,UAAU,CAAC;IACpF,CAAC;CACD;AApFD,gEAoFC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AbstractPostgresqlObjectProjection = void 0;
|
|
4
|
+
const AbstractProjection_ts_1 = require("../AbstractProjection.js");
|
|
5
|
+
const PostgresqlObjectView_ts_1 = require("./PostgresqlObjectView.js");
|
|
6
|
+
class AbstractPostgresqlObjectProjection extends AbstractProjection_ts_1.AbstractProjection {
|
|
7
|
+
static get tableName() {
|
|
8
|
+
throw new Error('tableName is not defined');
|
|
9
|
+
}
|
|
10
|
+
static get schemaVersion() {
|
|
11
|
+
throw new Error('schemaVersion is not defined');
|
|
12
|
+
}
|
|
13
|
+
constructor({ eventLockTableName, eventLockTtl, logger, postgresqlObjectStorageMaxRetries, viewLockTableName, viewLockTtl, viewModelPostgresqlDb, viewModelPostgresqlDbFactory }) {
|
|
14
|
+
super({ logger });
|
|
15
|
+
this.view = new PostgresqlObjectView_ts_1.PostgresqlObjectView({
|
|
16
|
+
schemaVersion: new.target.schemaVersion,
|
|
17
|
+
projectionName: new.target.name,
|
|
18
|
+
viewModelPostgresqlDb,
|
|
19
|
+
viewModelPostgresqlDbFactory,
|
|
20
|
+
tableNamePrefix: new.target.tableName,
|
|
21
|
+
eventLockTableName,
|
|
22
|
+
eventLockTtl,
|
|
23
|
+
postgresqlObjectStorageMaxRetries,
|
|
24
|
+
viewLockTableName,
|
|
25
|
+
viewLockTtl,
|
|
26
|
+
logger
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
async project(event, meta) {
|
|
30
|
+
if (this._viewLocker && !this._viewLocker.ready)
|
|
31
|
+
await this._viewLocker.once('ready');
|
|
32
|
+
await this.view.runInTransaction(() => super.project(event, meta));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
exports.AbstractPostgresqlObjectProjection = AbstractPostgresqlObjectProjection;
|
|
36
|
+
//# sourceMappingURL=AbstractPostgresqlObjectProjection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AbstractPostgresqlObjectProjection.js","sourceRoot":"","sources":["../../../src/postgresql/AbstractPostgresqlObjectProjection.ts"],"names":[],"mappings":";;;AACA,oEAA8D;AAE9D,uEAAiE;AAkBjE,MAAsB,kCAAsC,SAAQ,0CAA2C;IAE9G,MAAM,KAAK,SAAS;QACnB,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;IAC7C,CAAC;IAED,MAAM,KAAK,aAAa;QACvB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IACjD,CAAC;IAED,YAAY,EACX,kBAAkB,EAClB,YAAY,EACZ,MAAM,EACN,iCAAiC,EACjC,iBAAiB,EACjB,WAAW,EACX,qBAAqB,EACrB,4BAA4B,EACM;QAClC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QAElB,IAAI,CAAC,IAAI,GAAG,IAAI,8CAAoB,CAAC;YACpC,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,aAAa;YACvC,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI;YAC/B,qBAAqB;YACrB,4BAA4B;YAC5B,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS;YACrC,kBAAkB;YAClB,YAAY;YACZ,iCAAiC;YACjC,iBAAiB;YACjB,WAAW;YACX,MAAM;SACN,CAAC,CAAC;IACJ,CAAC;IAEQ,KAAK,CAAC,OAAO,CAAC,KAAa,EAAE,IAA0B;QAC/D,IAAI,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK;YAC9C,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAEtC,MAAM,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;IACpE,CAAC;CACD;AA3CD,gFA2CC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AbstractPostgresqlView = void 0;
|
|
4
|
+
const assert_ts_1 = require("../utils/assert.js");
|
|
5
|
+
const AbstractPostgresqlAccessor_ts_1 = require("./AbstractPostgresqlAccessor.js");
|
|
6
|
+
const PostgresqlEventLocker_ts_1 = require("./PostgresqlEventLocker.js");
|
|
7
|
+
const PostgresqlViewLocker_ts_1 = require("./PostgresqlViewLocker.js");
|
|
8
|
+
/**
|
|
9
|
+
* Base class for PostgreSQL-backed projection views with restore locking and last-processed-event tracking.
|
|
10
|
+
*/
|
|
11
|
+
class AbstractPostgresqlView extends AbstractPostgresqlAccessor_ts_1.AbstractPostgresqlAccessor {
|
|
12
|
+
schemaVersion;
|
|
13
|
+
viewLocker;
|
|
14
|
+
eventLocker;
|
|
15
|
+
logger;
|
|
16
|
+
get ready() {
|
|
17
|
+
return this.viewLocker.ready;
|
|
18
|
+
}
|
|
19
|
+
constructor(options) {
|
|
20
|
+
(0, assert_ts_1.assertString)(options.projectionName, 'projectionName');
|
|
21
|
+
(0, assert_ts_1.assertString)(options.schemaVersion, 'schemaVersion');
|
|
22
|
+
super(options);
|
|
23
|
+
this.schemaVersion = options.schemaVersion;
|
|
24
|
+
this.viewLocker = new PostgresqlViewLocker_ts_1.PostgresqlViewLocker(options);
|
|
25
|
+
this.eventLocker = new PostgresqlEventLocker_ts_1.PostgresqlEventLocker(options);
|
|
26
|
+
this.logger = options.logger && 'child' in options.logger ?
|
|
27
|
+
options.logger.child({ serviceName: new.target.name }) :
|
|
28
|
+
options.logger;
|
|
29
|
+
}
|
|
30
|
+
async lock() {
|
|
31
|
+
return this.viewLocker.lock();
|
|
32
|
+
}
|
|
33
|
+
async unlock() {
|
|
34
|
+
await this.viewLocker.unlock();
|
|
35
|
+
}
|
|
36
|
+
once(event) {
|
|
37
|
+
return this.viewLocker.once(event);
|
|
38
|
+
}
|
|
39
|
+
getLastEvent() {
|
|
40
|
+
return this.eventLocker.getLastEvent();
|
|
41
|
+
}
|
|
42
|
+
tryMarkAsProjecting(event) {
|
|
43
|
+
return this.eventLocker.tryMarkAsProjecting(event);
|
|
44
|
+
}
|
|
45
|
+
markAsProjected(event) {
|
|
46
|
+
return this.eventLocker.markAsProjected(event);
|
|
47
|
+
}
|
|
48
|
+
markAsLastEvent(event) {
|
|
49
|
+
return this.eventLocker.markAsLastEvent(event);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.AbstractPostgresqlView = AbstractPostgresqlView;
|
|
53
|
+
//# sourceMappingURL=AbstractPostgresqlView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AbstractPostgresqlView.js","sourceRoot":"","sources":["../../../src/postgresql/AbstractPostgresqlView.ts"],"names":[],"mappings":";;;AAEA,kDAAkD;AAClD,mFAA6E;AAC7E,yEAAqG;AACrG,uEAAkG;AAElG;;GAEG;AACH,MAAsB,sBAAuB,SAAQ,0DAA0B;IAE3D,aAAa,CAAS;IACtB,UAAU,CAAuB;IACjC,WAAW,CAAwB;IAC5C,MAAM,CAAsB;IAEtC,IAAI,KAAK;QACR,OAAO,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;IAC9B,CAAC;IAED,YAAY,OAEiB;QAC5B,IAAA,wBAAY,EAAC,OAAO,CAAC,cAAc,EAAE,gBAAgB,CAAC,CAAC;QACvD,IAAA,wBAAY,EAAC,OAAO,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC;QAErD,KAAK,CAAC,OAAO,CAAC,CAAC;QAEf,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;QAC3C,IAAI,CAAC,UAAU,GAAG,IAAI,8CAAoB,CAAC,OAAO,CAAC,CAAC;QACpD,IAAI,CAAC,WAAW,GAAG,IAAI,gDAAqB,CAAC,OAAO,CAAC,CAAC;QACtD,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;YAC1D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;YACxD,OAAO,CAAC,MAAM,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,IAAI;QACT,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,MAAM;QACX,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;IAChC,CAAC;IAED,IAAI,CAAC,KAAc;QAClB,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC;IAED,YAAY;QACX,OAAO,IAAI,CAAC,WAAW,CAAC,YAAY,EAAE,CAAC;IACxC,CAAC;IAED,mBAAmB,CAAC,KAAa;QAChC,OAAO,IAAI,CAAC,WAAW,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC;IACpD,CAAC;IAED,eAAe,CAAC,KAAa;QAC5B,OAAO,IAAI,CAAC,WAAW,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IAChD,CAAC;IAED,eAAe,CAAC,KAAa;QAC5B,OAAO,IAAI,CAAC,WAAW,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IAChD,CAAC;CACD;AAtDD,wDAsDC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IContainer.js","sourceRoot":"","sources":["../../../src/postgresql/IContainer.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PostgresqlConnection.js","sourceRoot":"","sources":["../../../src/postgresql/PostgresqlConnection.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PostgresqlEventLocker = void 0;
|
|
4
|
+
const assert_ts_1 = require("../utils/assert.js");
|
|
5
|
+
const AbstractPostgresqlAccessor_ts_1 = require("./AbstractPostgresqlAccessor.js");
|
|
6
|
+
const index_ts_1 = require("./utils/index.js");
|
|
7
|
+
/**
|
|
8
|
+
* PostgreSQL-backed implementation of IEventLocker.
|
|
9
|
+
*
|
|
10
|
+
* Uses one table for per-event processing locks and the view lock table for the
|
|
11
|
+
* last processed event checkpoint.
|
|
12
|
+
*/
|
|
13
|
+
class PostgresqlEventLocker extends AbstractPostgresqlAccessor_ts_1.AbstractPostgresqlAccessor {
|
|
14
|
+
static DEFAULT_EVENT_LOCK_TTL = 15_000;
|
|
15
|
+
static DEFAULT_EVENT_LOCK_TABLE = 'ncqrs_event_locks';
|
|
16
|
+
static DEFAULT_VIEW_LOCK_TABLE = 'ncqrs_view_locks';
|
|
17
|
+
#projectionName;
|
|
18
|
+
#schemaVersion;
|
|
19
|
+
#viewLockTableName;
|
|
20
|
+
#eventLockTableName;
|
|
21
|
+
#eventLockTtl;
|
|
22
|
+
constructor(o) {
|
|
23
|
+
super(o);
|
|
24
|
+
(0, assert_ts_1.assertString)(o.projectionName, 'o.projectionName');
|
|
25
|
+
(0, assert_ts_1.assertString)(o.schemaVersion, 'o.schemaVersion');
|
|
26
|
+
if (o.viewLockTableName !== undefined)
|
|
27
|
+
(0, assert_ts_1.assertString)(o.viewLockTableName, 'o.viewLockTableName');
|
|
28
|
+
if (o.eventLockTableName !== undefined)
|
|
29
|
+
(0, assert_ts_1.assertString)(o.eventLockTableName, 'o.eventLockTableName');
|
|
30
|
+
if (o.eventLockTtl !== undefined)
|
|
31
|
+
(0, assert_ts_1.assertNonNegativeInteger)(o.eventLockTtl, 'o.eventLockTtl');
|
|
32
|
+
this.#projectionName = o.projectionName;
|
|
33
|
+
this.#schemaVersion = o.schemaVersion;
|
|
34
|
+
this.#viewLockTableName = (0, index_ts_1.quoteIdentifier)(o.viewLockTableName ?? PostgresqlEventLocker.DEFAULT_VIEW_LOCK_TABLE);
|
|
35
|
+
this.#eventLockTableName = (0, index_ts_1.quoteIdentifier)(o.eventLockTableName ?? PostgresqlEventLocker.DEFAULT_EVENT_LOCK_TABLE);
|
|
36
|
+
this.#eventLockTtl = o.eventLockTtl ?? PostgresqlEventLocker.DEFAULT_EVENT_LOCK_TTL;
|
|
37
|
+
}
|
|
38
|
+
async initialize(db) {
|
|
39
|
+
await db.query(`
|
|
40
|
+
CREATE TABLE IF NOT EXISTS ${this.#viewLockTableName} (
|
|
41
|
+
projection_name text NOT NULL,
|
|
42
|
+
schema_version text NOT NULL,
|
|
43
|
+
locked_till timestamptz NULL,
|
|
44
|
+
lock_token text NULL,
|
|
45
|
+
last_event text NULL,
|
|
46
|
+
PRIMARY KEY (projection_name, schema_version)
|
|
47
|
+
)
|
|
48
|
+
`);
|
|
49
|
+
await db.query(`
|
|
50
|
+
CREATE TABLE IF NOT EXISTS ${this.#eventLockTableName} (
|
|
51
|
+
projection_name text NOT NULL,
|
|
52
|
+
schema_version text NOT NULL,
|
|
53
|
+
event_id text NOT NULL,
|
|
54
|
+
processing_at timestamptz NOT NULL DEFAULT NOW(),
|
|
55
|
+
processed_at timestamptz NULL,
|
|
56
|
+
PRIMARY KEY (projection_name, schema_version, event_id)
|
|
57
|
+
)
|
|
58
|
+
`);
|
|
59
|
+
await db.query(`
|
|
60
|
+
CREATE INDEX IF NOT EXISTS ${(0, index_ts_1.quoteIdentifier)(`${this.#tableNameForIndex()}_processing_at_idx`)}
|
|
61
|
+
ON ${this.#eventLockTableName} (processing_at)
|
|
62
|
+
`);
|
|
63
|
+
}
|
|
64
|
+
async tryMarkAsProjecting(event) {
|
|
65
|
+
await this.assertConnection();
|
|
66
|
+
const eventId = (0, index_ts_1.getEventId)(event);
|
|
67
|
+
const r = await this.connection.query(`
|
|
68
|
+
INSERT INTO ${this.#eventLockTableName} AS event_lock
|
|
69
|
+
(projection_name, schema_version, event_id, processing_at, processed_at)
|
|
70
|
+
VALUES ($1, $2, $3, NOW(), NULL)
|
|
71
|
+
ON CONFLICT (projection_name, schema_version, event_id)
|
|
72
|
+
DO UPDATE SET
|
|
73
|
+
processing_at = NOW(),
|
|
74
|
+
processed_at = NULL
|
|
75
|
+
WHERE
|
|
76
|
+
event_lock.processed_at IS NULL
|
|
77
|
+
AND event_lock.processing_at <= NOW() - ($4::double precision * INTERVAL '1 millisecond')
|
|
78
|
+
`, [this.#projectionName, this.#schemaVersion, eventId, this.#eventLockTtl]);
|
|
79
|
+
return r.rowCount !== 0;
|
|
80
|
+
}
|
|
81
|
+
async markAsProjected(event) {
|
|
82
|
+
await this.assertConnection();
|
|
83
|
+
const eventId = (0, index_ts_1.getEventId)(event);
|
|
84
|
+
const result = await this.connection.query(`
|
|
85
|
+
UPDATE ${this.#eventLockTableName}
|
|
86
|
+
SET
|
|
87
|
+
processed_at = NOW()
|
|
88
|
+
WHERE
|
|
89
|
+
projection_name = $1
|
|
90
|
+
AND schema_version = $2
|
|
91
|
+
AND event_id = $3
|
|
92
|
+
AND processed_at IS NULL
|
|
93
|
+
`, [this.#projectionName, this.#schemaVersion, eventId]);
|
|
94
|
+
if (result.rowCount !== 1)
|
|
95
|
+
throw new Error(`Event ${event.id} could not be marked as processed`);
|
|
96
|
+
}
|
|
97
|
+
async markAsLastEvent(event) {
|
|
98
|
+
await this.assertConnection();
|
|
99
|
+
await this.connection.query(`
|
|
100
|
+
INSERT INTO ${this.#viewLockTableName} (projection_name, schema_version, last_event)
|
|
101
|
+
VALUES ($1, $2, $3)
|
|
102
|
+
ON CONFLICT (projection_name, schema_version)
|
|
103
|
+
DO UPDATE SET
|
|
104
|
+
last_event = excluded.last_event
|
|
105
|
+
`, [this.#projectionName, this.#schemaVersion, JSON.stringify(event)]);
|
|
106
|
+
}
|
|
107
|
+
async getLastEvent() {
|
|
108
|
+
await this.assertConnection();
|
|
109
|
+
const viewInfoRecord = await this.connection.query(`
|
|
110
|
+
SELECT
|
|
111
|
+
last_event
|
|
112
|
+
FROM ${this.#viewLockTableName}
|
|
113
|
+
WHERE
|
|
114
|
+
projection_name = $1
|
|
115
|
+
AND schema_version = $2
|
|
116
|
+
`, [this.#projectionName, this.#schemaVersion]);
|
|
117
|
+
const lastEvent = viewInfoRecord.rows[0]?.last_event;
|
|
118
|
+
if (!lastEvent)
|
|
119
|
+
return undefined;
|
|
120
|
+
return JSON.parse(lastEvent);
|
|
121
|
+
}
|
|
122
|
+
#tableNameForIndex() {
|
|
123
|
+
return this.#eventLockTableName.replaceAll('"', '').replaceAll('.', '_');
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
exports.PostgresqlEventLocker = PostgresqlEventLocker;
|
|
127
|
+
//# sourceMappingURL=PostgresqlEventLocker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PostgresqlEventLocker.js","sourceRoot":"","sources":["../../../src/postgresql/PostgresqlEventLocker.ts"],"names":[],"mappings":"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"}
|