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
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
import { And, ArrayContainedBy, ArrayContains, Equal, FindOperator, ILike, In, IsNull, LessThan, LessThanOrEqual, Like, MoreThan, MoreThanOrEqual, Not, Or, Raw, FindOptionsWhere as ToFindOptionsWhere, FindOptionsWhereProperty as ToFindOptionsWhereProperty, DataSource as ToDataSource } from 'typeorm';
|
|
2
|
+
|
|
3
|
+
import { BaseEntity } from '../../../entity/base-entity.model';
|
|
4
|
+
import { PropertyMetadata, RelationMetadata } from '../../../entity/decorators/property.decorator';
|
|
5
|
+
import { Relation } from '../../../entity/models/relation.enum';
|
|
6
|
+
import { ExcludeStrict } from '../../../types/exclude-strict.type';
|
|
7
|
+
import { Newable } from '../../../types/newable.type';
|
|
8
|
+
import { MetadataUtilities } from '../../../utilities/metadata.utilities';
|
|
9
|
+
import { ObjectUtilities } from '../../../utilities/object.utilities';
|
|
10
|
+
import { ArrayWhereFilter } from '../../models/where/array-where-filter.model';
|
|
11
|
+
import { isWhereFilterKey, WhereFilterKeys } from '../../models/where/where-filter-keys.model';
|
|
12
|
+
import { Where, WhereFilter, WhereFilterProperty } from '../../models/where/where-filter.model';
|
|
13
|
+
|
|
14
|
+
// eslint-disable-next-line typescript/typedef
|
|
15
|
+
const lengthWhereFilterKeys = [
|
|
16
|
+
'length',
|
|
17
|
+
'lengthGreaterThan',
|
|
18
|
+
'lengthGreaterThanEquals',
|
|
19
|
+
'lengthLesserThan',
|
|
20
|
+
'lengthLesserThanEquals'
|
|
21
|
+
] as const satisfies (keyof ExcludeStrict<ArrayWhereFilter<object>, null | object[]>)[];
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Handler function for a single where-filter key.
|
|
25
|
+
*/
|
|
26
|
+
export type WhereFilterHandler = (
|
|
27
|
+
value: unknown,
|
|
28
|
+
metadata: PropertyMetadata,
|
|
29
|
+
nestedProperties: Record<string, PropertyMetadata> | undefined,
|
|
30
|
+
entityClass: Newable<unknown>
|
|
31
|
+
) => FindOperator<unknown>;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Abstract base converter that transforms a Zibri WhereFilter into a TypeORM FindOptionsWhere.
|
|
35
|
+
*/
|
|
36
|
+
export abstract class TypeOrmWhereFilterConverter {
|
|
37
|
+
/**
|
|
38
|
+
* A map that defines how Zibri's where filter properties are mapped to their typeorm counterpart.
|
|
39
|
+
*/
|
|
40
|
+
protected handleFilterKeyMap: Record<WhereFilterKeys, WhereFilterHandler> = {
|
|
41
|
+
not: (value) => Not(value),
|
|
42
|
+
like: (value) => Like(value),
|
|
43
|
+
oneOf: (value) => {
|
|
44
|
+
if (!Array.isArray(value)) {
|
|
45
|
+
throw new Error('The "oneOf" property of the where filter needs to be an array.');
|
|
46
|
+
}
|
|
47
|
+
return In(value);
|
|
48
|
+
},
|
|
49
|
+
notOneOf: (value) => {
|
|
50
|
+
if (!Array.isArray(value)) {
|
|
51
|
+
throw new Error('The "notOneOf" property of the where filter needs to be an array.');
|
|
52
|
+
}
|
|
53
|
+
return Not(In(value));
|
|
54
|
+
},
|
|
55
|
+
after: (value) => MoreThan(value),
|
|
56
|
+
before: (value) => LessThan(value),
|
|
57
|
+
greaterThan: (value) => MoreThan(value),
|
|
58
|
+
greaterThanEquals: (value) => MoreThanOrEqual(value),
|
|
59
|
+
lesserThan: (value) => LessThan(value),
|
|
60
|
+
lesserThanEquals: (value) => LessThanOrEqual(value),
|
|
61
|
+
iLike: (value) => ILike(value),
|
|
62
|
+
is: (value, metadata) => {
|
|
63
|
+
if (value === null) {
|
|
64
|
+
return IsNull();
|
|
65
|
+
}
|
|
66
|
+
// Unwrap a full entity for MANY_TO_ONE / BELONGS_TO_ONE
|
|
67
|
+
if (
|
|
68
|
+
(metadata.type === Relation.MANY_TO_ONE
|
|
69
|
+
|| metadata.type === Relation.BELONGS_TO_ONE)
|
|
70
|
+
&& value !== null
|
|
71
|
+
&& typeof value === 'object'
|
|
72
|
+
&& !Array.isArray(value)
|
|
73
|
+
&& 'id' in value
|
|
74
|
+
) {
|
|
75
|
+
return Equal(value.id);
|
|
76
|
+
}
|
|
77
|
+
return Equal(value);
|
|
78
|
+
},
|
|
79
|
+
where: (value, metadata, nestedProperties, entityClass) => this.whereHandler(value, metadata, nestedProperties, entityClass),
|
|
80
|
+
includes: (value) => {
|
|
81
|
+
if (!Array.isArray(value)) {
|
|
82
|
+
throw new Error('The "includes" property of the where filter needs to be an array.');
|
|
83
|
+
}
|
|
84
|
+
return ArrayContains(value);
|
|
85
|
+
},
|
|
86
|
+
isIncludedIn: (value) => {
|
|
87
|
+
if (!Array.isArray(value)) {
|
|
88
|
+
throw new Error('The "isIncludedIn" property of the where filter needs to be an array.');
|
|
89
|
+
}
|
|
90
|
+
return ArrayContainedBy(value);
|
|
91
|
+
},
|
|
92
|
+
length: (value) => Raw(alias => `array_length(${alias}, 1) = ${value}`),
|
|
93
|
+
lengthGreaterThan: (value) => Raw(alias => `array_length(${alias}, 1) > ${value}`),
|
|
94
|
+
lengthGreaterThanEquals: (value) => Raw(alias => `array_length(${alias}, 1) >= ${value}`),
|
|
95
|
+
lengthLesserThan: (value) => Raw(alias => `array_length(${alias}, 1) < ${value}`),
|
|
96
|
+
lengthLesserThanEquals: (value) => Raw(alias => `array_length(${alias}, 1) <= ${value}`)
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
constructor(protected readonly typeOrmDataSource: ToDataSource) {}
|
|
100
|
+
|
|
101
|
+
// ── Public entry point (concrete) ──────────────────────────
|
|
102
|
+
/**
|
|
103
|
+
* Converts the given zibri filter to a typeorm filter.
|
|
104
|
+
* @param filter - The zibri filter to convert.
|
|
105
|
+
* @param entityClass - The entity class to search for by this filter.
|
|
106
|
+
* @returns The typeorm filter.
|
|
107
|
+
*/
|
|
108
|
+
convert<T extends object>(
|
|
109
|
+
filter: Where<T>,
|
|
110
|
+
entityClass: Newable<T>
|
|
111
|
+
): ToFindOptionsWhere<T> | ToFindOptionsWhere<T>[] {
|
|
112
|
+
const properties: Record<string, PropertyMetadata> = MetadataUtilities.getModelProperties(entityClass);
|
|
113
|
+
if (Array.isArray(filter)) {
|
|
114
|
+
return filter.map(f => this.singleWhereFilterToFindOptionsWhere(f, properties, entityClass));
|
|
115
|
+
}
|
|
116
|
+
return this.singleWhereFilterToFindOptionsWhere(filter, properties, entityClass);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Handles converting a where filter to a typeorm FindOperator.
|
|
121
|
+
* @param value - The value of the where filter.
|
|
122
|
+
* @param metadata - The metadata of the property for which the where filter has been specified.
|
|
123
|
+
* @param nestedProperties - Nested properties on the where filter. Need to exist.
|
|
124
|
+
* @param entityClass - The entity class that the where filter belongs to.
|
|
125
|
+
* @returns A typeorm FindOperator.
|
|
126
|
+
* @throws Wheen now nested properties have been found.
|
|
127
|
+
*/
|
|
128
|
+
protected whereHandler(
|
|
129
|
+
value: unknown,
|
|
130
|
+
metadata: PropertyMetadata,
|
|
131
|
+
nestedProperties: Record<string, PropertyMetadata> | undefined,
|
|
132
|
+
entityClass: Newable<unknown>
|
|
133
|
+
): FindOperator<unknown> {
|
|
134
|
+
if (nestedProperties == undefined) {
|
|
135
|
+
throw new Error('The "where" operator is not supported on this property without nested metadata.');
|
|
136
|
+
}
|
|
137
|
+
let targetClass: Newable<unknown> = entityClass;
|
|
138
|
+
if (metadata.type === 'object') {
|
|
139
|
+
targetClass = metadata.cls();
|
|
140
|
+
}
|
|
141
|
+
else if (
|
|
142
|
+
metadata.type === Relation.HAS_ONE || metadata.type === Relation.BELONGS_TO_ONE
|
|
143
|
+
|| metadata.type === Relation.MANY_TO_ONE || metadata.type === Relation.ONE_TO_MANY
|
|
144
|
+
|| metadata.type === Relation.MANY_TO_MANY
|
|
145
|
+
) {
|
|
146
|
+
targetClass = metadata.target();
|
|
147
|
+
}
|
|
148
|
+
return this.singleWhereFilterToFindOptionsWhere(
|
|
149
|
+
value as WhereFilter<Record<string, unknown>>,
|
|
150
|
+
nestedProperties,
|
|
151
|
+
targetClass as Newable<Record<string, unknown>>
|
|
152
|
+
) as unknown as FindOperator<unknown>;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// ── Pipeline stages (concrete, overridable) ─────────────────
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Converts a single where filter to a typeorm FindOptionsWhere property.
|
|
159
|
+
* @param filter - The filter to convert.
|
|
160
|
+
* @param properties - The property metadata of the model that the filter is for.
|
|
161
|
+
* @param entityClass - The entity class to search for by this filter.
|
|
162
|
+
* @returns A typeorm FindOptionsWhere property.
|
|
163
|
+
*/
|
|
164
|
+
protected singleWhereFilterToFindOptionsWhere<T extends Object>(
|
|
165
|
+
filter: WhereFilter<T>,
|
|
166
|
+
properties: Record<string, PropertyMetadata>,
|
|
167
|
+
entityClass: Newable<T>
|
|
168
|
+
): ToFindOptionsWhere<T> {
|
|
169
|
+
const res: ToFindOptionsWhere<T> = {};
|
|
170
|
+
const extraRawConditions: FindOperator<unknown>[] = [];
|
|
171
|
+
|
|
172
|
+
for (const key of ObjectUtilities.keys(filter)) {
|
|
173
|
+
const prop: WhereFilterProperty<T[typeof key]> | WhereFilterProperty<T[typeof key]>[] | undefined = filter[key];
|
|
174
|
+
if (prop === undefined) {
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const propertyMetadata: PropertyMetadata = properties[key];
|
|
179
|
+
let nestedProperties: Record<string, PropertyMetadata> | undefined;
|
|
180
|
+
|
|
181
|
+
if (propertyMetadata.type === Relation.ONE_TO_MANY || propertyMetadata.type === Relation.MANY_TO_MANY) {
|
|
182
|
+
this.processRelationFilter(key, prop, propertyMetadata, entityClass, res, extraRawConditions);
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (propertyMetadata.type === 'object') {
|
|
187
|
+
nestedProperties = MetadataUtilities.getModelProperties(propertyMetadata.cls());
|
|
188
|
+
}
|
|
189
|
+
else if (
|
|
190
|
+
propertyMetadata.type === Relation.HAS_ONE
|
|
191
|
+
|| propertyMetadata.type === Relation.BELONGS_TO_ONE
|
|
192
|
+
|| propertyMetadata.type === Relation.MANY_TO_ONE
|
|
193
|
+
) {
|
|
194
|
+
nestedProperties = MetadataUtilities.getModelProperties(propertyMetadata.target());
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
res[key] = this.propertyToFindOperator(
|
|
198
|
+
prop,
|
|
199
|
+
propertyMetadata,
|
|
200
|
+
nestedProperties,
|
|
201
|
+
entityClass as Newable<T[Extract<keyof T, string>]>
|
|
202
|
+
) as typeof key extends 'toString' ? unknown : ToFindOptionsWhereProperty<NonNullable<T[typeof key]>>;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (extraRawConditions.length) {
|
|
206
|
+
const existingIdFilter: FindOperator<unknown> | undefined = res['id' as keyof T] as FindOperator<unknown> | undefined;
|
|
207
|
+
const combined: FindOperator<unknown> = existingIdFilter
|
|
208
|
+
? And(existingIdFilter, ...extraRawConditions)
|
|
209
|
+
: And(...extraRawConditions);
|
|
210
|
+
(res as Record<string, FindOperator<unknown>>)['id'] = combined;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return res;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
private processRelationFilter<T extends Object>(
|
|
217
|
+
key: string,
|
|
218
|
+
prop: WhereFilterProperty<T[Extract<keyof T, string>]> | WhereFilterProperty<T[Extract<keyof T, string>]>[],
|
|
219
|
+
propertyMetadata: RelationMetadata<BaseEntity>,
|
|
220
|
+
entityClass: Newable<T>,
|
|
221
|
+
res: ToFindOptionsWhere<T>,
|
|
222
|
+
extraRawConditions: FindOperator<unknown>[]
|
|
223
|
+
): void {
|
|
224
|
+
const filterObj: Record<string, unknown> = prop as Record<string, unknown>;
|
|
225
|
+
|
|
226
|
+
for (const lengthKey of lengthWhereFilterKeys) {
|
|
227
|
+
if (lengthKey in filterObj && typeof filterObj[lengthKey] === 'number') {
|
|
228
|
+
extraRawConditions.push(
|
|
229
|
+
this.buildRelationLengthRawOperator(
|
|
230
|
+
entityClass, key, propertyMetadata, lengthKey, filterObj[lengthKey]
|
|
231
|
+
)
|
|
232
|
+
);
|
|
233
|
+
// eslint-disable-next-line typescript/no-dynamic-delete
|
|
234
|
+
delete filterObj[lengthKey];
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// 2) includes / isIncludedIn
|
|
239
|
+
if ('includes' in filterObj && Array.isArray(filterObj.includes)) {
|
|
240
|
+
extraRawConditions.push(
|
|
241
|
+
this.buildRelationIncludesOperator(
|
|
242
|
+
entityClass, key, propertyMetadata, filterObj.includes as BaseEntity[]
|
|
243
|
+
)
|
|
244
|
+
);
|
|
245
|
+
delete filterObj.includes;
|
|
246
|
+
}
|
|
247
|
+
if ('isIncludedIn' in filterObj && Array.isArray(filterObj.isIncludedIn)) {
|
|
248
|
+
extraRawConditions.push(
|
|
249
|
+
this.buildRelationIsIncludedInOperator(
|
|
250
|
+
entityClass, key, propertyMetadata, filterObj.isIncludedIn as BaseEntity[]
|
|
251
|
+
)
|
|
252
|
+
);
|
|
253
|
+
delete filterObj.isIncludedIn;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// 3) Remaining element filters (e.g. where)
|
|
257
|
+
if (Object.keys(filterObj).length > 0) {
|
|
258
|
+
const targetEntity: Newable<BaseEntity> = propertyMetadata.target();
|
|
259
|
+
const nestedProps: Record<string, PropertyMetadata> = MetadataUtilities.getModelProperties(targetEntity);
|
|
260
|
+
(res as Record<string, unknown>)[key] = this.propertyToFindOperator(
|
|
261
|
+
filterObj as WhereFilterProperty<T> | WhereFilterProperty<T>[],
|
|
262
|
+
propertyMetadata,
|
|
263
|
+
nestedProps,
|
|
264
|
+
entityClass
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Converts a where filter property to a typeorm FindOperator property.
|
|
271
|
+
* @param property - The property to convert.
|
|
272
|
+
* @param propertyMetadata - The property metadata of the property.
|
|
273
|
+
* @param nestedProperties - Nested properties, if any.
|
|
274
|
+
* @param entityClass - The entity class that the property is on.
|
|
275
|
+
* @returns A typeorm FindOperator property.
|
|
276
|
+
*/
|
|
277
|
+
protected propertyToFindOperator<T>(
|
|
278
|
+
property: WhereFilterProperty<T> | WhereFilterProperty<T>[],
|
|
279
|
+
propertyMetadata: PropertyMetadata,
|
|
280
|
+
nestedProperties: Record<string, PropertyMetadata> | undefined,
|
|
281
|
+
entityClass: Newable<T>
|
|
282
|
+
): FindOperator<T> {
|
|
283
|
+
if (Array.isArray(property)) {
|
|
284
|
+
return propertyMetadata.type === 'array'
|
|
285
|
+
? this.singlePropertyToFindOperator(property as WhereFilterProperty<T>, propertyMetadata, nestedProperties, entityClass)
|
|
286
|
+
: Or(
|
|
287
|
+
...property.map(
|
|
288
|
+
p => this.singlePropertyToFindOperator<T>(
|
|
289
|
+
p as WhereFilterProperty<T>,
|
|
290
|
+
propertyMetadata,
|
|
291
|
+
nestedProperties,
|
|
292
|
+
entityClass
|
|
293
|
+
)
|
|
294
|
+
)
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
return this.singlePropertyToFindOperator(property, propertyMetadata, nestedProperties, entityClass);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Transforms a single where filter property to a typeorm FindOperator.
|
|
302
|
+
* @param property - The where filter property to transform.
|
|
303
|
+
* @param propertyMetadata - The metadata of the where filter property.
|
|
304
|
+
* @param nestedProperties - Any nested properties of the where filter.
|
|
305
|
+
* @param entityClass - The entity class that the property is on.
|
|
306
|
+
* @returns A typeorm FindOperator.
|
|
307
|
+
* @throws When the where filter property is invalid.
|
|
308
|
+
*/
|
|
309
|
+
protected singlePropertyToFindOperator<T>(
|
|
310
|
+
property: WhereFilterProperty<T>,
|
|
311
|
+
propertyMetadata: PropertyMetadata,
|
|
312
|
+
nestedProperties: Record<string, PropertyMetadata> | undefined,
|
|
313
|
+
entityClass: Newable<T>
|
|
314
|
+
): FindOperator<T> {
|
|
315
|
+
if (property === null) {
|
|
316
|
+
// eslint-disable-next-line typescript/no-unsafe-return
|
|
317
|
+
return IsNull();
|
|
318
|
+
}
|
|
319
|
+
if (
|
|
320
|
+
typeof property === 'string'
|
|
321
|
+
|| typeof property === 'bigint'
|
|
322
|
+
|| typeof property === 'number'
|
|
323
|
+
|| typeof property === 'boolean'
|
|
324
|
+
|| property instanceof Date
|
|
325
|
+
|| (Array.isArray(property) && propertyMetadata.type === 'array')
|
|
326
|
+
) {
|
|
327
|
+
return Equal(property as T);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const operators: FindOperator<T>[] = [];
|
|
331
|
+
const filterKeys: unknown[] = ObjectUtilities.keys(property);
|
|
332
|
+
if (!filterKeys.length) {
|
|
333
|
+
throw new Error('Empty where filter');
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
for (const key of filterKeys) {
|
|
337
|
+
if (!isWhereFilterKey(key)) {
|
|
338
|
+
throw new Error(`Unknown key "${key}" on where filter ${property}`);
|
|
339
|
+
}
|
|
340
|
+
const handler: WhereFilterHandler = this.handleFilterKeyMap[key];
|
|
341
|
+
const value: unknown = (property as Record<string, unknown>)[key];
|
|
342
|
+
const op: FindOperator<unknown> = handler(value, propertyMetadata, nestedProperties, entityClass);
|
|
343
|
+
if (op !== undefined) {
|
|
344
|
+
operators.push(op as FindOperator<T>);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
return operators.length === 1
|
|
349
|
+
? operators[0]
|
|
350
|
+
: And(...operators);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// ── Abstract – DB‑specific building blocks ───────────────────
|
|
354
|
+
|
|
355
|
+
protected abstract buildRelationLengthRawOperator<T>(
|
|
356
|
+
entityClass: Newable<T>,
|
|
357
|
+
propertyName: string,
|
|
358
|
+
metadata: RelationMetadata<BaseEntity>,
|
|
359
|
+
lengthKey: string,
|
|
360
|
+
value: number
|
|
361
|
+
): FindOperator<unknown>;
|
|
362
|
+
|
|
363
|
+
protected abstract buildRelationIncludesOperator<T>(
|
|
364
|
+
entityClass: Newable<T>,
|
|
365
|
+
propertyName: string,
|
|
366
|
+
metadata: RelationMetadata<BaseEntity>,
|
|
367
|
+
entities: BaseEntity[]
|
|
368
|
+
): FindOperator<unknown>;
|
|
369
|
+
|
|
370
|
+
protected abstract buildRelationIsIncludedInOperator<T>(
|
|
371
|
+
entityClass: Newable<T>,
|
|
372
|
+
propertyName: string,
|
|
373
|
+
metadata: RelationMetadata<BaseEntity>,
|
|
374
|
+
entities: BaseEntity[]
|
|
375
|
+
): FindOperator<unknown>;
|
|
376
|
+
}
|
|
@@ -26,8 +26,11 @@ class Order {
|
|
|
26
26
|
@Property.string({ exclude: true })
|
|
27
27
|
internalNote!: string;
|
|
28
28
|
|
|
29
|
-
@Property.manyToOne({ target: () => User, inverseSide: 'orders' })
|
|
29
|
+
@Property.manyToOne({ target: () => User, joinColumn: 'userId', inverseSide: 'orders' })
|
|
30
30
|
user!: unknown;
|
|
31
|
+
|
|
32
|
+
@Property.string({ format: 'uuid' })
|
|
33
|
+
userId!: string;
|
|
31
34
|
}
|
|
32
35
|
|
|
33
36
|
class User extends BaseEntity {
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import { afterAll, beforeAll, beforeEach, describe, expect, it } from '@jest/globals';
|
|
2
|
+
|
|
3
|
+
import { createTestDataSource, defaultTestServerEntities } from '../../__testing__/test-server/create-test-data-source.function';
|
|
4
|
+
import { StartedTestServer, startTestServer } from '../../__testing__/test-server/start-test-server.function';
|
|
5
|
+
import { ChangeSetEntity } from '../../change-sets/models/change-set-entity.model';
|
|
6
|
+
import { ChangeSetType } from '../../change-sets/models/change-set-type.enum';
|
|
7
|
+
import { ChangeSet } from '../../change-sets/models/change-set.model';
|
|
8
|
+
import { SoftDeleteEntity } from '../../change-sets/models/soft-delete-entity.model';
|
|
9
|
+
import { SoftDeleteRepository } from '../../change-sets/soft-delete-repository';
|
|
10
|
+
import { repositoryTokenFor } from '../../di/decorators/inject-repository.decorator';
|
|
11
|
+
import { inject } from '../../di/inject.function';
|
|
12
|
+
import { BaseEntity } from '../../entity/base-entity.model';
|
|
13
|
+
import { Entity } from '../../entity/decorators/entity.decorator';
|
|
14
|
+
import { Property } from '../../entity/decorators/property.decorator';
|
|
15
|
+
import { PostgresDataSource } from '../data-sources/postgres-typeorm-data-source.model';
|
|
16
|
+
import { Repository } from '../repository';
|
|
17
|
+
|
|
18
|
+
// ==================== TEST ENTITIES ====================
|
|
19
|
+
|
|
20
|
+
// Entity that tests ALL hook-related features
|
|
21
|
+
@Entity()
|
|
22
|
+
class HookTestEntity extends BaseEntity implements ChangeSetEntity, SoftDeleteEntity {
|
|
23
|
+
@Property.string()
|
|
24
|
+
name!: string;
|
|
25
|
+
|
|
26
|
+
@Property.string({ encryption: true, exclude: true })
|
|
27
|
+
secretValue!: string; // encrypted on save, decrypted on read, excluded from response
|
|
28
|
+
|
|
29
|
+
@Property.string({ hash: true })
|
|
30
|
+
password!: string; // hashed on save
|
|
31
|
+
|
|
32
|
+
@Property.boolean({ default: true })
|
|
33
|
+
isActive!: boolean; // default value set on create
|
|
34
|
+
|
|
35
|
+
@Property.string({ required: false, excludeFromChangeSets: true })
|
|
36
|
+
internalNote?: string; // excluded from change sets
|
|
37
|
+
|
|
38
|
+
@Property.boolean({ default: false })
|
|
39
|
+
deleted!: boolean; // required by SoftDeleteEntity
|
|
40
|
+
|
|
41
|
+
@Property.oneToMany({ target: () => ChangeSet, inverseSide: 'changeSetEntityId' })
|
|
42
|
+
changeSets!: ChangeSet[]; // required by ChangeSetEntity
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
let server: StartedTestServer;
|
|
46
|
+
let repo: Repository<HookTestEntity>;
|
|
47
|
+
let changeSetRepo: Repository<ChangeSet>;
|
|
48
|
+
|
|
49
|
+
beforeAll(async () => {
|
|
50
|
+
server = await startTestServer({
|
|
51
|
+
dataSources: [
|
|
52
|
+
createTestDataSource({
|
|
53
|
+
entities: [...defaultTestServerEntities, HookTestEntity, ChangeSet]
|
|
54
|
+
})
|
|
55
|
+
]
|
|
56
|
+
});
|
|
57
|
+
repo = inject(repositoryTokenFor(HookTestEntity));
|
|
58
|
+
changeSetRepo = inject(repositoryTokenFor(ChangeSet));
|
|
59
|
+
}, 15000);
|
|
60
|
+
|
|
61
|
+
afterAll(async () => {
|
|
62
|
+
await server.shutdown();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
beforeEach(async () => {
|
|
66
|
+
await changeSetRepo.deleteAll({});
|
|
67
|
+
await repo.deleteAll({});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe('before‑save hooks', () => {
|
|
71
|
+
describe('on create', () => {
|
|
72
|
+
it('encrypts properties marked with encryption', async () => {
|
|
73
|
+
const entity: HookTestEntity = await repo.create({
|
|
74
|
+
name: 'Test',
|
|
75
|
+
secretValue: 'top-secret',
|
|
76
|
+
password: 'plain'
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// secretValue should be encrypted (not the plain text)
|
|
80
|
+
expect(entity.secretValue).toBe('top-secret');
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('hashes properties marked with hash', async () => {
|
|
84
|
+
const entity: HookTestEntity = await repo.create({
|
|
85
|
+
name: 'Test',
|
|
86
|
+
secretValue: 'top-secret',
|
|
87
|
+
password: 'my-password'
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// password should be hashed (not the plain text)
|
|
91
|
+
expect(entity.password).not.toBe('my-password');
|
|
92
|
+
expect(entity.password).toContain('$'); // hash contains algorithm prefix
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('sets default values when not provided', async () => {
|
|
96
|
+
const entity: HookTestEntity = await repo.create({
|
|
97
|
+
name: 'Test',
|
|
98
|
+
secretValue: 'top-secret',
|
|
99
|
+
password: 'plain'
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// isActive should default to true
|
|
103
|
+
expect(entity.isActive).toBe(true);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('does NOT override explicitly provided values with defaults', async () => {
|
|
107
|
+
const entity: HookTestEntity = await repo.create({
|
|
108
|
+
name: 'Test',
|
|
109
|
+
secretValue: 'top-secret',
|
|
110
|
+
password: 'plain',
|
|
111
|
+
isActive: false
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
expect(entity.isActive).toBe(false);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('encrypts values at rest (raw database access)', async () => {
|
|
118
|
+
const entity: HookTestEntity = await repo.create({
|
|
119
|
+
name: 'EncAtRest',
|
|
120
|
+
secretValue: 'super-secret',
|
|
121
|
+
password: 'pw'
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// Use the query builder to read the raw column – no before‑return hook runs
|
|
125
|
+
const raw: HookTestEntity | null = await (repo.dataSource as PostgresDataSource)
|
|
126
|
+
.query(HookTestEntity)
|
|
127
|
+
.select(`${HookTestEntity.name}.secretValue`)
|
|
128
|
+
.where(`${HookTestEntity.name}.id = :id`, { id: entity.id })
|
|
129
|
+
.getOne();
|
|
130
|
+
|
|
131
|
+
// The stored value must be encrypted (not plain text)
|
|
132
|
+
expect(raw?.secretValue).not.toBe('super-secret');
|
|
133
|
+
expect(raw?.secretValue.length).toBeGreaterThan(20);
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
describe('on update', () => {
|
|
138
|
+
let entityId: string;
|
|
139
|
+
|
|
140
|
+
beforeEach(async () => {
|
|
141
|
+
const entity: HookTestEntity = await repo.create({
|
|
142
|
+
name: 'Original',
|
|
143
|
+
secretValue: 'initial-secret',
|
|
144
|
+
password: 'initial-password'
|
|
145
|
+
});
|
|
146
|
+
entityId = entity.id;
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('encrypts updated encrypted properties', async () => {
|
|
150
|
+
const updated: HookTestEntity = await repo.updateById(entityId, { secretValue: 'new-secret' });
|
|
151
|
+
expect(updated.secretValue).toBe('new-secret');
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('hashes updated hash properties', async () => {
|
|
155
|
+
const updated: HookTestEntity = await repo.updateById(entityId, { password: 'new-password' });
|
|
156
|
+
expect(updated.password).not.toBe('new-password');
|
|
157
|
+
expect(updated.password).toContain('$');
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('does NOT re‑set default values (setDefault = false)', async () => {
|
|
161
|
+
// Update without providing isActive
|
|
162
|
+
const updated: HookTestEntity = await repo.updateById(entityId, { name: 'Updated' });
|
|
163
|
+
// isActive should remain its original value (true from create's default)
|
|
164
|
+
expect(updated.isActive).toBe(true);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
describe('before‑return hooks', () => {
|
|
170
|
+
describe('on find', () => {
|
|
171
|
+
let entityId: string;
|
|
172
|
+
let originalSecret: string;
|
|
173
|
+
|
|
174
|
+
beforeEach(async () => {
|
|
175
|
+
// We need the entity as stored (with encrypted/hashed values) before the return hook runs.
|
|
176
|
+
// So we create one and capture what findById returns after decryption.
|
|
177
|
+
const entity: HookTestEntity = await repo.create({
|
|
178
|
+
name: 'ReturnTest',
|
|
179
|
+
secretValue: 'my-secret',
|
|
180
|
+
password: 'my-password'
|
|
181
|
+
});
|
|
182
|
+
entityId = entity.id;
|
|
183
|
+
// After create, before‑return has already run, so we see decrypted values.
|
|
184
|
+
originalSecret = entity.secretValue;
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('decrypts encrypted properties on findById', async () => {
|
|
188
|
+
const fetched: HookTestEntity = await repo.findById(entityId);
|
|
189
|
+
// secretValue should be decrypted (equal to the original plain text after re‑encryption/decryption)
|
|
190
|
+
expect(fetched.secretValue).toBe(originalSecret);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('decrypts encrypted properties on findAll', async () => {
|
|
194
|
+
const results: HookTestEntity[] = await repo.findAll();
|
|
195
|
+
expect(results).toHaveLength(1);
|
|
196
|
+
expect(results[0].secretValue).toBe(originalSecret);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('decrypts encrypted properties on findOne', async () => {
|
|
200
|
+
const fetched: HookTestEntity = await repo.findOne({ where: { id: entityId } }, true);
|
|
201
|
+
expect(fetched.secretValue).toBe(originalSecret);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('removes excluded properties from the returned entity', async () => {
|
|
205
|
+
const fetched: HookTestEntity = await repo.findById(entityId);
|
|
206
|
+
expect(fetched.secretValue).toBe(originalSecret);
|
|
207
|
+
expect(JSON.stringify(fetched)).not.toContain('secretValue');
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
describe('ChangeSetRepository hooks integration', () => {
|
|
213
|
+
it('excludes properties marked with excludeFromChangeSets from change sets', async () => {
|
|
214
|
+
const entity: HookTestEntity = await repo.create({
|
|
215
|
+
name: 'ChangeSetTest',
|
|
216
|
+
secretValue: 'test-secret',
|
|
217
|
+
password: 'test-password',
|
|
218
|
+
internalNote: 'do not track'
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
const changeSets: ChangeSet[] = await changeSetRepo.findAll({ where: { changeSetEntityId: entity.id } });
|
|
222
|
+
expect(changeSets).toHaveLength(1);
|
|
223
|
+
|
|
224
|
+
const cs: ChangeSet = changeSets[0];
|
|
225
|
+
// internalNote should NOT appear in changes
|
|
226
|
+
expect(cs.changes.some(c => c.key === 'internalNote')).toBe(false);
|
|
227
|
+
// other properties should be tracked
|
|
228
|
+
expect(cs.changes.some(c => c.key === 'name')).toBe(true);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it('records change sets for create and update operations', async () => {
|
|
232
|
+
const entity: HookTestEntity = await repo.create({
|
|
233
|
+
name: 'TrackingTest',
|
|
234
|
+
secretValue: 'secret',
|
|
235
|
+
password: 'pass'
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// Update name
|
|
239
|
+
await repo.updateById(entity.id, { name: 'Updated' });
|
|
240
|
+
|
|
241
|
+
const changeSets: ChangeSet[] = await changeSetRepo.findAll({
|
|
242
|
+
where: { changeSetEntityId: entity.id },
|
|
243
|
+
order: { createdAt: 'ASC' }
|
|
244
|
+
});
|
|
245
|
+
expect(changeSets).toHaveLength(2);
|
|
246
|
+
expect(changeSets[0].type).toBe(ChangeSetType.CREATE);
|
|
247
|
+
expect(changeSets[1].type).toBe(ChangeSetType.UPDATE);
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
describe('SoftDeleteRepository hooks integration', () => {
|
|
252
|
+
it('excludes "deleted" from change sets', async () => {
|
|
253
|
+
const entity: HookTestEntity = await repo.create({
|
|
254
|
+
name: 'SoftDeleteTest',
|
|
255
|
+
secretValue: 'secret',
|
|
256
|
+
password: 'pass'
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
// Soft delete
|
|
260
|
+
await (repo as unknown as SoftDeleteRepository<HookTestEntity>).deleteById(entity.id);
|
|
261
|
+
|
|
262
|
+
const changeSets: ChangeSet[] = await changeSetRepo.findAll({ where: { changeSetEntityId: entity.id } });
|
|
263
|
+
const deleteCs: ChangeSet | undefined = changeSets.find(cs => cs.type === ChangeSetType.DELETE);
|
|
264
|
+
expect(deleteCs).toBeDefined();
|
|
265
|
+
// deleted flag should NOT appear in changes
|
|
266
|
+
expect(deleteCs?.changes.some(c => c.key === 'deleted')).toBe(false);
|
|
267
|
+
});
|
|
268
|
+
});
|
|
@@ -19,8 +19,9 @@ import { Entity } from '../../entity/decorators/entity.decorator';
|
|
|
19
19
|
import { Property } from '../../entity/decorators/property.decorator';
|
|
20
20
|
import { GlobalRegistry } from '../../global/global-registry';
|
|
21
21
|
import { Newable } from '../../types/newable.type';
|
|
22
|
+
import { OmitStrict } from '../../types/omit-strict.type';
|
|
22
23
|
import { Version } from '../../types/version.type';
|
|
23
|
-
import { PostgresDataSource, PostgresOptions } from '../data-sources/postgres-data-source.model';
|
|
24
|
+
import { PostgresDataSource, PostgresOptions } from '../data-sources/postgres-typeorm-data-source.model';
|
|
24
25
|
import { DataSource } from '../decorators/data-source.decorator';
|
|
25
26
|
import { Repository } from '../repository';
|
|
26
27
|
import { Transaction } from '../transaction/transaction.model';
|
|
@@ -33,7 +34,7 @@ class LegacyItem {
|
|
|
33
34
|
|
|
34
35
|
@DataSource()
|
|
35
36
|
class LegacyDbDataSource extends PostgresDataSource {
|
|
36
|
-
options: PostgresOptions = {
|
|
37
|
+
options: OmitStrict<PostgresOptions, 'type'> = {
|
|
37
38
|
host: 'localhost',
|
|
38
39
|
username: 'postgres',
|
|
39
40
|
password: 'password',
|
|
@@ -54,7 +55,7 @@ class Item {
|
|
|
54
55
|
|
|
55
56
|
@DataSource()
|
|
56
57
|
class DbDataSource extends PostgresDataSource {
|
|
57
|
-
options: PostgresOptions = {
|
|
58
|
+
options: OmitStrict<PostgresOptions, 'type'> = {
|
|
58
59
|
host: 'localhost',
|
|
59
60
|
username: 'postgres',
|
|
60
61
|
password: 'password',
|