@archi-code/ddd 0.0.0-stage → 3.0.0-alpha.1
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/LICENSE +46 -0
- package/README.md +2693 -2
- package/SKILL.md +104 -0
- package/ddd-skills/archi-code-ddd/imports.md +84 -0
- package/ddd-skills/archi-code-ddd/layers.md +299 -0
- package/ddd-skills/archi-code-ddd/patterns.md +676 -0
- package/ddd-skills/archi-code-ddd/what-not-to-do.md +189 -0
- package/ddd-skills/archi-code-ddd/where-each-class-goes.md +63 -0
- package/ddd-skills/ddd-agregados/GUIA.md +114 -0
- package/ddd-skills/ddd-agregados/references/consistencia-eventual.md +159 -0
- package/ddd-skills/ddd-agregados/references/ejemplo-ecommerce.md +52 -0
- package/ddd-skills/ddd-agregados/references/fabricas.md +196 -0
- package/ddd-skills/ddd-agregados/references/implementacion-ts.md +711 -0
- package/ddd-skills/ddd-arquitectura/GUIA.md +80 -0
- package/ddd-skills/ddd-arquitectura/assets/dependency-cruiser.cjs +92 -0
- package/ddd-skills/ddd-arquitectura/references/estilos-adicionales.md +51 -0
- package/ddd-skills/ddd-arquitectura/references/estructura-hexagonal-ts.md +352 -0
- package/ddd-skills/ddd-arquitectura/references/modulos.md +48 -0
- package/ddd-skills/ddd-auditoria-refactorizacion/GUIA.md +85 -0
- package/ddd-skills/ddd-auditoria-refactorizacion/references/ejemplo-auditoria.md +316 -0
- package/ddd-skills/ddd-auditoria-refactorizacion/references/lista-comprobacion.md +54 -0
- package/ddd-skills/ddd-auditoria-refactorizacion/references/plan-migracion.md +73 -0
- package/ddd-skills/ddd-auditoria-refactorizacion/scripts/scan_ddd_smells.py +264 -0
- package/ddd-skills/ddd-context-mapping/GUIA.md +83 -0
- package/ddd-skills/ddd-context-mapping/references/anticorrupcion-ts.md +404 -0
- package/ddd-skills/ddd-context-mapping/references/estilos-integracion.md +155 -0
- package/ddd-skills/ddd-event-sourcing-cqrs/GUIA.md +92 -0
- package/ddd-skills/ddd-event-sourcing-cqrs/references/event-sourcing-ts.md +471 -0
- package/ddd-skills/ddd-event-sourcing-cqrs/references/proyecciones-cqrs-ts.md +285 -0
- package/ddd-skills/ddd-eventos-dominio/GUIA.md +106 -0
- package/ddd-skills/ddd-eventos-dominio/references/diseno-eventos.md +131 -0
- package/ddd-skills/ddd-eventos-dominio/references/ejemplo-ecommerce.md +240 -0
- package/ddd-skills/ddd-eventos-dominio/references/publicacion-ts.md +526 -0
- package/ddd-skills/ddd-orquestador/GUIA.md +40 -0
- package/ddd-skills/ddd-orquestador/references/chuleta-reglas.md +35 -0
- package/ddd-skills/ddd-repositorios-persistencia/GUIA.md +121 -0
- package/ddd-skills/ddd-repositorios-persistencia/references/implementacion-ts.md +296 -0
- package/ddd-skills/ddd-repositorios-persistencia/references/tests-repositorios.md +177 -0
- package/ddd-skills/ddd-repositorios-persistencia/references/transacciones-ts.md +294 -0
- package/ddd-skills/ddd-servicios-capa-aplicacion/GUIA.md +99 -0
- package/ddd-skills/ddd-servicios-capa-aplicacion/references/capa-aplicacion-ts.md +264 -0
- package/ddd-skills/ddd-servicios-capa-aplicacion/references/ejemplo-ecommerce.md +324 -0
- package/ddd-skills/ddd-servicios-capa-aplicacion/references/servicios-dominio-ts.md +191 -0
- package/ddd-skills/ddd-value-objects-entidades/GUIA.md +118 -0
- package/ddd-skills/ddd-value-objects-entidades/references/ejemplo-ecommerce.md +87 -0
- package/ddd-skills/ddd-value-objects-entidades/references/entidades-ts.md +220 -0
- package/ddd-skills/ddd-value-objects-entidades/references/persistencia-valores.md +88 -0
- package/ddd-skills/ddd-value-objects-entidades/references/specification-y-diseno-flexible.md +119 -0
- package/ddd-skills/ddd-value-objects-entidades/references/validacion.md +96 -0
- package/ddd-skills/ddd-value-objects-entidades/references/value-objects-ts.md +377 -0
- package/dist/cjs/application/event/event-bus.d.ts +4 -0
- package/dist/cjs/application/event/event-bus.js +2 -0
- package/dist/cjs/application/event/event-listener.d.ts +4 -0
- package/dist/cjs/application/event/event-listener.js +6 -0
- package/dist/cjs/application/event/listens-to.d.ts +15 -0
- package/dist/cjs/application/event/listens-to.js +28 -0
- package/dist/cjs/application/index.d.ts +7 -0
- package/dist/cjs/application/index.js +9 -0
- package/dist/cjs/application/ports/clock.d.ts +3 -0
- package/dist/cjs/application/ports/clock.js +2 -0
- package/dist/cjs/application/ports/logger.d.ts +8 -0
- package/dist/cjs/application/ports/logger.js +2 -0
- package/dist/cjs/application/use-case/use-case.d.ts +6 -0
- package/dist/cjs/application/use-case/use-case.js +24 -0
- package/dist/cjs/domain/aggregate/aggregate-root.d.ts +14 -0
- package/dist/cjs/domain/aggregate/aggregate-root.js +33 -0
- package/dist/cjs/domain/entity/entity.d.ts +9 -0
- package/dist/cjs/domain/entity/entity.js +19 -0
- package/dist/cjs/domain/event/event-base.d.ts +29 -0
- package/dist/cjs/domain/event/event-base.js +51 -0
- package/dist/cjs/domain/index.d.ts +10 -0
- package/dist/cjs/domain/index.js +24 -0
- package/dist/cjs/domain/primitive/primitive-types.d.ts +22 -0
- package/dist/cjs/domain/primitive/primitive-types.js +2 -0
- package/dist/cjs/domain/repository/aggregate-finder.d.ts +4 -0
- package/dist/cjs/domain/repository/aggregate-finder.js +2 -0
- package/dist/cjs/domain/repository/aggregate-remover.d.ts +4 -0
- package/dist/cjs/domain/repository/aggregate-remover.js +2 -0
- package/dist/cjs/domain/repository/aggregate-saver.d.ts +4 -0
- package/dist/cjs/domain/repository/aggregate-saver.js +2 -0
- package/dist/cjs/domain/specification/specification.d.ts +9 -0
- package/dist/cjs/domain/specification/specification.js +44 -0
- package/dist/cjs/domain/type/abstract-type.d.ts +20 -0
- package/dist/cjs/domain/type/abstract-type.js +69 -0
- package/dist/cjs/domain/type/array-type.d.ts +16 -0
- package/dist/cjs/domain/type/array-type.js +65 -0
- package/dist/cjs/domain/type/boolean-type.d.ts +4 -0
- package/dist/cjs/domain/type/boolean-type.js +16 -0
- package/dist/cjs/domain/type/composite/composite-field.d.ts +19 -0
- package/dist/cjs/domain/type/composite/composite-field.js +63 -0
- package/dist/cjs/domain/type/composite/composite.d.ts +26 -0
- package/dist/cjs/domain/type/composite/composite.js +55 -0
- package/dist/cjs/domain/type/date-type.d.ts +18 -0
- package/dist/cjs/domain/type/date-type.js +35 -0
- package/dist/cjs/domain/type/enum-type.d.ts +7 -0
- package/dist/cjs/domain/type/enum-type.js +30 -0
- package/dist/cjs/domain/type/equality/value-equality.d.ts +7 -0
- package/dist/cjs/domain/type/equality/value-equality.js +41 -0
- package/dist/cjs/domain/type/id-type.d.ts +7 -0
- package/dist/cjs/domain/type/id-type.js +17 -0
- package/dist/cjs/domain/type/immutable/immutable-date.d.ts +4 -0
- package/dist/cjs/domain/type/immutable/immutable-date.js +37 -0
- package/dist/cjs/domain/type/immutable/immutable.d.ts +4 -0
- package/dist/cjs/domain/type/immutable/immutable.js +19 -0
- package/dist/cjs/domain/type/index.d.ts +17 -0
- package/dist/cjs/domain/type/index.js +33 -0
- package/dist/cjs/domain/type/json-type.d.ts +5 -0
- package/dist/cjs/domain/type/json-type.js +17 -0
- package/dist/cjs/domain/type/number-type.d.ts +4 -0
- package/dist/cjs/domain/type/number-type.js +16 -0
- package/dist/cjs/domain/type/required/required-mark.d.ts +9 -0
- package/dist/cjs/domain/type/required/required-mark.js +13 -0
- package/dist/cjs/domain/type/required/required.d.ts +7 -0
- package/dist/cjs/domain/type/required/required.js +21 -0
- package/dist/cjs/domain/type/string-type.d.ts +4 -0
- package/dist/cjs/domain/type/string-type.js +16 -0
- package/dist/cjs/domain/type/uuid-type.d.ts +7 -0
- package/dist/cjs/domain/type/uuid-type.js +27 -0
- package/dist/cjs/domain/type/value-objects/value-objects.d.ts +16 -0
- package/dist/cjs/domain/type/value-objects/value-objects.js +70 -0
- package/dist/cjs/exceptions/abstract.exception.d.ts +23 -0
- package/dist/cjs/exceptions/abstract.exception.js +66 -0
- package/dist/cjs/exceptions/application/aggregate-not-found.exception.d.ts +5 -0
- package/dist/cjs/exceptions/application/aggregate-not-found.exception.js +17 -0
- package/dist/cjs/exceptions/application/application.exception.d.ts +6 -0
- package/dist/cjs/exceptions/application/application.exception.js +17 -0
- package/dist/cjs/exceptions/application/concurrency.exception.d.ts +5 -0
- package/dist/cjs/exceptions/application/concurrency.exception.js +17 -0
- package/dist/cjs/exceptions/application/not-allowed.exception.d.ts +5 -0
- package/dist/cjs/exceptions/application/not-allowed.exception.js +17 -0
- package/dist/cjs/exceptions/brand/exception-brand.d.ts +6 -0
- package/dist/cjs/exceptions/brand/exception-brand.js +29 -0
- package/dist/cjs/exceptions/domain/domain.exception.d.ts +6 -0
- package/dist/cjs/exceptions/domain/domain.exception.js +17 -0
- package/dist/cjs/exceptions/domain/required-value.exception.d.ts +4 -0
- package/dist/cjs/exceptions/domain/required-value.exception.js +21 -0
- package/dist/cjs/exceptions/domain/type-primitive.exception.d.ts +4 -0
- package/dist/cjs/exceptions/domain/type-primitive.exception.js +21 -0
- package/dist/cjs/exceptions/domain/validation.exception.d.ts +14 -0
- package/dist/cjs/exceptions/domain/validation.exception.js +23 -0
- package/dist/cjs/exceptions/exception-code.d.ts +15 -0
- package/dist/cjs/exceptions/exception-code.js +19 -0
- package/dist/cjs/exceptions/index.d.ts +14 -0
- package/dist/cjs/exceptions/index.js +30 -0
- package/dist/cjs/exceptions/infrastructure/event-delivery.exception.d.ts +5 -0
- package/dist/cjs/exceptions/infrastructure/event-delivery.exception.js +20 -0
- package/dist/cjs/exceptions/infrastructure/infrastructure.exception.d.ts +6 -0
- package/dist/cjs/exceptions/infrastructure/infrastructure.exception.js +17 -0
- package/dist/cjs/exceptions/infrastructure/internal-error.exception.d.ts +5 -0
- package/dist/cjs/exceptions/infrastructure/internal-error.exception.js +17 -0
- package/dist/cjs/exceptions/infrastructure/unknown-event.exception.d.ts +4 -0
- package/dist/cjs/exceptions/infrastructure/unknown-event.exception.js +19 -0
- package/dist/cjs/exceptions/received/received-value.d.ts +4 -0
- package/dist/cjs/exceptions/received/received-value.js +13 -0
- package/dist/cjs/infrastructure/clock/fixed-clock.d.ts +8 -0
- package/dist/cjs/infrastructure/clock/fixed-clock.js +19 -0
- package/dist/cjs/infrastructure/clock/system-clock.d.ts +4 -0
- package/dist/cjs/infrastructure/clock/system-clock.js +9 -0
- package/dist/cjs/infrastructure/event/domain-event-bus.d.ts +16 -0
- package/dist/cjs/infrastructure/event/domain-event-bus.js +60 -0
- package/dist/cjs/infrastructure/event/event-channel.d.ts +9 -0
- package/dist/cjs/infrastructure/event/event-channel.js +2 -0
- package/dist/cjs/infrastructure/event/event-registry.d.ts +9 -0
- package/dist/cjs/infrastructure/event/event-registry.js +43 -0
- package/dist/cjs/infrastructure/event/in-memory/emitter.d.ts +11 -0
- package/dist/cjs/infrastructure/event/in-memory/emitter.js +54 -0
- package/dist/cjs/infrastructure/event/in-memory/in-memory-event-channel.d.ts +16 -0
- package/dist/cjs/infrastructure/event/in-memory/in-memory-event-channel.js +51 -0
- package/dist/cjs/infrastructure/http/http-error-mapper.d.ts +23 -0
- package/dist/cjs/infrastructure/http/http-error-mapper.js +63 -0
- package/dist/cjs/infrastructure/index.d.ts +16 -0
- package/dist/cjs/infrastructure/index.js +21 -0
- package/dist/cjs/infrastructure/logging/console-logger.d.ts +17 -0
- package/dist/cjs/infrastructure/logging/console-logger.js +37 -0
- package/dist/cjs/infrastructure/logging/in-memory-logger.d.ts +15 -0
- package/dist/cjs/infrastructure/logging/in-memory-logger.js +27 -0
- package/dist/cjs/infrastructure/logging/log-serializer.d.ts +7 -0
- package/dist/cjs/infrastructure/logging/log-serializer.js +59 -0
- package/dist/cjs/infrastructure/logging/silent-logger.d.ts +7 -0
- package/dist/cjs/infrastructure/logging/silent-logger.js +18 -0
- package/dist/esm/application/event/event-bus.d.ts +4 -0
- package/dist/esm/application/event/event-bus.js +1 -0
- package/dist/esm/application/event/event-listener.d.ts +4 -0
- package/dist/esm/application/event/event-listener.js +2 -0
- package/dist/esm/application/event/listens-to.d.ts +15 -0
- package/dist/esm/application/event/listens-to.js +25 -0
- package/dist/esm/application/index.d.ts +7 -0
- package/dist/esm/application/index.js +3 -0
- package/dist/esm/application/ports/clock.d.ts +3 -0
- package/dist/esm/application/ports/clock.js +1 -0
- package/dist/esm/application/ports/logger.d.ts +8 -0
- package/dist/esm/application/ports/logger.js +1 -0
- package/dist/esm/application/use-case/use-case.d.ts +6 -0
- package/dist/esm/application/use-case/use-case.js +20 -0
- package/dist/esm/domain/aggregate/aggregate-root.d.ts +14 -0
- package/dist/esm/domain/aggregate/aggregate-root.js +29 -0
- package/dist/esm/domain/entity/entity.d.ts +9 -0
- package/dist/esm/domain/entity/entity.js +15 -0
- package/dist/esm/domain/event/event-base.d.ts +29 -0
- package/dist/esm/domain/event/event-base.js +47 -0
- package/dist/esm/domain/index.d.ts +10 -0
- package/dist/esm/domain/index.js +6 -0
- package/dist/esm/domain/primitive/primitive-types.d.ts +22 -0
- package/dist/esm/domain/primitive/primitive-types.js +1 -0
- package/dist/esm/domain/repository/aggregate-finder.d.ts +4 -0
- package/dist/esm/domain/repository/aggregate-finder.js +1 -0
- package/dist/esm/domain/repository/aggregate-remover.d.ts +4 -0
- package/dist/esm/domain/repository/aggregate-remover.js +1 -0
- package/dist/esm/domain/repository/aggregate-saver.d.ts +4 -0
- package/dist/esm/domain/repository/aggregate-saver.js +1 -0
- package/dist/esm/domain/specification/specification.d.ts +9 -0
- package/dist/esm/domain/specification/specification.js +40 -0
- package/dist/esm/domain/type/abstract-type.d.ts +20 -0
- package/dist/esm/domain/type/abstract-type.js +65 -0
- package/dist/esm/domain/type/array-type.d.ts +16 -0
- package/dist/esm/domain/type/array-type.js +61 -0
- package/dist/esm/domain/type/boolean-type.d.ts +4 -0
- package/dist/esm/domain/type/boolean-type.js +12 -0
- package/dist/esm/domain/type/composite/composite-field.d.ts +19 -0
- package/dist/esm/domain/type/composite/composite-field.js +59 -0
- package/dist/esm/domain/type/composite/composite.d.ts +26 -0
- package/dist/esm/domain/type/composite/composite.js +52 -0
- package/dist/esm/domain/type/date-type.d.ts +18 -0
- package/dist/esm/domain/type/date-type.js +29 -0
- package/dist/esm/domain/type/enum-type.d.ts +7 -0
- package/dist/esm/domain/type/enum-type.js +26 -0
- package/dist/esm/domain/type/equality/value-equality.d.ts +7 -0
- package/dist/esm/domain/type/equality/value-equality.js +37 -0
- package/dist/esm/domain/type/id-type.d.ts +7 -0
- package/dist/esm/domain/type/id-type.js +13 -0
- package/dist/esm/domain/type/immutable/immutable-date.d.ts +4 -0
- package/dist/esm/domain/type/immutable/immutable-date.js +33 -0
- package/dist/esm/domain/type/immutable/immutable.d.ts +4 -0
- package/dist/esm/domain/type/immutable/immutable.js +15 -0
- package/dist/esm/domain/type/index.d.ts +17 -0
- package/dist/esm/domain/type/index.js +14 -0
- package/dist/esm/domain/type/json-type.d.ts +5 -0
- package/dist/esm/domain/type/json-type.js +13 -0
- package/dist/esm/domain/type/number-type.d.ts +4 -0
- package/dist/esm/domain/type/number-type.js +12 -0
- package/dist/esm/domain/type/required/required-mark.d.ts +9 -0
- package/dist/esm/domain/type/required/required-mark.js +9 -0
- package/dist/esm/domain/type/required/required.d.ts +7 -0
- package/dist/esm/domain/type/required/required.js +18 -0
- package/dist/esm/domain/type/string-type.d.ts +4 -0
- package/dist/esm/domain/type/string-type.js +12 -0
- package/dist/esm/domain/type/uuid-type.d.ts +7 -0
- package/dist/esm/domain/type/uuid-type.js +23 -0
- package/dist/esm/domain/type/value-objects/value-objects.d.ts +16 -0
- package/dist/esm/domain/type/value-objects/value-objects.js +66 -0
- package/dist/esm/exceptions/abstract.exception.d.ts +23 -0
- package/dist/esm/exceptions/abstract.exception.js +62 -0
- package/dist/esm/exceptions/application/aggregate-not-found.exception.d.ts +5 -0
- package/dist/esm/exceptions/application/aggregate-not-found.exception.js +13 -0
- package/dist/esm/exceptions/application/application.exception.d.ts +6 -0
- package/dist/esm/exceptions/application/application.exception.js +13 -0
- package/dist/esm/exceptions/application/concurrency.exception.d.ts +5 -0
- package/dist/esm/exceptions/application/concurrency.exception.js +13 -0
- package/dist/esm/exceptions/application/not-allowed.exception.d.ts +5 -0
- package/dist/esm/exceptions/application/not-allowed.exception.js +13 -0
- package/dist/esm/exceptions/brand/exception-brand.d.ts +6 -0
- package/dist/esm/exceptions/brand/exception-brand.js +25 -0
- package/dist/esm/exceptions/domain/domain.exception.d.ts +6 -0
- package/dist/esm/exceptions/domain/domain.exception.js +13 -0
- package/dist/esm/exceptions/domain/required-value.exception.d.ts +4 -0
- package/dist/esm/exceptions/domain/required-value.exception.js +17 -0
- package/dist/esm/exceptions/domain/type-primitive.exception.d.ts +4 -0
- package/dist/esm/exceptions/domain/type-primitive.exception.js +17 -0
- package/dist/esm/exceptions/domain/validation.exception.d.ts +14 -0
- package/dist/esm/exceptions/domain/validation.exception.js +19 -0
- package/dist/esm/exceptions/exception-code.d.ts +15 -0
- package/dist/esm/exceptions/exception-code.js +16 -0
- package/dist/esm/exceptions/index.d.ts +14 -0
- package/dist/esm/exceptions/index.js +14 -0
- package/dist/esm/exceptions/infrastructure/event-delivery.exception.d.ts +5 -0
- package/dist/esm/exceptions/infrastructure/event-delivery.exception.js +16 -0
- package/dist/esm/exceptions/infrastructure/infrastructure.exception.d.ts +6 -0
- package/dist/esm/exceptions/infrastructure/infrastructure.exception.js +13 -0
- package/dist/esm/exceptions/infrastructure/internal-error.exception.d.ts +5 -0
- package/dist/esm/exceptions/infrastructure/internal-error.exception.js +13 -0
- package/dist/esm/exceptions/infrastructure/unknown-event.exception.d.ts +4 -0
- package/dist/esm/exceptions/infrastructure/unknown-event.exception.js +15 -0
- package/dist/esm/exceptions/received/received-value.d.ts +4 -0
- package/dist/esm/exceptions/received/received-value.js +9 -0
- package/dist/esm/infrastructure/clock/fixed-clock.d.ts +8 -0
- package/dist/esm/infrastructure/clock/fixed-clock.js +15 -0
- package/dist/esm/infrastructure/clock/system-clock.d.ts +4 -0
- package/dist/esm/infrastructure/clock/system-clock.js +5 -0
- package/dist/esm/infrastructure/event/domain-event-bus.d.ts +16 -0
- package/dist/esm/infrastructure/event/domain-event-bus.js +56 -0
- package/dist/esm/infrastructure/event/event-channel.d.ts +9 -0
- package/dist/esm/infrastructure/event/event-channel.js +1 -0
- package/dist/esm/infrastructure/event/event-registry.d.ts +9 -0
- package/dist/esm/infrastructure/event/event-registry.js +39 -0
- package/dist/esm/infrastructure/event/in-memory/emitter.d.ts +11 -0
- package/dist/esm/infrastructure/event/in-memory/emitter.js +50 -0
- package/dist/esm/infrastructure/event/in-memory/in-memory-event-channel.d.ts +16 -0
- package/dist/esm/infrastructure/event/in-memory/in-memory-event-channel.js +47 -0
- package/dist/esm/infrastructure/http/http-error-mapper.d.ts +23 -0
- package/dist/esm/infrastructure/http/http-error-mapper.js +59 -0
- package/dist/esm/infrastructure/index.d.ts +16 -0
- package/dist/esm/infrastructure/index.js +9 -0
- package/dist/esm/infrastructure/logging/console-logger.d.ts +17 -0
- package/dist/esm/infrastructure/logging/console-logger.js +33 -0
- package/dist/esm/infrastructure/logging/in-memory-logger.d.ts +15 -0
- package/dist/esm/infrastructure/logging/in-memory-logger.js +23 -0
- package/dist/esm/infrastructure/logging/log-serializer.d.ts +7 -0
- package/dist/esm/infrastructure/logging/log-serializer.js +55 -0
- package/dist/esm/infrastructure/logging/silent-logger.d.ts +7 -0
- package/dist/esm/infrastructure/logging/silent-logger.js +14 -0
- package/dist/esm/package.json +3 -0
- package/package.json +106 -4
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export interface EventMetadata {
|
|
2
|
+
eventId?: string;
|
|
3
|
+
occurredOn?: Date | string;
|
|
4
|
+
clock?: {
|
|
5
|
+
now(): Date;
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
export interface SerializedEvent {
|
|
9
|
+
eventName: string;
|
|
10
|
+
eventVersion: number;
|
|
11
|
+
eventId: string;
|
|
12
|
+
aggregateId: string;
|
|
13
|
+
occurredOn: string;
|
|
14
|
+
[payload: string]: unknown;
|
|
15
|
+
}
|
|
16
|
+
export interface EventClass<Event extends EventBase = EventBase> {
|
|
17
|
+
readonly eventName: string;
|
|
18
|
+
readonly eventVersion?: number;
|
|
19
|
+
new (...args: any[]): Event;
|
|
20
|
+
}
|
|
21
|
+
export declare abstract class EventBase {
|
|
22
|
+
readonly eventId: string;
|
|
23
|
+
readonly aggregateId: string;
|
|
24
|
+
readonly occurredOn: Date;
|
|
25
|
+
constructor(aggregateId: string, metadata?: EventMetadata);
|
|
26
|
+
eventName(): string;
|
|
27
|
+
eventVersion(): number;
|
|
28
|
+
toJSON(): SerializedEvent;
|
|
29
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { CreatedAt } from '../type/date-type.js';
|
|
2
|
+
import { IdType } from '../type/id-type.js';
|
|
3
|
+
import { UuidType } from '../type/uuid-type.js';
|
|
4
|
+
import { InternalErrorException, RequiredValueException } from '../../exceptions/index.js';
|
|
5
|
+
export class EventBase {
|
|
6
|
+
constructor(aggregateId, metadata = {}) {
|
|
7
|
+
const { eventName, eventVersion = 1 } = this.constructor;
|
|
8
|
+
if (typeof eventName !== 'string' || eventName.trim() === '') {
|
|
9
|
+
throw new InternalErrorException(`${this.constructor.name} must declare a static eventName`);
|
|
10
|
+
}
|
|
11
|
+
if (!Number.isSafeInteger(eventVersion) || eventVersion < 1) {
|
|
12
|
+
throw new InternalErrorException(`${this.constructor.name}.eventVersion must be a whole number from 1`);
|
|
13
|
+
}
|
|
14
|
+
if (aggregateId === null ||
|
|
15
|
+
aggregateId === undefined ||
|
|
16
|
+
(typeof aggregateId === 'string' && aggregateId.trim() === '')) {
|
|
17
|
+
throw new RequiredValueException(`${this.constructor.name}.aggregateId`, aggregateId);
|
|
18
|
+
}
|
|
19
|
+
this.aggregateId = aggregateId;
|
|
20
|
+
this.eventId = new IdType(metadata.eventId ?? UuidType.random()).value;
|
|
21
|
+
this.occurredOn =
|
|
22
|
+
metadata.occurredOn === undefined
|
|
23
|
+
? CreatedAt.now(metadata.clock).value
|
|
24
|
+
: new CreatedAt(metadata.occurredOn).value;
|
|
25
|
+
}
|
|
26
|
+
eventName() {
|
|
27
|
+
return this.constructor.eventName;
|
|
28
|
+
}
|
|
29
|
+
eventVersion() {
|
|
30
|
+
return this.constructor.eventVersion ?? 1;
|
|
31
|
+
}
|
|
32
|
+
toJSON() {
|
|
33
|
+
const serialized = {
|
|
34
|
+
eventName: this.eventName(),
|
|
35
|
+
eventVersion: this.eventVersion(),
|
|
36
|
+
eventId: this.eventId,
|
|
37
|
+
aggregateId: this.aggregateId,
|
|
38
|
+
occurredOn: this.occurredOn.toISOString(),
|
|
39
|
+
};
|
|
40
|
+
for (const [key, value] of Object.entries(this)) {
|
|
41
|
+
if (!(key in serialized)) {
|
|
42
|
+
serialized[key] = value;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return serialized;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from './event/event-base.js';
|
|
2
|
+
export * from './entity/entity.js';
|
|
3
|
+
export * from './aggregate/aggregate-root.js';
|
|
4
|
+
export * from './type/index.js';
|
|
5
|
+
export * from './primitive/primitive-types.js';
|
|
6
|
+
export type { AggregateFinder } from './repository/aggregate-finder.js';
|
|
7
|
+
export type { AggregateSaver } from './repository/aggregate-saver.js';
|
|
8
|
+
export type { AggregateRemover } from './repository/aggregate-remover.js';
|
|
9
|
+
export { Specification } from './specification/specification.js';
|
|
10
|
+
export type { SatisfiedBy } from './specification/specification.js';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export * from './event/event-base.js';
|
|
2
|
+
export * from './entity/entity.js';
|
|
3
|
+
export * from './aggregate/aggregate-root.js';
|
|
4
|
+
export * from './type/index.js';
|
|
5
|
+
export * from './primitive/primitive-types.js';
|
|
6
|
+
export { Specification } from './specification/specification.js';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { AggregateRoot } from '../aggregate/aggregate-root.js';
|
|
2
|
+
import type { AbstractType } from '../type/abstract-type.js';
|
|
3
|
+
export type Methods<T> = {
|
|
4
|
+
[P in keyof T]-?: T[P] extends Function ? P : never;
|
|
5
|
+
}[keyof T];
|
|
6
|
+
export type MethodsAndProperties<T> = {
|
|
7
|
+
[key in keyof T]: T[key];
|
|
8
|
+
};
|
|
9
|
+
export type Properties<T> = Omit<MethodsAndProperties<T>, Methods<T>>;
|
|
10
|
+
export type MutablePropertiesData<T> = Mutable<Required<Properties<T>>>;
|
|
11
|
+
export type PropertiesData<T> = Required<Properties<T>>;
|
|
12
|
+
type RemoveUnderscore<S extends string> = S extends `_${infer R}` ? R : S;
|
|
13
|
+
type Mutable<T> = {
|
|
14
|
+
-readonly [P in keyof T]: T[P];
|
|
15
|
+
};
|
|
16
|
+
type AggregateBookkeeping<T> = T extends AggregateRoot<any, any> ? 'version' : never;
|
|
17
|
+
export type PrimitiveTypes<T> = {
|
|
18
|
+
[key in keyof Mutable<Properties<T>> as key extends AggregateBookkeeping<T> ? never : RemoveUnderscore<string & key>]: PrimitiveType<T[key]>;
|
|
19
|
+
};
|
|
20
|
+
export type DataTypes<T> = Partial<PrimitiveTypes<T>>;
|
|
21
|
+
export type PrimitiveType<T> = T extends (infer U)[] ? PrimitiveType<U>[] : T extends AbstractType<any> ? T['value'] : T extends null ? null : T extends Date ? never : T extends object ? PrimitiveTypes<T> : never;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface SatisfiedBy<Candidate> {
|
|
2
|
+
isSatisfiedBy(candidate: Candidate): boolean;
|
|
3
|
+
}
|
|
4
|
+
export declare abstract class Specification<Candidate> implements SatisfiedBy<Candidate> {
|
|
5
|
+
abstract isSatisfiedBy(candidate: Candidate): boolean;
|
|
6
|
+
and(other: SatisfiedBy<Candidate>): Specification<Candidate>;
|
|
7
|
+
or(other: SatisfiedBy<Candidate>): Specification<Candidate>;
|
|
8
|
+
not(): Specification<Candidate>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export class Specification {
|
|
2
|
+
and(other) {
|
|
3
|
+
return new BothSpecification(this, other);
|
|
4
|
+
}
|
|
5
|
+
or(other) {
|
|
6
|
+
return new EitherSpecification(this, other);
|
|
7
|
+
}
|
|
8
|
+
not() {
|
|
9
|
+
return new NegatedSpecification(this);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
class BothSpecification extends Specification {
|
|
13
|
+
constructor(left, right) {
|
|
14
|
+
super();
|
|
15
|
+
this.left = left;
|
|
16
|
+
this.right = right;
|
|
17
|
+
}
|
|
18
|
+
isSatisfiedBy(candidate) {
|
|
19
|
+
return this.left.isSatisfiedBy(candidate) && this.right.isSatisfiedBy(candidate);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
class EitherSpecification extends Specification {
|
|
23
|
+
constructor(left, right) {
|
|
24
|
+
super();
|
|
25
|
+
this.left = left;
|
|
26
|
+
this.right = right;
|
|
27
|
+
}
|
|
28
|
+
isSatisfiedBy(candidate) {
|
|
29
|
+
return this.left.isSatisfiedBy(candidate) || this.right.isSatisfiedBy(candidate);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
class NegatedSpecification extends Specification {
|
|
33
|
+
constructor(negated) {
|
|
34
|
+
super();
|
|
35
|
+
this.negated = negated;
|
|
36
|
+
}
|
|
37
|
+
isSatisfiedBy(candidate) {
|
|
38
|
+
return !this.negated.isSatisfiedBy(candidate);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Validatable, ValidationResult } from '@archi-code/validation';
|
|
2
|
+
import type { ValueOf } from './required/required-mark.js';
|
|
3
|
+
import type { ValidationIssue } from '../../exceptions/index.js';
|
|
4
|
+
type JsonValue<T> = T extends Date ? string : T;
|
|
5
|
+
export declare abstract class AbstractType<T, Input = T> implements Validatable<T | null> {
|
|
6
|
+
protected readonly _value: T | null;
|
|
7
|
+
static [Symbol.hasInstance](candidate: unknown): boolean;
|
|
8
|
+
constructor(value?: Input | null);
|
|
9
|
+
get value(): ValueOf<T, this>;
|
|
10
|
+
get isNull(): boolean;
|
|
11
|
+
toString(): string;
|
|
12
|
+
toJSON(): ValueOf<JsonValue<T>, this>;
|
|
13
|
+
equals(other: unknown): boolean;
|
|
14
|
+
validate(): ValidationResult<ValueOf<T, this>>;
|
|
15
|
+
protected brokenRules(value: unknown): ValidationIssue[];
|
|
16
|
+
protected abstract filter(value: unknown): T | null;
|
|
17
|
+
private acceptInput;
|
|
18
|
+
private static isMissingInput;
|
|
19
|
+
}
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
var _a;
|
|
2
|
+
import { anyToString, runValidations } from '@archi-code/validation';
|
|
3
|
+
import { ValueEquality } from './equality/value-equality.js';
|
|
4
|
+
import { RequiredMark } from './required/required-mark.js';
|
|
5
|
+
import { RequiredValueException, ValidationException } from '../../exceptions/index.js';
|
|
6
|
+
const VALUE_OBJECT = Symbol.for('@archi-code/ddd/value-object.v1');
|
|
7
|
+
export class AbstractType {
|
|
8
|
+
static [Symbol.hasInstance](candidate) {
|
|
9
|
+
return (Function.prototype[Symbol.hasInstance].call(this, candidate) ||
|
|
10
|
+
(this === _a &&
|
|
11
|
+
typeof candidate === 'object' &&
|
|
12
|
+
candidate !== null &&
|
|
13
|
+
candidate[VALUE_OBJECT] === true));
|
|
14
|
+
}
|
|
15
|
+
constructor(value = null) {
|
|
16
|
+
this._value = this.acceptInput(value);
|
|
17
|
+
const brokenRules = this.brokenRules(this._value);
|
|
18
|
+
if (brokenRules.length > 0) {
|
|
19
|
+
throw new ValidationException(brokenRules);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
get value() {
|
|
23
|
+
return this._value;
|
|
24
|
+
}
|
|
25
|
+
get isNull() {
|
|
26
|
+
return this._value === null;
|
|
27
|
+
}
|
|
28
|
+
toString() {
|
|
29
|
+
return this.isNull ? '' : anyToString(this._value);
|
|
30
|
+
}
|
|
31
|
+
toJSON() {
|
|
32
|
+
const value = this._value;
|
|
33
|
+
return (value instanceof Date ? value.toISOString() : value);
|
|
34
|
+
}
|
|
35
|
+
equals(other) {
|
|
36
|
+
return (typeof other === 'object' &&
|
|
37
|
+
other !== null &&
|
|
38
|
+
other.constructor === this.constructor &&
|
|
39
|
+
ValueEquality.equals(this._value, other._value));
|
|
40
|
+
}
|
|
41
|
+
validate() {
|
|
42
|
+
return runValidations(this.constructor, this._value);
|
|
43
|
+
}
|
|
44
|
+
brokenRules(value) {
|
|
45
|
+
return runValidations(this.constructor, value).errors.map((error) => ({
|
|
46
|
+
field: null,
|
|
47
|
+
code: 'validator' in error ? error.validator : error.custom,
|
|
48
|
+
message: `${this.constructor.name}: ${error.message}`,
|
|
49
|
+
}));
|
|
50
|
+
}
|
|
51
|
+
acceptInput(value) {
|
|
52
|
+
const accepted = _a.isMissingInput(value) ? null : this.filter(value);
|
|
53
|
+
if (accepted === null && RequiredMark.isMarked(this)) {
|
|
54
|
+
throw new RequiredValueException(this.constructor.name, value);
|
|
55
|
+
}
|
|
56
|
+
return accepted;
|
|
57
|
+
}
|
|
58
|
+
static isMissingInput(value) {
|
|
59
|
+
return (value === null || value === undefined || (typeof value === 'string' && value.trim() === ''));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
_a = AbstractType;
|
|
63
|
+
(() => {
|
|
64
|
+
Object.defineProperty(_a.prototype, VALUE_OBJECT, { value: true });
|
|
65
|
+
})();
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ValidationResult } from '@archi-code/validation';
|
|
2
|
+
import { AbstractType } from './abstract-type.js';
|
|
3
|
+
import type { ValueOf } from './required/required-mark.js';
|
|
4
|
+
type ItemValue<Item extends AbstractType<any>> = Item['value'];
|
|
5
|
+
export declare abstract class ArrayType<Item extends AbstractType<any>> extends AbstractType<ItemValue<Item>[]> {
|
|
6
|
+
protected abstract createItem(value: unknown): Item;
|
|
7
|
+
get items(): Item[];
|
|
8
|
+
toString(): string;
|
|
9
|
+
hasItem(value: ItemValue<Item>): boolean;
|
|
10
|
+
withItem(value: ItemValue<Item>): this;
|
|
11
|
+
withoutItem(value: ItemValue<Item>): this;
|
|
12
|
+
protected filter(value: unknown): ItemValue<Item>[];
|
|
13
|
+
validate(): ValidationResult<ValueOf<ItemValue<Item>[], this>>;
|
|
14
|
+
private copyWith;
|
|
15
|
+
}
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { toArray } from '@archi-code/validation';
|
|
2
|
+
import { AbstractType } from './abstract-type.js';
|
|
3
|
+
import { Immutable } from './immutable/immutable.js';
|
|
4
|
+
import { ValueEquality } from './equality/value-equality.js';
|
|
5
|
+
import { ValueObjects } from './value-objects/value-objects.js';
|
|
6
|
+
import { TypePrimitiveException, ValidationException } from '../../exceptions/index.js';
|
|
7
|
+
export class ArrayType extends AbstractType {
|
|
8
|
+
get items() {
|
|
9
|
+
return (this._value ?? []).map((value) => this.createItem(value));
|
|
10
|
+
}
|
|
11
|
+
toString() {
|
|
12
|
+
return this.items.map((item) => item.toString()).join(', ');
|
|
13
|
+
}
|
|
14
|
+
hasItem(value) {
|
|
15
|
+
const itemValue = this.createItem(value).value;
|
|
16
|
+
return (this._value ?? []).some((current) => ValueEquality.equals(current, itemValue));
|
|
17
|
+
}
|
|
18
|
+
withItem(value) {
|
|
19
|
+
return this.copyWith([...(this._value ?? []), value]);
|
|
20
|
+
}
|
|
21
|
+
withoutItem(value) {
|
|
22
|
+
if (this._value === null) {
|
|
23
|
+
return this;
|
|
24
|
+
}
|
|
25
|
+
const itemValue = this.createItem(value).value;
|
|
26
|
+
return this.copyWith(this._value.filter((current) => !ValueEquality.equals(current, itemValue)));
|
|
27
|
+
}
|
|
28
|
+
filter(value) {
|
|
29
|
+
const converted = toArray(value);
|
|
30
|
+
if (!converted.ok) {
|
|
31
|
+
throw new TypePrimitiveException('Array', value);
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
return Immutable.freeze(ValueObjects.buildList(converted.value, (item) => this.createItem(item).value));
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
if (error instanceof ValidationException) {
|
|
38
|
+
throw new ValidationException([...this.brokenRules(converted.value), ...error.errors]);
|
|
39
|
+
}
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
validate() {
|
|
44
|
+
const own = super.validate();
|
|
45
|
+
const itemErrors = (this._value ?? []).flatMap((itemValue, index) => this.createItem(itemValue)
|
|
46
|
+
.validate()
|
|
47
|
+
.errors.map((error) => Object.freeze({ ...error, message: `Item ${index + 1}: ${error.message}` })));
|
|
48
|
+
if (itemErrors.length === 0) {
|
|
49
|
+
return own;
|
|
50
|
+
}
|
|
51
|
+
return Object.freeze({
|
|
52
|
+
ok: false,
|
|
53
|
+
value: own.value,
|
|
54
|
+
errors: Object.freeze([...own.errors, ...itemErrors]),
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
copyWith(values) {
|
|
58
|
+
const SameType = this.constructor;
|
|
59
|
+
return new SameType(values);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { toBoolean } from '@archi-code/validation';
|
|
2
|
+
import { AbstractType } from './abstract-type.js';
|
|
3
|
+
import { TypePrimitiveException } from '../../exceptions/index.js';
|
|
4
|
+
export class BooleanType extends AbstractType {
|
|
5
|
+
filter(value) {
|
|
6
|
+
const converted = toBoolean(value);
|
|
7
|
+
if (!converted.ok) {
|
|
8
|
+
throw new TypePrimitiveException('Boolean', value);
|
|
9
|
+
}
|
|
10
|
+
return converted.value;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { AbstractType } from '../abstract-type.js';
|
|
2
|
+
export type ValueClass = new (value: any) => AbstractType<any>;
|
|
3
|
+
export interface CompositeClass {
|
|
4
|
+
readonly name: string;
|
|
5
|
+
readonly prototype: object;
|
|
6
|
+
new (props: any): object;
|
|
7
|
+
fromPrimitives(primitives: any): object;
|
|
8
|
+
}
|
|
9
|
+
export type FieldClass = ValueClass | CompositeClass;
|
|
10
|
+
export type FieldSpec = FieldClass | readonly [FieldClass];
|
|
11
|
+
export declare class CompositeField {
|
|
12
|
+
static brand(prototype: object): void;
|
|
13
|
+
static isComposite(value: unknown): boolean;
|
|
14
|
+
static accept(owner: string, field: string, spec: FieldSpec, value: unknown): unknown;
|
|
15
|
+
static fromPrimitive(spec: FieldSpec, primitive: unknown): unknown;
|
|
16
|
+
static equals(left: unknown, right: unknown): boolean;
|
|
17
|
+
static primitive(value: unknown): unknown;
|
|
18
|
+
private static acceptOne;
|
|
19
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { ValueObjects } from '../value-objects/value-objects.js';
|
|
2
|
+
import { RequiredValueException, TypePrimitiveException } from '../../../exceptions/index.js';
|
|
3
|
+
const COMPOSITE = Symbol.for('@archi-code/ddd/composite.v1');
|
|
4
|
+
export class CompositeField {
|
|
5
|
+
static brand(prototype) {
|
|
6
|
+
Object.defineProperty(prototype, COMPOSITE, { value: true });
|
|
7
|
+
}
|
|
8
|
+
static isComposite(value) {
|
|
9
|
+
return (typeof value === 'object' &&
|
|
10
|
+
value !== null &&
|
|
11
|
+
value[COMPOSITE] === true);
|
|
12
|
+
}
|
|
13
|
+
static accept(owner, field, spec, value) {
|
|
14
|
+
if (!Array.isArray(spec)) {
|
|
15
|
+
return CompositeField.acceptOne(owner, field, spec, value);
|
|
16
|
+
}
|
|
17
|
+
if (!Array.isArray(value)) {
|
|
18
|
+
throw new TypePrimitiveException(`list for ${owner}.${field}`, value);
|
|
19
|
+
}
|
|
20
|
+
return Object.freeze(value.map((item, index) => CompositeField.acceptOne(owner, `${field}.${index}`, spec[0], item)));
|
|
21
|
+
}
|
|
22
|
+
static fromPrimitive(spec, primitive) {
|
|
23
|
+
if (Array.isArray(spec)) {
|
|
24
|
+
if (!Array.isArray(primitive)) {
|
|
25
|
+
throw new TypePrimitiveException('Array', primitive);
|
|
26
|
+
}
|
|
27
|
+
return ValueObjects.buildList(primitive, (item) => CompositeField.fromPrimitive(spec[0], item));
|
|
28
|
+
}
|
|
29
|
+
const fieldClass = spec;
|
|
30
|
+
return CompositeField.isComposite(fieldClass.prototype)
|
|
31
|
+
? fieldClass.fromPrimitives(primitive)
|
|
32
|
+
: new fieldClass(primitive);
|
|
33
|
+
}
|
|
34
|
+
static equals(left, right) {
|
|
35
|
+
if (Array.isArray(left)) {
|
|
36
|
+
return (Array.isArray(right) &&
|
|
37
|
+
left.length === right.length &&
|
|
38
|
+
left.every((item, index) => CompositeField.equals(item, right[index])));
|
|
39
|
+
}
|
|
40
|
+
return left.equals(right);
|
|
41
|
+
}
|
|
42
|
+
static primitive(value) {
|
|
43
|
+
if (Array.isArray(value)) {
|
|
44
|
+
return value.map((item) => CompositeField.primitive(item));
|
|
45
|
+
}
|
|
46
|
+
return CompositeField.isComposite(value)
|
|
47
|
+
? value.toPrimitives()
|
|
48
|
+
: value.value;
|
|
49
|
+
}
|
|
50
|
+
static acceptOne(owner, field, fieldClass, value) {
|
|
51
|
+
if (value === null || value === undefined) {
|
|
52
|
+
throw new RequiredValueException(`${owner}.${field}`, value);
|
|
53
|
+
}
|
|
54
|
+
if (!(value instanceof fieldClass)) {
|
|
55
|
+
throw new TypePrimitiveException(`${fieldClass.name} for ${owner}.${field}`, value);
|
|
56
|
+
}
|
|
57
|
+
return value;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { FieldSpec } from './composite-field.js';
|
|
2
|
+
import type { PrimitiveType } from '../../primitive/primitive-types.js';
|
|
3
|
+
export type CompositeSchema = Record<string, FieldSpec>;
|
|
4
|
+
type FieldOf<Spec> = Spec extends readonly [infer Item] ? FieldOf<Item>[] : Spec extends abstract new (...args: any[]) => infer Instance ? Instance : never;
|
|
5
|
+
export type CompositeProps<Schema extends CompositeSchema> = {
|
|
6
|
+
readonly [Field in keyof Schema]: FieldOf<Schema[Field]>;
|
|
7
|
+
};
|
|
8
|
+
export type CompositePrimitives<Schema extends CompositeSchema> = {
|
|
9
|
+
[Field in keyof Schema]: PrimitiveType<FieldOf<Schema[Field]>>;
|
|
10
|
+
};
|
|
11
|
+
type InputOf<Spec> = Spec extends readonly [infer Item] ? InputOf<Item>[] : Spec extends {
|
|
12
|
+
fromPrimitives(this: any, primitives: infer Primitives): unknown;
|
|
13
|
+
} ? Primitives : Spec extends abstract new (value: infer Value) => unknown ? Exclude<Value, undefined> : never;
|
|
14
|
+
export type CompositeInput<Schema extends CompositeSchema> = {
|
|
15
|
+
[Field in keyof Schema]: InputOf<Schema[Field]>;
|
|
16
|
+
};
|
|
17
|
+
export interface CompositeValue<Schema extends CompositeSchema> {
|
|
18
|
+
equals(other: unknown): boolean;
|
|
19
|
+
toPrimitives(): CompositePrimitives<Schema>;
|
|
20
|
+
}
|
|
21
|
+
export interface CompositeType<Schema extends CompositeSchema> {
|
|
22
|
+
new (props: CompositeProps<Schema>): CompositeProps<Schema> & CompositeValue<Schema>;
|
|
23
|
+
fromPrimitives<Composed>(this: new (props: CompositeProps<Schema>) => Composed, primitives: CompositeInput<Schema>): Composed;
|
|
24
|
+
}
|
|
25
|
+
export declare function Composite<Schema extends CompositeSchema>(schema: Schema): CompositeType<Schema>;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { runValidations } from '@archi-code/validation';
|
|
2
|
+
import { CompositeField } from './composite-field.js';
|
|
3
|
+
import { ValueObjects } from '../value-objects/value-objects.js';
|
|
4
|
+
import { TypePrimitiveException, ValidationException } from '../../../exceptions/index.js';
|
|
5
|
+
export function Composite(schema) {
|
|
6
|
+
const fields = Object.keys(schema);
|
|
7
|
+
class CompositeValueObject {
|
|
8
|
+
static fromPrimitives(primitives) {
|
|
9
|
+
if (typeof primitives !== 'object' || primitives === null || Array.isArray(primitives)) {
|
|
10
|
+
throw new TypePrimitiveException(this.name, primitives);
|
|
11
|
+
}
|
|
12
|
+
const record = primitives;
|
|
13
|
+
const props = ValueObjects.build(Object.fromEntries(fields.map((field) => [
|
|
14
|
+
field,
|
|
15
|
+
() => CompositeField.fromPrimitive(schema[field], record[field]),
|
|
16
|
+
])));
|
|
17
|
+
return new this(props);
|
|
18
|
+
}
|
|
19
|
+
constructor(props) {
|
|
20
|
+
const owner = this.constructor.name;
|
|
21
|
+
for (const field of fields) {
|
|
22
|
+
Object.defineProperty(this, field, {
|
|
23
|
+
value: CompositeField.accept(owner, field, schema[field], props?.[field]),
|
|
24
|
+
enumerable: true,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
const brokenRules = runValidations(this.constructor, this).errors;
|
|
28
|
+
if (brokenRules.length > 0) {
|
|
29
|
+
throw new ValidationException(brokenRules.map((error) => ({
|
|
30
|
+
field: null,
|
|
31
|
+
code: 'custom' in error ? error.custom : error.validator,
|
|
32
|
+
message: `${owner}: ${error.message}`,
|
|
33
|
+
})));
|
|
34
|
+
}
|
|
35
|
+
Object.freeze(this);
|
|
36
|
+
}
|
|
37
|
+
equals(other) {
|
|
38
|
+
return (typeof other === 'object' &&
|
|
39
|
+
other !== null &&
|
|
40
|
+
other.constructor === this.constructor &&
|
|
41
|
+
fields.every((field) => CompositeField.equals(this[field], other[field])));
|
|
42
|
+
}
|
|
43
|
+
toPrimitives() {
|
|
44
|
+
return Object.fromEntries(fields.map((field) => [
|
|
45
|
+
field,
|
|
46
|
+
CompositeField.primitive(this[field]),
|
|
47
|
+
]));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
CompositeField.brand(CompositeValueObject.prototype);
|
|
51
|
+
return CompositeValueObject;
|
|
52
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { AbstractType } from './abstract-type.js';
|
|
2
|
+
export declare class DateType extends AbstractType<Date, Date | string> {
|
|
3
|
+
protected filter(value: unknown): Date;
|
|
4
|
+
toString(): string;
|
|
5
|
+
}
|
|
6
|
+
declare const CreatedAt_base: import("./required/required.js").RequiredType<typeof DateType>;
|
|
7
|
+
export declare class CreatedAt extends CreatedAt_base {
|
|
8
|
+
static now(clock?: {
|
|
9
|
+
now(): Date;
|
|
10
|
+
}): CreatedAt;
|
|
11
|
+
}
|
|
12
|
+
declare const UpdatedAt_base: import("./required/required.js").RequiredType<typeof DateType>;
|
|
13
|
+
export declare class UpdatedAt extends UpdatedAt_base {
|
|
14
|
+
static now(clock?: {
|
|
15
|
+
now(): Date;
|
|
16
|
+
}): UpdatedAt;
|
|
17
|
+
}
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { toDate } from '@archi-code/validation';
|
|
2
|
+
import { AbstractType } from './abstract-type.js';
|
|
3
|
+
import { Immutable } from './immutable/immutable.js';
|
|
4
|
+
import { Required } from './required/required.js';
|
|
5
|
+
import { TypePrimitiveException } from '../../exceptions/index.js';
|
|
6
|
+
const TIME_WITHOUT_ZONE = /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:\.\d+)?$/;
|
|
7
|
+
export class DateType extends AbstractType {
|
|
8
|
+
filter(value) {
|
|
9
|
+
const converted = toDate(value, { iso: true });
|
|
10
|
+
if (!converted.ok || (typeof value === 'string' && TIME_WITHOUT_ZONE.test(value))) {
|
|
11
|
+
throw new TypePrimitiveException('Date', value);
|
|
12
|
+
}
|
|
13
|
+
return Immutable.date(converted.value);
|
|
14
|
+
}
|
|
15
|
+
toString() {
|
|
16
|
+
return this._value === null ? '' : this._value.toISOString();
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const SYSTEM_TIME = { now: () => new Date() };
|
|
20
|
+
export class CreatedAt extends Required(DateType) {
|
|
21
|
+
static now(clock = SYSTEM_TIME) {
|
|
22
|
+
return new CreatedAt(clock.now());
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export class UpdatedAt extends Required(DateType) {
|
|
26
|
+
static now(clock = SYSTEM_TIME) {
|
|
27
|
+
return new UpdatedAt(clock.now());
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { AbstractType } from './abstract-type.js';
|
|
2
|
+
export declare abstract class EnumType<T extends string | number> extends AbstractType<T> {
|
|
3
|
+
protected abstract getEnum(): Record<string, string | number>;
|
|
4
|
+
protected filter(value: unknown): T;
|
|
5
|
+
private static matches;
|
|
6
|
+
private options;
|
|
7
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { AbstractType } from './abstract-type.js';
|
|
2
|
+
import { TypePrimitiveException } from '../../exceptions/index.js';
|
|
3
|
+
const NUMERIC_TEXT = /^-?\d+(?:\.\d+)?$/;
|
|
4
|
+
export class EnumType extends AbstractType {
|
|
5
|
+
filter(value) {
|
|
6
|
+
const options = this.options();
|
|
7
|
+
const option = options.find((candidate) => EnumType.matches(candidate, value));
|
|
8
|
+
if (option === undefined) {
|
|
9
|
+
throw new TypePrimitiveException(`Expected one of [${options.join(', ')}]`, value, '');
|
|
10
|
+
}
|
|
11
|
+
return option;
|
|
12
|
+
}
|
|
13
|
+
static matches(option, value) {
|
|
14
|
+
return (option === value ||
|
|
15
|
+
(typeof option === 'number' &&
|
|
16
|
+
typeof value === 'string' &&
|
|
17
|
+
NUMERIC_TEXT.test(value) &&
|
|
18
|
+
Number(value) === option));
|
|
19
|
+
}
|
|
20
|
+
options() {
|
|
21
|
+
const enumObject = this.getEnum();
|
|
22
|
+
return Object.entries(enumObject)
|
|
23
|
+
.filter(([, option]) => typeof enumObject[option] !== 'number')
|
|
24
|
+
.map(([, option]) => option);
|
|
25
|
+
}
|
|
26
|
+
}
|