zibri 2.4.0 → 2.4.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/dist/cjs/application.d.ts.map +1 -1
- package/dist/cjs/application.js +8 -2
- package/dist/cjs/application.js.map +1 -1
- package/dist/cjs/auth/encryption/encryption-key.model.d.ts +5 -1
- package/dist/cjs/auth/encryption/encryption-key.model.d.ts.map +1 -1
- package/dist/cjs/auth/encryption/encryption-key.model.js +9 -1
- package/dist/cjs/auth/encryption/encryption-key.model.js.map +1 -1
- package/dist/cjs/auth/strategies/cookie/cookie-auth.auth-strategy.d.ts.map +1 -1
- package/dist/cjs/auth/strategies/cookie/cookie-auth.auth-strategy.js.map +1 -1
- package/dist/cjs/auth/strategies/jwt/jwt-credentials.model.d.ts +5 -1
- package/dist/cjs/auth/strategies/jwt/jwt-credentials.model.d.ts.map +1 -1
- package/dist/cjs/auth/strategies/jwt/jwt-credentials.model.js +9 -1
- package/dist/cjs/auth/strategies/jwt/jwt-credentials.model.js.map +1 -1
- package/dist/cjs/auth/strategies/jwt/jwt.auth-strategy.d.ts.map +1 -1
- package/dist/cjs/auth/strategies/jwt/jwt.auth-strategy.js +2 -1
- package/dist/cjs/auth/strategies/jwt/jwt.auth-strategy.js.map +1 -1
- package/dist/cjs/backup/backup-resource-entity.model.d.ts +5 -1
- package/dist/cjs/backup/backup-resource-entity.model.d.ts.map +1 -1
- package/dist/cjs/backup/backup-resource-entity.model.js +9 -1
- package/dist/cjs/backup/backup-resource-entity.model.js.map +1 -1
- package/dist/cjs/backup/backup.service.js +2 -2
- package/dist/cjs/backup/backup.service.js.map +1 -1
- package/dist/cjs/caching/cache/base-cache.model.js.map +1 -1
- package/dist/cjs/caching/cache/multi-tier.cache.js.map +1 -1
- package/dist/cjs/caching/cache/read-aside/read-aside.cache.js.map +1 -1
- package/dist/cjs/caching/cache/read-aside/write-around-read-aside.cache.js.map +1 -1
- package/dist/cjs/caching/cache/read-aside/write-behind-read-aside.cache.js.map +1 -1
- package/dist/cjs/caching/cache/read-aside/write-invalidate-read-aside-args-only.cache.js.map +1 -1
- package/dist/cjs/caching/cache/read-aside/write-invalidate-read-aside-with-result.cache.js.map +1 -1
- package/dist/cjs/caching/cache/read-aside/write-through-read-aside.cache.js.map +1 -1
- package/dist/cjs/caching/cache/read-through/read-through.cache.js.map +1 -1
- package/dist/cjs/caching/cache/read-through/write-around-read-through.cache.js.map +1 -1
- package/dist/cjs/caching/cache/read-through/write-behind-read-through.cache.js.map +1 -1
- package/dist/cjs/caching/cache/read-through/write-invalidate-read-through-args-only.cache.js.map +1 -1
- package/dist/cjs/caching/cache/read-through/write-invalidate-read-through-with-result.cache.js.map +1 -1
- package/dist/cjs/caching/cache/read-through/write-through-read-through.cache.js.map +1 -1
- package/dist/cjs/change-sets/change-set-repository.d.ts +5 -3
- package/dist/cjs/change-sets/change-set-repository.d.ts.map +1 -1
- package/dist/cjs/change-sets/change-set-repository.js +16 -16
- package/dist/cjs/change-sets/change-set-repository.js.map +1 -1
- package/dist/cjs/change-sets/models/change-set-entity.model.d.ts +2 -2
- package/dist/cjs/change-sets/models/change-set-entity.model.d.ts.map +1 -1
- package/dist/cjs/change-sets/models/change-set-entity.model.js +29 -1
- package/dist/cjs/change-sets/models/change-set-entity.model.js.map +1 -1
- package/dist/cjs/change-sets/models/change-set.model.js +1 -1
- package/dist/cjs/change-sets/models/change-set.model.js.map +1 -1
- package/dist/cjs/change-sets/models/change.model.d.ts +5 -1
- package/dist/cjs/change-sets/models/change.model.d.ts.map +1 -1
- package/dist/cjs/change-sets/models/change.model.js +9 -1
- package/dist/cjs/change-sets/models/change.model.js.map +1 -1
- package/dist/cjs/change-sets/models/soft-delete-entity.model.d.ts +2 -2
- package/dist/cjs/change-sets/models/soft-delete-entity.model.d.ts.map +1 -1
- package/dist/cjs/change-sets/models/soft-delete-entity.model.js +26 -0
- package/dist/cjs/change-sets/models/soft-delete-entity.model.js.map +1 -1
- package/dist/cjs/change-sets/soft-delete-repository.d.ts +6 -5
- package/dist/cjs/change-sets/soft-delete-repository.d.ts.map +1 -1
- package/dist/cjs/change-sets/soft-delete-repository.js +22 -6
- package/dist/cjs/change-sets/soft-delete-repository.js.map +1 -1
- package/dist/cjs/context/als.utilities.d.ts +3 -3
- package/dist/cjs/context/als.utilities.d.ts.map +1 -1
- package/dist/cjs/context/als.utilities.js.map +1 -1
- package/dist/cjs/context/cache/cache.context.d.ts +27 -0
- package/dist/cjs/context/cache/cache.context.d.ts.map +1 -0
- package/dist/cjs/context/cache/cache.context.js +61 -0
- package/dist/cjs/context/cache/cache.context.js.map +1 -0
- package/dist/cjs/data-source/data-sources/data-source-initialization.error.d.ts +7 -0
- package/dist/cjs/data-source/data-sources/data-source-initialization.error.d.ts.map +1 -0
- package/dist/cjs/data-source/data-sources/data-source-initialization.error.js +14 -0
- package/dist/cjs/data-source/data-sources/data-source-initialization.error.js.map +1 -0
- package/dist/cjs/data-source/data-sources/data-source.interface.d.ts +9 -1
- package/dist/cjs/data-source/data-sources/data-source.interface.d.ts.map +1 -1
- package/dist/cjs/data-source/data-sources/data-source.interface.js.map +1 -1
- package/dist/cjs/data-source/data-sources/postgres-typeorm-data-source.model.d.ts +44 -0
- package/dist/cjs/data-source/data-sources/postgres-typeorm-data-source.model.d.ts.map +1 -0
- package/dist/cjs/data-source/data-sources/postgres-typeorm-data-source.model.js +289 -0
- package/dist/cjs/data-source/data-sources/postgres-typeorm-data-source.model.js.map +1 -0
- package/dist/cjs/data-source/data-sources/sql-data-source.interface.d.ts +32 -0
- package/dist/cjs/data-source/data-sources/sql-data-source.interface.d.ts.map +1 -0
- package/dist/cjs/{entity/models/one-to-one-property-metadata.model.js → data-source/data-sources/sql-data-source.interface.js} +1 -1
- package/dist/cjs/data-source/data-sources/sql-data-source.interface.js.map +1 -0
- package/dist/cjs/data-source/data-sources/typeorm-base-data-source.model.d.ts +156 -0
- package/dist/cjs/data-source/data-sources/typeorm-base-data-source.model.d.ts.map +1 -0
- package/dist/cjs/data-source/data-sources/typeorm-base-data-source.model.js +378 -0
- package/dist/cjs/data-source/data-sources/typeorm-base-data-source.model.js.map +1 -0
- package/dist/cjs/data-source/data-sources/where-converter/postgres-typeorm-where-filter.converter.d.ts +25 -0
- package/dist/cjs/data-source/data-sources/where-converter/postgres-typeorm-where-filter.converter.d.ts.map +1 -0
- package/dist/cjs/data-source/data-sources/where-converter/postgres-typeorm-where-filter.converter.js +353 -0
- package/dist/cjs/data-source/data-sources/where-converter/postgres-typeorm-where-filter.converter.js.map +1 -0
- package/dist/cjs/data-source/data-sources/where-converter/typeorm-where-filter.converter.d.ts +70 -0
- package/dist/cjs/data-source/data-sources/where-converter/typeorm-where-filter.converter.d.ts.map +1 -0
- package/dist/cjs/data-source/data-sources/where-converter/typeorm-where-filter.converter.js +248 -0
- package/dist/cjs/data-source/data-sources/where-converter/typeorm-where-filter.converter.js.map +1 -0
- package/dist/cjs/data-source/models/options/count-options.model.d.ts +2 -7
- package/dist/cjs/data-source/models/options/count-options.model.d.ts.map +1 -1
- package/dist/cjs/data-source/models/options/delete-all-options.model.d.ts +2 -4
- package/dist/cjs/data-source/models/options/delete-all-options.model.d.ts.map +1 -1
- package/dist/cjs/data-source/models/options/find-all-options.model.d.ts +2 -2
- package/dist/cjs/data-source/models/options/find-all-options.model.d.ts.map +1 -1
- package/dist/cjs/data-source/models/options/find-by-id-options.model.d.ts +1 -6
- package/dist/cjs/data-source/models/options/find-by-id-options.model.d.ts.map +1 -1
- package/dist/cjs/data-source/models/options/find-one-options.model.d.ts +2 -11
- package/dist/cjs/data-source/models/options/find-one-options.model.d.ts.map +1 -1
- package/dist/cjs/data-source/models/options/update-all-options.model.d.ts +1 -7
- package/dist/cjs/data-source/models/options/update-all-options.model.d.ts.map +1 -1
- package/dist/cjs/data-source/models/options/update-by-id-options.model.d.ts +1 -7
- package/dist/cjs/data-source/models/options/update-by-id-options.model.d.ts.map +1 -1
- package/dist/cjs/data-source/models/where/array-where-filter.model.d.ts +142 -3
- package/dist/cjs/data-source/models/where/array-where-filter.model.d.ts.map +1 -1
- package/dist/cjs/data-source/models/where/base-where-filter.model.d.ts +18 -1
- package/dist/cjs/data-source/models/where/base-where-filter.model.d.ts.map +1 -1
- package/dist/cjs/data-source/models/where/boolean-where-filter.model.d.ts +4 -2
- package/dist/cjs/data-source/models/where/boolean-where-filter.model.d.ts.map +1 -1
- package/dist/cjs/data-source/models/where/date-where-filter.model.d.ts +8 -15
- package/dist/cjs/data-source/models/where/date-where-filter.model.d.ts.map +1 -1
- package/dist/cjs/data-source/models/where/number-where-filter.model.d.ts +8 -15
- package/dist/cjs/data-source/models/where/number-where-filter.model.d.ts.map +1 -1
- package/dist/cjs/data-source/models/where/object-where-filter.model.d.ts +52 -7
- package/dist/cjs/data-source/models/where/object-where-filter.model.d.ts.map +1 -1
- package/dist/cjs/data-source/models/where/string-where-filter.model.d.ts +8 -15
- package/dist/cjs/data-source/models/where/string-where-filter.model.d.ts.map +1 -1
- package/dist/cjs/data-source/models/where/where-filter-keys.model.d.ts +46 -0
- package/dist/cjs/data-source/models/where/where-filter-keys.model.d.ts.map +1 -0
- package/dist/cjs/data-source/models/where/where-filter-keys.model.js +36 -0
- package/dist/cjs/data-source/models/where/where-filter-keys.model.js.map +1 -0
- package/dist/cjs/data-source/models/where/where-filter.model.d.ts +2 -2
- package/dist/cjs/data-source/models/where/where-filter.model.d.ts.map +1 -1
- package/dist/cjs/data-source/query-failed.error.js +27 -1
- package/dist/cjs/data-source/query-failed.error.js.map +1 -1
- package/dist/cjs/data-source/repository.d.ts +8 -3
- package/dist/cjs/data-source/repository.d.ts.map +1 -1
- package/dist/cjs/data-source/repository.js +42 -16
- package/dist/cjs/data-source/repository.js.map +1 -1
- package/dist/cjs/di/decorators/inject-repository.decorator.d.ts +2 -2
- package/dist/cjs/di/decorators/inject-repository.decorator.d.ts.map +1 -1
- package/dist/cjs/di/decorators/inject-repository.decorator.js.map +1 -1
- package/dist/cjs/di/default/zibri-di-tokens.default.d.ts +2 -2
- package/dist/cjs/di/default/zibri-di-tokens.default.d.ts.map +1 -1
- package/dist/cjs/di/default/zibri-di-tokens.default.js.map +1 -1
- package/dist/cjs/email/email.service.d.ts +2 -2
- package/dist/cjs/email/email.service.d.ts.map +1 -1
- package/dist/cjs/email/email.service.js +4 -6
- package/dist/cjs/email/email.service.js.map +1 -1
- package/dist/cjs/email/models/email.model.js +1 -1
- package/dist/cjs/email/models/email.model.js.map +1 -1
- package/dist/cjs/entity/decorators/entity.decorator.d.ts +28 -1
- package/dist/cjs/entity/decorators/entity.decorator.d.ts.map +1 -1
- package/dist/cjs/entity/decorators/entity.decorator.js +6 -3
- package/dist/cjs/entity/decorators/entity.decorator.js.map +1 -1
- package/dist/cjs/entity/decorators/property.decorator.d.ts +5 -8
- package/dist/cjs/entity/decorators/property.decorator.d.ts.map +1 -1
- package/dist/cjs/entity/decorators/property.decorator.js +34 -20
- package/dist/cjs/entity/decorators/property.decorator.js.map +1 -1
- package/dist/cjs/entity/entity-metadata-missing.error.d.ts +9 -0
- package/dist/cjs/entity/entity-metadata-missing.error.d.ts.map +1 -0
- package/dist/cjs/entity/entity-metadata-missing.error.js +17 -0
- package/dist/cjs/entity/entity-metadata-missing.error.js.map +1 -0
- package/dist/cjs/entity/models/base-relation-metadata.model.d.ts +1 -1
- package/dist/cjs/entity/models/belongs-to-one-property-metadata.model.d.ts +28 -0
- package/dist/cjs/entity/models/belongs-to-one-property-metadata.model.d.ts.map +1 -0
- package/dist/cjs/entity/models/belongs-to-one-property-metadata.model.js +3 -0
- package/dist/cjs/entity/models/belongs-to-one-property-metadata.model.js.map +1 -0
- package/dist/cjs/entity/models/has-one-property-metadata.model.d.ts +18 -0
- package/dist/cjs/entity/models/has-one-property-metadata.model.d.ts.map +1 -0
- package/dist/{esm/entity/models/one-to-one-property-metadata.model.js → cjs/entity/models/has-one-property-metadata.model.js} +1 -1
- package/dist/cjs/entity/models/has-one-property-metadata.model.js.map +1 -0
- package/dist/cjs/entity/models/many-to-many-property-metadata.model.d.ts +3 -3
- package/dist/cjs/entity/models/many-to-many-property-metadata.model.d.ts.map +1 -1
- package/dist/cjs/entity/models/many-to-one-property-metadata.model.d.ts +11 -1
- package/dist/cjs/entity/models/many-to-one-property-metadata.model.d.ts.map +1 -1
- package/dist/cjs/entity/models/relation.enum.d.ts +2 -1
- package/dist/cjs/entity/models/relation.enum.d.ts.map +1 -1
- package/dist/cjs/entity/models/relation.enum.js +2 -1
- package/dist/cjs/entity/models/relation.enum.js.map +1 -1
- package/dist/cjs/entity/partial-class.model.js +1 -1
- package/dist/cjs/entity/partial-class.model.js.map +1 -1
- package/dist/cjs/event/event-cleanup.cron-job.d.ts.map +1 -1
- package/dist/cjs/event/event-cleanup.cron-job.js +4 -6
- package/dist/cjs/event/event-cleanup.cron-job.js.map +1 -1
- package/dist/cjs/event/event-subscriber-run.model.d.ts +6 -8
- package/dist/cjs/event/event-subscriber-run.model.d.ts.map +1 -1
- package/dist/cjs/event/event-subscriber-run.model.js +10 -17
- package/dist/cjs/event/event-subscriber-run.model.js.map +1 -1
- package/dist/cjs/event/event.model.js +1 -1
- package/dist/cjs/event/event.model.js.map +1 -1
- package/dist/cjs/event/event.service.d.ts.map +1 -1
- package/dist/cjs/event/event.service.js +6 -3
- package/dist/cjs/event/event.service.js.map +1 -1
- package/dist/cjs/global/model-registry/default-descriptor.d.ts.map +1 -1
- package/dist/cjs/global/model-registry/default-descriptor.js +2 -1
- package/dist/cjs/global/model-registry/default-descriptor.js.map +1 -1
- package/dist/cjs/global/model-registry/encryption-descriptor.d.ts.map +1 -1
- package/dist/cjs/global/model-registry/encryption-descriptor.js +2 -1
- package/dist/cjs/global/model-registry/encryption-descriptor.js.map +1 -1
- package/dist/cjs/global/model-registry/exclude-descriptor.d.ts.map +1 -1
- package/dist/cjs/global/model-registry/exclude-descriptor.js +2 -1
- package/dist/cjs/global/model-registry/exclude-descriptor.js.map +1 -1
- package/dist/cjs/global/model-registry/hash-descriptor.d.ts.map +1 -1
- package/dist/cjs/global/model-registry/hash-descriptor.js +2 -1
- package/dist/cjs/global/model-registry/hash-descriptor.js.map +1 -1
- package/dist/cjs/index.d.ts +12 -3
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +12 -3
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/logging/log-context.model.d.ts +2 -27
- package/dist/cjs/logging/log-context.model.d.ts.map +1 -1
- package/dist/cjs/logging/log-context.model.js +3 -49
- package/dist/cjs/logging/log-context.model.js.map +1 -1
- package/dist/cjs/open-api/open-api.service.d.ts.map +1 -1
- package/dist/cjs/open-api/open-api.service.js +20 -11
- package/dist/cjs/open-api/open-api.service.js.map +1 -1
- package/dist/cjs/parsing/form-data/form-data.body-parser.d.ts.map +1 -1
- package/dist/cjs/parsing/form-data/form-data.body-parser.js +2 -1
- package/dist/cjs/parsing/form-data/form-data.body-parser.js.map +1 -1
- package/dist/cjs/parsing/functions/parse-boolean.function.d.ts.map +1 -1
- package/dist/cjs/parsing/functions/parse-boolean.function.js.map +1 -1
- package/dist/cjs/parsing/functions/parse-object.function.d.ts.map +1 -1
- package/dist/cjs/parsing/functions/parse-object.function.js +2 -1
- package/dist/cjs/parsing/functions/parse-object.function.js.map +1 -1
- package/dist/cjs/parsing/parser.d.ts.map +1 -1
- package/dist/cjs/parsing/parser.js +2 -1
- package/dist/cjs/parsing/parser.js.map +1 -1
- package/dist/cjs/routing/decorators/body.decorator.js +2 -1
- package/dist/cjs/routing/decorators/body.decorator.js.map +1 -1
- package/dist/cjs/routing/resolve-route-params.function.js +1 -1
- package/dist/cjs/routing/resolve-route-params.function.js.map +1 -1
- package/dist/cjs/routing/router.d.ts.map +1 -1
- package/dist/cjs/routing/router.js +38 -2
- package/dist/cjs/routing/router.js.map +1 -1
- package/dist/cjs/utilities/metadata-injection-keys.enum.d.ts +1 -0
- package/dist/cjs/utilities/metadata-injection-keys.enum.d.ts.map +1 -1
- package/dist/cjs/utilities/metadata-injection-keys.enum.js +1 -0
- package/dist/cjs/utilities/metadata-injection-keys.enum.js.map +1 -1
- package/dist/cjs/utilities/typeorm.utilities.d.ts +39 -0
- package/dist/cjs/utilities/typeorm.utilities.d.ts.map +1 -0
- package/dist/cjs/utilities/typeorm.utilities.js +47 -0
- package/dist/cjs/utilities/typeorm.utilities.js.map +1 -0
- package/dist/cjs/validation/validation-problem.model.d.ts.map +1 -1
- package/dist/cjs/validation/validation-problem.model.js +4 -7
- package/dist/cjs/validation/validation-problem.model.js.map +1 -1
- package/dist/cjs/validation/validation.service.d.ts.map +1 -1
- package/dist/cjs/validation/validation.service.js +6 -4
- package/dist/cjs/validation/validation.service.js.map +1 -1
- package/dist/cjs/websocket/models/websocket-message.model.js +1 -1
- package/dist/cjs/websocket/models/websocket-message.model.js.map +1 -1
- package/dist/cjs/websocket/models/websocket-request.model.d.ts +5 -11
- package/dist/cjs/websocket/models/websocket-request.model.d.ts.map +1 -1
- package/dist/cjs/websocket/models/websocket-request.model.js.map +1 -1
- package/dist/cjs/websocket/services/websocket.service.d.ts.map +1 -1
- package/dist/cjs/websocket/services/websocket.service.js +1 -2
- package/dist/cjs/websocket/services/websocket.service.js.map +1 -1
- package/dist/esm/application.js +8 -2
- package/dist/esm/application.js.map +1 -1
- package/dist/esm/auth/encryption/encryption-key.model.js +9 -1
- package/dist/esm/auth/encryption/encryption-key.model.js.map +1 -1
- package/dist/esm/auth/strategies/cookie/cookie-auth.auth-strategy.js.map +1 -1
- package/dist/esm/auth/strategies/jwt/jwt-credentials.model.js +9 -1
- package/dist/esm/auth/strategies/jwt/jwt-credentials.model.js.map +1 -1
- package/dist/esm/auth/strategies/jwt/jwt.auth-strategy.js +2 -1
- package/dist/esm/auth/strategies/jwt/jwt.auth-strategy.js.map +1 -1
- package/dist/esm/backup/backup-resource-entity.model.js +9 -1
- package/dist/esm/backup/backup-resource-entity.model.js.map +1 -1
- package/dist/esm/backup/backup.service.js +2 -2
- package/dist/esm/backup/backup.service.js.map +1 -1
- package/dist/esm/caching/cache/base-cache.model.js.map +1 -1
- package/dist/esm/caching/cache/multi-tier.cache.js.map +1 -1
- package/dist/esm/caching/cache/read-aside/read-aside.cache.js.map +1 -1
- package/dist/esm/caching/cache/read-aside/write-around-read-aside.cache.js.map +1 -1
- package/dist/esm/caching/cache/read-aside/write-behind-read-aside.cache.js.map +1 -1
- package/dist/esm/caching/cache/read-aside/write-invalidate-read-aside-args-only.cache.js.map +1 -1
- package/dist/esm/caching/cache/read-aside/write-invalidate-read-aside-with-result.cache.js.map +1 -1
- package/dist/esm/caching/cache/read-aside/write-through-read-aside.cache.js.map +1 -1
- package/dist/esm/caching/cache/read-through/read-through.cache.js.map +1 -1
- package/dist/esm/caching/cache/read-through/write-around-read-through.cache.js.map +1 -1
- package/dist/esm/caching/cache/read-through/write-behind-read-through.cache.js.map +1 -1
- package/dist/esm/caching/cache/read-through/write-invalidate-read-through-args-only.cache.js.map +1 -1
- package/dist/esm/caching/cache/read-through/write-invalidate-read-through-with-result.cache.js.map +1 -1
- package/dist/esm/caching/cache/read-through/write-through-read-through.cache.js.map +1 -1
- package/dist/esm/change-sets/change-set-repository.js +16 -16
- package/dist/esm/change-sets/change-set-repository.js.map +1 -1
- package/dist/esm/change-sets/models/change-set-entity.model.js +29 -1
- package/dist/esm/change-sets/models/change-set-entity.model.js.map +1 -1
- package/dist/esm/change-sets/models/change-set.model.js +1 -1
- package/dist/esm/change-sets/models/change-set.model.js.map +1 -1
- package/dist/esm/change-sets/models/change.model.js +9 -1
- package/dist/esm/change-sets/models/change.model.js.map +1 -1
- package/dist/esm/change-sets/models/soft-delete-entity.model.js +26 -0
- package/dist/esm/change-sets/models/soft-delete-entity.model.js.map +1 -1
- package/dist/esm/change-sets/soft-delete-repository.js +22 -6
- package/dist/esm/change-sets/soft-delete-repository.js.map +1 -1
- package/dist/esm/context/als.utilities.js.map +1 -1
- package/dist/esm/context/cache/cache.context.js +61 -0
- package/dist/esm/context/cache/cache.context.js.map +1 -0
- package/dist/esm/data-source/data-sources/data-source-initialization.error.js +14 -0
- package/dist/esm/data-source/data-sources/data-source-initialization.error.js.map +1 -0
- package/dist/esm/data-source/data-sources/data-source.interface.js.map +1 -1
- package/dist/esm/data-source/data-sources/postgres-typeorm-data-source.model.js +289 -0
- package/dist/esm/data-source/data-sources/postgres-typeorm-data-source.model.js.map +1 -0
- package/dist/esm/data-source/data-sources/sql-data-source.interface.js +3 -0
- package/dist/esm/data-source/data-sources/sql-data-source.interface.js.map +1 -0
- package/dist/esm/data-source/data-sources/typeorm-base-data-source.model.js +378 -0
- package/dist/esm/data-source/data-sources/typeorm-base-data-source.model.js.map +1 -0
- package/dist/esm/data-source/data-sources/where-converter/postgres-typeorm-where-filter.converter.js +353 -0
- package/dist/esm/data-source/data-sources/where-converter/postgres-typeorm-where-filter.converter.js.map +1 -0
- package/dist/esm/data-source/data-sources/where-converter/typeorm-where-filter.converter.js +248 -0
- package/dist/esm/data-source/data-sources/where-converter/typeorm-where-filter.converter.js.map +1 -0
- package/dist/esm/data-source/models/where/where-filter-keys.model.js +36 -0
- package/dist/esm/data-source/models/where/where-filter-keys.model.js.map +1 -0
- package/dist/esm/data-source/query-failed.error.js +27 -1
- package/dist/esm/data-source/query-failed.error.js.map +1 -1
- package/dist/esm/data-source/repository.js +42 -16
- package/dist/esm/data-source/repository.js.map +1 -1
- package/dist/esm/di/decorators/inject-repository.decorator.js.map +1 -1
- package/dist/esm/di/default/zibri-di-tokens.default.js.map +1 -1
- package/dist/esm/email/email.service.js +4 -6
- package/dist/esm/email/email.service.js.map +1 -1
- package/dist/esm/email/models/email.model.js +1 -1
- package/dist/esm/email/models/email.model.js.map +1 -1
- package/dist/esm/entity/decorators/entity.decorator.js +6 -3
- package/dist/esm/entity/decorators/entity.decorator.js.map +1 -1
- package/dist/esm/entity/decorators/property.decorator.js +34 -20
- package/dist/esm/entity/decorators/property.decorator.js.map +1 -1
- package/dist/esm/entity/entity-metadata-missing.error.js +17 -0
- package/dist/esm/entity/entity-metadata-missing.error.js.map +1 -0
- package/dist/esm/entity/models/belongs-to-one-property-metadata.model.js +3 -0
- package/dist/esm/entity/models/belongs-to-one-property-metadata.model.js.map +1 -0
- package/dist/esm/entity/models/has-one-property-metadata.model.js +3 -0
- package/dist/esm/entity/models/has-one-property-metadata.model.js.map +1 -0
- package/dist/esm/entity/models/relation.enum.js +2 -1
- package/dist/esm/entity/models/relation.enum.js.map +1 -1
- package/dist/esm/entity/partial-class.model.js +1 -1
- package/dist/esm/entity/partial-class.model.js.map +1 -1
- package/dist/esm/event/event-cleanup.cron-job.js +4 -6
- package/dist/esm/event/event-cleanup.cron-job.js.map +1 -1
- package/dist/esm/event/event-subscriber-run.model.js +10 -17
- package/dist/esm/event/event-subscriber-run.model.js.map +1 -1
- package/dist/esm/event/event.model.js +1 -1
- package/dist/esm/event/event.model.js.map +1 -1
- package/dist/esm/event/event.service.js +6 -3
- package/dist/esm/event/event.service.js.map +1 -1
- package/dist/esm/global/model-registry/default-descriptor.js +2 -1
- package/dist/esm/global/model-registry/default-descriptor.js.map +1 -1
- package/dist/esm/global/model-registry/encryption-descriptor.js +2 -1
- package/dist/esm/global/model-registry/encryption-descriptor.js.map +1 -1
- package/dist/esm/global/model-registry/exclude-descriptor.js +2 -1
- package/dist/esm/global/model-registry/exclude-descriptor.js.map +1 -1
- package/dist/esm/global/model-registry/hash-descriptor.js +2 -1
- package/dist/esm/global/model-registry/hash-descriptor.js.map +1 -1
- package/dist/esm/index.js +12 -3
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/logging/log-context.model.js +3 -49
- package/dist/esm/logging/log-context.model.js.map +1 -1
- package/dist/esm/open-api/open-api.service.js +20 -11
- package/dist/esm/open-api/open-api.service.js.map +1 -1
- package/dist/esm/parsing/form-data/form-data.body-parser.js +2 -1
- package/dist/esm/parsing/form-data/form-data.body-parser.js.map +1 -1
- package/dist/esm/parsing/functions/parse-boolean.function.js.map +1 -1
- package/dist/esm/parsing/functions/parse-object.function.js +2 -1
- package/dist/esm/parsing/functions/parse-object.function.js.map +1 -1
- package/dist/esm/parsing/parser.js +2 -1
- package/dist/esm/parsing/parser.js.map +1 -1
- package/dist/esm/routing/decorators/body.decorator.js +2 -1
- package/dist/esm/routing/decorators/body.decorator.js.map +1 -1
- package/dist/esm/routing/resolve-route-params.function.js +1 -1
- package/dist/esm/routing/resolve-route-params.function.js.map +1 -1
- package/dist/esm/routing/router.js +38 -2
- package/dist/esm/routing/router.js.map +1 -1
- package/dist/esm/utilities/metadata-injection-keys.enum.js +1 -0
- package/dist/esm/utilities/metadata-injection-keys.enum.js.map +1 -1
- package/dist/esm/utilities/typeorm.utilities.js +47 -0
- package/dist/esm/utilities/typeorm.utilities.js.map +1 -0
- package/dist/esm/validation/validation-problem.model.js +4 -7
- package/dist/esm/validation/validation-problem.model.js.map +1 -1
- package/dist/esm/validation/validation.service.js +6 -4
- package/dist/esm/validation/validation.service.js.map +1 -1
- package/dist/esm/websocket/models/websocket-message.model.js +1 -1
- package/dist/esm/websocket/models/websocket-message.model.js.map +1 -1
- package/dist/esm/websocket/models/websocket-request.model.js.map +1 -1
- package/dist/esm/websocket/services/websocket.service.js +1 -2
- package/dist/esm/websocket/services/websocket.service.js.map +1 -1
- package/package.json +9 -9
- package/src/__testing__/mocks/entities/child.entity.ts +4 -1
- package/src/__testing__/mocks/entities/company.entity.ts +5 -2
- package/src/__testing__/mocks/entities/profile.entity.ts +5 -2
- package/src/__testing__/mocks/entities/role.entity.ts +1 -1
- package/src/__testing__/mocks/entities/user.entity.ts +1 -1
- package/src/__testing__/test-server/create-test-data-source.function.ts +5 -5
- package/src/__testing__/test-server/start-test-server.function.ts +8 -6
- package/src/__testing__/test-server/user-repository.ts +4 -3
- package/src/application.ts +8 -2
- package/src/auth/2fa/two-factor.service.test.ts +151 -0
- package/src/auth/auth.service.test.ts +381 -0
- package/src/auth/encryption/encryption-key.model.ts +7 -2
- package/src/auth/strategies/cookie/cookie-auth.auth-strategy.ts +3 -2
- package/src/auth/strategies/jwt/jwt-credentials.model.ts +7 -1
- package/src/auth/strategies/jwt/jwt.auth-strategy.ts +5 -3
- package/src/backup/backup-resource-entity.model.ts +7 -2
- package/src/backup/backup-service.test.ts +1 -1
- package/src/backup/backup.service.ts +1 -1
- package/src/caching/cache/base-cache.model.ts +3 -3
- package/src/caching/cache/multi-tier.cache.ts +3 -3
- package/src/caching/cache/read-aside/read-aside.cache.ts +2 -2
- package/src/caching/cache/read-aside/write-around-read-aside.cache.ts +2 -2
- package/src/caching/cache/read-aside/write-behind-read-aside.cache.ts +2 -2
- package/src/caching/cache/read-aside/write-invalidate-read-aside-args-only.cache.ts +2 -2
- package/src/caching/cache/read-aside/write-invalidate-read-aside-with-result.cache.ts +2 -2
- package/src/caching/cache/read-aside/write-through-read-aside.cache.ts +2 -2
- package/src/caching/cache/read-through/read-through.cache.ts +2 -2
- package/src/caching/cache/read-through/write-around-read-through.cache.ts +2 -2
- package/src/caching/cache/read-through/write-behind-read-through.cache.ts +2 -2
- package/src/caching/cache/read-through/write-invalidate-read-through-args-only.cache.ts +2 -2
- package/src/caching/cache/read-through/write-invalidate-read-through-with-result.cache.ts +2 -2
- package/src/caching/cache/read-through/write-through-read-through.cache.ts +2 -2
- package/src/change-sets/change-set-repository.test.ts +317 -0
- package/src/change-sets/change-set-repository.ts +17 -17
- package/src/change-sets/models/change-set-entity.model.ts +6 -4
- package/src/change-sets/models/change-set.model.ts +1 -1
- package/src/change-sets/models/change.model.ts +7 -2
- package/src/change-sets/models/soft-delete-entity.model.ts +5 -3
- package/src/change-sets/soft-delete-repository.test.ts +326 -0
- package/src/change-sets/soft-delete-repository.ts +29 -10
- package/src/context/als.utilities.ts +5 -5
- package/src/context/cache/cache.context.ts +33 -0
- package/src/cron/cron.test.ts +421 -0
- package/src/data-source/array-where-filter.test.ts +332 -0
- package/src/data-source/data-sources/data-source-initialization.error.ts +9 -0
- package/src/data-source/data-sources/data-source.interface.ts +14 -1
- package/src/data-source/data-sources/postgres-typeorm-data-source.model.ts +330 -0
- package/src/data-source/data-sources/sql-data-source.interface.ts +35 -0
- package/src/data-source/data-sources/typeorm-base-data-source.model.ts +544 -0
- package/src/data-source/data-sources/where-converter/postgres-typeorm-where-filter.converter.ts +451 -0
- package/src/data-source/data-sources/where-converter/typeorm-where-filter.converter.ts +376 -0
- package/src/data-source/exclude-property.test.ts +4 -1
- package/src/data-source/hooks/hooks.test.ts +268 -0
- package/src/data-source/migration/migration.test.ts +4 -3
- package/src/data-source/models/options/count-options.model.ts +2 -7
- package/src/data-source/models/options/delete-all-options.model.ts +2 -4
- package/src/data-source/models/options/find-all-options.model.ts +2 -2
- package/src/data-source/models/options/find-by-id-options.model.ts +1 -6
- package/src/data-source/models/options/find-one-options.model.ts +2 -11
- package/src/data-source/models/options/update-all-options.model.ts +2 -5
- package/src/data-source/models/options/update-by-id-options.model.ts +2 -5
- package/src/data-source/models/where/array-where-filter.model.ts +147 -5
- package/src/data-source/models/where/base-where-filter.model.ts +19 -1
- package/src/data-source/models/where/boolean-where-filter.model.ts +7 -2
- package/src/data-source/models/where/date-where-filter.model.ts +9 -16
- package/src/data-source/models/where/number-where-filter.model.ts +9 -16
- package/src/data-source/models/where/object-where-filter.model.ts +66 -7
- package/src/data-source/models/where/string-where-filter.model.ts +9 -16
- package/src/data-source/models/where/where-filter-keys.model.ts +88 -0
- package/src/data-source/models/where/where-filter-to-find-options-where-function.test.ts +35 -13
- package/src/data-source/models/where/where-filter.model.ts +7 -4
- package/src/data-source/nested-where-filter.test.ts +344 -0
- package/src/data-source/query-failed.error.ts +38 -1
- package/src/data-source/repository-relation-pitfalls.test.ts +232 -0
- package/src/data-source/repository.test.ts +274 -37
- package/src/data-source/repository.ts +50 -16
- package/src/data-source/transaction/transaction.test.ts +1 -1
- package/src/data-source/where-filter.test.ts +479 -0
- package/src/di/decorators/inject-repository.decorator.ts +3 -2
- package/src/di/default/zibri-di-tokens.default.ts +2 -2
- package/src/email/email.service.test.ts +382 -0
- package/src/email/email.service.ts +4 -5
- package/src/email/models/email.model.ts +1 -1
- package/src/entity/decorators/entity.decorator.ts +44 -5
- package/src/entity/decorators/property.decorator.ts +54 -36
- package/src/entity/entity-metadata-missing.error.ts +15 -0
- package/src/entity/models/base-relation-metadata.model.ts +1 -1
- package/src/entity/models/belongs-to-one-property-metadata.model.ts +34 -0
- package/src/entity/models/has-one-property-metadata.model.ts +20 -0
- package/src/entity/models/many-to-many-property-metadata.model.ts +3 -3
- package/src/entity/models/many-to-one-property-metadata.model.ts +17 -3
- package/src/entity/models/relation.enum.ts +2 -1
- package/src/entity/partial-class.model.ts +1 -1
- package/src/event/event-cleanup.cron-job.ts +4 -6
- package/src/event/event-subscriber-run.model.ts +8 -9
- package/src/event/event.model.ts +1 -1
- package/src/event/event.service.ts +6 -3
- package/src/global/model-registry/default-descriptor.ts +2 -1
- package/src/global/model-registry/encryption-descriptor.ts +2 -1
- package/src/global/model-registry/exclude-descriptor.ts +2 -1
- package/src/global/model-registry/hash-descriptor.ts +2 -1
- package/src/index.ts +15 -3
- package/src/logging/log-context.model.ts +3 -34
- package/src/open-api/open-api.service.ts +32 -13
- package/src/parsing/form-data/form-data.body-parser.ts +2 -1
- package/src/parsing/functions/parse-boolean.function.ts +0 -1
- package/src/parsing/functions/parse-object.function.ts +2 -1
- package/src/parsing/parser.ts +2 -1
- package/src/routing/decorators/body.decorator.ts +2 -1
- package/src/routing/resolve-route-params.function.ts +1 -1
- package/src/routing/router.ts +41 -7
- package/src/utilities/metadata-injection-keys.enum.ts +1 -0
- package/src/utilities/typeorm.utilities.ts +75 -0
- package/src/validation/validation-problem.model.ts +7 -9
- package/src/validation/validation.service.ts +6 -4
- package/src/websocket/models/websocket-message.model.ts +1 -1
- package/src/websocket/models/websocket-request.model.ts +17 -9
- package/src/websocket/services/websocket.service.ts +1 -2
- package/dist/cjs/data-source/data-sources/postgres-data-source.model.d.ts +0 -129
- package/dist/cjs/data-source/data-sources/postgres-data-source.model.d.ts.map +0 -1
- package/dist/cjs/data-source/data-sources/postgres-data-source.model.js +0 -534
- package/dist/cjs/data-source/data-sources/postgres-data-source.model.js.map +0 -1
- package/dist/cjs/data-source/models/where/where-filter-to-find-options-where.function.d.ts +0 -11
- package/dist/cjs/data-source/models/where/where-filter-to-find-options-where.function.d.ts.map +0 -1
- package/dist/cjs/data-source/models/where/where-filter-to-find-options-where.function.js +0 -229
- package/dist/cjs/data-source/models/where/where-filter-to-find-options-where.function.js.map +0 -1
- package/dist/cjs/entity/models/one-to-one-property-metadata.model.d.ts +0 -30
- package/dist/cjs/entity/models/one-to-one-property-metadata.model.d.ts.map +0 -1
- package/dist/cjs/entity/models/one-to-one-property-metadata.model.js.map +0 -1
- package/dist/esm/data-source/data-sources/postgres-data-source.model.js +0 -534
- package/dist/esm/data-source/data-sources/postgres-data-source.model.js.map +0 -1
- package/dist/esm/data-source/models/where/where-filter-to-find-options-where.function.js +0 -229
- package/dist/esm/data-source/models/where/where-filter-to-find-options-where.function.js.map +0 -1
- package/dist/esm/entity/models/one-to-one-property-metadata.model.js.map +0 -1
- package/src/data-source/data-sources/postgres-data-source.model.ts +0 -675
- package/src/data-source/models/where/where-filter-to-find-options-where.function.ts +0 -307
- package/src/entity/models/one-to-one-property-metadata.model.ts +0 -35
|
@@ -8,6 +8,7 @@ import { ChangeSetType } from './models/change-set-type.enum';
|
|
|
8
8
|
import { ChangeSet, CreateChangeSetData } from './models/change-set.model';
|
|
9
9
|
import { NewChange } from './models/change.model';
|
|
10
10
|
import { BaseUser } from '../auth/models/base-user.model';
|
|
11
|
+
import { AlsUtilities } from '../context/als.utilities';
|
|
11
12
|
import { HttpRequestContext } from '../context/request/http-request.context';
|
|
12
13
|
import { WebsocketRequestContext } from '../context/request/websocket-request.context';
|
|
13
14
|
import { DataSourceInterface } from '../data-source/data-sources/data-source.interface';
|
|
@@ -20,9 +21,6 @@ import { UpdateAllOptions } from '../data-source/models/options/update-all-optio
|
|
|
20
21
|
import { UpdateByIdOptions } from '../data-source/models/options/update-by-id-options.model';
|
|
21
22
|
import { Where } from '../data-source/models/where/where-filter.model';
|
|
22
23
|
import { Repository } from '../data-source/repository';
|
|
23
|
-
import { repositoryTokenFor } from '../di/decorators/inject-repository.decorator';
|
|
24
|
-
import { ZIBRI_DI_TOKENS } from '../di/default/zibri-di-tokens.default';
|
|
25
|
-
import { inject } from '../di/inject.function';
|
|
26
24
|
import { PropertyMetadata } from '../entity/decorators/property.decorator';
|
|
27
25
|
import { BadRequestError } from '../error-handling/errors/bad-request.error';
|
|
28
26
|
import { removeExcludeProperties } from '../global/model-registry/remove-exclude-properties.function';
|
|
@@ -64,22 +62,19 @@ export class ChangeSetRepository<
|
|
|
64
62
|
*/
|
|
65
63
|
protected readonly keysToExcludeFromChangeSets: Set<keyof T> = new Set();
|
|
66
64
|
|
|
67
|
-
private readonly changeSetRepository: Repository<ChangeSet, CreateChangeSetData>;
|
|
68
|
-
private readonly authService: AuthServiceInterface;
|
|
69
|
-
|
|
70
65
|
constructor(
|
|
71
66
|
entityClass: Newable<T>,
|
|
72
67
|
repo: TORepository<T> | Repository<T>,
|
|
73
68
|
logger: LoggerInterface,
|
|
74
69
|
dataSource: DataSourceInterface,
|
|
75
70
|
beforeSave: BeforeSaveHook<T, CreateData, UpdateData>,
|
|
76
|
-
beforeReturn: BeforeReturnHook<T
|
|
71
|
+
beforeReturn: BeforeReturnHook<T>,
|
|
72
|
+
private readonly authService: AuthServiceInterface,
|
|
73
|
+
private readonly changeSetRepository: Repository<ChangeSet, CreateChangeSetData>
|
|
74
|
+
|
|
77
75
|
) {
|
|
78
76
|
super(entityClass, repo, logger, dataSource, beforeSave, beforeReturn);
|
|
79
77
|
|
|
80
|
-
this.authService = inject(ZIBRI_DI_TOKENS.AUTH_SERVICE);
|
|
81
|
-
this.changeSetRepository = inject(repositoryTokenFor(ChangeSet));
|
|
82
|
-
|
|
83
78
|
this.keysToExcludeFromChangeSets.add('changeSets');
|
|
84
79
|
const props: Record<string, PropertyMetadata> = MetadataUtilities.getModelProperties(entityClass);
|
|
85
80
|
for (const [key, m] of ObjectUtilities.entries(props)) {
|
|
@@ -102,14 +97,16 @@ export class ChangeSetRepository<
|
|
|
102
97
|
}
|
|
103
98
|
|
|
104
99
|
override async updateById(id: T['id'], data: UpdateData, options?: UpdateByIdOptions): Promise<T> {
|
|
100
|
+
const original: T = await this.findById(id, options);
|
|
105
101
|
const res: T = await super.updateById(id, data, options);
|
|
106
|
-
await this.createChangeSet(
|
|
102
|
+
await this.createChangeSet(original, data, ChangeSetType.UPDATE, options);
|
|
107
103
|
return res;
|
|
108
104
|
}
|
|
109
105
|
|
|
110
106
|
override async updateAll(where: Where<T>, data: UpdateData, options?: UpdateAllOptions): Promise<T[]> {
|
|
107
|
+
const original: T[] = await this.findAll({ where, ...options });
|
|
111
108
|
const res: T[] = await super.updateAll(where, data, options);
|
|
112
|
-
await this.createAllChangeSets(
|
|
109
|
+
await this.createAllChangeSets(original, original.map(() => data), ChangeSetType.UPDATE, options);
|
|
113
110
|
return res;
|
|
114
111
|
}
|
|
115
112
|
|
|
@@ -275,8 +272,7 @@ export class ChangeSetRepository<
|
|
|
275
272
|
): Promise<T> {
|
|
276
273
|
const changeSets: ChangeSet[] = await this.changeSetRepository.findAll({
|
|
277
274
|
where: { changeSetEntityId: entity.id, createdAt: { greaterThan: timestampInNs } },
|
|
278
|
-
relations: ['changes']
|
|
279
|
-
order: { createdAt: 'ASC' }
|
|
275
|
+
relations: ['changes']
|
|
280
276
|
});
|
|
281
277
|
let data: DeepPartial<T> = {} as DeepPartial<T>;
|
|
282
278
|
for (const changeSet of changeSets) {
|
|
@@ -455,9 +451,9 @@ export class ChangeSetRepository<
|
|
|
455
451
|
* @returns The id of the currently logged in user or undefined if that didn't work.
|
|
456
452
|
*/
|
|
457
453
|
protected async getCreatedBy(): Promise<string | undefined> {
|
|
458
|
-
const context: HttpRequestContext | WebsocketRequestContext | undefined =
|
|
454
|
+
const context: HttpRequestContext | WebsocketRequestContext | undefined = AlsUtilities.getCurrentRequestContext();
|
|
459
455
|
if (!context) {
|
|
460
|
-
|
|
456
|
+
return undefined;
|
|
461
457
|
}
|
|
462
458
|
const user: BaseUser<string> | undefined = await this.authService.getCurrentUser(
|
|
463
459
|
context,
|
|
@@ -477,7 +473,11 @@ export class ChangeSetRepository<
|
|
|
477
473
|
): (keyof (CreateData | UpdateData | DeepPartial<T>))[] {
|
|
478
474
|
const keys: (keyof (CreateData | UpdateData | DeepPartial<T>))[] = [];
|
|
479
475
|
for (const key in data) {
|
|
480
|
-
if (
|
|
476
|
+
if (
|
|
477
|
+
!this.keysToExcludeFromChangeSets.has(key as keyof T)
|
|
478
|
+
// we need to use triple equals here, setting a value to null is valid and should be tracked
|
|
479
|
+
&& data[key as keyof (CreateData | UpdateData | DeepPartial<T>)] !== undefined
|
|
480
|
+
) {
|
|
481
481
|
keys.push(key as keyof (CreateData | UpdateData | DeepPartial<T>));
|
|
482
482
|
}
|
|
483
483
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ChangeSet } from './change-set.model';
|
|
2
2
|
import { BaseEntity } from '../../entity/base-entity.model';
|
|
3
|
+
import { Property } from '../../entity/decorators/property.decorator';
|
|
3
4
|
import { Newable } from '../../types/newable.type';
|
|
4
5
|
import { MetadataUtilities } from '../../utilities/metadata.utilities';
|
|
5
6
|
|
|
@@ -7,12 +8,13 @@ import { MetadataUtilities } from '../../utilities/metadata.utilities';
|
|
|
7
8
|
* An entity that can be handled by the ChangeSetRepository.
|
|
8
9
|
* Has an uuid id and a relation to all its changeSets.
|
|
9
10
|
*/
|
|
10
|
-
export
|
|
11
|
+
export class ChangeSetEntity extends BaseEntity {
|
|
11
12
|
/**
|
|
12
13
|
* The change sets of the entity.
|
|
13
14
|
*/
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
@Property.oneToMany({ target: () => ChangeSet, inverseSide: 'changeSetEntityId' })
|
|
16
|
+
changeSets!: ChangeSet[];
|
|
17
|
+
}
|
|
16
18
|
|
|
17
19
|
/**
|
|
18
20
|
* Checks whether the given class is a ChangeSetEntity class.
|
|
@@ -20,5 +22,5 @@ export type ChangeSetEntity = BaseEntity & {
|
|
|
20
22
|
* @returns True if it has a changeSets property of type array.
|
|
21
23
|
*/
|
|
22
24
|
export function isChangeSetEntityNewable(cls: Newable<unknown>): cls is Newable<ChangeSetEntity> {
|
|
23
|
-
return MetadataUtilities.getModelProperties(cls)['changeSets']
|
|
25
|
+
return MetadataUtilities.getModelProperties(cls)['changeSets'] !== undefined;
|
|
24
26
|
}
|
|
@@ -10,7 +10,7 @@ import { OmitStrict } from '../../types/omit-strict.type';
|
|
|
10
10
|
* A single change set.
|
|
11
11
|
* Gets automatically created for configured entities whenever they are changed.
|
|
12
12
|
*/
|
|
13
|
-
@Entity()
|
|
13
|
+
@Entity({ defaultOrder: { createdAt: 'ASC' }, defaultRelations: { changes: true } })
|
|
14
14
|
export class ChangeSet extends BaseEntity {
|
|
15
15
|
/**
|
|
16
16
|
* Whether this change set was initialized on creating, updating or deleting the entity.
|
|
@@ -27,8 +27,13 @@ export class Change<T = unknown> extends BaseEntity {
|
|
|
27
27
|
/**
|
|
28
28
|
* The change set that this change belongs to.
|
|
29
29
|
*/
|
|
30
|
-
@Property.manyToOne({ target: () => ChangeSet, inverseSide: 'changes' })
|
|
30
|
+
@Property.manyToOne({ target: () => ChangeSet, inverseSide: 'changes', joinColumn: 'changeSetId' })
|
|
31
31
|
changeSet!: ChangeSet;
|
|
32
|
+
/**
|
|
33
|
+
* The id of the change set that this change belongs to.
|
|
34
|
+
*/
|
|
35
|
+
@Property.string({ format: 'uuid' })
|
|
36
|
+
changeSetId!: string;
|
|
32
37
|
}
|
|
33
38
|
|
|
34
39
|
/**
|
|
@@ -39,4 +44,4 @@ export type CreateChangeData = OmitStrict<Change, 'id'>;
|
|
|
39
44
|
/**
|
|
40
45
|
* A new change.
|
|
41
46
|
*/
|
|
42
|
-
export type NewChange = OmitStrict<Change, 'id' | 'changeSet'>;
|
|
47
|
+
export type NewChange = OmitStrict<Change, 'id' | 'changeSetId' | 'changeSet'>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ChangeSetEntity, isChangeSetEntityNewable } from './change-set-entity.model';
|
|
2
|
+
import { Property } from '../../entity/decorators/property.decorator';
|
|
2
3
|
import { Newable } from '../../types/newable.type';
|
|
3
4
|
import { MetadataUtilities } from '../../utilities/metadata.utilities';
|
|
4
5
|
|
|
@@ -6,12 +7,13 @@ import { MetadataUtilities } from '../../utilities/metadata.utilities';
|
|
|
6
7
|
* An entity that can be handled by the SoftDeleteRepository.
|
|
7
8
|
* Has an uuid id, a relation to all its changeSets and a flag that determines whether it is "soft deleted" or not.
|
|
8
9
|
*/
|
|
9
|
-
export
|
|
10
|
+
export class SoftDeleteEntity extends ChangeSetEntity {
|
|
10
11
|
/**
|
|
11
12
|
* Whether or not the entity is soft deleted.
|
|
12
13
|
*/
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
@Property.boolean({ default: false })
|
|
15
|
+
deleted!: boolean;
|
|
16
|
+
}
|
|
15
17
|
|
|
16
18
|
/**
|
|
17
19
|
* Checks whether the given class is a SoftDeleteEntity class.
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
import assert from 'node:assert';
|
|
2
|
+
|
|
3
|
+
import { afterAll, beforeAll, beforeEach, describe, expect, it } from '@jest/globals';
|
|
4
|
+
|
|
5
|
+
import { ChangeSetType } from './models/change-set-type.enum';
|
|
6
|
+
import { ChangeSet, CreateChangeSetData } from './models/change-set.model';
|
|
7
|
+
import { Change } from './models/change.model';
|
|
8
|
+
import { SoftDeleteEntity } from './models/soft-delete-entity.model';
|
|
9
|
+
import { SoftDeleteWhere } from './models/soft-delete-where.model';
|
|
10
|
+
import { SoftDeleteRepository } from './soft-delete-repository';
|
|
11
|
+
import { Roles } from '../__testing__/mocks/entities/roles.enum';
|
|
12
|
+
import { createTestDataSource, defaultTestServerEntities } from '../__testing__/test-server/create-test-data-source.function';
|
|
13
|
+
import { startTestServer, StartedTestServer } from '../__testing__/test-server/start-test-server.function';
|
|
14
|
+
import { DefaultTestServerUserRepository } from '../__testing__/test-server/user-repository';
|
|
15
|
+
import { AuthServiceInterface } from '../auth/auth-service.interface';
|
|
16
|
+
import { Auth } from '../auth/decorators/auth.decorator';
|
|
17
|
+
import { BaseUserEntity } from '../auth/models/base-user.model';
|
|
18
|
+
import { JwtAuthData } from '../auth/strategies/jwt/jwt-auth-data.model';
|
|
19
|
+
import { JwtCredentials } from '../auth/strategies/jwt/jwt-credentials.model';
|
|
20
|
+
import { JwtAuthStrategy } from '../auth/strategies/jwt/jwt.auth-strategy';
|
|
21
|
+
import { Repository } from '../data-source/repository';
|
|
22
|
+
import { InjectRepository, repositoryTokenFor } from '../di/decorators/inject-repository.decorator';
|
|
23
|
+
import { ZIBRI_DI_TOKENS } from '../di/default/zibri-di-tokens.default';
|
|
24
|
+
import { inject } from '../di/inject.function';
|
|
25
|
+
import { Entity } from '../entity/decorators/entity.decorator';
|
|
26
|
+
import { Property } from '../entity/decorators/property.decorator';
|
|
27
|
+
import { OmitClass } from '../entity/omit-class.model';
|
|
28
|
+
import { PartialClass } from '../entity/partial-class.model';
|
|
29
|
+
import { Body } from '../routing/decorators/body.decorator';
|
|
30
|
+
import { Controller } from '../routing/decorators/controller.decorator';
|
|
31
|
+
import { Delete } from '../routing/decorators/delete.decorator';
|
|
32
|
+
import { Get } from '../routing/decorators/get.decorator';
|
|
33
|
+
import { Param } from '../routing/decorators/param.decorator';
|
|
34
|
+
import { Patch } from '../routing/decorators/patch.decorator';
|
|
35
|
+
import { Post } from '../routing/decorators/post.decorator';
|
|
36
|
+
import { JsonUtilities } from '../utilities/json.utilities';
|
|
37
|
+
|
|
38
|
+
// ---------- Test entity ----------
|
|
39
|
+
@Entity()
|
|
40
|
+
class Task extends SoftDeleteEntity {
|
|
41
|
+
@Property.string()
|
|
42
|
+
title!: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
class CreateTaskDto extends OmitClass(Task, ['changeSets', 'id', 'deleted']) {}
|
|
46
|
+
class UpdateTaskDto extends PartialClass(OmitClass(Task, ['changeSets', 'id', 'deleted'])) {}
|
|
47
|
+
|
|
48
|
+
@Entity()
|
|
49
|
+
class TestUser extends BaseUserEntity(Roles) {
|
|
50
|
+
@Property.string({ hash: true })
|
|
51
|
+
password!: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// ---------- Controller ----------
|
|
55
|
+
@Controller('/tasks')
|
|
56
|
+
class TaskController {
|
|
57
|
+
constructor(
|
|
58
|
+
@InjectRepository(Task)
|
|
59
|
+
private readonly repo: SoftDeleteRepository<Task>
|
|
60
|
+
) {}
|
|
61
|
+
|
|
62
|
+
@Post('/')
|
|
63
|
+
@Auth.isLoggedIn([JwtAuthStrategy])
|
|
64
|
+
async create(@Body(CreateTaskDto) body: CreateTaskDto): Promise<Task> {
|
|
65
|
+
return this.repo.create(body);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
@Patch('/:id')
|
|
69
|
+
@Auth.isLoggedIn([JwtAuthStrategy])
|
|
70
|
+
async update(
|
|
71
|
+
@Param.path('id')
|
|
72
|
+
id: string,
|
|
73
|
+
@Body(UpdateTaskDto)
|
|
74
|
+
body: UpdateTaskDto,
|
|
75
|
+
@Param.query('withDeleted', { type: 'boolean', required: false })
|
|
76
|
+
withDeleted: boolean = false
|
|
77
|
+
): Promise<Task> {
|
|
78
|
+
return this.repo.updateById(id, body, { withDeleted });
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
@Delete('/:id')
|
|
82
|
+
@Auth.isLoggedIn([JwtAuthStrategy])
|
|
83
|
+
async softDelete(@Param.path('id') id: string): Promise<Task> {
|
|
84
|
+
return this.repo.deleteById(id);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
@Delete('/:id/hard')
|
|
88
|
+
@Auth.isLoggedIn([JwtAuthStrategy])
|
|
89
|
+
async hardDelete(@Param.path('id') id: string): Promise<Task> {
|
|
90
|
+
return this.repo.deleteById(id, { hardDelete: true });
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
@Get('/')
|
|
94
|
+
@Auth.isLoggedIn([JwtAuthStrategy])
|
|
95
|
+
async getAll(): Promise<Task[]> {
|
|
96
|
+
return this.repo.findAll();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
@Get('/with-deleted')
|
|
100
|
+
@Auth.isLoggedIn([JwtAuthStrategy])
|
|
101
|
+
async getAllWithDeleted(): Promise<Task[]> {
|
|
102
|
+
return this.repo.findAll({ withDeleted: true });
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
@Get('/:id')
|
|
106
|
+
@Auth.isLoggedIn([JwtAuthStrategy])
|
|
107
|
+
async getById(@Param.path('id') id: string): Promise<Task> {
|
|
108
|
+
return this.repo.findById(id);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ---------- Test setup ----------
|
|
113
|
+
let server: StartedTestServer;
|
|
114
|
+
let baseUrl: string;
|
|
115
|
+
let accessToken: string;
|
|
116
|
+
|
|
117
|
+
let changeSetRepo: Repository<ChangeSet, CreateChangeSetData>;
|
|
118
|
+
let changeRepo: Repository<Change>;
|
|
119
|
+
let taskRepo: SoftDeleteRepository<Task>;
|
|
120
|
+
|
|
121
|
+
beforeAll(async () => {
|
|
122
|
+
server = await startTestServer({
|
|
123
|
+
dataSources: [
|
|
124
|
+
createTestDataSource({
|
|
125
|
+
entities: [...defaultTestServerEntities, Task, TestUser]
|
|
126
|
+
})
|
|
127
|
+
],
|
|
128
|
+
controllers: [TaskController]
|
|
129
|
+
});
|
|
130
|
+
baseUrl = await server.start();
|
|
131
|
+
|
|
132
|
+
changeSetRepo = inject(repositoryTokenFor(ChangeSet));
|
|
133
|
+
changeRepo = inject(repositoryTokenFor(Change));
|
|
134
|
+
taskRepo = inject(repositoryTokenFor(Task)) as SoftDeleteRepository<Task>;
|
|
135
|
+
|
|
136
|
+
const userRepo: DefaultTestServerUserRepository = inject(DefaultTestServerUserRepository);
|
|
137
|
+
const credentialsRepo: Repository<JwtCredentials> = inject(repositoryTokenFor(JwtCredentials));
|
|
138
|
+
|
|
139
|
+
const testEmail: string = 'task-test@example.com';
|
|
140
|
+
const testPassword: string = 'test123';
|
|
141
|
+
await userRepo.create({ email: testEmail, roles: [Roles.USER] });
|
|
142
|
+
await credentialsRepo.create({
|
|
143
|
+
email: testEmail,
|
|
144
|
+
password: testPassword,
|
|
145
|
+
userId: (await userRepo.findOne({ where: { email: testEmail } }, true)).id
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const authService: AuthServiceInterface = inject(ZIBRI_DI_TOKENS.AUTH_SERVICE);
|
|
149
|
+
const authData: JwtAuthData<Roles> = await authService.login(JwtAuthStrategy<Roles>, {
|
|
150
|
+
email: testEmail,
|
|
151
|
+
password: testPassword
|
|
152
|
+
});
|
|
153
|
+
accessToken = authData.accessToken.value;
|
|
154
|
+
}, 15000);
|
|
155
|
+
|
|
156
|
+
afterAll(async () => {
|
|
157
|
+
await server.shutdown();
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
beforeEach(async () => {
|
|
161
|
+
await changeSetRepo.deleteAll({});
|
|
162
|
+
await changeRepo.deleteAll({});
|
|
163
|
+
await taskRepo.deleteAll({}, { hardDelete: true });
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
async function authFetch(path: string, options: RequestInit = {}): Promise<Response> {
|
|
167
|
+
const res: Response = await fetch(`${baseUrl}${path}`, {
|
|
168
|
+
...options,
|
|
169
|
+
headers: {
|
|
170
|
+
...options.headers,
|
|
171
|
+
Authorization: `Bearer ${accessToken}`,
|
|
172
|
+
'Content-Type': 'application/json'
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
if (!res.ok) {
|
|
176
|
+
const body: unknown = await res.json();
|
|
177
|
+
throw new Error(`Request "${options.method ?? 'GET'} ${path}" failed:\n${JsonUtilities.stringify(body, undefined, 4)}`);
|
|
178
|
+
}
|
|
179
|
+
return res;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// ---------- Tests ----------
|
|
183
|
+
describe('SoftDeleteRepository behavior', () => {
|
|
184
|
+
it('created task is not deleted', async () => {
|
|
185
|
+
const res: Response = await authFetch('/tasks', {
|
|
186
|
+
method: 'POST',
|
|
187
|
+
body: JSON.stringify({ title: 'Buy milk' })
|
|
188
|
+
});
|
|
189
|
+
const task: Task = await res.json() as Task;
|
|
190
|
+
expect(task.deleted).toBe(false);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
describe('soft delete', () => {
|
|
194
|
+
let taskId: string;
|
|
195
|
+
|
|
196
|
+
beforeEach(async () => {
|
|
197
|
+
const res: Response = await authFetch('/tasks', {
|
|
198
|
+
method: 'POST',
|
|
199
|
+
body: JSON.stringify({ title: 'Temporary' })
|
|
200
|
+
});
|
|
201
|
+
const task: Task = await res.json() as Task;
|
|
202
|
+
taskId = task.id;
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('marks the entity as deleted and creates a DELETE change set', async () => {
|
|
206
|
+
await authFetch(`/tasks/${taskId}`, { method: 'DELETE' });
|
|
207
|
+
|
|
208
|
+
const tasks: Task[] = await taskRepo.findAll({ withDeleted: true });
|
|
209
|
+
const task: Task | undefined = tasks.find(t => t.id === taskId);
|
|
210
|
+
assert(task);
|
|
211
|
+
expect(task.deleted).toBe(true);
|
|
212
|
+
|
|
213
|
+
const changeSets: ChangeSet[] = await changeSetRepo.findAll({ where: { changeSetEntityId: taskId } });
|
|
214
|
+
expect(changeSets.some(cs => cs.type === ChangeSetType.DELETE)).toBe(true);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it('findById throws NotFoundError for soft-deleted task', async () => {
|
|
218
|
+
await authFetch(`/tasks/${taskId}`, { method: 'DELETE' });
|
|
219
|
+
await expect(taskRepo.findById(taskId)).rejects.toThrow('Could not find');
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('findById with withDeleted=true returns the task', async () => {
|
|
223
|
+
await authFetch(`/tasks/${taskId}`, { method: 'DELETE' });
|
|
224
|
+
const task: Task = await taskRepo.findById(taskId, { withDeleted: true });
|
|
225
|
+
expect(task.deleted).toBe(true);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it('soft-deleted task can be updated if withDeleted is passed', async () => {
|
|
229
|
+
await authFetch(`/tasks/${taskId}`, { method: 'DELETE' });
|
|
230
|
+
const params: URLSearchParams = new URLSearchParams({ withDeleted: 'true' });
|
|
231
|
+
// Update using the controller, which uses updateById with options that allow withDeleted
|
|
232
|
+
await authFetch(`/tasks/${taskId}?${params.toString()}`, {
|
|
233
|
+
method: 'PATCH',
|
|
234
|
+
body: JSON.stringify({ title: 'Still here' })
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
describe('hard delete', () => {
|
|
240
|
+
let taskId: string;
|
|
241
|
+
|
|
242
|
+
beforeEach(async () => {
|
|
243
|
+
const res: Response = await authFetch('/tasks', {
|
|
244
|
+
method: 'POST',
|
|
245
|
+
body: JSON.stringify({ title: 'To be removed' })
|
|
246
|
+
});
|
|
247
|
+
const task: Task = await res.json() as Task;
|
|
248
|
+
taskId = task.id;
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it('removes the entity from the database', async () => {
|
|
252
|
+
await authFetch(`/tasks/${taskId}/hard`, { method: 'DELETE' });
|
|
253
|
+
await expect(taskRepo.findById(taskId)).rejects.toThrow('Could not find');
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
describe('findAll queries', () => {
|
|
258
|
+
let activeId: string;
|
|
259
|
+
let deletedId: string;
|
|
260
|
+
|
|
261
|
+
beforeEach(async () => {
|
|
262
|
+
const res1: Response = await authFetch('/tasks', {
|
|
263
|
+
method: 'POST',
|
|
264
|
+
body: JSON.stringify({ title: 'Active' })
|
|
265
|
+
});
|
|
266
|
+
activeId = (await res1.json() as Task).id;
|
|
267
|
+
|
|
268
|
+
const res2: Response = await authFetch('/tasks', {
|
|
269
|
+
method: 'POST',
|
|
270
|
+
body: JSON.stringify({ title: 'Removed' })
|
|
271
|
+
});
|
|
272
|
+
deletedId = (await res2.json() as Task).id;
|
|
273
|
+
await authFetch(`/tasks/${deletedId}`, { method: 'DELETE' });
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
it('default findAll returns only non-deleted entities', async () => {
|
|
277
|
+
const res: Response = await authFetch('/tasks');
|
|
278
|
+
const tasks: Task[] = await res.json() as Task[];
|
|
279
|
+
expect(tasks.map(t => t.id)).toEqual([activeId]);
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
it('findAll with withDeleted returns all entities', async () => {
|
|
283
|
+
const res: Response = await authFetch('/tasks/with-deleted');
|
|
284
|
+
const tasks: Task[] = await res.json() as Task[];
|
|
285
|
+
expect(tasks.map(t => t.id).sort()).toEqual([activeId, deletedId].sort());
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
describe('deleteAll', () => {
|
|
290
|
+
let id1: string, id2: string;
|
|
291
|
+
|
|
292
|
+
beforeEach(async () => {
|
|
293
|
+
const res1: Response = await authFetch('/tasks', {
|
|
294
|
+
method: 'POST',
|
|
295
|
+
body: JSON.stringify({ title: 'Task 1' })
|
|
296
|
+
});
|
|
297
|
+
id1 = (await res1.json() as Task).id;
|
|
298
|
+
|
|
299
|
+
const res2: Response = await authFetch('/tasks', {
|
|
300
|
+
method: 'POST',
|
|
301
|
+
body: JSON.stringify({ title: 'Task 2' })
|
|
302
|
+
});
|
|
303
|
+
id2 = (await res2.json() as Task).id;
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
it('soft deletes all matching entities', async () => {
|
|
307
|
+
const where: SoftDeleteWhere<Task> = { title: 'Task 1' };
|
|
308
|
+
await taskRepo.deleteAll(where); // soft delete by default
|
|
309
|
+
|
|
310
|
+
const allTasks: Task[] = await taskRepo.findAll({ withDeleted: true });
|
|
311
|
+
const task1: Task | undefined = allTasks.find(t => t.id === id1);
|
|
312
|
+
const task2: Task | undefined = allTasks.find(t => t.id === id2);
|
|
313
|
+
assert(task1 && task2);
|
|
314
|
+
expect(task1.deleted).toBe(true);
|
|
315
|
+
expect(task2.deleted).toBe(false);
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
it('hard deletes all matching entities', async () => {
|
|
319
|
+
const where: SoftDeleteWhere<Task> = { title: 'Task 2' };
|
|
320
|
+
await taskRepo.deleteAll(where, { hardDelete: true });
|
|
321
|
+
|
|
322
|
+
const allTasks: Task[] = await taskRepo.findAll({ withDeleted: true });
|
|
323
|
+
expect(allTasks.find(t => t.id === id2)).toBeUndefined();
|
|
324
|
+
});
|
|
325
|
+
});
|
|
326
|
+
});
|
|
@@ -16,12 +16,14 @@ import { SoftDeleteFindOneOptions } from './models/soft-delete-find-one-options.
|
|
|
16
16
|
import { SoftDeleteUpdateAllOptions } from './models/soft-delete-update-all-options.model';
|
|
17
17
|
import { SoftDeleteUpdateByIdOptions } from './models/soft-delete-update-by-id-options.model';
|
|
18
18
|
import { SoftDeleteWhere } from './models/soft-delete-where.model';
|
|
19
|
-
import { DataSourceInterface } from '../data-source/data-sources/data-source.interface';
|
|
20
19
|
import { BeforeReturnHook } from '../data-source/hooks/before-return';
|
|
21
20
|
import { BeforeSaveHook } from '../data-source/hooks/before-save';
|
|
22
21
|
import { Where } from '../data-source/models/where/where-filter.model';
|
|
23
22
|
import { NotFoundError } from '../error-handling/errors/not-found.error';
|
|
24
23
|
import { LoggerInterface } from '../logging/logger.interface';
|
|
24
|
+
import { ChangeSet, CreateChangeSetData } from './models/change-set.model';
|
|
25
|
+
import { AuthServiceInterface } from '../auth/auth-service.interface';
|
|
26
|
+
import { DataSourceInterface } from '../data-source/data-sources/data-source.interface';
|
|
25
27
|
|
|
26
28
|
/**
|
|
27
29
|
* Options for deleting a soft delete entity by its id.
|
|
@@ -36,7 +38,7 @@ export type SoftDeleteByIdOptions = DeleteByIdOptions & {
|
|
|
36
38
|
/**
|
|
37
39
|
* Options for deleting multiple soft delete entities.
|
|
38
40
|
*/
|
|
39
|
-
export type SoftDeleteAllOptions
|
|
41
|
+
export type SoftDeleteAllOptions = DeleteAllOptions & {
|
|
40
42
|
/**
|
|
41
43
|
* Whether or not to "actual" delete entities, rather than marking them as deleted.
|
|
42
44
|
*/
|
|
@@ -54,17 +56,17 @@ export class SoftDeleteRepository<
|
|
|
54
56
|
>
|
|
55
57
|
extends ChangeSetRepository<T, CreateData, UpdateData> {
|
|
56
58
|
|
|
57
|
-
protected override readonly keysToExcludeFromChangeSets: Set<keyof T> = new Set();
|
|
58
|
-
|
|
59
59
|
constructor(
|
|
60
60
|
entityClass: Newable<T>,
|
|
61
61
|
repo: TORepository<T> | Repository<T>,
|
|
62
62
|
logger: LoggerInterface,
|
|
63
63
|
dataSource: DataSourceInterface,
|
|
64
64
|
beforeSave: BeforeSaveHook<T, CreateData, UpdateData>,
|
|
65
|
-
beforeReturn: BeforeReturnHook<T
|
|
65
|
+
beforeReturn: BeforeReturnHook<T>,
|
|
66
|
+
authService: AuthServiceInterface,
|
|
67
|
+
changeSetRepository: Repository<ChangeSet, CreateChangeSetData>
|
|
66
68
|
) {
|
|
67
|
-
super(entityClass, repo, logger, dataSource, beforeSave, beforeReturn);
|
|
69
|
+
super(entityClass, repo, logger, dataSource, beforeSave, beforeReturn, authService, changeSetRepository);
|
|
68
70
|
this.keysToExcludeFromChangeSets.add('deleted');
|
|
69
71
|
}
|
|
70
72
|
|
|
@@ -130,7 +132,19 @@ export class SoftDeleteRepository<
|
|
|
130
132
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
131
133
|
async updateById(id: T['id'], data: UpdateData, options?: SoftDeleteUpdateByIdOptions): Promise<T> {
|
|
132
134
|
await this.findById(id, options);
|
|
133
|
-
|
|
135
|
+
try {
|
|
136
|
+
// The base updateById saves and then calls this.findById again.
|
|
137
|
+
// If the update set deleted = true, that final findById will throw NotFoundError
|
|
138
|
+
// because the soft‑delete guard now sees the entity as deleted.
|
|
139
|
+
return await super.updateById(id, data, options);
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
// Only catch the case where the update itself caused the soft‑delete
|
|
143
|
+
if (error instanceof NotFoundError && data.deleted === true) {
|
|
144
|
+
return this.findById(id, { ...options, withDeleted: true });
|
|
145
|
+
}
|
|
146
|
+
throw error;
|
|
147
|
+
}
|
|
134
148
|
}
|
|
135
149
|
|
|
136
150
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
@@ -154,9 +168,14 @@ export class SoftDeleteRepository<
|
|
|
154
168
|
}
|
|
155
169
|
|
|
156
170
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
157
|
-
async deleteAll(where: SoftDeleteWhere<T>, options?: SoftDeleteAllOptions
|
|
171
|
+
async deleteAll(where: SoftDeleteWhere<T>, options?: SoftDeleteAllOptions | undefined): Promise<T[]> {
|
|
158
172
|
if (options?.hardDelete === true) {
|
|
159
|
-
|
|
173
|
+
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
174
|
+
const finalOptions: DeleteAllOptions & { withDeleted?: boolean } = {
|
|
175
|
+
...options,
|
|
176
|
+
withDeleted: true
|
|
177
|
+
};
|
|
178
|
+
return await super.deleteAll(this.softDeleteWhereToWhere(true, where), finalOptions);
|
|
160
179
|
}
|
|
161
180
|
const res: T[] = await this.updateAllWithoutChangeSet(
|
|
162
181
|
this.softDeleteWhereToWhere(false, where),
|
|
@@ -169,7 +188,7 @@ export class SoftDeleteRepository<
|
|
|
169
188
|
|
|
170
189
|
private softDeleteWhereToWhere(withDeleted: boolean = false, where?: SoftDeleteWhere<T>): Where<T> {
|
|
171
190
|
if (where == undefined) {
|
|
172
|
-
return { deleted: false } as Where<T>;
|
|
191
|
+
return { deleted: withDeleted ? undefined : false } as Where<T>;
|
|
173
192
|
}
|
|
174
193
|
if (Array.isArray(where)) {
|
|
175
194
|
return where.map(f => ({ ...f, deleted: withDeleted ? undefined : false }));
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
2
|
|
|
3
|
+
import { CacheContext } from './cache/cache.context';
|
|
3
4
|
import { HttpRequestContext } from './request/http-request.context';
|
|
4
5
|
import { WebsocketRequestContext } from './request/websocket-request.context';
|
|
5
|
-
import { LogCacheContext } from '../logging/log-context.model';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Encapsulates functionality around async local storage.
|
|
@@ -10,7 +10,7 @@ import { LogCacheContext } from '../logging/log-context.model';
|
|
|
10
10
|
export abstract class AlsUtilities {
|
|
11
11
|
private static readonly httpRequest: AsyncLocalStorage<HttpRequestContext> = new AsyncLocalStorage<HttpRequestContext>();
|
|
12
12
|
private static readonly websocketRequest: AsyncLocalStorage<WebsocketRequestContext> = new AsyncLocalStorage<WebsocketRequestContext>();
|
|
13
|
-
private static readonly cacheContext: AsyncLocalStorage<
|
|
13
|
+
private static readonly cacheContext: AsyncLocalStorage<CacheContext[]> = new AsyncLocalStorage<CacheContext[]>();
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Resolves the currently active request context from the async local storage.
|
|
@@ -67,8 +67,8 @@ export abstract class AlsUtilities {
|
|
|
67
67
|
* @param fn - The function to run.
|
|
68
68
|
* @returns The result of the function.
|
|
69
69
|
*/
|
|
70
|
-
static runWithCacheContext<T>(context:
|
|
71
|
-
const existing:
|
|
70
|
+
static runWithCacheContext<T>(context: CacheContext, fn: () => T): T {
|
|
71
|
+
const existing: CacheContext[] = this.getCurrentCacheContext() ?? [];
|
|
72
72
|
// New array — doesn't mutate the parent scope's array
|
|
73
73
|
return this.cacheContext.run([...existing, context], fn);
|
|
74
74
|
}
|
|
@@ -78,7 +78,7 @@ export abstract class AlsUtilities {
|
|
|
78
78
|
* @returns The currently active cache context.
|
|
79
79
|
* @throws When the async local storage store has not been initialized yet.
|
|
80
80
|
*/
|
|
81
|
-
static getCurrentCacheContext():
|
|
81
|
+
static getCurrentCacheContext(): CacheContext[] | undefined {
|
|
82
82
|
return this.cacheContext.getStore();
|
|
83
83
|
}
|
|
84
84
|
}
|