@quilla-be-kit/persistence-init-test 0.1.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 +684 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/dao/audit-columns.d.ts +19 -0
- package/dist/dao/audit-columns.d.ts.map +1 -0
- package/dist/dao/audit-columns.js +26 -0
- package/dist/dao/audit-columns.js.map +1 -0
- package/dist/dao/base-read.dao.d.ts +50 -0
- package/dist/dao/base-read.dao.d.ts.map +1 -0
- package/dist/dao/base-read.dao.js +65 -0
- package/dist/dao/base-read.dao.js.map +1 -0
- package/dist/dao/base-write.dao.d.ts +49 -0
- package/dist/dao/base-write.dao.d.ts.map +1 -0
- package/dist/dao/base-write.dao.js +130 -0
- package/dist/dao/base-write.dao.js.map +1 -0
- package/dist/dao/index.d.ts +3 -0
- package/dist/dao/index.d.ts.map +1 -0
- package/dist/dao/index.js +3 -0
- package/dist/dao/index.js.map +1 -0
- package/dist/database/database-health.type.d.ts +4 -0
- package/dist/database/database-health.type.d.ts.map +1 -0
- package/dist/database/database-health.type.js +2 -0
- package/dist/database/database-health.type.js.map +1 -0
- package/dist/database/database-result.type.d.ts +5 -0
- package/dist/database/database-result.type.d.ts.map +1 -0
- package/dist/database/database-result.type.js +2 -0
- package/dist/database/database-result.type.js.map +1 -0
- package/dist/database/database-transaction.interface.d.ts +10 -0
- package/dist/database/database-transaction.interface.d.ts.map +1 -0
- package/dist/database/database-transaction.interface.js +2 -0
- package/dist/database/database-transaction.interface.js.map +1 -0
- package/dist/database/database.interface.d.ts +10 -0
- package/dist/database/database.interface.d.ts.map +1 -0
- package/dist/database/database.interface.js +2 -0
- package/dist/database/database.interface.js.map +1 -0
- package/dist/database/index.d.ts +5 -0
- package/dist/database/index.d.ts.map +1 -0
- package/dist/database/index.js +2 -0
- package/dist/database/index.js.map +1 -0
- package/dist/db-adapter/filter-query.type.d.ts +4 -0
- package/dist/db-adapter/filter-query.type.d.ts.map +1 -0
- package/dist/db-adapter/filter-query.type.js +2 -0
- package/dist/db-adapter/filter-query.type.js.map +1 -0
- package/dist/db-adapter/index.d.ts +4 -0
- package/dist/db-adapter/index.d.ts.map +1 -0
- package/dist/db-adapter/index.js +2 -0
- package/dist/db-adapter/index.js.map +1 -0
- package/dist/db-adapter/read-db-adapter.interface.d.ts +37 -0
- package/dist/db-adapter/read-db-adapter.interface.d.ts.map +1 -0
- package/dist/db-adapter/read-db-adapter.interface.js +2 -0
- package/dist/db-adapter/read-db-adapter.interface.js.map +1 -0
- package/dist/db-adapter/write-db-adapter.interface.d.ts +61 -0
- package/dist/db-adapter/write-db-adapter.interface.d.ts.map +1 -0
- package/dist/db-adapter/write-db-adapter.interface.js +2 -0
- package/dist/db-adapter/write-db-adapter.interface.js.map +1 -0
- package/dist/errors/cross-scope-access.error.d.ts +10 -0
- package/dist/errors/cross-scope-access.error.d.ts.map +1 -0
- package/dist/errors/cross-scope-access.error.js +15 -0
- package/dist/errors/cross-scope-access.error.js.map +1 -0
- package/dist/errors/index.d.ts +3 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +3 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/errors/optimistic-lock.error.d.ts +9 -0
- package/dist/errors/optimistic-lock.error.d.ts.map +1 -0
- package/dist/errors/optimistic-lock.error.js +11 -0
- package/dist/errors/optimistic-lock.error.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/postgres/index.d.ts +7 -0
- package/dist/postgres/index.d.ts.map +1 -0
- package/dist/postgres/index.js +7 -0
- package/dist/postgres/index.js.map +1 -0
- package/dist/postgres/pg-query-builder.d.ts +42 -0
- package/dist/postgres/pg-query-builder.d.ts.map +1 -0
- package/dist/postgres/pg-query-builder.js +260 -0
- package/dist/postgres/pg-query-builder.js.map +1 -0
- package/dist/postgres/pg-read-db-adapter.d.ts +20 -0
- package/dist/postgres/pg-read-db-adapter.d.ts.map +1 -0
- package/dist/postgres/pg-read-db-adapter.js +28 -0
- package/dist/postgres/pg-read-db-adapter.js.map +1 -0
- package/dist/postgres/pg-sql.d.ts +44 -0
- package/dist/postgres/pg-sql.d.ts.map +1 -0
- package/dist/postgres/pg-sql.js +128 -0
- package/dist/postgres/pg-sql.js.map +1 -0
- package/dist/postgres/pg-write-db-adapter.d.ts +30 -0
- package/dist/postgres/pg-write-db-adapter.d.ts.map +1 -0
- package/dist/postgres/pg-write-db-adapter.js +133 -0
- package/dist/postgres/pg-write-db-adapter.js.map +1 -0
- package/dist/postgres/pg.database.d.ts +25 -0
- package/dist/postgres/pg.database.d.ts.map +1 -0
- package/dist/postgres/pg.database.js +48 -0
- package/dist/postgres/pg.database.js.map +1 -0
- package/dist/postgres/pg.transaction.d.ts +22 -0
- package/dist/postgres/pg.transaction.d.ts.map +1 -0
- package/dist/postgres/pg.transaction.js +78 -0
- package/dist/postgres/pg.transaction.js.map +1 -0
- package/dist/query/case.d.ts +3 -0
- package/dist/query/case.d.ts.map +1 -0
- package/dist/query/case.js +7 -0
- package/dist/query/case.js.map +1 -0
- package/dist/query/column-resolver.interface.d.ts +4 -0
- package/dist/query/column-resolver.interface.d.ts.map +1 -0
- package/dist/query/column-resolver.interface.js +2 -0
- package/dist/query/column-resolver.interface.js.map +1 -0
- package/dist/query/default.resolver.d.ts +10 -0
- package/dist/query/default.resolver.d.ts.map +1 -0
- package/dist/query/default.resolver.js +14 -0
- package/dist/query/default.resolver.js.map +1 -0
- package/dist/query/field-descriptor.type.d.ts +11 -0
- package/dist/query/field-descriptor.type.d.ts.map +1 -0
- package/dist/query/field-descriptor.type.js +20 -0
- package/dist/query/field-descriptor.type.js.map +1 -0
- package/dist/query/filter-query.type.d.ts +4 -0
- package/dist/query/filter-query.type.d.ts.map +1 -0
- package/dist/query/filter-query.type.js +2 -0
- package/dist/query/filter-query.type.js.map +1 -0
- package/dist/query/index.d.ts +9 -0
- package/dist/query/index.d.ts.map +1 -0
- package/dist/query/index.js +3 -0
- package/dist/query/index.js.map +1 -0
- package/dist/query/list-query.type.d.ts +12 -0
- package/dist/query/list-query.type.d.ts.map +1 -0
- package/dist/query/list-query.type.js +2 -0
- package/dist/query/list-query.type.js.map +1 -0
- package/dist/query/paginated-result.type.d.ts +7 -0
- package/dist/query/paginated-result.type.d.ts.map +1 -0
- package/dist/query/paginated-result.type.js +2 -0
- package/dist/query/paginated-result.type.js.map +1 -0
- package/dist/query/query-product.type.d.ts +6 -0
- package/dist/query/query-product.type.d.ts.map +1 -0
- package/dist/query/query-product.type.js +2 -0
- package/dist/query/query-product.type.js.map +1 -0
- package/dist/query/read-query-builder.interface.d.ts +17 -0
- package/dist/query/read-query-builder.interface.d.ts.map +1 -0
- package/dist/query/read-query-builder.interface.js +2 -0
- package/dist/query/read-query-builder.interface.js.map +1 -0
- package/dist/query/sql-query-builder.interface.d.ts +99 -0
- package/dist/query/sql-query-builder.interface.d.ts.map +1 -0
- package/dist/query/sql-query-builder.interface.js +2 -0
- package/dist/query/sql-query-builder.interface.js.map +1 -0
- package/dist/query/sql-statement.type.d.ts +5 -0
- package/dist/query/sql-statement.type.d.ts.map +1 -0
- package/dist/query/sql-statement.type.js +2 -0
- package/dist/query/sql-statement.type.js.map +1 -0
- package/dist/query/write-query-builder.interface.d.ts +34 -0
- package/dist/query/write-query-builder.interface.d.ts.map +1 -0
- package/dist/query/write-query-builder.interface.js +2 -0
- package/dist/query/write-query-builder.interface.js.map +1 -0
- package/dist/query-schema/field-descriptor-from-zod.d.ts +4 -0
- package/dist/query-schema/field-descriptor-from-zod.d.ts.map +1 -0
- package/dist/query-schema/field-descriptor-from-zod.js +31 -0
- package/dist/query-schema/field-descriptor-from-zod.js.map +1 -0
- package/dist/query-schema/index.d.ts +3 -0
- package/dist/query-schema/index.d.ts.map +1 -0
- package/dist/query-schema/index.js +3 -0
- package/dist/query-schema/index.js.map +1 -0
- package/dist/query-schema/zod.d.ts +73 -0
- package/dist/query-schema/zod.d.ts.map +1 -0
- package/dist/query-schema/zod.js +191 -0
- package/dist/query-schema/zod.js.map +1 -0
- package/dist/repository/base-aggregate.repository.d.ts +28 -0
- package/dist/repository/base-aggregate.repository.d.ts.map +1 -0
- package/dist/repository/base-aggregate.repository.js +49 -0
- package/dist/repository/base-aggregate.repository.js.map +1 -0
- package/dist/repository/base-basic.repository.d.ts +22 -0
- package/dist/repository/base-basic.repository.d.ts.map +1 -0
- package/dist/repository/base-basic.repository.js +30 -0
- package/dist/repository/base-basic.repository.js.map +1 -0
- package/dist/repository/base-persistence.mapper.d.ts +61 -0
- package/dist/repository/base-persistence.mapper.d.ts.map +1 -0
- package/dist/repository/base-persistence.mapper.js +119 -0
- package/dist/repository/base-persistence.mapper.js.map +1 -0
- package/dist/repository/base-scoped-aggregate.repository.d.ts +19 -0
- package/dist/repository/base-scoped-aggregate.repository.d.ts.map +1 -0
- package/dist/repository/base-scoped-aggregate.repository.js +35 -0
- package/dist/repository/base-scoped-aggregate.repository.js.map +1 -0
- package/dist/repository/base-unscoped-aggregate.repository.d.ts +17 -0
- package/dist/repository/base-unscoped-aggregate.repository.d.ts.map +1 -0
- package/dist/repository/base-unscoped-aggregate.repository.js +21 -0
- package/dist/repository/base-unscoped-aggregate.repository.js.map +1 -0
- package/dist/repository/index.d.ts +7 -0
- package/dist/repository/index.d.ts.map +1 -0
- package/dist/repository/index.js +6 -0
- package/dist/repository/index.js.map +1 -0
- package/dist/repository/mapper.interface.d.ts +5 -0
- package/dist/repository/mapper.interface.d.ts.map +1 -0
- package/dist/repository/mapper.interface.js +2 -0
- package/dist/repository/mapper.interface.js.map +1 -0
- package/dist/unit-of-work/event-sink.interface.d.ts +5 -0
- package/dist/unit-of-work/event-sink.interface.d.ts.map +1 -0
- package/dist/unit-of-work/event-sink.interface.js +2 -0
- package/dist/unit-of-work/event-sink.interface.js.map +1 -0
- package/dist/unit-of-work/index.d.ts +4 -0
- package/dist/unit-of-work/index.d.ts.map +1 -0
- package/dist/unit-of-work/index.js +2 -0
- package/dist/unit-of-work/index.js.map +1 -0
- package/dist/unit-of-work/outbox-writer.interface.d.ts +14 -0
- package/dist/unit-of-work/outbox-writer.interface.d.ts.map +1 -0
- package/dist/unit-of-work/outbox-writer.interface.js +2 -0
- package/dist/unit-of-work/outbox-writer.interface.js.map +1 -0
- package/dist/unit-of-work/unit-of-work-context.type.d.ts +8 -0
- package/dist/unit-of-work/unit-of-work-context.type.d.ts.map +1 -0
- package/dist/unit-of-work/unit-of-work-context.type.js +2 -0
- package/dist/unit-of-work/unit-of-work-context.type.js.map +1 -0
- package/dist/unit-of-work/unit-of-work.d.ts +20 -0
- package/dist/unit-of-work/unit-of-work.d.ts.map +1 -0
- package/dist/unit-of-work/unit-of-work.js +60 -0
- package/dist/unit-of-work/unit-of-work.js.map +1 -0
- package/package.json +83 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-basic.repository.d.ts","sourceRoot":"","sources":["../../src/repository/base-basic.repository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,+CAA+C,CAAC;AAEzF;;;;GAIG;AACH,8BAAsB,mBAAmB,CAAC,IAAI,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE;IACvD,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC,IAAI,CAAC;gBAA5B,QAAQ,EAAE,YAAY,CAAC,IAAI,CAAC;IAErD,MAAM,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3D,UAAU,CAAC,IAAI,EAAE,SAAS,IAAI,EAAE,EAAE,GAAG,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3E,MAAM,CAAC,GAAG,EAAE,IAAI,GAAG;QAAE,UAAU,CAAC,EAAE,IAAI,CAAA;KAAE,EAAE,GAAG,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAInF,UAAU,CAAC,IAAI,EAAE,SAAS,IAAI,EAAE,EAAE,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAI1E,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAI5D,UAAU,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;CAGnF"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repository for non-aggregate entities (no domain events, no aggregate
|
|
3
|
+
* registration). Use for simple persistence shapes without DDD tactical
|
|
4
|
+
* pattern requirements.
|
|
5
|
+
*/
|
|
6
|
+
export class BaseBasicRepository {
|
|
7
|
+
writeDao;
|
|
8
|
+
constructor(writeDao) {
|
|
9
|
+
this.writeDao = writeDao;
|
|
10
|
+
}
|
|
11
|
+
async create(row, trx) {
|
|
12
|
+
await this.writeDao.create(row, trx);
|
|
13
|
+
}
|
|
14
|
+
async createMany(rows, trx) {
|
|
15
|
+
await this.writeDao.createMany(rows, trx);
|
|
16
|
+
}
|
|
17
|
+
async update(row, trx) {
|
|
18
|
+
await this.writeDao.update(row, trx);
|
|
19
|
+
}
|
|
20
|
+
async updateMany(rows, trx) {
|
|
21
|
+
await this.writeDao.updateMany(rows, trx);
|
|
22
|
+
}
|
|
23
|
+
async delete(id, trx) {
|
|
24
|
+
await this.writeDao.delete(id, trx);
|
|
25
|
+
}
|
|
26
|
+
async deleteMany(ids, trx) {
|
|
27
|
+
await this.writeDao.deleteMany(ids, trx);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=base-basic.repository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-basic.repository.js","sourceRoot":"","sources":["../../src/repository/base-basic.repository.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,MAAM,OAAgB,mBAAmB;IACR;IAA/B,YAA+B,QAA4B;QAA5B,aAAQ,GAAR,QAAQ,CAAoB;IAAG,CAAC;IAE/D,KAAK,CAAC,MAAM,CAAC,GAAS,EAAE,GAAyB;QAC/C,MAAM,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,IAAqB,EAAE,GAAyB;QAC/D,MAAM,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAiC,EAAE,GAAyB;QACvE,MAAM,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,IAAqB,EAAE,GAAwB;QAC9D,MAAM,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,EAAU,EAAE,GAAyB;QAChD,MAAM,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IACtC,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,GAAsB,EAAE,GAAyB;QAChE,MAAM,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC3C,CAAC;CACF"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { PersistenceMapper } from './mapper.interface.js';
|
|
2
|
+
/**
|
|
3
|
+
* Abstract base for `PersistenceMapper` implementations. Handles
|
|
4
|
+
* bidirectional row↔aggregate conversion via prototype reflection:
|
|
5
|
+
*
|
|
6
|
+
* - **On write**, the aggregate's prototype chain is walked for every
|
|
7
|
+
* accessor that has BOTH `get` and `set` — those are the persisted
|
|
8
|
+
* properties. Getter-only accessors (computed / derived) are excluded.
|
|
9
|
+
* - **On read**, each column in the received row is reverse-mapped to a
|
|
10
|
+
* domain property name.
|
|
11
|
+
* - **Name resolution** converts camelCase ↔ snake_case by default;
|
|
12
|
+
* `columnOverrides` covers any column whose domain name deviates.
|
|
13
|
+
*
|
|
14
|
+
* Consumers implement:
|
|
15
|
+
* - `createDomain(props, id)` — reconstructs the aggregate.
|
|
16
|
+
* - `createPersistence(aggregate)` — optional; serializes value objects or
|
|
17
|
+
* emits derived columns. Merged *over* the default conversion.
|
|
18
|
+
* - `columnOverrides` — optional sparse map (`domainKey → columnName`).
|
|
19
|
+
*
|
|
20
|
+
* @example Tenant — zero-boilerplate case:
|
|
21
|
+
* ```ts
|
|
22
|
+
* class TenantInfraMapper extends BasePersistenceMapper<Tenant, TenantProps, TenantRow> {
|
|
23
|
+
* protected createDomain(props: TenantProps, id: string) {
|
|
24
|
+
* return Tenant.reconstitute(props, id);
|
|
25
|
+
* }
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @example User — mixed overrides + value-object serialization:
|
|
30
|
+
* ```ts
|
|
31
|
+
* class UserInfraMapper extends BasePersistenceMapper<User, UserProps, UserRow> {
|
|
32
|
+
* protected override readonly columnOverrides = {
|
|
33
|
+
* password: 'password_hash',
|
|
34
|
+
* resetPasswordTokenExpiresAt: 'reset_password_token_expiration',
|
|
35
|
+
* } as const;
|
|
36
|
+
*
|
|
37
|
+
* protected createDomain(props: UserProps, id: string) {
|
|
38
|
+
* return User.reconstitute({
|
|
39
|
+
* ...props,
|
|
40
|
+
* password: Password.fromHashedValue(props.password as string),
|
|
41
|
+
* }, id);
|
|
42
|
+
* }
|
|
43
|
+
*
|
|
44
|
+
* protected override createPersistence(user: User): Partial<UserRow> {
|
|
45
|
+
* return { password_hash: user.password.getHashedValue() };
|
|
46
|
+
* }
|
|
47
|
+
* }
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare abstract class BasePersistenceMapper<TAggregate, TProps, TRow> implements PersistenceMapper<TAggregate, TRow> {
|
|
51
|
+
protected readonly columnOverrides: Readonly<Record<string, string>>;
|
|
52
|
+
protected abstract createDomain(props: TProps, id: string): TAggregate;
|
|
53
|
+
protected createPersistence?(aggregate: TAggregate): Partial<TRow>;
|
|
54
|
+
private _inverseOverrides;
|
|
55
|
+
toDomain(row: TRow): TAggregate;
|
|
56
|
+
toPersistence(aggregate: TAggregate): TRow;
|
|
57
|
+
private columnFor;
|
|
58
|
+
private domainKeyFor;
|
|
59
|
+
private buildInverseOverrides;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=base-persistence.mapper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-persistence.mapper.d.ts","sourceRoot":"","sources":["../../src/repository/base-persistence.mapper.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,8BAAsB,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,CAClE,YAAW,iBAAiB,CAAC,UAAU,EAAE,IAAI,CAAC;IAE9C,SAAS,CAAC,QAAQ,CAAC,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAM;IAE1E,SAAS,CAAC,QAAQ,CAAC,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,UAAU;IAEtE,SAAS,CAAC,iBAAiB,CAAC,CAAC,SAAS,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlE,OAAO,CAAC,iBAAiB,CAAqC;IAE9D,QAAQ,CAAC,GAAG,EAAE,IAAI,GAAG,UAAU;IAa/B,aAAa,CAAC,SAAS,EAAE,UAAU,GAAG,IAAI;IAY1C,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,YAAY;IAKpB,OAAO,CAAC,qBAAqB;CAQ9B"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { camelToSnake, snakeToCamel } from '../query/case.js';
|
|
2
|
+
/**
|
|
3
|
+
* Abstract base for `PersistenceMapper` implementations. Handles
|
|
4
|
+
* bidirectional row↔aggregate conversion via prototype reflection:
|
|
5
|
+
*
|
|
6
|
+
* - **On write**, the aggregate's prototype chain is walked for every
|
|
7
|
+
* accessor that has BOTH `get` and `set` — those are the persisted
|
|
8
|
+
* properties. Getter-only accessors (computed / derived) are excluded.
|
|
9
|
+
* - **On read**, each column in the received row is reverse-mapped to a
|
|
10
|
+
* domain property name.
|
|
11
|
+
* - **Name resolution** converts camelCase ↔ snake_case by default;
|
|
12
|
+
* `columnOverrides` covers any column whose domain name deviates.
|
|
13
|
+
*
|
|
14
|
+
* Consumers implement:
|
|
15
|
+
* - `createDomain(props, id)` — reconstructs the aggregate.
|
|
16
|
+
* - `createPersistence(aggregate)` — optional; serializes value objects or
|
|
17
|
+
* emits derived columns. Merged *over* the default conversion.
|
|
18
|
+
* - `columnOverrides` — optional sparse map (`domainKey → columnName`).
|
|
19
|
+
*
|
|
20
|
+
* @example Tenant — zero-boilerplate case:
|
|
21
|
+
* ```ts
|
|
22
|
+
* class TenantInfraMapper extends BasePersistenceMapper<Tenant, TenantProps, TenantRow> {
|
|
23
|
+
* protected createDomain(props: TenantProps, id: string) {
|
|
24
|
+
* return Tenant.reconstitute(props, id);
|
|
25
|
+
* }
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @example User — mixed overrides + value-object serialization:
|
|
30
|
+
* ```ts
|
|
31
|
+
* class UserInfraMapper extends BasePersistenceMapper<User, UserProps, UserRow> {
|
|
32
|
+
* protected override readonly columnOverrides = {
|
|
33
|
+
* password: 'password_hash',
|
|
34
|
+
* resetPasswordTokenExpiresAt: 'reset_password_token_expiration',
|
|
35
|
+
* } as const;
|
|
36
|
+
*
|
|
37
|
+
* protected createDomain(props: UserProps, id: string) {
|
|
38
|
+
* return User.reconstitute({
|
|
39
|
+
* ...props,
|
|
40
|
+
* password: Password.fromHashedValue(props.password as string),
|
|
41
|
+
* }, id);
|
|
42
|
+
* }
|
|
43
|
+
*
|
|
44
|
+
* protected override createPersistence(user: User): Partial<UserRow> {
|
|
45
|
+
* return { password_hash: user.password.getHashedValue() };
|
|
46
|
+
* }
|
|
47
|
+
* }
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export class BasePersistenceMapper {
|
|
51
|
+
columnOverrides = {};
|
|
52
|
+
// Lazy reverse-map cache: columnName → domainKey. Built once per instance
|
|
53
|
+
// on first `toDomain`; subsequent lookups are O(1).
|
|
54
|
+
_inverseOverrides;
|
|
55
|
+
toDomain(row) {
|
|
56
|
+
const rowRecord = row;
|
|
57
|
+
const id = String(rowRecord.id ?? '');
|
|
58
|
+
const props = {};
|
|
59
|
+
for (const [column, value] of Object.entries(rowRecord)) {
|
|
60
|
+
if (column === 'id')
|
|
61
|
+
continue;
|
|
62
|
+
props[this.domainKeyFor(column)] = value;
|
|
63
|
+
}
|
|
64
|
+
return this.createDomain(props, id);
|
|
65
|
+
}
|
|
66
|
+
toPersistence(aggregate) {
|
|
67
|
+
const instance = aggregate;
|
|
68
|
+
const row = { id: instance.id };
|
|
69
|
+
for (const domainKey of discoverPersistedKeys(aggregate)) {
|
|
70
|
+
row[this.columnFor(domainKey)] = instance[domainKey];
|
|
71
|
+
}
|
|
72
|
+
const custom = this.createPersistence?.(aggregate) ?? {};
|
|
73
|
+
return { ...row, ...custom };
|
|
74
|
+
}
|
|
75
|
+
columnFor(domainKey) {
|
|
76
|
+
return this.columnOverrides[domainKey] ?? camelToSnake(domainKey);
|
|
77
|
+
}
|
|
78
|
+
domainKeyFor(column) {
|
|
79
|
+
const inverse = this._inverseOverrides ?? this.buildInverseOverrides();
|
|
80
|
+
return inverse[column] ?? snakeToCamel(column);
|
|
81
|
+
}
|
|
82
|
+
buildInverseOverrides() {
|
|
83
|
+
const inverse = {};
|
|
84
|
+
for (const [domainKey, columnName] of Object.entries(this.columnOverrides)) {
|
|
85
|
+
inverse[columnName] = domainKey;
|
|
86
|
+
}
|
|
87
|
+
this._inverseOverrides = inverse;
|
|
88
|
+
return inverse;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// Persisted-keys cache keyed by the aggregate's prototype. Prototypes are
|
|
92
|
+
// immutable post class-definition, so the result is stable for the process
|
|
93
|
+
// lifetime. WeakMap lets prototypes be GC'd if a class is ever discarded.
|
|
94
|
+
const persistedKeysCache = new WeakMap();
|
|
95
|
+
function discoverPersistedKeys(instance) {
|
|
96
|
+
const proto = Object.getPrototypeOf(instance);
|
|
97
|
+
if (!proto)
|
|
98
|
+
return [];
|
|
99
|
+
const cached = persistedKeysCache.get(proto);
|
|
100
|
+
if (cached)
|
|
101
|
+
return cached;
|
|
102
|
+
const keys = new Set();
|
|
103
|
+
let current = proto;
|
|
104
|
+
while (current && current !== Object.prototype) {
|
|
105
|
+
for (const name of Object.getOwnPropertyNames(current)) {
|
|
106
|
+
if (name === 'constructor' || name === 'id')
|
|
107
|
+
continue;
|
|
108
|
+
const desc = Object.getOwnPropertyDescriptor(current, name);
|
|
109
|
+
if (desc && typeof desc.get === 'function' && typeof desc.set === 'function') {
|
|
110
|
+
keys.add(name);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
current = Object.getPrototypeOf(current);
|
|
114
|
+
}
|
|
115
|
+
const result = [...keys];
|
|
116
|
+
persistedKeysCache.set(proto, result);
|
|
117
|
+
return result;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=base-persistence.mapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-persistence.mapper.js","sourceRoot":"","sources":["../../src/repository/base-persistence.mapper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAG9D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,MAAM,OAAgB,qBAAqB;IAGtB,eAAe,GAAqC,EAAE,CAAC;IAM1E,0EAA0E;IAC1E,oDAAoD;IAC5C,iBAAiB,CAAqC;IAE9D,QAAQ,CAAC,GAAS;QAChB,MAAM,SAAS,GAAG,GAA8B,CAAC;QACjD,MAAM,EAAE,GAAG,MAAM,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QAEtC,MAAM,KAAK,GAA4B,EAAE,CAAC;QAC1C,KAAK,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;YACxD,IAAI,MAAM,KAAK,IAAI;gBAAE,SAAS;YAC9B,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,CAAC;QAC3C,CAAC;QAED,OAAO,IAAI,CAAC,YAAY,CAAC,KAAe,EAAE,EAAE,CAAC,CAAC;IAChD,CAAC;IAED,aAAa,CAAC,SAAqB;QACjC,MAAM,QAAQ,GAAG,SAAqD,CAAC;QACvE,MAAM,GAAG,GAA4B,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC;QAEzD,KAAK,MAAM,SAAS,IAAI,qBAAqB,CAAC,SAAmB,CAAC,EAAE,CAAC;YACnE,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;QACvD,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QACzD,OAAO,EAAE,GAAG,GAAG,EAAE,GAAG,MAAM,EAAU,CAAC;IACvC,CAAC;IAEO,SAAS,CAAC,SAAiB;QACjC,OAAO,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC,IAAI,YAAY,CAAC,SAAS,CAAC,CAAC;IACpE,CAAC;IAEO,YAAY,CAAC,MAAc;QACjC,MAAM,OAAO,GAAG,IAAI,CAAC,iBAAiB,IAAI,IAAI,CAAC,qBAAqB,EAAE,CAAC;QACvE,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;IACjD,CAAC;IAEO,qBAAqB;QAC3B,MAAM,OAAO,GAA2B,EAAE,CAAC;QAC3C,KAAK,MAAM,CAAC,SAAS,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC;YAC3E,OAAO,CAAC,UAAU,CAAC,GAAG,SAAS,CAAC;QAClC,CAAC;QACD,IAAI,CAAC,iBAAiB,GAAG,OAAO,CAAC;QACjC,OAAO,OAAO,CAAC;IACjB,CAAC;CACF;AAED,0EAA0E;AAC1E,2EAA2E;AAC3E,0EAA0E;AAC1E,MAAM,kBAAkB,GAAG,IAAI,OAAO,EAA6B,CAAC;AAEpE,SAAS,qBAAqB,CAAC,QAAgB;IAC7C,MAAM,KAAK,GAAG,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAkB,CAAC;IAC/D,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IACtB,MAAM,MAAM,GAAG,kBAAkB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC7C,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAE1B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,IAAI,OAAO,GAAkB,KAAK,CAAC;IACnC,OAAO,OAAO,IAAI,OAAO,KAAK,MAAM,CAAC,SAAS,EAAE,CAAC;QAC/C,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,mBAAmB,CAAC,OAAO,CAAC,EAAE,CAAC;YACvD,IAAI,IAAI,KAAK,aAAa,IAAI,IAAI,KAAK,IAAI;gBAAE,SAAS;YACtD,MAAM,IAAI,GAAG,MAAM,CAAC,wBAAwB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YAC5D,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,GAAG,KAAK,UAAU,IAAI,OAAO,IAAI,CAAC,GAAG,KAAK,UAAU,EAAE,CAAC;gBAC7E,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACjB,CAAC;QACH,CAAC;QACD,OAAO,GAAG,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;IAC3C,CAAC;IACD,MAAM,MAAM,GAAsB,CAAC,GAAG,IAAI,CAAC,CAAC;IAC5C,kBAAkB,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACtC,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { AggregateRoot } from '@quilla-be-kit/ddd';
|
|
2
|
+
import type { UnitOfWorkContext } from '../unit-of-work/unit-of-work-context.type.js';
|
|
3
|
+
import { BaseAggregateRepository } from './base-aggregate.repository.js';
|
|
4
|
+
/**
|
|
5
|
+
* Repository for aggregates bound to a scope (tenant / workspace /
|
|
6
|
+
* organization / project / etc.). Every load method takes `scopeId` and
|
|
7
|
+
* throws `CrossScopeAccessError` on mismatch or miss — from the scope's
|
|
8
|
+
* point of view, there is no such resource.
|
|
9
|
+
*/
|
|
10
|
+
export declare abstract class BaseScopedAggregateRepository<TAggregate extends AggregateRoot<object> & {
|
|
11
|
+
id: string;
|
|
12
|
+
}, TRow extends {
|
|
13
|
+
id: string;
|
|
14
|
+
scope_id: string;
|
|
15
|
+
}> extends BaseAggregateRepository<TAggregate, TRow> {
|
|
16
|
+
loadByIdAndScopeOrFail(id: string, scopeId: string): Promise<TAggregate>;
|
|
17
|
+
loadForUpdateByIdAndScopeOrFail(id: string, scopeId: string, ctx: UnitOfWorkContext): Promise<TAggregate>;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=base-scoped-aggregate.repository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-scoped-aggregate.repository.d.ts","sourceRoot":"","sources":["../../src/repository/base-scoped-aggregate.repository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGxD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8CAA8C,CAAC;AACtF,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAEzE;;;;;GAKG;AACH,8BAAsB,6BAA6B,CACjD,UAAU,SAAS,aAAa,CAAC,MAAM,CAAC,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EACzD,IAAI,SAAS;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAC7C,SAAQ,uBAAuB,CAAC,UAAU,EAAE,IAAI,CAAC;IAC3C,sBAAsB,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAYxE,+BAA+B,CACnC,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,iBAAiB,GACrB,OAAO,CAAC,UAAU,CAAC;CAavB"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { CrossScopeAccessError } from '../errors/cross-scope-access.error.js';
|
|
2
|
+
import { BaseAggregateRepository } from './base-aggregate.repository.js';
|
|
3
|
+
/**
|
|
4
|
+
* Repository for aggregates bound to a scope (tenant / workspace /
|
|
5
|
+
* organization / project / etc.). Every load method takes `scopeId` and
|
|
6
|
+
* throws `CrossScopeAccessError` on mismatch or miss — from the scope's
|
|
7
|
+
* point of view, there is no such resource.
|
|
8
|
+
*/
|
|
9
|
+
export class BaseScopedAggregateRepository extends BaseAggregateRepository {
|
|
10
|
+
async loadByIdAndScopeOrFail(id, scopeId) {
|
|
11
|
+
const row = await this.writeDao.findOneById(id);
|
|
12
|
+
if (!row || row.scope_id !== scopeId) {
|
|
13
|
+
throw new CrossScopeAccessError({
|
|
14
|
+
entity: this.constructor.name,
|
|
15
|
+
id,
|
|
16
|
+
scopeId,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
return this.mapper.toDomain(row);
|
|
20
|
+
}
|
|
21
|
+
async loadForUpdateByIdAndScopeOrFail(id, scopeId, ctx) {
|
|
22
|
+
const row = await this.writeDao.findOneForUpdate({ id }, ctx.trx);
|
|
23
|
+
if (!row || row.scope_id !== scopeId) {
|
|
24
|
+
throw new CrossScopeAccessError({
|
|
25
|
+
entity: this.constructor.name,
|
|
26
|
+
id,
|
|
27
|
+
scopeId,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
const aggregate = this.mapper.toDomain(row);
|
|
31
|
+
ctx.registerAggregate(aggregate);
|
|
32
|
+
return aggregate;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=base-scoped-aggregate.repository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-scoped-aggregate.repository.js","sourceRoot":"","sources":["../../src/repository/base-scoped-aggregate.repository.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAE9E,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAEzE;;;;;GAKG;AACH,MAAM,OAAgB,6BAGpB,SAAQ,uBAAyC;IACjD,KAAK,CAAC,sBAAsB,CAAC,EAAU,EAAE,OAAe;QACtD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QAChD,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;YACrC,MAAM,IAAI,qBAAqB,CAAC;gBAC9B,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI;gBAC7B,EAAE;gBACF,OAAO;aACR,CAAC,CAAC;QACL,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IACnC,CAAC;IAED,KAAK,CAAC,+BAA+B,CACnC,EAAU,EACV,OAAe,EACf,GAAsB;QAEtB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,EAAE,EAAuB,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;QACvF,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;YACrC,MAAM,IAAI,qBAAqB,CAAC;gBAC9B,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI;gBAC7B,EAAE;gBACF,OAAO;aACR,CAAC,CAAC;QACL,CAAC;QACD,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC5C,GAAG,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC;QACjC,OAAO,SAAS,CAAC;IACnB,CAAC;CACF"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AggregateRoot } from '@quilla-be-kit/ddd';
|
|
2
|
+
import type { UnitOfWorkContext } from '../unit-of-work/unit-of-work-context.type.js';
|
|
3
|
+
import { BaseAggregateRepository } from './base-aggregate.repository.js';
|
|
4
|
+
/**
|
|
5
|
+
* Repository for global aggregates with no scope boundary (e.g. system
|
|
6
|
+
* configuration, shared reference data). Returns `null` for missing rows
|
|
7
|
+
* — absence is a legitimate state, not an access violation.
|
|
8
|
+
*/
|
|
9
|
+
export declare abstract class BaseUnscopedAggregateRepository<TAggregate extends AggregateRoot<object> & {
|
|
10
|
+
id: string;
|
|
11
|
+
}, TRow extends {
|
|
12
|
+
id: string;
|
|
13
|
+
}> extends BaseAggregateRepository<TAggregate, TRow> {
|
|
14
|
+
loadById(id: string): Promise<TAggregate | null>;
|
|
15
|
+
loadForUpdateById(id: string, ctx: UnitOfWorkContext): Promise<TAggregate | null>;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=base-unscoped-aggregate.repository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-unscoped-aggregate.repository.d.ts","sourceRoot":"","sources":["../../src/repository/base-unscoped-aggregate.repository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8CAA8C,CAAC;AACtF,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAEzE;;;;GAIG;AACH,8BAAsB,+BAA+B,CACnD,UAAU,SAAS,aAAa,CAAC,MAAM,CAAC,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EACzD,IAAI,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAC3B,SAAQ,uBAAuB,CAAC,UAAU,EAAE,IAAI,CAAC;IAC3C,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAKhD,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;CAOxF"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { BaseAggregateRepository } from './base-aggregate.repository.js';
|
|
2
|
+
/**
|
|
3
|
+
* Repository for global aggregates with no scope boundary (e.g. system
|
|
4
|
+
* configuration, shared reference data). Returns `null` for missing rows
|
|
5
|
+
* — absence is a legitimate state, not an access violation.
|
|
6
|
+
*/
|
|
7
|
+
export class BaseUnscopedAggregateRepository extends BaseAggregateRepository {
|
|
8
|
+
async loadById(id) {
|
|
9
|
+
const row = await this.writeDao.findOneById(id);
|
|
10
|
+
return row ? this.mapper.toDomain(row) : null;
|
|
11
|
+
}
|
|
12
|
+
async loadForUpdateById(id, ctx) {
|
|
13
|
+
const row = await this.writeDao.findOneForUpdate({ id }, ctx.trx);
|
|
14
|
+
if (!row)
|
|
15
|
+
return null;
|
|
16
|
+
const aggregate = this.mapper.toDomain(row);
|
|
17
|
+
ctx.registerAggregate(aggregate);
|
|
18
|
+
return aggregate;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=base-unscoped-aggregate.repository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-unscoped-aggregate.repository.js","sourceRoot":"","sources":["../../src/repository/base-unscoped-aggregate.repository.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAEzE;;;;GAIG;AACH,MAAM,OAAgB,+BAGpB,SAAQ,uBAAyC;IACjD,KAAK,CAAC,QAAQ,CAAC,EAAU;QACvB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QAChD,OAAO,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAChD,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,EAAU,EAAE,GAAsB;QACxD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,EAAE,EAAuB,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;QACvF,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC;QACtB,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC5C,GAAG,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC;QACjC,OAAO,SAAS,CAAC;IACnB,CAAC;CACF"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { BaseBasicRepository } from './base-basic.repository.js';
|
|
2
|
+
export { BaseAggregateRepository } from './base-aggregate.repository.js';
|
|
3
|
+
export { BaseScopedAggregateRepository } from './base-scoped-aggregate.repository.js';
|
|
4
|
+
export { BaseUnscopedAggregateRepository } from './base-unscoped-aggregate.repository.js';
|
|
5
|
+
export type { PersistenceMapper } from './mapper.interface.js';
|
|
6
|
+
export { BasePersistenceMapper } from './base-persistence.mapper.js';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/repository/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AACzE,OAAO,EAAE,6BAA6B,EAAE,MAAM,uCAAuC,CAAC;AACtF,OAAO,EAAE,+BAA+B,EAAE,MAAM,yCAAyC,CAAC;AAC1F,YAAY,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { BaseBasicRepository } from './base-basic.repository.js';
|
|
2
|
+
export { BaseAggregateRepository } from './base-aggregate.repository.js';
|
|
3
|
+
export { BaseScopedAggregateRepository } from './base-scoped-aggregate.repository.js';
|
|
4
|
+
export { BaseUnscopedAggregateRepository } from './base-unscoped-aggregate.repository.js';
|
|
5
|
+
export { BasePersistenceMapper } from './base-persistence.mapper.js';
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/repository/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AACzE,OAAO,EAAE,6BAA6B,EAAE,MAAM,uCAAuC,CAAC;AACtF,OAAO,EAAE,+BAA+B,EAAE,MAAM,yCAAyC,CAAC;AAE1F,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mapper.interface.d.ts","sourceRoot":"","sources":["../../src/repository/mapper.interface.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB,CAAC,UAAU,EAAE,IAAI;IACjD,QAAQ,CAAC,GAAG,EAAE,IAAI,GAAG,UAAU,CAAC;IAChC,aAAa,CAAC,SAAS,EAAE,UAAU,GAAG,IAAI,CAAC;CAC5C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mapper.interface.js","sourceRoot":"","sources":["../../src/repository/mapper.interface.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { DatabaseTransaction } from '../database/database-transaction.interface.js';
|
|
2
|
+
export interface EventSink<TEntry = unknown> {
|
|
3
|
+
sink(entries: readonly TEntry[], trx: DatabaseTransaction): Promise<void>;
|
|
4
|
+
}
|
|
5
|
+
//# sourceMappingURL=event-sink.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-sink.interface.d.ts","sourceRoot":"","sources":["../../src/unit-of-work/event-sink.interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,+CAA+C,CAAC;AAEzF,MAAM,WAAW,SAAS,CAAC,MAAM,GAAG,OAAO;IACzC,IAAI,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3E"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-sink.interface.js","sourceRoot":"","sources":["../../src/unit-of-work/event-sink.interface.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/unit-of-work/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACvE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACxE,YAAY,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/unit-of-work/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAA0B,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AnyEvent } from '@quilla-kit/ddd';
|
|
2
|
+
import type { DatabaseTransaction } from '../database/database-transaction.interface.js';
|
|
3
|
+
/**
|
|
4
|
+
* Optional injection point on `UnitOfWork`. When provided, the UoW drains
|
|
5
|
+
* aggregates' domain events plus registered integration events and writes
|
|
6
|
+
* them in the same transaction as the aggregate state changes. When absent,
|
|
7
|
+
* the UoW just commits — no outbox behavior.
|
|
8
|
+
*
|
|
9
|
+
* Concrete implementations live in `@quilla-kit/messaging`.
|
|
10
|
+
*/
|
|
11
|
+
export interface OutboxWriter {
|
|
12
|
+
write(events: readonly AnyEvent[], trx: DatabaseTransaction): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=outbox-writer.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbox-writer.interface.d.ts","sourceRoot":"","sources":["../../src/unit-of-work/outbox-writer.interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,+CAA+C,CAAC;AAEzF;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,MAAM,EAAE,SAAS,QAAQ,EAAE,EAAE,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7E"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbox-writer.interface.js","sourceRoot":"","sources":["../../src/unit-of-work/outbox-writer.interface.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AggregateRoot, IntegrationEvent } from '@quilla-be-kit/ddd';
|
|
2
|
+
import type { DatabaseTransaction } from '../database/database-transaction.interface.js';
|
|
3
|
+
export type UnitOfWorkContext = {
|
|
4
|
+
readonly trx: DatabaseTransaction;
|
|
5
|
+
registerAggregate(...aggregates: readonly AggregateRoot<object>[]): void;
|
|
6
|
+
registerIntegrationEvent(event: IntegrationEvent): void;
|
|
7
|
+
};
|
|
8
|
+
//# sourceMappingURL=unit-of-work-context.type.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unit-of-work-context.type.d.ts","sourceRoot":"","sources":["../../src/unit-of-work/unit-of-work-context.type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,+CAA+C,CAAC;AAEzF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,GAAG,EAAE,mBAAmB,CAAC;IAClC,iBAAiB,CAAC,GAAG,UAAU,EAAE,SAAS,aAAa,CAAC,MAAM,CAAC,EAAE,GAAG,IAAI,CAAC;IACzE,wBAAwB,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAAC;CACzD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unit-of-work-context.type.js","sourceRoot":"","sources":["../../src/unit-of-work/unit-of-work-context.type.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AnyEvent } from '@quilla-be-kit/ddd';
|
|
2
|
+
import type { Database } from '../database/database.interface.js';
|
|
3
|
+
import type { EventSink } from './event-sink.interface.js';
|
|
4
|
+
import type { UnitOfWorkContext } from './unit-of-work-context.type.js';
|
|
5
|
+
export type UnitOfWorkOptions<TEntry = unknown> = {
|
|
6
|
+
readonly db: Database;
|
|
7
|
+
readonly events?: {
|
|
8
|
+
readonly sink: EventSink<TEntry>;
|
|
9
|
+
readonly serialize: (event: AnyEvent) => TEntry;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
export declare class UnitOfWork<TEntry = unknown> {
|
|
13
|
+
private readonly db;
|
|
14
|
+
private readonly events;
|
|
15
|
+
private readonly storage;
|
|
16
|
+
constructor(options: UnitOfWorkOptions<TEntry>);
|
|
17
|
+
getContext(): UnitOfWorkContext | undefined;
|
|
18
|
+
transaction<T>(operation: (ctx: UnitOfWorkContext) => Promise<T>): Promise<T>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=unit-of-work.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unit-of-work.d.ts","sourceRoot":"","sources":["../../src/unit-of-work/unit-of-work.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAiB,QAAQ,EAAoB,MAAM,oBAAoB,CAAC;AACpF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAC;AAClE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAExE,MAAM,MAAM,iBAAiB,CAAC,MAAM,GAAG,OAAO,IAAI;IAChD,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC;IACtB,QAAQ,CAAC,MAAM,CAAC,EAAE;QAChB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;QACjC,QAAQ,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,MAAM,CAAC;KACjD,CAAC;CACH,CAAC;AAEF,qBAAa,UAAU,CAAC,MAAM,GAAG,OAAO;IACtC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAW;IAC9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsC;IAC7D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA8C;gBAE1D,OAAO,EAAE,iBAAiB,CAAC,MAAM,CAAC;IAK9C,UAAU,IAAI,iBAAiB,GAAG,SAAS;IAIrC,WAAW,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,GAAG,EAAE,iBAAiB,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;CAmDpF"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
+
export class UnitOfWork {
|
|
3
|
+
db;
|
|
4
|
+
events;
|
|
5
|
+
storage = new AsyncLocalStorage();
|
|
6
|
+
constructor(options) {
|
|
7
|
+
this.db = options.db;
|
|
8
|
+
this.events = options.events;
|
|
9
|
+
}
|
|
10
|
+
getContext() {
|
|
11
|
+
return this.storage.getStore();
|
|
12
|
+
}
|
|
13
|
+
async transaction(operation) {
|
|
14
|
+
const existing = this.storage.getStore();
|
|
15
|
+
if (existing) {
|
|
16
|
+
return operation(existing);
|
|
17
|
+
}
|
|
18
|
+
const trx = await this.db.getDbTransaction();
|
|
19
|
+
await trx.start();
|
|
20
|
+
const tracked = new Map();
|
|
21
|
+
const integrationEvents = [];
|
|
22
|
+
const ctx = {
|
|
23
|
+
trx,
|
|
24
|
+
registerAggregate: (...aggregates) => {
|
|
25
|
+
for (const agg of aggregates) {
|
|
26
|
+
tracked.set(`${agg.constructor.name}:${agg.id}`, agg);
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
registerIntegrationEvent: (event) => {
|
|
30
|
+
integrationEvents.push(event);
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
try {
|
|
34
|
+
const result = await this.storage.run(ctx, async () => {
|
|
35
|
+
const opResult = await operation(ctx);
|
|
36
|
+
const events = this.events;
|
|
37
|
+
if (events) {
|
|
38
|
+
const domainEvents = [...tracked.values()].flatMap((a) => a.drainDomainEvents());
|
|
39
|
+
const allEvents = [...domainEvents, ...integrationEvents];
|
|
40
|
+
if (allEvents.length > 0) {
|
|
41
|
+
const entries = allEvents.map((e) => events.serialize(e));
|
|
42
|
+
await events.sink.sink(entries, trx);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return opResult;
|
|
46
|
+
});
|
|
47
|
+
await trx.commit();
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
const reason = error instanceof Error ? error : new Error(String(error));
|
|
52
|
+
await trx.rollback(reason);
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
await trx.release();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=unit-of-work.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unit-of-work.js","sourceRoot":"","sources":["../../src/unit-of-work/unit-of-work.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAcrD,MAAM,OAAO,UAAU;IACJ,EAAE,CAAW;IACb,MAAM,CAAsC;IAC5C,OAAO,GAAG,IAAI,iBAAiB,EAAqB,CAAC;IAEtE,YAAY,OAAkC;QAC5C,IAAI,CAAC,EAAE,GAAG,OAAO,CAAC,EAAE,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAC/B,CAAC;IAED,UAAU;QACR,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,WAAW,CAAI,SAAiD;QACpE,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;QACzC,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,SAAS,CAAC,QAAQ,CAAC,CAAC;QAC7B,CAAC;QAED,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,gBAAgB,EAAE,CAAC;QAC7C,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC;QAElB,MAAM,OAAO,GAAG,IAAI,GAAG,EAAiC,CAAC;QACzD,MAAM,iBAAiB,GAAuB,EAAE,CAAC;QAEjD,MAAM,GAAG,GAAsB;YAC7B,GAAG;YACH,iBAAiB,EAAE,CAAC,GAAG,UAAU,EAAE,EAAE;gBACnC,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;oBAC7B,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,WAAW,CAAC,IAAI,IAAI,GAAG,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC;gBACxD,CAAC;YACH,CAAC;YACD,wBAAwB,EAAE,CAAC,KAAK,EAAE,EAAE;gBAClC,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAChC,CAAC;SACF,CAAC;QAEF,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,IAAI,EAAE;gBACpD,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,CAAC;gBAEtC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;gBAC3B,IAAI,MAAM,EAAE,CAAC;oBACX,MAAM,YAAY,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC,CAAC;oBACjF,MAAM,SAAS,GAAe,CAAC,GAAG,YAAY,EAAE,GAAG,iBAAiB,CAAC,CAAC;oBACtE,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBACzB,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;wBAC1D,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;oBACvC,CAAC;gBACH,CAAC;gBAED,OAAO,QAAQ,CAAC;YAClB,CAAC,CAAC,CAAC;YAEH,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC;YACnB,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,MAAM,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YACzE,MAAM,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YAC3B,MAAM,KAAK,CAAC;QACd,CAAC;gBAAS,CAAC;YACT,MAAM,GAAG,CAAC,OAAO,EAAE,CAAC;QACtB,CAAC;IACH,CAAC;CACF"}
|