@invariant--labs/foundation 1.1.2 → 1.1.4
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/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +108 -45
- package/.pnp.cjs +0 -22192
- package/.pnp.loader.mjs +0 -2126
- package/.yarnrc.yml +0 -1
- package/CHANGELOG.md +0 -527
- package/eslint.config.mjs +0 -52
- package/invariant.json +0 -22
- package/jest/jest.config.base.ts +0 -30
- package/jest/jest.spec.base.ts +0 -7
- package/jest.config.js +0 -49
- package/src/core/application/index.ts +0 -1
- package/src/core/application/persistence/index.ts +0 -3
- package/src/core/application/persistence/query-builder.ts +0 -2
- package/src/core/application/persistence/read-projection.ts +0 -2
- package/src/core/application/persistence/repository.ts +0 -23
- package/src/core/domain/entities/aggregate-root.ts +0 -34
- package/src/core/domain/entities/entity.spec.ts +0 -43
- package/src/core/domain/entities/entity.ts +0 -29
- package/src/core/domain/entities/identifier.spec.ts +0 -34
- package/src/core/domain/entities/identifier.ts +0 -16
- package/src/core/domain/entities/index.ts +0 -5
- package/src/core/domain/entities/projection.ts +0 -7
- package/src/core/domain/entities/unique-entity-id.ts +0 -9
- package/src/core/domain/events/domain-event.ts +0 -7
- package/src/core/domain/events/index.ts +0 -1
- package/src/core/domain/index.ts +0 -3
- package/src/core/domain/value-objects/index.ts +0 -2
- package/src/core/domain/value-objects/range.ts +0 -4
- package/src/core/domain/value-objects/value-object.spec.ts +0 -45
- package/src/core/domain/value-objects/value-object.ts +0 -17
- package/src/core/errors/command-failure.error.spec.ts +0 -30
- package/src/core/errors/command-failure.error.ts +0 -9
- package/src/core/errors/command-filter.error.ts +0 -3
- package/src/core/errors/detailed.error.ts +0 -25
- package/src/core/errors/domain.error.spec.ts +0 -27
- package/src/core/errors/domain.error.ts +0 -9
- package/src/core/errors/entity-not-found.error.spec.ts +0 -32
- package/src/core/errors/entity-not-found.error.ts +0 -9
- package/src/core/errors/fake-implementation.error.spec.ts +0 -27
- package/src/core/errors/fake-implementation.error.ts +0 -15
- package/src/core/errors/index.ts +0 -8
- package/src/core/errors/query-failure.error.ts +0 -8
- package/src/core/errors/too-many-results.error.ts +0 -3
- package/src/core/index.ts +0 -4
- package/src/core/infrastructure/config/config.provider.ts +0 -78
- package/src/core/infrastructure/config/config.service.ts +0 -25
- package/src/core/infrastructure/config/index.ts +0 -2
- package/src/core/infrastructure/messaging/fake/fake-messaging.service.ts +0 -17
- package/src/core/infrastructure/messaging/fake/fake-queue-manager.service.ts +0 -9
- package/src/core/infrastructure/messaging/fake/fake-queue-messaging.service.ts +0 -9
- package/src/core/infrastructure/messaging/fake/index.ts +0 -3
- package/src/core/infrastructure/messaging/index.ts +0 -6
- package/src/core/infrastructure/messaging/messaging.service.ts +0 -3
- package/src/core/infrastructure/messaging/queue-manager.service.ts +0 -6
- package/src/core/infrastructure/messaging/queue-messaging.service.ts +0 -3
- package/src/core/infrastructure/messaging/rabbitmq/index.ts +0 -2
- package/src/core/infrastructure/messaging/rabbitmq/rabbit-messaging.service.ts +0 -11
- package/src/core/infrastructure/messaging/rabbitmq/rabbit-queue-messaging.service.ts +0 -11
- package/src/core/infrastructure/messaging/types.ts +0 -28
- package/src/core/infrastructure/persistence/errors/index.ts +0 -2
- package/src/core/infrastructure/persistence/errors/model-to-entity-conversion.error.ts +0 -9
- package/src/core/infrastructure/persistence/errors/persistence.error.ts +0 -8
- package/src/core/infrastructure/persistence/in-memory/fake.repository.ts +0 -79
- package/src/core/infrastructure/persistence/in-memory/in-memory.query-builder.ts +0 -4
- package/src/core/infrastructure/persistence/in-memory/in-memory.repository.spec.ts +0 -50
- package/src/core/infrastructure/persistence/in-memory/in-memory.repository.ts +0 -81
- package/src/core/infrastructure/persistence/in-memory/index.ts +0 -3
- package/src/core/infrastructure/persistence/index.ts +0 -4
- package/src/core/infrastructure/persistence/read-side/in-memory.query-builder.ts +0 -4
- package/src/core/infrastructure/persistence/read-side/index.ts +0 -1
- package/src/core/infrastructure/persistence/read-side/knex/index.ts +0 -2
- package/src/core/infrastructure/persistence/read-side/knex/knex-types.definition.ts +0 -13
- package/src/core/infrastructure/persistence/read-side/knex/knex.query-builder.ts +0 -70
- package/src/core/infrastructure/persistence/read-side/knex-query-builder.ts +0 -70
- package/src/core/infrastructure/persistence/read-side/knex-types.definition.ts +0 -13
- package/src/core/infrastructure/persistence/write-side/aggregate-typeorm-repository.ts +0 -87
- package/src/core/infrastructure/persistence/write-side/entity-typeorm-repository.ts +0 -64
- package/src/core/infrastructure/persistence/write-side/in-memory.repository.ts +0 -82
- package/src/core/infrastructure/persistence/write-side/index.ts +0 -1
- package/src/core/infrastructure/persistence/write-side/model-attributes.ts +0 -4
- package/src/core/infrastructure/persistence/write-side/orm-embedded-mapper.ts +0 -11
- package/src/core/infrastructure/persistence/write-side/orm-mapper.ts +0 -11
- package/src/core/infrastructure/persistence/write-side/typeorm/aggregate-typeorm.repository.ts +0 -87
- package/src/core/infrastructure/persistence/write-side/typeorm/entity-typeorm.repository.ts +0 -64
- package/src/core/infrastructure/persistence/write-side/typeorm/index.ts +0 -5
- package/src/core/infrastructure/persistence/write-side/typeorm/model-attributes.ts +0 -4
- package/src/core/infrastructure/persistence/write-side/typeorm/orm-embedded.mapper.ts +0 -11
- package/src/core/infrastructure/persistence/write-side/typeorm/orm.mapper.ts +0 -11
- package/src/core/types/architecture-layer.ts +0 -52
- package/src/core/types/array-element.ts +0 -5
- package/src/core/types/index.ts +0 -2
- package/src/index.ts +0 -30
- package/src/modules/config/config.module.ts +0 -9
- package/src/modules/config/index.ts +0 -2
- package/src/modules/graphql/index.ts +0 -1
- package/src/modules/graphql/paginated-response.object-type.ts +0 -23
- package/src/modules/healthcheck/healthcheck-out.dto.ts +0 -43
- package/src/modules/healthcheck/index.ts +0 -1
- package/src/modules/knex/index.ts +0 -3
- package/src/modules/knex/knex-core.module.ts +0 -30
- package/src/modules/knex/knex.decorator.ts +0 -5
- package/src/modules/knex/knex.interface.ts +0 -12
- package/src/modules/knex/knex.module.ts +0 -14
- package/src/modules/knex/knex.token.ts +0 -2
- package/src/modules/logger/app-logger.ts +0 -28
- package/src/modules/logger/index.ts +0 -5
- package/src/modules/logger/log.ts +0 -26
- package/src/modules/logger/logger.module.ts +0 -47
- package/src/modules/logger/logger.service.ts +0 -131
- package/src/modules/logger/transports/console-color.transport.ts +0 -41
- package/src/modules/logger/transports/console-json.transport.ts +0 -23
- package/src/modules/logger/transports/console.transport.ts +0 -10
- package/src/modules/logger/transports/fake.transport.ts +0 -18
- package/src/modules/logger/transports/index.ts +0 -5
- package/src/modules/logger/transports/logger-transport.ts +0 -22
- package/src/modules/messaging/index.ts +0 -2
- package/src/modules/messaging/messaging.module.ts +0 -92
- package/src/modules/queue/default-queue-name.resolver.ts +0 -5
- package/src/modules/queue/index.ts +0 -3
- package/src/modules/queue/queue.module.ts +0 -73
- package/src/modules/queue/rabbit-queue-manager.service.ts +0 -67
- package/src/nestjs/errors/handlers/error-handler.ts +0 -38
- package/src/nestjs/errors/handlers/error-handler.type.ts +0 -23
- package/src/nestjs/errors/handlers/generic-error-handler.ts +0 -59
- package/src/nestjs/errors/handlers/handle-errors.decorator.ts +0 -43
- package/src/nestjs/errors/handlers/index.ts +0 -5
- package/src/nestjs/errors/handlers/validation-error-handler.ts +0 -46
- package/src/nestjs/errors/index.ts +0 -2
- package/src/nestjs/errors/parsers/axios-metadata.parser.ts +0 -21
- package/src/nestjs/errors/parsers/error-metadata.definition.ts +0 -1
- package/src/nestjs/errors/parsers/index.ts +0 -5
- package/src/nestjs/errors/parsers/knex-metadata.parser.ts +0 -18
- package/src/nestjs/errors/parsers/typeorm-metadata.parser.ts +0 -19
- package/src/nestjs/errors/parsers/workos-metadata.parser.ts +0 -17
- package/src/nestjs/http/decorators/index.ts +0 -1
- package/src/nestjs/http/decorators/log-app-ctx.decorator.ts +0 -32
- package/src/nestjs/http/dtos/date-range.dto.ts +0 -15
- package/src/nestjs/http/dtos/index.ts +0 -1
- package/src/nestjs/http/filters/all-exceptions.filter.ts +0 -92
- package/src/nestjs/http/filters/command-failure.filter.ts +0 -12
- package/src/nestjs/http/filters/index.ts +0 -4
- package/src/nestjs/http/filters/rpc-exceptions.filter.ts +0 -10
- package/src/nestjs/http/filters/too-many-results.filter.ts +0 -12
- package/src/nestjs/http/index.ts +0 -6
- package/src/nestjs/http/interceptors/index.ts +0 -2
- package/src/nestjs/http/interceptors/log-app-ctx.interceptor.ts +0 -109
- package/src/nestjs/http/interceptors/serialize-output.interceptor.ts +0 -19
- package/src/nestjs/http/middleware/http-logger.middleware.ts +0 -31
- package/src/nestjs/http/middleware/index.ts +0 -2
- package/src/nestjs/http/middleware/logger.middleware.ts +0 -21
- package/src/nestjs/http/swagger/index.ts +0 -1
- package/src/nestjs/http/swagger/swagger.ts +0 -44
- package/src/nestjs/index.ts +0 -2
- package/src/testing/command-bus.stub.ts +0 -33
- package/src/testing/event-bus.stub.ts +0 -56
- package/src/testing/event-publisher.stub.ts +0 -24
- package/src/testing/fake-logger.ts +0 -20
- package/src/testing/index.ts +0 -2
- package/src/testing/query-bus.stub.ts +0 -27
- package/src/testing/stub.spec.ts +0 -250
- package/src/testing/stub.ts +0 -170
- package/src/testing/stubs/command-bus.stub.ts +0 -33
- package/src/testing/stubs/event-bus.stub.ts +0 -56
- package/src/testing/stubs/event-publisher.stub.ts +0 -24
- package/src/testing/stubs/index.ts +0 -5
- package/src/testing/stubs/query-bus.stub.ts +0 -27
- package/src/testing/stubs/stub.ts +0 -170
- package/src/utils/array.spec.ts +0 -29
- package/src/utils/array.ts +0 -10
- package/src/utils/base64.spec.ts +0 -18
- package/src/utils/base64.ts +0 -6
- package/src/utils/collection.ts +0 -4
- package/src/utils/common.ts +0 -13
- package/src/utils/csv.ts +0 -49
- package/src/utils/date/date-range.ts +0 -4
- package/src/utils/date/date.spec.ts +0 -100
- package/src/utils/date/date.ts +0 -177
- package/src/utils/date/diff.spec.ts +0 -66
- package/src/utils/date/diffYear.spec.ts +0 -23
- package/src/utils/date/fillMissingRangeValues.spec.ts +0 -523
- package/src/utils/date/groubBy.spec.ts +0 -183
- package/src/utils/date/index.ts +0 -2
- package/src/utils/date/isSame.spec.ts +0 -111
- package/src/utils/file.spec.ts +0 -66
- package/src/utils/file.ts +0 -5
- package/src/utils/hash-key.ts +0 -23
- package/src/utils/index.ts +0 -14
- package/src/utils/invariant.ts +0 -3
- package/src/utils/iso-date.ts +0 -11
- package/src/utils/object.spec.ts +0 -18
- package/src/utils/object.ts +0 -6
- package/src/utils/paginated.ts +0 -36
- package/src/utils/string.spec.ts +0 -10
- package/src/utils/string.ts +0 -19
- package/src/utils/type.ts +0 -9
- package/src/utils/xml.ts +0 -6
- package/src/validation/ensure-array.decorator.ts +0 -5
- package/src/validation/index.ts +0 -7
- package/src/validation/is-iso-date.decorator.spec.ts +0 -29
- package/src/validation/is-iso-date.decorator.ts +0 -30
- package/src/validation/is-less-than-or-equal.decorator.spec.ts +0 -30
- package/src/validation/is-less-than-or-equal.decorator.ts +0 -52
- package/src/validation/is-less-than.decorator.spec.ts +0 -36
- package/src/validation/is-less-than.decorator.ts +0 -52
- package/src/validation/is-more-than-or-equal.decorator.spec.ts +0 -30
- package/src/validation/is-more-than-or-equal.decorator.ts +0 -52
- package/src/validation/is-more-than.decorator.spec.ts +0 -36
- package/src/validation/is-more-than.decorator.ts +0 -52
- package/src/validation/is-time-string.decorator.spec.ts +0 -35
- package/src/validation/is-time-string.decorator.ts +0 -29
- package/tsconfig.build.json +0 -6
- package/tsconfig.json +0 -34
- package/tsconfig.spec.json +0 -14
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
type CamelToSnakeCase<S extends string> = S extends `${infer T}${infer U}`
|
|
2
|
-
? `${T extends Capitalize<T> ? "_" : ""}${Lowercase<T>}${CamelToSnakeCase<U>}`
|
|
3
|
-
: S;
|
|
4
|
-
|
|
5
|
-
export type knexInfer<T> = {
|
|
6
|
-
[K in keyof T as CamelToSnakeCase<Extract<K, string>>]: T[K] extends CallableFunction ? never : T[K];
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export type knexTableAlias<Table, Alias extends string> = {
|
|
10
|
-
[K in keyof Table as `${Alias}.${string & CamelToSnakeCase<Extract<K, string>>}`]: Table[K] extends CallableFunction
|
|
11
|
-
? never
|
|
12
|
-
: Table[K];
|
|
13
|
-
};
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { DataSource, EntityManager, ObjectLiteral, SelectQueryBuilder } from "typeorm";
|
|
2
|
-
|
|
3
|
-
import { Repository } from "../../../application";
|
|
4
|
-
import { AggregateRoot, EntityProps } from "../../../domain";
|
|
5
|
-
import { ArchitectureLevel } from "../../../types";
|
|
6
|
-
import { typeormMetadataParser } from "../../../../nestjs/errors/parsers/typeorm-metadata.parser";
|
|
7
|
-
import { EntityNotFoundError } from "../../../errors";
|
|
8
|
-
import { PersistenceError } from "../errors/persistence.error";
|
|
9
|
-
|
|
10
|
-
export abstract class AggregateTypeormRepository<
|
|
11
|
-
DomainAggregate extends AggregateRoot<EntityProps>,
|
|
12
|
-
OrmModel extends ObjectLiteral,
|
|
13
|
-
> implements Repository<AggregateRoot<EntityProps>>
|
|
14
|
-
{
|
|
15
|
-
protected abstract createDefaultQueryBuilder(): SelectQueryBuilder<OrmModel>;
|
|
16
|
-
protected abstract toEntity(model: OrmModel): DomainAggregate;
|
|
17
|
-
protected abstract toModel(aggregate: DomainAggregate): OrmModel | Promise<OrmModel>;
|
|
18
|
-
protected manager: EntityManager;
|
|
19
|
-
|
|
20
|
-
constructor(
|
|
21
|
-
dataSource: DataSource,
|
|
22
|
-
private readonly aggregateName: string,
|
|
23
|
-
) {
|
|
24
|
-
this.manager = dataSource.manager;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
async count(): Promise<number> {
|
|
28
|
-
return this.createDefaultQueryBuilder().getCount();
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
async exists(id: string): Promise<boolean> {
|
|
32
|
-
const count = await this.createDefaultQueryBuilder().where({ id }).getCount();
|
|
33
|
-
return count === 1;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
async findOne(id: string): Promise<DomainAggregate | null> {
|
|
37
|
-
const model = await this.createDefaultQueryBuilder().where({ id }).getOne();
|
|
38
|
-
return model ? this.toEntity(model) : null;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async findOneOrFail(aggregateId: string): Promise<DomainAggregate> {
|
|
42
|
-
const aggregate = await this.findOne(aggregateId);
|
|
43
|
-
if (!aggregate) {
|
|
44
|
-
throw new EntityNotFoundError(
|
|
45
|
-
this.aggregateName,
|
|
46
|
-
{ [ArchitectureLevel.INFRASTRUCTURE]: { "persistence-sql": { className: "AggregateTypeormRepository" } } },
|
|
47
|
-
{ id: aggregateId },
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
return aggregate;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async findByIds(ids: string[]): Promise<DomainAggregate[]> {
|
|
54
|
-
const models = await this.createDefaultQueryBuilder().whereInIds(ids).getMany();
|
|
55
|
-
return models.map((model) => this.toEntity(model));
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
async save(aggregate: DomainAggregate): Promise<DomainAggregate> {
|
|
59
|
-
try {
|
|
60
|
-
const model = await this.manager.save(this.toModel(aggregate));
|
|
61
|
-
aggregate.commit();
|
|
62
|
-
return this.toEntity(model);
|
|
63
|
-
} catch (error) {
|
|
64
|
-
throw new PersistenceError("Failed to save aggregate", {
|
|
65
|
-
"aggregate-root": {
|
|
66
|
-
className: AggregateTypeormRepository.name,
|
|
67
|
-
meta: typeormMetadataParser(error, { method: this.save.name }),
|
|
68
|
-
},
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
async saveAll(aggregates: DomainAggregate[]): Promise<void> {
|
|
74
|
-
try {
|
|
75
|
-
const models = await Promise.all(aggregates.map((a) => Promise.resolve(this.toModel(a))));
|
|
76
|
-
await this.manager.save(models);
|
|
77
|
-
aggregates.forEach((a) => a.commit());
|
|
78
|
-
} catch (error) {
|
|
79
|
-
throw new PersistenceError("Failed to save aggregates", {
|
|
80
|
-
"aggregate-root": {
|
|
81
|
-
className: AggregateTypeormRepository.name,
|
|
82
|
-
meta: typeormMetadataParser(error, { method: this.saveAll.name }),
|
|
83
|
-
},
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { DataSource, EntityManager, ObjectLiteral, SelectQueryBuilder } from "typeorm";
|
|
2
|
-
|
|
3
|
-
import { Repository } from "../../../application";
|
|
4
|
-
import { Entity, EntityProps } from "../../../domain";
|
|
5
|
-
import { ArchitectureLevel } from "../../../types";
|
|
6
|
-
import { EntityNotFoundError } from "../../../errors";
|
|
7
|
-
|
|
8
|
-
export abstract class EntityTypeormRepository<DomainEntity extends Entity<EntityProps>, OrmModel extends ObjectLiteral>
|
|
9
|
-
implements Repository<Entity<EntityProps>>
|
|
10
|
-
{
|
|
11
|
-
protected manager: EntityManager;
|
|
12
|
-
|
|
13
|
-
constructor(
|
|
14
|
-
dataSource: DataSource,
|
|
15
|
-
private readonly entityName: string,
|
|
16
|
-
) {
|
|
17
|
-
this.manager = dataSource.manager;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
async count(): Promise<number> {
|
|
21
|
-
return this.createDefaultQueryBuilder().getCount();
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
async exists(id: string): Promise<boolean> {
|
|
25
|
-
const count = await this.createDefaultQueryBuilder().where({ id }).getCount();
|
|
26
|
-
return count === 1;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
async findOne(id: string): Promise<DomainEntity | null> {
|
|
30
|
-
const model = await this.createDefaultQueryBuilder().where({ id }).getOne();
|
|
31
|
-
return model ? this.toEntity(model) : null;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
async findOneOrFail(entityId: string): Promise<DomainEntity> {
|
|
35
|
-
const entity = await this.findOne(entityId);
|
|
36
|
-
if (!entity) {
|
|
37
|
-
throw new EntityNotFoundError(
|
|
38
|
-
this.entityName,
|
|
39
|
-
{ [ArchitectureLevel.INFRASTRUCTURE]: { "persistence-sql": { className: "EntityTypeormRepository" } } },
|
|
40
|
-
{ id: entityId },
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
return entity;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
async findByIds(ids: string[]): Promise<DomainEntity[]> {
|
|
47
|
-
const models = await this.createDefaultQueryBuilder().whereInIds(ids).getMany();
|
|
48
|
-
return models.map((model) => this.toEntity(model));
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
async save(entity: DomainEntity): Promise<DomainEntity> {
|
|
52
|
-
const model = await this.manager.save(await this.toModel(entity));
|
|
53
|
-
return this.toEntity(model);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
async saveAll(entities: DomainEntity[]): Promise<void> {
|
|
57
|
-
const models = await Promise.all(entities.map((e) => Promise.resolve(this.toModel(e))));
|
|
58
|
-
await this.manager.save(models);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
protected abstract createDefaultQueryBuilder(): SelectQueryBuilder<OrmModel>;
|
|
62
|
-
protected abstract toEntity(model: OrmModel): DomainEntity;
|
|
63
|
-
protected abstract toModel(entity: DomainEntity): OrmModel | Promise<OrmModel>;
|
|
64
|
-
}
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/require-await */
|
|
2
|
-
import _ from "lodash";
|
|
3
|
-
|
|
4
|
-
import { FindManyOptions, Repository } from "../../../application/persistence/repository";
|
|
5
|
-
import { AggregateRoot } from "../../../domain";
|
|
6
|
-
import { Entity, EntityProps } from "../../../domain/entities/entity";
|
|
7
|
-
import { ArchitectureLevel } from "../../../types";
|
|
8
|
-
import { EntityNotFoundError } from "../../../errors";
|
|
9
|
-
|
|
10
|
-
export class InMemoryRepository<DomainEntity extends Entity<EntityProps> | AggregateRoot<EntityProps>>
|
|
11
|
-
implements Repository<DomainEntity>
|
|
12
|
-
{
|
|
13
|
-
protected store: Map<string, DomainEntity>;
|
|
14
|
-
|
|
15
|
-
constructor(
|
|
16
|
-
defaultEntities: DomainEntity[] = [],
|
|
17
|
-
protected error?: Error,
|
|
18
|
-
) {
|
|
19
|
-
this.store = new Map(defaultEntities.map((e) => [e.id.toString(), e]));
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
async save(entity: DomainEntity): Promise<DomainEntity> {
|
|
23
|
-
this.checkError();
|
|
24
|
-
this.store.set(entity.id.toString(), entity);
|
|
25
|
-
return entity;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
async saveAll(entities: DomainEntity[]): Promise<void> {
|
|
29
|
-
this.checkError();
|
|
30
|
-
for (const entity of entities) {await this.save(entity);}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
async findOne(id: string): Promise<DomainEntity | null> {
|
|
34
|
-
return this.store.get(id) ?? null;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
async findOneOrFail(id: string): Promise<DomainEntity> {
|
|
38
|
-
const entity = await this.findOne(id);
|
|
39
|
-
if (!entity) {
|
|
40
|
-
throw new EntityNotFoundError("InMemoryEntity", {
|
|
41
|
-
[ArchitectureLevel.INFRASTRUCTURE]: { "persistence-fake": { className: "InMemoryRepository" } },
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
return entity;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
async findByIds(ids: string[]): Promise<DomainEntity[]> {
|
|
48
|
-
return this.toArray().filter((entity) => ids.includes(entity.id.toString()));
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
async delete(entity: DomainEntity): Promise<void> {
|
|
52
|
-
this.checkError();
|
|
53
|
-
this.store.delete(entity.id.toString());
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
async exists(id: string): Promise<boolean> {
|
|
57
|
-
this.checkError();
|
|
58
|
-
return this.store.has(id);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
async count(options: FindManyOptions<DomainEntity>): Promise<number> {
|
|
62
|
-
this.checkError();
|
|
63
|
-
return _.filter(this.toArray(), options.filters).length;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
clear(): void {
|
|
67
|
-
this.store.clear();
|
|
68
|
-
this.error = undefined;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
setError(error: Error): void {
|
|
72
|
-
this.error = error;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
protected checkError(): void {
|
|
76
|
-
if (this.error) {throw this.error;}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
protected toArray(): DomainEntity[] {
|
|
80
|
-
return [...this.store.values()];
|
|
81
|
-
}
|
|
82
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./typeorm";
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { ValueObject } from "../../../domain";
|
|
2
|
-
|
|
3
|
-
export interface OrmEmbeddedMapper<
|
|
4
|
-
DomainValueObject extends ValueObject,
|
|
5
|
-
OrmEmbeddedModel,
|
|
6
|
-
ToPersistenceArgs extends unknown[] = [],
|
|
7
|
-
ToDomainArgs extends unknown[] = [],
|
|
8
|
-
> {
|
|
9
|
-
toObjectValue(embeddedModel: OrmEmbeddedModel | null, ...args: ToDomainArgs): DomainValueObject | undefined;
|
|
10
|
-
toEmbeddedModel(valueObject?: DomainValueObject, ...args: ToPersistenceArgs): OrmEmbeddedModel | null;
|
|
11
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { AggregateRoot, Entity } from "../../../domain";
|
|
2
|
-
|
|
3
|
-
export interface OrmMapper<
|
|
4
|
-
DomainObject extends AggregateRoot | Entity,
|
|
5
|
-
OrmModel,
|
|
6
|
-
ToPersistenceArgs extends unknown[] = [],
|
|
7
|
-
ToDomainArgs extends unknown[] = [],
|
|
8
|
-
> {
|
|
9
|
-
toEntity(model: OrmModel, ...args: ToDomainArgs): DomainObject;
|
|
10
|
-
toModel(entity: DomainObject, ...args: ToPersistenceArgs): OrmModel;
|
|
11
|
-
}
|
package/src/core/infrastructure/persistence/write-side/typeorm/aggregate-typeorm.repository.ts
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { DataSource, EntityManager, ObjectLiteral, SelectQueryBuilder } from "typeorm";
|
|
2
|
-
|
|
3
|
-
import { Repository } from "../../../../application";
|
|
4
|
-
import { AggregateRoot, EntityProps } from "../../../../domain";
|
|
5
|
-
import { ArchitectureLevel } from "../../../../types";
|
|
6
|
-
import { EntityNotFoundError } from "../../../../errors";
|
|
7
|
-
import { typeormMetadataParser } from "../../../../../nestjs/errors/parsers/typeorm-metadata.parser";
|
|
8
|
-
import { PersistenceError } from "../../errors/persistence.error";
|
|
9
|
-
|
|
10
|
-
export abstract class AggregateTypeormRepository<
|
|
11
|
-
DomainAggregate extends AggregateRoot<EntityProps>,
|
|
12
|
-
OrmModel extends ObjectLiteral,
|
|
13
|
-
> implements Repository<AggregateRoot<EntityProps>>
|
|
14
|
-
{
|
|
15
|
-
protected abstract createDefaultQueryBuilder(): SelectQueryBuilder<OrmModel>;
|
|
16
|
-
protected abstract toEntity(model: OrmModel): DomainAggregate;
|
|
17
|
-
protected abstract toModel(aggregate: DomainAggregate): OrmModel | Promise<OrmModel>;
|
|
18
|
-
protected manager: EntityManager;
|
|
19
|
-
|
|
20
|
-
constructor(
|
|
21
|
-
dataSource: DataSource,
|
|
22
|
-
private readonly aggregateName: string,
|
|
23
|
-
) {
|
|
24
|
-
this.manager = dataSource.manager;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
async count(): Promise<number> {
|
|
28
|
-
return this.createDefaultQueryBuilder().getCount();
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
async exists(id: string): Promise<boolean> {
|
|
32
|
-
const count = await this.createDefaultQueryBuilder().where({ id }).getCount();
|
|
33
|
-
return count === 1;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
async findOne(id: string): Promise<DomainAggregate | null> {
|
|
37
|
-
const model = await this.createDefaultQueryBuilder().where({ id }).getOne();
|
|
38
|
-
return model ? this.toEntity(model) : null;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async findOneOrFail(aggregateId: string): Promise<DomainAggregate> {
|
|
42
|
-
const aggregate = await this.findOne(aggregateId);
|
|
43
|
-
if (!aggregate) {
|
|
44
|
-
throw new EntityNotFoundError(
|
|
45
|
-
this.aggregateName,
|
|
46
|
-
{ [ArchitectureLevel.INFRASTRUCTURE]: { "persistence-sql": { className: "AggregateTypeormRepository" } } },
|
|
47
|
-
{ id: aggregateId },
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
return aggregate;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async findByIds(ids: string[]): Promise<DomainAggregate[]> {
|
|
54
|
-
const models = await this.createDefaultQueryBuilder().whereInIds(ids).getMany();
|
|
55
|
-
return models.map((model) => this.toEntity(model));
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
async save(aggregate: DomainAggregate): Promise<DomainAggregate> {
|
|
59
|
-
try {
|
|
60
|
-
const model = await this.manager.save(this.toModel(aggregate));
|
|
61
|
-
aggregate.commit();
|
|
62
|
-
return this.toEntity(model);
|
|
63
|
-
} catch (error) {
|
|
64
|
-
throw new PersistenceError("Failed to save aggregate", {
|
|
65
|
-
"aggregate-root": {
|
|
66
|
-
className: AggregateTypeormRepository.name,
|
|
67
|
-
meta: typeormMetadataParser(error, { method: this.save.name }),
|
|
68
|
-
},
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
async saveAll(aggregates: DomainAggregate[]): Promise<void> {
|
|
74
|
-
try {
|
|
75
|
-
const models = await Promise.all(aggregates.map((a) => Promise.resolve(this.toModel(a))));
|
|
76
|
-
await this.manager.save(models);
|
|
77
|
-
aggregates.forEach((a) => a.commit());
|
|
78
|
-
} catch (error) {
|
|
79
|
-
throw new PersistenceError("Failed to save aggregates", {
|
|
80
|
-
"aggregate-root": {
|
|
81
|
-
className: AggregateTypeormRepository.name,
|
|
82
|
-
meta: typeormMetadataParser(error, { method: this.saveAll.name }),
|
|
83
|
-
},
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { DataSource, EntityManager, ObjectLiteral, SelectQueryBuilder } from "typeorm";
|
|
2
|
-
|
|
3
|
-
import { Repository } from "../../../../application";
|
|
4
|
-
import { Entity, EntityProps } from "../../../../domain";
|
|
5
|
-
import { ArchitectureLevel } from "../../../../types";
|
|
6
|
-
import { EntityNotFoundError } from "../../../../errors";
|
|
7
|
-
|
|
8
|
-
export abstract class EntityTypeormRepository<DomainEntity extends Entity<EntityProps>, OrmModel extends ObjectLiteral>
|
|
9
|
-
implements Repository<Entity<EntityProps>>
|
|
10
|
-
{
|
|
11
|
-
protected manager: EntityManager;
|
|
12
|
-
|
|
13
|
-
constructor(
|
|
14
|
-
dataSource: DataSource,
|
|
15
|
-
private readonly entityName: string,
|
|
16
|
-
) {
|
|
17
|
-
this.manager = dataSource.manager;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
async count(): Promise<number> {
|
|
21
|
-
return this.createDefaultQueryBuilder().getCount();
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
async exists(id: string): Promise<boolean> {
|
|
25
|
-
const count = await this.createDefaultQueryBuilder().where({ id }).getCount();
|
|
26
|
-
return count === 1;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
async findOne(id: string): Promise<DomainEntity | null> {
|
|
30
|
-
const model = await this.createDefaultQueryBuilder().where({ id }).getOne();
|
|
31
|
-
return model ? this.toEntity(model) : null;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
async findOneOrFail(entityId: string): Promise<DomainEntity> {
|
|
35
|
-
const entity = await this.findOne(entityId);
|
|
36
|
-
if (!entity) {
|
|
37
|
-
throw new EntityNotFoundError(
|
|
38
|
-
this.entityName,
|
|
39
|
-
{ [ArchitectureLevel.INFRASTRUCTURE]: { "persistence-sql": { className: "EntityTypeormRepository" } } },
|
|
40
|
-
{ id: entityId },
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
return entity;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
async findByIds(ids: string[]): Promise<DomainEntity[]> {
|
|
47
|
-
const models = await this.createDefaultQueryBuilder().whereInIds(ids).getMany();
|
|
48
|
-
return models.map((model) => this.toEntity(model));
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
async save(entity: DomainEntity): Promise<DomainEntity> {
|
|
52
|
-
const model = await this.manager.save(await this.toModel(entity));
|
|
53
|
-
return this.toEntity(model);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
async saveAll(entities: DomainEntity[]): Promise<void> {
|
|
57
|
-
const models = await Promise.all(entities.map((e) => Promise.resolve(this.toModel(e))));
|
|
58
|
-
await this.manager.save(models);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
protected abstract createDefaultQueryBuilder(): SelectQueryBuilder<OrmModel>;
|
|
62
|
-
protected abstract toEntity(model: OrmModel): DomainEntity;
|
|
63
|
-
protected abstract toModel(entity: DomainEntity): OrmModel | Promise<OrmModel>;
|
|
64
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { ValueObject } from "../../../../domain";
|
|
2
|
-
|
|
3
|
-
export interface OrmEmbeddedMapper<
|
|
4
|
-
DomainValueObject extends ValueObject,
|
|
5
|
-
OrmEmbeddedModel,
|
|
6
|
-
ToPersistenceArgs extends unknown[] = [],
|
|
7
|
-
ToDomainArgs extends unknown[] = [],
|
|
8
|
-
> {
|
|
9
|
-
toObjectValue(embeddedModel: OrmEmbeddedModel | null, ...args: ToDomainArgs): DomainValueObject | undefined;
|
|
10
|
-
toEmbeddedModel(valueObject?: DomainValueObject, ...args: ToPersistenceArgs): OrmEmbeddedModel | null;
|
|
11
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { AggregateRoot, Entity } from "../../../../domain";
|
|
2
|
-
|
|
3
|
-
export interface OrmMapper<
|
|
4
|
-
DomainObject extends AggregateRoot | Entity,
|
|
5
|
-
OrmModel,
|
|
6
|
-
ToPersistenceArgs extends unknown[] = [],
|
|
7
|
-
ToDomainArgs extends unknown[] = [],
|
|
8
|
-
> {
|
|
9
|
-
toEntity(model: OrmModel, ...args: ToDomainArgs): DomainObject;
|
|
10
|
-
toModel(entity: DomainObject, ...args: ToPersistenceArgs): OrmModel;
|
|
11
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
type Values<V> = V[keyof V];
|
|
2
|
-
type OneOf<V> = Values<{
|
|
3
|
-
[K in keyof V]: { [K1 in K]: V[K1] };
|
|
4
|
-
}>;
|
|
5
|
-
|
|
6
|
-
export enum ArchitectureLevel {
|
|
7
|
-
DOMAIN = "DOMAIN",
|
|
8
|
-
APPLICATION = "APPLICATION",
|
|
9
|
-
INFRASTRUCTURE = "INFRASTRUCTURE",
|
|
10
|
-
UNDEFINED = "UNDEFINED",
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export type ArchitectureLayerType =
|
|
14
|
-
| "aggregate-root"
|
|
15
|
-
| "entity"
|
|
16
|
-
| "value-object"
|
|
17
|
-
| "query"
|
|
18
|
-
| "command"
|
|
19
|
-
| "event-handler"
|
|
20
|
-
| "event-saga"
|
|
21
|
-
| "service"
|
|
22
|
-
| "authorization"
|
|
23
|
-
| "authentication"
|
|
24
|
-
| "web-dto"
|
|
25
|
-
| "web-rest"
|
|
26
|
-
| "web-graphql"
|
|
27
|
-
| "web-socket"
|
|
28
|
-
| "web-rpc"
|
|
29
|
-
| "persistence-sql"
|
|
30
|
-
| "persistence-saas"
|
|
31
|
-
| "persistence-fake"
|
|
32
|
-
| "persistence-other"
|
|
33
|
-
| "persistence-s3"
|
|
34
|
-
| "persistence-disk"
|
|
35
|
-
| "messaging-inmem"
|
|
36
|
-
| "messaging-pubsub"
|
|
37
|
-
| "unknown";
|
|
38
|
-
|
|
39
|
-
export type ArchitectureLayerTraceBase = {
|
|
40
|
-
[Type in ArchitectureLayerType]: {
|
|
41
|
-
className: string;
|
|
42
|
-
meta?: unknown;
|
|
43
|
-
};
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
export type ArchitectureLayerTrace = OneOf<ArchitectureLayerTraceBase>;
|
|
47
|
-
|
|
48
|
-
export type DDD = {
|
|
49
|
-
[key in `${ArchitectureLevel}`]: ArchitectureLayerTrace;
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
export type ArchitectureLayer = OneOf<DDD>;
|
package/src/core/types/index.ts
DELETED
package/src/index.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
// Core
|
|
2
|
-
export * from "./core/domain";
|
|
3
|
-
export * from "./core/application";
|
|
4
|
-
export * from "./core/errors";
|
|
5
|
-
export * from "./core/types";
|
|
6
|
-
export * from "./core/infrastructure/persistence";
|
|
7
|
-
export * from "./core/infrastructure/messaging";
|
|
8
|
-
export * from "./core/infrastructure/config";
|
|
9
|
-
|
|
10
|
-
// Modules
|
|
11
|
-
export * from "./modules/config";
|
|
12
|
-
export * from "./modules/logger";
|
|
13
|
-
export * from "./modules/messaging";
|
|
14
|
-
export * from "./modules/queue";
|
|
15
|
-
export * from "./modules/knex";
|
|
16
|
-
export * from "./modules/graphql";
|
|
17
|
-
export * from "./modules/healthcheck";
|
|
18
|
-
|
|
19
|
-
// NestJS Integration
|
|
20
|
-
export * from "./nestjs/http";
|
|
21
|
-
export * from "./nestjs/errors";
|
|
22
|
-
|
|
23
|
-
// Validation
|
|
24
|
-
export * from "./validation";
|
|
25
|
-
|
|
26
|
-
// Utils
|
|
27
|
-
export * from "./utils";
|
|
28
|
-
|
|
29
|
-
// Testing
|
|
30
|
-
export * from "./testing";
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { Module } from "@nestjs/common";
|
|
2
|
-
|
|
3
|
-
import { ConfigProvider, ConfigService } from "../../core/infrastructure/config";
|
|
4
|
-
|
|
5
|
-
@Module({
|
|
6
|
-
providers: [{ provide: ConfigService, useClass: ConfigProvider }],
|
|
7
|
-
exports: [ConfigService],
|
|
8
|
-
})
|
|
9
|
-
export class ConfigModule {}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./paginated-response.object-type";
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { Type } from "@nestjs/common";
|
|
2
|
-
import { Field, Int, ObjectType } from "@nestjs/graphql";
|
|
3
|
-
|
|
4
|
-
export type PaginatedResponse<TItem> = {
|
|
5
|
-
items: TItem[];
|
|
6
|
-
total: number;
|
|
7
|
-
hasMore: boolean;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export function PaginatedResponse<T>(classRef: Type<T>): Type<PaginatedResponse<T>> {
|
|
11
|
-
@ObjectType(`${classRef.name}Edge`, { isAbstract: true })
|
|
12
|
-
abstract class PaginatedType {
|
|
13
|
-
@Field(() => [classRef])
|
|
14
|
-
items: T[];
|
|
15
|
-
|
|
16
|
-
@Field(() => Int)
|
|
17
|
-
total: number;
|
|
18
|
-
|
|
19
|
-
@Field()
|
|
20
|
-
hasMore: boolean;
|
|
21
|
-
}
|
|
22
|
-
return PaginatedType as unknown as Type<PaginatedResponse<T>>;
|
|
23
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { Expose, Type } from "class-transformer";
|
|
2
|
-
import { IsOptional } from "class-validator";
|
|
3
|
-
|
|
4
|
-
export class HealthStatus {
|
|
5
|
-
@Expose()
|
|
6
|
-
status: "up" | "down";
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export class HealthIndicatorResult {
|
|
10
|
-
@Expose()
|
|
11
|
-
@Type(() => HealthStatus)
|
|
12
|
-
@IsOptional()
|
|
13
|
-
database?: HealthStatus;
|
|
14
|
-
|
|
15
|
-
@Expose()
|
|
16
|
-
@Type(() => HealthStatus)
|
|
17
|
-
@IsOptional()
|
|
18
|
-
memory_heap?: HealthStatus;
|
|
19
|
-
|
|
20
|
-
@Expose()
|
|
21
|
-
@Type(() => HealthStatus)
|
|
22
|
-
@IsOptional()
|
|
23
|
-
rabbitmq?: HealthStatus;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export class HealthcheckOutDto {
|
|
27
|
-
@Expose()
|
|
28
|
-
status: "error" | "ok" | "shutting_down";
|
|
29
|
-
|
|
30
|
-
@Expose()
|
|
31
|
-
@Type(() => HealthIndicatorResult)
|
|
32
|
-
details: HealthIndicatorResult;
|
|
33
|
-
|
|
34
|
-
@Expose()
|
|
35
|
-
@Type(() => HealthIndicatorResult)
|
|
36
|
-
@IsOptional()
|
|
37
|
-
info?: HealthIndicatorResult;
|
|
38
|
-
|
|
39
|
-
@Expose()
|
|
40
|
-
@Type(() => HealthIndicatorResult)
|
|
41
|
-
@IsOptional()
|
|
42
|
-
error?: HealthIndicatorResult;
|
|
43
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./healthcheck-out.dto";
|