@tstdl/base 0.93.182 → 0.93.184
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/api/server/api-request-token.provider.js +1 -1
- package/api/server/gateway.js +6 -1
- package/authentication/authentication.api.d.ts +13 -40
- package/authentication/authentication.api.js +5 -14
- package/authentication/client/authentication.service.d.ts +6 -14
- package/authentication/client/authentication.service.js +22 -4
- package/authentication/client/module.d.ts +1 -1
- package/authentication/client/module.js +4 -4
- package/authentication/models/index.d.ts +1 -0
- package/authentication/models/index.js +1 -0
- package/authentication/models/totp-results.model.d.ts +11 -0
- package/authentication/models/totp-results.model.js +37 -0
- package/authentication/server/authentication.api-controller.d.ts +3 -3
- package/authentication/server/authentication.api-controller.js +31 -4
- package/authentication/server/authentication.service.d.ts +5 -14
- package/authentication/server/authentication.service.js +6 -4
- package/core.d.ts +0 -5
- package/core.js +0 -8
- package/document-management/api/document-management.api.d.ts +2 -2
- package/document-management/service-models/document.service-model.d.ts +1 -1
- package/examples/config.d.ts +25 -0
- package/examples/config.js +26 -0
- package/notification/server/module.d.ts +1 -1
- package/notification/server/module.js +1 -1
- package/package.json +5 -5
- package/signals/api.d.ts +5 -1
- package/signals/api.js +3 -1
- package/signals/implementation/api.d.ts +10 -1
- package/signals/implementation/api.js +7 -1
- package/signals/implementation/asserts.d.ts +2 -2
- package/signals/implementation/asserts.js +3 -3
- package/signals/implementation/computed.d.ts +7 -34
- package/signals/implementation/computed.js +14 -83
- package/signals/implementation/configure.js +6 -2
- package/signals/implementation/effect.d.ts +65 -46
- package/signals/implementation/effect.js +97 -62
- package/signals/implementation/index.d.ts +2 -4
- package/signals/implementation/index.js +2 -4
- package/signals/implementation/linked_signal.d.ts +36 -0
- package/signals/implementation/linked_signal.js +34 -0
- package/signals/implementation/primitive/computed.d.ts +55 -0
- package/signals/implementation/primitive/computed.js +107 -0
- package/signals/implementation/primitive/effect.d.ts +26 -0
- package/signals/implementation/primitive/effect.js +31 -0
- package/signals/implementation/{equality.d.ts → primitive/equality.d.ts} +1 -1
- package/signals/implementation/{equality.js → primitive/equality.js} +1 -1
- package/signals/implementation/primitive/errors.d.ts +10 -0
- package/signals/implementation/{errors.js → primitive/errors.js} +3 -4
- package/signals/implementation/primitive/formatter.d.ts +19 -0
- package/signals/implementation/primitive/formatter.js +136 -0
- package/signals/implementation/{graph.d.ts → primitive/graph.d.ts} +68 -36
- package/signals/implementation/primitive/graph.js +386 -0
- package/signals/implementation/primitive/linked_signal.d.ts +46 -0
- package/signals/implementation/primitive/linked_signal.js +110 -0
- package/signals/implementation/primitive/signal.d.ts +31 -0
- package/signals/implementation/primitive/signal.js +80 -0
- package/signals/implementation/primitive/untracked.d.ts +12 -0
- package/signals/implementation/primitive/untracked.js +23 -0
- package/signals/implementation/{watch.d.ts → primitive/watch.d.ts} +1 -2
- package/signals/implementation/{watch.js → primitive/watch.js} +22 -16
- package/signals/implementation/resource/api.d.ts +275 -0
- package/signals/implementation/resource/api.js +26 -0
- package/signals/implementation/resource/debounce.d.ts +13 -0
- package/signals/implementation/resource/debounce.js +113 -0
- package/signals/implementation/resource/from_snapshots.d.ts +16 -0
- package/signals/implementation/resource/from_snapshots.js +44 -0
- package/signals/implementation/resource/index.d.ts +11 -0
- package/signals/implementation/resource/index.js +11 -0
- package/signals/implementation/resource/resource.d.ts +110 -0
- package/signals/implementation/resource/resource.js +402 -0
- package/signals/implementation/root_effect_scheduler.d.ts +50 -0
- package/signals/implementation/root_effect_scheduler.js +66 -0
- package/signals/implementation/signal.d.ts +42 -18
- package/signals/implementation/signal.js +29 -49
- package/signals/implementation/to-observable.d.ts +12 -5
- package/signals/implementation/to-observable.js +12 -2
- package/signals/implementation/to-signal.d.ts +9 -18
- package/signals/implementation/to-signal.js +46 -13
- package/signals/implementation/untracked.d.ts +1 -1
- package/signals/implementation/untracked.js +3 -11
- package/signals/operators/debounce.d.ts +8 -0
- package/signals/operators/debounce.js +19 -0
- package/signals/operators/derive-async.js +43 -15
- package/signals/operators/index.d.ts +2 -0
- package/signals/operators/index.js +2 -0
- package/signals/operators/throttle.d.ts +8 -0
- package/signals/operators/throttle.js +31 -0
- package/ai/genkit/tests/multi-region.test.d.ts +0 -2
- package/ai/genkit/tests/multi-region.test.js +0 -179
- package/ai/genkit/tests/token-limit-fallback.test.d.ts +0 -2
- package/ai/genkit/tests/token-limit-fallback.test.js +0 -209
- package/ai/prompts/tests/prompt-builder.test.d.ts +0 -1
- package/ai/prompts/tests/prompt-builder.test.js +0 -22
- package/ai/tests/instructions-formatter.test.d.ts +0 -1
- package/ai/tests/instructions-formatter.test.js +0 -116
- package/ai/tests/steering.test.d.ts +0 -1
- package/ai/tests/steering.test.js +0 -37
- package/api/client/tests/api-client.test.d.ts +0 -1
- package/api/client/tests/api-client.test.js +0 -194
- package/api/server/tests/csrf.middleware.test.d.ts +0 -1
- package/api/server/tests/csrf.middleware.test.js +0 -91
- package/authentication/tests/authentication-password-requirements.validator.test.d.ts +0 -1
- package/authentication/tests/authentication-password-requirements.validator.test.js +0 -29
- package/authentication/tests/authentication.api-controller.test.d.ts +0 -1
- package/authentication/tests/authentication.api-controller.test.js +0 -156
- package/authentication/tests/authentication.api-request-token.provider.test.d.ts +0 -1
- package/authentication/tests/authentication.api-request-token.provider.test.js +0 -48
- package/authentication/tests/authentication.client-error-handling.test.d.ts +0 -1
- package/authentication/tests/authentication.client-error-handling.test.js +0 -123
- package/authentication/tests/authentication.client-middleware.test.d.ts +0 -1
- package/authentication/tests/authentication.client-middleware.test.js +0 -118
- package/authentication/tests/authentication.client-service-methods.test.d.ts +0 -1
- package/authentication/tests/authentication.client-service-methods.test.js +0 -177
- package/authentication/tests/authentication.client-service-refresh.test.d.ts +0 -1
- package/authentication/tests/authentication.client-service-refresh.test.js +0 -153
- package/authentication/tests/authentication.client-service.test.d.ts +0 -1
- package/authentication/tests/authentication.client-service.test.js +0 -76
- package/authentication/tests/authentication.refresh-busy-loop.test.d.ts +0 -1
- package/authentication/tests/authentication.refresh-busy-loop.test.js +0 -84
- package/authentication/tests/authentication.service.test.d.ts +0 -1
- package/authentication/tests/authentication.service.test.js +0 -167
- package/authentication/tests/authentication.test-ancillary-service.d.ts +0 -9
- package/authentication/tests/authentication.test-ancillary-service.js +0 -27
- package/authentication/tests/brute-force-protection.test.d.ts +0 -1
- package/authentication/tests/brute-force-protection.test.js +0 -211
- package/authentication/tests/helper.test.d.ts +0 -1
- package/authentication/tests/helper.test.js +0 -122
- package/authentication/tests/password-requirements.error.test.d.ts +0 -1
- package/authentication/tests/password-requirements.error.test.js +0 -14
- package/authentication/tests/remember.api.test.d.ts +0 -1
- package/authentication/tests/remember.api.test.js +0 -117
- package/authentication/tests/remember.service.test.d.ts +0 -1
- package/authentication/tests/remember.service.test.js +0 -83
- package/authentication/tests/subject.service.test.d.ts +0 -1
- package/authentication/tests/subject.service.test.js +0 -140
- package/authentication/tests/suspended-subject.test.d.ts +0 -1
- package/authentication/tests/suspended-subject.test.js +0 -120
- package/authentication/tests/totp.enrollment.test.d.ts +0 -1
- package/authentication/tests/totp.enrollment.test.js +0 -123
- package/authentication/tests/totp.login.test.d.ts +0 -1
- package/authentication/tests/totp.login.test.js +0 -213
- package/authentication/tests/totp.recovery-codes.test.d.ts +0 -1
- package/authentication/tests/totp.recovery-codes.test.js +0 -97
- package/authentication/tests/totp.status.test.d.ts +0 -1
- package/authentication/tests/totp.status.test.js +0 -72
- package/cancellation/tests/coverage.test.d.ts +0 -1
- package/cancellation/tests/coverage.test.js +0 -49
- package/cancellation/tests/leak.test.d.ts +0 -1
- package/cancellation/tests/leak.test.js +0 -35
- package/cancellation/tests/token.test.d.ts +0 -1
- package/cancellation/tests/token.test.js +0 -136
- package/circuit-breaker/tests/circuit-breaker.test.d.ts +0 -1
- package/circuit-breaker/tests/circuit-breaker.test.js +0 -116
- package/cryptography/tests/cryptography.test.d.ts +0 -1
- package/cryptography/tests/cryptography.test.js +0 -175
- package/cryptography/tests/jwt.test.d.ts +0 -1
- package/cryptography/tests/jwt.test.js +0 -54
- package/cryptography/tests/modern.test.d.ts +0 -1
- package/cryptography/tests/modern.test.js +0 -105
- package/cryptography/tests/module.test.d.ts +0 -1
- package/cryptography/tests/module.test.js +0 -100
- package/cryptography/tests/totp.test.d.ts +0 -1
- package/cryptography/tests/totp.test.js +0 -108
- package/document-management/tests/ai-config-hierarchy.test.d.ts +0 -1
- package/document-management/tests/ai-config-hierarchy.test.js +0 -59
- package/document-management/tests/ai-config-integration.test.d.ts +0 -1
- package/document-management/tests/ai-config-integration.test.js +0 -125
- package/document-management/tests/ai-config-merge.test.d.ts +0 -1
- package/document-management/tests/ai-config-merge.test.js +0 -46
- package/document-management/tests/document-management-ai-overrides.test.d.ts +0 -1
- package/document-management/tests/document-management-ai-overrides.test.js +0 -63
- package/document-management/tests/document-management-core.test.d.ts +0 -1
- package/document-management/tests/document-management-core.test.js +0 -157
- package/document-management/tests/document-management.api.test.d.ts +0 -1
- package/document-management/tests/document-management.api.test.js +0 -101
- package/document-management/tests/document-statistics.service.test.d.ts +0 -1
- package/document-management/tests/document-statistics.service.test.js +0 -498
- package/document-management/tests/document-validation-ai-overrides.test.d.ts +0 -1
- package/document-management/tests/document-validation-ai-overrides.test.js +0 -87
- package/document-management/tests/document.service.test.d.ts +0 -1
- package/document-management/tests/document.service.test.js +0 -143
- package/document-management/tests/enum-helpers.test.d.ts +0 -1
- package/document-management/tests/enum-helpers.test.js +0 -452
- package/document-management/tests/helper.d.ts +0 -24
- package/document-management/tests/helper.js +0 -39
- package/errors/tests/format.test.d.ts +0 -1
- package/errors/tests/format.test.js +0 -84
- package/http/tests/server-timing.test.d.ts +0 -1
- package/http/tests/server-timing.test.js +0 -42
- package/injector/tests/advanced.test.d.ts +0 -1
- package/injector/tests/advanced.test.js +0 -116
- package/injector/tests/async-init.test.d.ts +0 -1
- package/injector/tests/async-init.test.js +0 -77
- package/injector/tests/basic.test.d.ts +0 -1
- package/injector/tests/basic.test.js +0 -114
- package/injector/tests/hierarchical.test.d.ts +0 -1
- package/injector/tests/hierarchical.test.js +0 -59
- package/injector/tests/leak.test.d.ts +0 -1
- package/injector/tests/leak.test.js +0 -45
- package/injector/tests/lifecycles.test.d.ts +0 -1
- package/injector/tests/lifecycles.test.js +0 -109
- package/logger/tests/pretty-print.test.d.ts +0 -1
- package/logger/tests/pretty-print.test.js +0 -60
- package/notification/tests/notification-api.test.d.ts +0 -1
- package/notification/tests/notification-api.test.js +0 -124
- package/notification/tests/notification-client.test.d.ts +0 -1
- package/notification/tests/notification-client.test.js +0 -101
- package/notification/tests/notification-flow.test.d.ts +0 -1
- package/notification/tests/notification-flow.test.js +0 -296
- package/notification/tests/notification-sse.service.test.d.ts +0 -1
- package/notification/tests/notification-sse.service.test.js +0 -43
- package/notification/tests/notification-type.service.test.d.ts +0 -1
- package/notification/tests/notification-type.service.test.js +0 -41
- package/object-storage/s3/tests/s3.object-storage.integration.test.d.ts +0 -1
- package/object-storage/s3/tests/s3.object-storage.integration.test.js +0 -303
- package/orm/tests/build-jsonb.test.d.ts +0 -1
- package/orm/tests/build-jsonb.test.js +0 -39
- package/orm/tests/data-types.test.d.ts +0 -1
- package/orm/tests/data-types.test.js +0 -39
- package/orm/tests/database-extension.test.d.ts +0 -1
- package/orm/tests/database-extension.test.js +0 -63
- package/orm/tests/database-migration.test.d.ts +0 -1
- package/orm/tests/database-migration.test.js +0 -83
- package/orm/tests/decorators.test.d.ts +0 -1
- package/orm/tests/decorators.test.js +0 -77
- package/orm/tests/encryption.test.d.ts +0 -1
- package/orm/tests/encryption.test.js +0 -31
- package/orm/tests/query-complex.test.d.ts +0 -1
- package/orm/tests/query-complex.test.js +0 -172
- package/orm/tests/query-converter-complex.test.d.ts +0 -1
- package/orm/tests/query-converter-complex.test.js +0 -131
- package/orm/tests/query-converter.test.d.ts +0 -1
- package/orm/tests/query-converter.test.js +0 -123
- package/orm/tests/repository-advanced.test.d.ts +0 -1
- package/orm/tests/repository-advanced.test.js +0 -189
- package/orm/tests/repository-attributes.test.d.ts +0 -1
- package/orm/tests/repository-attributes.test.js +0 -83
- package/orm/tests/repository-compound-primary-key.test.d.ts +0 -2
- package/orm/tests/repository-compound-primary-key.test.js +0 -226
- package/orm/tests/repository-comprehensive.test.d.ts +0 -1
- package/orm/tests/repository-comprehensive.test.js +0 -162
- package/orm/tests/repository-coverage.test.d.ts +0 -2
- package/orm/tests/repository-coverage.test.js +0 -242
- package/orm/tests/repository-cti-complex.test.d.ts +0 -1
- package/orm/tests/repository-cti-complex.test.js +0 -151
- package/orm/tests/repository-cti-embedded.test.d.ts +0 -1
- package/orm/tests/repository-cti-embedded.test.js +0 -178
- package/orm/tests/repository-cti-extensive.test.d.ts +0 -2
- package/orm/tests/repository-cti-extensive.test.js +0 -279
- package/orm/tests/repository-cti-mapping.test.d.ts +0 -2
- package/orm/tests/repository-cti-mapping.test.js +0 -108
- package/orm/tests/repository-cti-search.test.d.ts +0 -1
- package/orm/tests/repository-cti-search.test.js +0 -141
- package/orm/tests/repository-cti-soft-delete.test.d.ts +0 -2
- package/orm/tests/repository-cti-soft-delete.test.js +0 -103
- package/orm/tests/repository-cti-transactions.test.d.ts +0 -1
- package/orm/tests/repository-cti-transactions.test.js +0 -112
- package/orm/tests/repository-cti-upsert-many.test.d.ts +0 -2
- package/orm/tests/repository-cti-upsert-many.test.js +0 -115
- package/orm/tests/repository-cti.test.d.ts +0 -2
- package/orm/tests/repository-cti.test.js +0 -390
- package/orm/tests/repository-edge-cases.test.d.ts +0 -1
- package/orm/tests/repository-edge-cases.test.js +0 -178
- package/orm/tests/repository-expiration.test.d.ts +0 -2
- package/orm/tests/repository-expiration.test.js +0 -140
- package/orm/tests/repository-extra-coverage.test.d.ts +0 -2
- package/orm/tests/repository-extra-coverage.test.js +0 -402
- package/orm/tests/repository-mapping.test.d.ts +0 -2
- package/orm/tests/repository-mapping.test.js +0 -65
- package/orm/tests/repository-regression.test.d.ts +0 -1
- package/orm/tests/repository-regression.test.js +0 -288
- package/orm/tests/repository-search-coverage.test.d.ts +0 -1
- package/orm/tests/repository-search-coverage.test.js +0 -107
- package/orm/tests/repository-search.test.d.ts +0 -1
- package/orm/tests/repository-search.test.js +0 -105
- package/orm/tests/repository-soft-delete.test.d.ts +0 -1
- package/orm/tests/repository-soft-delete.test.js +0 -118
- package/orm/tests/repository-transactions-nested.test.d.ts +0 -1
- package/orm/tests/repository-transactions-nested.test.js +0 -178
- package/orm/tests/repository-types.test.d.ts +0 -1
- package/orm/tests/repository-types.test.js +0 -184
- package/orm/tests/repository-undelete.test.d.ts +0 -2
- package/orm/tests/repository-undelete.test.js +0 -201
- package/orm/tests/schema-converter.test.d.ts +0 -1
- package/orm/tests/schema-converter.test.js +0 -82
- package/orm/tests/schema-generation.test.d.ts +0 -2
- package/orm/tests/schema-generation.test.js +0 -174
- package/orm/tests/sql-helpers.test.d.ts +0 -1
- package/orm/tests/sql-helpers.test.js +0 -67
- package/orm/tests/transaction-safety.test.d.ts +0 -1
- package/orm/tests/transaction-safety.test.js +0 -81
- package/orm/tests/transactional.test.d.ts +0 -1
- package/orm/tests/transactional.test.js +0 -215
- package/orm/tests/utils.test.d.ts +0 -1
- package/orm/tests/utils.test.js +0 -70
- package/pdf/tests/utils.test.d.ts +0 -1
- package/pdf/tests/utils.test.js +0 -187
- package/process/tests/spawn.test.d.ts +0 -1
- package/process/tests/spawn.test.js +0 -182
- package/rate-limit/tests/postgres-rate-limiter.test.d.ts +0 -1
- package/rate-limit/tests/postgres-rate-limiter.test.js +0 -84
- package/renderer/tests/renderer.test.d.ts +0 -1
- package/renderer/tests/renderer.test.js +0 -88
- package/rpc/tests/rpc.integration.test.d.ts +0 -1
- package/rpc/tests/rpc.integration.test.js +0 -615
- package/signals/implementation/errors.d.ts +0 -2
- package/signals/implementation/graph.js +0 -312
- package/signals/implementation/writable-signal.d.ts +0 -48
- package/signals/implementation/writable-signal.js +0 -32
- package/task-queue/tests/coverage-branch.test.d.ts +0 -1
- package/task-queue/tests/coverage-branch.test.js +0 -395
- package/task-queue/tests/coverage-enhancement.test.d.ts +0 -1
- package/task-queue/tests/coverage-enhancement.test.js +0 -150
- package/task-queue/tests/dag.test.d.ts +0 -1
- package/task-queue/tests/dag.test.js +0 -188
- package/task-queue/tests/dependencies.test.d.ts +0 -1
- package/task-queue/tests/dependencies.test.js +0 -296
- package/task-queue/tests/enqueue-batch.test.d.ts +0 -1
- package/task-queue/tests/enqueue-batch.test.js +0 -125
- package/task-queue/tests/enqueue-item.test.d.ts +0 -1
- package/task-queue/tests/enqueue-item.test.js +0 -12
- package/task-queue/tests/fan-out-spawning.test.d.ts +0 -1
- package/task-queue/tests/fan-out-spawning.test.js +0 -94
- package/task-queue/tests/idempotent-replacement.test.d.ts +0 -1
- package/task-queue/tests/idempotent-replacement.test.js +0 -114
- package/task-queue/tests/missing-idempotent-tasks.test.d.ts +0 -1
- package/task-queue/tests/missing-idempotent-tasks.test.js +0 -39
- package/task-queue/tests/optimization-edge-cases.test.d.ts +0 -1
- package/task-queue/tests/optimization-edge-cases.test.js +0 -124
- package/task-queue/tests/queue-generic.test.d.ts +0 -1
- package/task-queue/tests/queue-generic.test.js +0 -8
- package/task-queue/tests/queue.test.d.ts +0 -1
- package/task-queue/tests/queue.test.js +0 -756
- package/task-queue/tests/shutdown.test.d.ts +0 -1
- package/task-queue/tests/shutdown.test.js +0 -41
- package/task-queue/tests/task-context.test.d.ts +0 -1
- package/task-queue/tests/task-context.test.js +0 -7
- package/task-queue/tests/task-union.test.d.ts +0 -1
- package/task-queue/tests/task-union.test.js +0 -18
- package/task-queue/tests/transactions.test.d.ts +0 -1
- package/task-queue/tests/transactions.test.js +0 -47
- package/task-queue/tests/typing.test.d.ts +0 -1
- package/task-queue/tests/typing.test.js +0 -9
- package/task-queue/tests/worker.test.d.ts +0 -1
- package/task-queue/tests/worker.test.js +0 -258
- package/task-queue/tests/zombie-parent.test.d.ts +0 -1
- package/task-queue/tests/zombie-parent.test.js +0 -45
- package/task-queue/tests/zombie-recovery.test.d.ts +0 -1
- package/task-queue/tests/zombie-recovery.test.js +0 -51
- package/utils/tests/backoff.test.d.ts +0 -1
- package/utils/tests/backoff.test.js +0 -41
- package/utils/tests/retry-with-backoff.test.d.ts +0 -1
- package/utils/tests/retry-with-backoff.test.js +0 -49
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
-
};
|
|
7
|
-
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
-
};
|
|
10
|
-
import { sql } from 'drizzle-orm';
|
|
11
|
-
import { beforeAll, describe, expect, test } from 'vitest';
|
|
12
|
-
import { Singleton } from '../../injector/decorators.js';
|
|
13
|
-
import { StringProperty } from '../../schema/index.js';
|
|
14
|
-
import { setupIntegrationTest } from '../../testing/index.js';
|
|
15
|
-
import { ChildEntity, Column, Inheritance, Table } from '../decorators.js';
|
|
16
|
-
import { Entity } from '../entity.js';
|
|
17
|
-
import { getRepository } from '../server/repository.js';
|
|
18
|
-
import { Transactional } from '../server/transactional.js';
|
|
19
|
-
describe('ORM Repository CTI Transactions (Integration)', () => {
|
|
20
|
-
let injector;
|
|
21
|
-
let db;
|
|
22
|
-
let service;
|
|
23
|
-
const schema = 'test_orm_cti_transactions';
|
|
24
|
-
let Parent = class Parent extends Entity {
|
|
25
|
-
type;
|
|
26
|
-
name;
|
|
27
|
-
};
|
|
28
|
-
__decorate([
|
|
29
|
-
StringProperty(),
|
|
30
|
-
Column({ name: 'type' }),
|
|
31
|
-
__metadata("design:type", String)
|
|
32
|
-
], Parent.prototype, "type", void 0);
|
|
33
|
-
__decorate([
|
|
34
|
-
StringProperty(),
|
|
35
|
-
__metadata("design:type", String)
|
|
36
|
-
], Parent.prototype, "name", void 0);
|
|
37
|
-
Parent = __decorate([
|
|
38
|
-
Table('parents', { schema }),
|
|
39
|
-
Inheritance({ strategy: 'joined', discriminatorColumn: 'type' })
|
|
40
|
-
], Parent);
|
|
41
|
-
let Child = class Child extends Parent {
|
|
42
|
-
childData;
|
|
43
|
-
};
|
|
44
|
-
__decorate([
|
|
45
|
-
StringProperty(),
|
|
46
|
-
__metadata("design:type", String)
|
|
47
|
-
], Child.prototype, "childData", void 0);
|
|
48
|
-
Child = __decorate([
|
|
49
|
-
Table('children', { schema }),
|
|
50
|
-
ChildEntity('child')
|
|
51
|
-
], Child);
|
|
52
|
-
let TestService = class TestService extends Transactional {
|
|
53
|
-
#childRepo = getRepository(Child);
|
|
54
|
-
async createTwo(name1, name2, failSecond) {
|
|
55
|
-
await this.transaction(async (tx) => {
|
|
56
|
-
const repo = injector.resolve(this.#childRepo).withTransaction(tx);
|
|
57
|
-
await repo.insert(Object.assign(new Child(), { name: name1, childData: 'data1' }));
|
|
58
|
-
if (failSecond) {
|
|
59
|
-
throw new Error('Planned failure');
|
|
60
|
-
}
|
|
61
|
-
await repo.insert(Object.assign(new Child(), { name: name2, childData: 'data2' }));
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
TestService = __decorate([
|
|
66
|
-
Singleton()
|
|
67
|
-
], TestService);
|
|
68
|
-
beforeAll(async () => {
|
|
69
|
-
({ injector, database: db } = await setupIntegrationTest({
|
|
70
|
-
orm: { schema },
|
|
71
|
-
}));
|
|
72
|
-
service = injector.resolve(TestService);
|
|
73
|
-
await db.execute(sql `CREATE SCHEMA IF NOT EXISTS ${sql.identifier(schema)}`);
|
|
74
|
-
await db.execute(sql `DROP TABLE IF EXISTS ${sql.identifier(schema)}.${sql.identifier('children')} CASCADE`);
|
|
75
|
-
await db.execute(sql `DROP TABLE IF EXISTS ${sql.identifier(schema)}.${sql.identifier('parents')} CASCADE`);
|
|
76
|
-
await db.execute(sql `
|
|
77
|
-
CREATE TABLE ${sql.identifier(schema)}.${sql.identifier('parents')} (
|
|
78
|
-
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
79
|
-
type TEXT NOT NULL,
|
|
80
|
-
name TEXT NOT NULL,
|
|
81
|
-
revision INTEGER NOT NULL,
|
|
82
|
-
revision_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
83
|
-
create_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
84
|
-
delete_timestamp TIMESTAMP WITH TIME ZONE,
|
|
85
|
-
attributes JSONB NOT NULL DEFAULT '{}',
|
|
86
|
-
UNIQUE (id, type)
|
|
87
|
-
)
|
|
88
|
-
`);
|
|
89
|
-
await db.execute(sql `
|
|
90
|
-
CREATE TABLE ${sql.identifier(schema)}.${sql.identifier('children')} (
|
|
91
|
-
id UUID PRIMARY KEY,
|
|
92
|
-
type TEXT NOT NULL CHECK (type = 'child'),
|
|
93
|
-
child_data TEXT NOT NULL,
|
|
94
|
-
FOREIGN KEY (id, type) REFERENCES ${sql.identifier(schema)}.${sql.identifier('parents')} (id, type) ON DELETE CASCADE
|
|
95
|
-
)
|
|
96
|
-
`);
|
|
97
|
-
});
|
|
98
|
-
test('should rollback inheritance inserts across multiple tables on service error', async () => {
|
|
99
|
-
await expect(service.createTwo('ShouldRollback', 'Fails', true)).rejects.toThrow('Planned failure');
|
|
100
|
-
const { rows: parentRows } = await db.execute(sql `SELECT * FROM ${sql.identifier(schema)}.${sql.identifier('parents')}`);
|
|
101
|
-
const { rows: childRows } = await db.execute(sql `SELECT * FROM ${sql.identifier(schema)}.${sql.identifier('children')}`);
|
|
102
|
-
expect(parentRows).toHaveLength(0);
|
|
103
|
-
expect(childRows).toHaveLength(0);
|
|
104
|
-
});
|
|
105
|
-
test('should commit inheritance inserts across multiple tables on success', async () => {
|
|
106
|
-
await service.createTwo('C1', 'C2', false);
|
|
107
|
-
const { rows: parentRows } = await db.execute(sql `SELECT * FROM ${sql.identifier(schema)}.${sql.identifier('parents')}`);
|
|
108
|
-
const { rows: childRows } = await db.execute(sql `SELECT * FROM ${sql.identifier(schema)}.${sql.identifier('children')}`);
|
|
109
|
-
expect(parentRows).toHaveLength(2);
|
|
110
|
-
expect(childRows).toHaveLength(2);
|
|
111
|
-
});
|
|
112
|
-
});
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
/** biome-ignore-all lint/nursery/noExcessiveClassesPerFile: <explanation> */
|
|
2
|
-
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
-
};
|
|
8
|
-
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
-
};
|
|
11
|
-
import { sql } from 'drizzle-orm';
|
|
12
|
-
import { beforeAll, describe, expect, test } from 'vitest';
|
|
13
|
-
import { StringProperty } from '../../schema/index.js';
|
|
14
|
-
import { setupIntegrationTest } from '../../testing/index.js';
|
|
15
|
-
import { ChildEntity, Column, Inheritance, Table } from '../decorators.js';
|
|
16
|
-
import { Entity } from '../entity.js';
|
|
17
|
-
import { getRepository } from '../server/index.js';
|
|
18
|
-
describe('ORM Repository CTI UpsertMany (Integration)', () => {
|
|
19
|
-
let injector;
|
|
20
|
-
let db;
|
|
21
|
-
let itemRepo;
|
|
22
|
-
let bookRepo;
|
|
23
|
-
const schema = 'test_orm_cti_upsert_many';
|
|
24
|
-
let Item = class Item extends Entity {
|
|
25
|
-
type;
|
|
26
|
-
title;
|
|
27
|
-
};
|
|
28
|
-
__decorate([
|
|
29
|
-
StringProperty(),
|
|
30
|
-
Column({ name: 'type' }),
|
|
31
|
-
__metadata("design:type", String)
|
|
32
|
-
], Item.prototype, "type", void 0);
|
|
33
|
-
__decorate([
|
|
34
|
-
StringProperty(),
|
|
35
|
-
__metadata("design:type", String)
|
|
36
|
-
], Item.prototype, "title", void 0);
|
|
37
|
-
Item = __decorate([
|
|
38
|
-
Table('items', { schema }),
|
|
39
|
-
Inheritance({ strategy: 'joined', discriminatorColumn: 'type' })
|
|
40
|
-
], Item);
|
|
41
|
-
let Book = class Book extends Item {
|
|
42
|
-
author;
|
|
43
|
-
};
|
|
44
|
-
__decorate([
|
|
45
|
-
StringProperty(),
|
|
46
|
-
__metadata("design:type", String)
|
|
47
|
-
], Book.prototype, "author", void 0);
|
|
48
|
-
Book = __decorate([
|
|
49
|
-
Table('books', { schema }),
|
|
50
|
-
ChildEntity('book')
|
|
51
|
-
], Book);
|
|
52
|
-
beforeAll(async () => {
|
|
53
|
-
({ injector, database: db } = await setupIntegrationTest({
|
|
54
|
-
orm: { schema },
|
|
55
|
-
}));
|
|
56
|
-
itemRepo = injector.resolve(getRepository(Item));
|
|
57
|
-
bookRepo = injector.resolve(getRepository(Book));
|
|
58
|
-
await db.execute(sql `CREATE SCHEMA IF NOT EXISTS ${sql.identifier(schema)}`);
|
|
59
|
-
await db.execute(sql `DROP TABLE IF EXISTS ${sql.identifier(schema)}.${sql.identifier('books')} CASCADE`);
|
|
60
|
-
await db.execute(sql `DROP TABLE IF EXISTS ${sql.identifier(schema)}.${sql.identifier('items')} CASCADE`);
|
|
61
|
-
await db.execute(sql `
|
|
62
|
-
CREATE TABLE ${sql.identifier(schema)}.${sql.identifier('items')} (
|
|
63
|
-
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
64
|
-
type TEXT NOT NULL,
|
|
65
|
-
title TEXT NOT NULL,
|
|
66
|
-
revision INTEGER NOT NULL,
|
|
67
|
-
revision_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
68
|
-
create_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
69
|
-
delete_timestamp TIMESTAMP WITH TIME ZONE,
|
|
70
|
-
attributes JSONB NOT NULL DEFAULT '{}',
|
|
71
|
-
UNIQUE (id, type)
|
|
72
|
-
)
|
|
73
|
-
`);
|
|
74
|
-
await db.execute(sql `
|
|
75
|
-
CREATE TABLE ${sql.identifier(schema)}.${sql.identifier('books')} (
|
|
76
|
-
id UUID PRIMARY KEY,
|
|
77
|
-
type TEXT NOT NULL CHECK (type = 'book'),
|
|
78
|
-
author TEXT NOT NULL,
|
|
79
|
-
FOREIGN KEY (id, type) REFERENCES ${sql.identifier(schema)}.${sql.identifier('items')} (id, type) ON DELETE CASCADE
|
|
80
|
-
)
|
|
81
|
-
`);
|
|
82
|
-
});
|
|
83
|
-
test('should upsertMany child entities (insert and update mixed)', async () => {
|
|
84
|
-
// 1. Insert initial books
|
|
85
|
-
const book1 = Object.assign(new Book(), { title: 'Book 1', author: 'Author 1' });
|
|
86
|
-
const book2 = Object.assign(new Book(), { title: 'Book 2', author: 'Author 2' });
|
|
87
|
-
const [inserted1, inserted2] = await bookRepo.insertMany([book1, book2]);
|
|
88
|
-
// 2. Prepare upsert payload: update book1, new book3
|
|
89
|
-
const update1 = Object.assign(new Book(), { id: inserted1.id, title: 'Book 1 Updated', author: 'Author 1 Updated' });
|
|
90
|
-
const book3 = Object.assign(new Book(), { title: 'Book 3', author: 'Author 3' });
|
|
91
|
-
const results = await bookRepo.upsertMany('id', [update1, book3]);
|
|
92
|
-
expect(results).toHaveLength(2);
|
|
93
|
-
const updated1 = results.find((b) => b.id === inserted1.id);
|
|
94
|
-
const inserted3 = results.find((b) => b.title === 'Book 3');
|
|
95
|
-
expect(updated1).toBeDefined();
|
|
96
|
-
expect(updated1.title).toBe('Book 1 Updated');
|
|
97
|
-
expect(updated1.author).toBe('Author 1 Updated');
|
|
98
|
-
expect(inserted3).toBeDefined();
|
|
99
|
-
expect(inserted3.id).toBeDefined();
|
|
100
|
-
expect(inserted3.author).toBe('Author 3');
|
|
101
|
-
// Verify book2 is untouched
|
|
102
|
-
const loaded2 = await bookRepo.load(inserted2.id);
|
|
103
|
-
expect(loaded2.title).toBe('Book 2');
|
|
104
|
-
});
|
|
105
|
-
test('should polymorphic tryLoadByQuery', async () => {
|
|
106
|
-
await bookRepo.insert(Object.assign(new Book(), { title: 'Unique Book', author: 'Unique Author' }));
|
|
107
|
-
// Load via Item repo using a book-specific property (should fail if not joined, but here we query by title)
|
|
108
|
-
// Querying by book-specific property requires casting query or using raw sql if repository type doesn't have it.
|
|
109
|
-
// But we can query by base property 'title'.
|
|
110
|
-
const loaded = await itemRepo.tryLoadByQuery({ title: 'Unique Book' }, { includeSubclasses: true });
|
|
111
|
-
expect(loaded).toBeDefined();
|
|
112
|
-
expect(loaded).toBeInstanceOf(Book);
|
|
113
|
-
expect(loaded.author).toBe('Unique Author');
|
|
114
|
-
});
|
|
115
|
-
});
|
|
@@ -1,390 +0,0 @@
|
|
|
1
|
-
/** biome-ignore-all lint/nursery/noExcessiveClassesPerFile: <explanation> */
|
|
2
|
-
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
-
};
|
|
8
|
-
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
-
};
|
|
11
|
-
import { sql } from 'drizzle-orm';
|
|
12
|
-
import { beforeAll, beforeEach, describe, expect, test } from 'vitest';
|
|
13
|
-
import { StringProperty } from '../../schema/index.js';
|
|
14
|
-
import { dropTables, setupIntegrationTest, truncateTables } from '../../testing/index.js';
|
|
15
|
-
import { ChildEntity, Column, Inheritance, Table } from '../decorators.js';
|
|
16
|
-
import { Entity } from '../entity.js';
|
|
17
|
-
import { getRepository } from '../server/index.js';
|
|
18
|
-
describe('ORM Repository CTI (Integration)', () => {
|
|
19
|
-
let injector;
|
|
20
|
-
let database;
|
|
21
|
-
let adminRepository;
|
|
22
|
-
let guestRepository;
|
|
23
|
-
let userRepository;
|
|
24
|
-
let managerRepository;
|
|
25
|
-
const schema = 'test_orm_cti';
|
|
26
|
-
let BaseUser = class BaseUser extends Entity {
|
|
27
|
-
type;
|
|
28
|
-
name;
|
|
29
|
-
};
|
|
30
|
-
__decorate([
|
|
31
|
-
StringProperty(),
|
|
32
|
-
Column({ name: 'type' }),
|
|
33
|
-
__metadata("design:type", String)
|
|
34
|
-
], BaseUser.prototype, "type", void 0);
|
|
35
|
-
__decorate([
|
|
36
|
-
StringProperty(),
|
|
37
|
-
Column({ name: 'name' }),
|
|
38
|
-
__metadata("design:type", String)
|
|
39
|
-
], BaseUser.prototype, "name", void 0);
|
|
40
|
-
BaseUser = __decorate([
|
|
41
|
-
Table('users', { schema }),
|
|
42
|
-
Inheritance({ strategy: 'joined', discriminatorColumn: 'type' })
|
|
43
|
-
], BaseUser);
|
|
44
|
-
let Admin = class Admin extends BaseUser {
|
|
45
|
-
role;
|
|
46
|
-
};
|
|
47
|
-
__decorate([
|
|
48
|
-
StringProperty(),
|
|
49
|
-
Column({ name: 'role' }),
|
|
50
|
-
__metadata("design:type", String)
|
|
51
|
-
], Admin.prototype, "role", void 0);
|
|
52
|
-
Admin = __decorate([
|
|
53
|
-
Table('admins', { schema }),
|
|
54
|
-
ChildEntity('admin')
|
|
55
|
-
], Admin);
|
|
56
|
-
let Guest = class Guest extends BaseUser {
|
|
57
|
-
permissions;
|
|
58
|
-
};
|
|
59
|
-
__decorate([
|
|
60
|
-
StringProperty(),
|
|
61
|
-
Column({ name: 'permissions' }),
|
|
62
|
-
__metadata("design:type", String)
|
|
63
|
-
], Guest.prototype, "permissions", void 0);
|
|
64
|
-
Guest = __decorate([
|
|
65
|
-
Table('guests', { schema }),
|
|
66
|
-
ChildEntity('guest')
|
|
67
|
-
], Guest);
|
|
68
|
-
let Staff = class Staff extends BaseUser {
|
|
69
|
-
employeeId;
|
|
70
|
-
};
|
|
71
|
-
__decorate([
|
|
72
|
-
StringProperty(),
|
|
73
|
-
Column({ name: 'employee_id' }),
|
|
74
|
-
__metadata("design:type", String)
|
|
75
|
-
], Staff.prototype, "employeeId", void 0);
|
|
76
|
-
Staff = __decorate([
|
|
77
|
-
Table('staff', { schema }),
|
|
78
|
-
Inheritance({ strategy: 'joined' }),
|
|
79
|
-
ChildEntity('staff')
|
|
80
|
-
], Staff);
|
|
81
|
-
let Manager = class Manager extends Staff {
|
|
82
|
-
department;
|
|
83
|
-
};
|
|
84
|
-
__decorate([
|
|
85
|
-
StringProperty(),
|
|
86
|
-
Column({ name: 'department' }),
|
|
87
|
-
__metadata("design:type", String)
|
|
88
|
-
], Manager.prototype, "department", void 0);
|
|
89
|
-
Manager = __decorate([
|
|
90
|
-
Table('managers', { schema }),
|
|
91
|
-
ChildEntity('manager')
|
|
92
|
-
], Manager);
|
|
93
|
-
beforeAll(async () => {
|
|
94
|
-
({ injector, database } = await setupIntegrationTest({ orm: { schema } }));
|
|
95
|
-
adminRepository = injector.resolve(getRepository(Admin));
|
|
96
|
-
guestRepository = injector.resolve(getRepository(Guest));
|
|
97
|
-
userRepository = injector.resolve(getRepository(BaseUser));
|
|
98
|
-
managerRepository = injector.resolve(getRepository(Manager));
|
|
99
|
-
await database.execute(sql `CREATE SCHEMA IF NOT EXISTS ${sql.identifier(schema)}`);
|
|
100
|
-
await dropTables(database, schema, ['managers', 'staff', 'guests', 'admins', 'users']);
|
|
101
|
-
await database.execute(sql `
|
|
102
|
-
CREATE TABLE ${sql.identifier(schema)}.${sql.identifier('users')} (
|
|
103
|
-
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
104
|
-
type TEXT NOT NULL,
|
|
105
|
-
name TEXT NOT NULL,
|
|
106
|
-
revision INTEGER NOT NULL,
|
|
107
|
-
revision_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
108
|
-
create_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
109
|
-
delete_timestamp TIMESTAMP WITH TIME ZONE,
|
|
110
|
-
attributes JSONB NOT NULL DEFAULT '{}',
|
|
111
|
-
UNIQUE (id, type)
|
|
112
|
-
)
|
|
113
|
-
`);
|
|
114
|
-
await database.execute(sql `
|
|
115
|
-
CREATE TABLE ${sql.identifier(schema)}.${sql.identifier('admins')} (
|
|
116
|
-
id UUID PRIMARY KEY,
|
|
117
|
-
type TEXT NOT NULL CHECK (type = 'admin'),
|
|
118
|
-
role TEXT NOT NULL,
|
|
119
|
-
FOREIGN KEY (id, type) REFERENCES ${sql.identifier(schema)}.${sql.identifier('users')} (id, type) ON DELETE CASCADE
|
|
120
|
-
)
|
|
121
|
-
`);
|
|
122
|
-
await database.execute(sql `
|
|
123
|
-
CREATE TABLE ${sql.identifier(schema)}.${sql.identifier('guests')} (
|
|
124
|
-
id UUID PRIMARY KEY,
|
|
125
|
-
type TEXT NOT NULL CHECK (type = 'guest'),
|
|
126
|
-
permissions TEXT NOT NULL,
|
|
127
|
-
FOREIGN KEY (id, type) REFERENCES ${sql.identifier(schema)}.${sql.identifier('users')} (id, type) ON DELETE CASCADE
|
|
128
|
-
)
|
|
129
|
-
`);
|
|
130
|
-
await database.execute(sql `
|
|
131
|
-
CREATE TABLE ${sql.identifier(schema)}.${sql.identifier('staff')} (
|
|
132
|
-
id UUID PRIMARY KEY,
|
|
133
|
-
type TEXT NOT NULL,
|
|
134
|
-
employee_id TEXT NOT NULL,
|
|
135
|
-
UNIQUE (id, type),
|
|
136
|
-
FOREIGN KEY (id, type) REFERENCES ${sql.identifier(schema)}.${sql.identifier('users')} (id, type) ON DELETE CASCADE
|
|
137
|
-
)
|
|
138
|
-
`);
|
|
139
|
-
await database.execute(sql `
|
|
140
|
-
CREATE TABLE ${sql.identifier(schema)}.${sql.identifier('managers')} (
|
|
141
|
-
id UUID PRIMARY KEY,
|
|
142
|
-
type TEXT NOT NULL CHECK (type = 'manager'),
|
|
143
|
-
department TEXT NOT NULL,
|
|
144
|
-
FOREIGN KEY (id, type) REFERENCES ${sql.identifier(schema)}.${sql.identifier('staff')} (id, type) ON DELETE CASCADE
|
|
145
|
-
)
|
|
146
|
-
`);
|
|
147
|
-
});
|
|
148
|
-
beforeEach(async () => {
|
|
149
|
-
await truncateTables(database, schema, ['users']);
|
|
150
|
-
});
|
|
151
|
-
test('should insert into both parent and child tables', async () => {
|
|
152
|
-
const newAdmin = new Admin();
|
|
153
|
-
newAdmin.name = 'Alice';
|
|
154
|
-
newAdmin.role = 'SuperAdmin';
|
|
155
|
-
const inserted = await adminRepository.insert(newAdmin);
|
|
156
|
-
expect(inserted).toBeInstanceOf(Admin);
|
|
157
|
-
expect(inserted.id).toBeDefined();
|
|
158
|
-
expect(inserted.name).toBe('Alice');
|
|
159
|
-
expect(inserted.role).toBe('SuperAdmin');
|
|
160
|
-
expect(inserted.type).toBe('admin');
|
|
161
|
-
expect(inserted.metadata.revision).toBe(1);
|
|
162
|
-
// Verify DB state
|
|
163
|
-
const { rows: [userRow] } = await database.execute(sql `SELECT * FROM ${sql.identifier(schema)}.${sql.identifier('users')} WHERE id = ${inserted.id}`);
|
|
164
|
-
expect(userRow).toBeDefined();
|
|
165
|
-
expect(userRow['type']).toBe('admin');
|
|
166
|
-
expect(userRow['name']).toBe('Alice');
|
|
167
|
-
expect(userRow['revision']).toBe(1);
|
|
168
|
-
const { rows: [adminRow] } = await database.execute(sql `SELECT * FROM ${sql.identifier(schema)}.${sql.identifier('admins')} WHERE id = ${inserted.id}`);
|
|
169
|
-
expect(adminRow).toBeDefined();
|
|
170
|
-
expect(adminRow['type']).toBe('admin');
|
|
171
|
-
expect(adminRow['role']).toBe('SuperAdmin');
|
|
172
|
-
});
|
|
173
|
-
test('should insert many into both parent and child tables', async () => {
|
|
174
|
-
const admins = [
|
|
175
|
-
Object.assign(new Admin(), { name: 'Bob', role: 'Admin' }),
|
|
176
|
-
Object.assign(new Admin(), { name: 'Charlie', role: 'Moderator' }),
|
|
177
|
-
];
|
|
178
|
-
const insertedAdmins = await adminRepository.insertMany(admins);
|
|
179
|
-
expect(insertedAdmins).toHaveLength(2);
|
|
180
|
-
expect(insertedAdmins[0].name).toBe('Bob');
|
|
181
|
-
expect(insertedAdmins[1].name).toBe('Charlie');
|
|
182
|
-
expect(insertedAdmins[0].type).toBe('admin');
|
|
183
|
-
expect(insertedAdmins[1].type).toBe('admin');
|
|
184
|
-
for (const inserted of insertedAdmins) {
|
|
185
|
-
const { rows: [userRow] } = await database.execute(sql `SELECT * FROM ${sql.identifier(schema)}.${sql.identifier('users')} WHERE id = ${inserted.id}`);
|
|
186
|
-
expect(userRow['name']).toBe(inserted.name);
|
|
187
|
-
const { rows: [adminRow] } = await database.execute(sql `SELECT * FROM ${sql.identifier(schema)}.${sql.identifier('admins')} WHERE id = ${inserted.id}`);
|
|
188
|
-
expect(adminRow['role']).toBe(inserted.role);
|
|
189
|
-
}
|
|
190
|
-
});
|
|
191
|
-
test('should update both parent and child tables', async () => {
|
|
192
|
-
const newAdmin = Object.assign(new Admin(), { name: 'Alice', role: 'SuperAdmin' });
|
|
193
|
-
const inserted = await adminRepository.insert(newAdmin);
|
|
194
|
-
const update = { name: 'Alice Updated', role: 'MegaAdmin' };
|
|
195
|
-
const updated = await adminRepository.update(inserted.id, update);
|
|
196
|
-
expect(updated.name).toBe('Alice Updated');
|
|
197
|
-
expect(updated.role).toBe('MegaAdmin');
|
|
198
|
-
expect(updated.metadata.revision).toBe(2);
|
|
199
|
-
// Verify DB state
|
|
200
|
-
const { rows: [userRow] } = await database.execute(sql `SELECT * FROM ${sql.identifier(schema)}.${sql.identifier('users')} WHERE id = ${inserted.id}`);
|
|
201
|
-
expect(userRow['name']).toBe('Alice Updated');
|
|
202
|
-
expect(userRow['revision']).toBe(2);
|
|
203
|
-
const { rows: [adminRow] } = await database.execute(sql `SELECT * FROM ${sql.identifier(schema)}.${sql.identifier('admins')} WHERE id = ${inserted.id}`);
|
|
204
|
-
expect(adminRow['role']).toBe('MegaAdmin');
|
|
205
|
-
});
|
|
206
|
-
test('should soft delete from parent table', async () => {
|
|
207
|
-
const newAdmin = Object.assign(new Admin(), { name: 'Alice', role: 'SuperAdmin' });
|
|
208
|
-
const inserted = await adminRepository.insert(newAdmin);
|
|
209
|
-
await adminRepository.delete(inserted.id);
|
|
210
|
-
// Verify DB state
|
|
211
|
-
const { rows: [userRow] } = await database.execute(sql `SELECT * FROM ${sql.identifier(schema)}.${sql.identifier('users')} WHERE id = ${inserted.id}`);
|
|
212
|
-
expect(userRow['delete_timestamp']).not.toBeNull();
|
|
213
|
-
// Child table should still have the row (soft delete only affects parent)
|
|
214
|
-
const { rows: [adminRow] } = await database.execute(sql `SELECT * FROM ${sql.identifier(schema)}.${sql.identifier('admins')} WHERE id = ${inserted.id}`);
|
|
215
|
-
expect(adminRow).toBeDefined();
|
|
216
|
-
});
|
|
217
|
-
test('should hard delete from both tables via cascade', async () => {
|
|
218
|
-
const newAdmin = Object.assign(new Admin(), { name: 'Alice', role: 'SuperAdmin' });
|
|
219
|
-
const inserted = await adminRepository.insert(newAdmin);
|
|
220
|
-
await adminRepository.hardDelete(inserted.id);
|
|
221
|
-
// Verify DB state
|
|
222
|
-
const { rows: userRows } = await database.execute(sql `SELECT * FROM ${sql.identifier(schema)}.${sql.identifier('users')} WHERE id = ${inserted.id}`);
|
|
223
|
-
expect(userRows).toHaveLength(0);
|
|
224
|
-
const { rows: adminRows } = await database.execute(sql `SELECT * FROM ${sql.identifier(schema)}.${sql.identifier('admins')} WHERE id = ${inserted.id}`);
|
|
225
|
-
expect(adminRows).toHaveLength(0);
|
|
226
|
-
});
|
|
227
|
-
test('should load entities polymorphically from parent repository', async () => {
|
|
228
|
-
await adminRepository.insert(Object.assign(new Admin(), { name: 'Admin1', role: 'Super' }));
|
|
229
|
-
await guestRepository.insert(Object.assign(new Guest(), { name: 'Guest1', permissions: 'Read' }));
|
|
230
|
-
// Load without subclasses (default)
|
|
231
|
-
const users = await userRepository.loadAll();
|
|
232
|
-
expect(users).toHaveLength(2);
|
|
233
|
-
expect(users[0]).toBeInstanceOf(BaseUser);
|
|
234
|
-
expect(users[1]).toBeInstanceOf(BaseUser);
|
|
235
|
-
expect(users[0].role).toBeUndefined();
|
|
236
|
-
// Load with subclasses
|
|
237
|
-
const polymorphicUsers = await userRepository.loadAll({ includeSubclasses: true });
|
|
238
|
-
expect(polymorphicUsers).toHaveLength(2);
|
|
239
|
-
const admin = polymorphicUsers.find((u) => u instanceof Admin);
|
|
240
|
-
const guest = polymorphicUsers.find((u) => u instanceof Guest);
|
|
241
|
-
expect(admin).toBeDefined();
|
|
242
|
-
expect(admin).toBeInstanceOf(Admin);
|
|
243
|
-
expect(admin.name).toBe('Admin1');
|
|
244
|
-
expect(admin.role).toBe('Super');
|
|
245
|
-
expect(guest).toBeDefined();
|
|
246
|
-
expect(guest).toBeInstanceOf(Guest);
|
|
247
|
-
expect(guest.name).toBe('Guest1');
|
|
248
|
-
expect(guest).toBeInstanceOf(Guest);
|
|
249
|
-
expect(guest.name).toBe('Guest1');
|
|
250
|
-
expect(guest.permissions).toBe('Read');
|
|
251
|
-
});
|
|
252
|
-
test('should load polymorphic subset from parent repository', async () => {
|
|
253
|
-
await adminRepository.insert(Object.assign(new Admin(), { name: 'Admin1', role: 'Super' }));
|
|
254
|
-
await guestRepository.insert(Object.assign(new Guest(), { name: 'Guest1', permissions: 'Read' }));
|
|
255
|
-
// Load ONLY Admins polymorphically
|
|
256
|
-
const onlyAdmins = await userRepository.loadManyByQuery({}, { includeSubclasses: [Admin] });
|
|
257
|
-
expect(onlyAdmins).toHaveLength(2); // Still returns all users from base table
|
|
258
|
-
const admin = onlyAdmins.find((u) => u instanceof Admin);
|
|
259
|
-
const guestAsBase = onlyAdmins.find((u) => u.name === 'Guest1');
|
|
260
|
-
expect(admin).toBeInstanceOf(Admin);
|
|
261
|
-
expect(admin.role).toBe('Super');
|
|
262
|
-
expect(guestAsBase).not.toBeInstanceOf(Guest);
|
|
263
|
-
expect(guestAsBase).toBeInstanceOf(BaseUser);
|
|
264
|
-
});
|
|
265
|
-
test('should count and check existence for child entities', async () => {
|
|
266
|
-
await adminRepository.insert(Object.assign(new Admin(), { name: 'Admin1', role: 'Super' }));
|
|
267
|
-
await adminRepository.insert(Object.assign(new Admin(), { name: 'Admin2', role: 'Normal' }));
|
|
268
|
-
await guestRepository.insert(Object.assign(new Guest(), { name: 'Guest1', permissions: 'Read' }));
|
|
269
|
-
expect(await adminRepository.count()).toBe(2);
|
|
270
|
-
expect(await guestRepository.count()).toBe(1);
|
|
271
|
-
const admins = await adminRepository.loadAll();
|
|
272
|
-
expect(await adminRepository.has(admins[0].id)).toBe(true);
|
|
273
|
-
expect(await adminRepository.hasByQuery({ name: 'Admin2' })).toBe(true);
|
|
274
|
-
expect(await adminRepository.hasByQuery({ name: 'Guest1' })).toBe(false); // Different table
|
|
275
|
-
});
|
|
276
|
-
test('should query child entities by parent fields', async () => {
|
|
277
|
-
await adminRepository.insert(Object.assign(new Admin(), { name: 'TargetAdmin', role: 'Super' }));
|
|
278
|
-
await adminRepository.insert(Object.assign(new Admin(), { name: 'OtherAdmin', role: 'Normal' }));
|
|
279
|
-
const results = await adminRepository.loadManyByQuery({ name: 'TargetAdmin' });
|
|
280
|
-
expect(results).toHaveLength(1);
|
|
281
|
-
expect(results[0].name).toBe('TargetAdmin');
|
|
282
|
-
expect(results[0].role).toBe('Super');
|
|
283
|
-
});
|
|
284
|
-
test('should perform partial updates on parent or child fields', async () => {
|
|
285
|
-
const inserted = await adminRepository.insert(Object.assign(new Admin(), { name: 'Alice', role: 'Super' }));
|
|
286
|
-
// Update only parent field
|
|
287
|
-
await adminRepository.update(inserted.id, { name: 'Alice Renamed' });
|
|
288
|
-
let updated = await adminRepository.load(inserted.id);
|
|
289
|
-
expect(updated.name).toBe('Alice Renamed');
|
|
290
|
-
expect(updated.role).toBe('Super');
|
|
291
|
-
// Update only child field
|
|
292
|
-
await adminRepository.update(inserted.id, { role: 'Demoted' });
|
|
293
|
-
updated = await adminRepository.load(inserted.id);
|
|
294
|
-
expect(updated.name).toBe('Alice Renamed');
|
|
295
|
-
expect(updated.role).toBe('Demoted');
|
|
296
|
-
});
|
|
297
|
-
test('should fail when violating discriminator check constraint', async () => {
|
|
298
|
-
// Attempt manual insert with mismatched type
|
|
299
|
-
const query = database.execute(sql `
|
|
300
|
-
INSERT INTO ${sql.identifier(schema)}.${sql.identifier('admins')} (id, type, role)
|
|
301
|
-
VALUES (gen_random_uuid(), 'guest', 'Invalid')
|
|
302
|
-
`);
|
|
303
|
-
await expect(query).rejects.toThrow();
|
|
304
|
-
});
|
|
305
|
-
test('should fail when violating composite foreign key', async () => {
|
|
306
|
-
// Insert user with type 'guest'
|
|
307
|
-
const userId = '00000000-0000-0000-0000-000000000001';
|
|
308
|
-
await database.execute(sql `
|
|
309
|
-
INSERT INTO ${sql.identifier(schema)}.${sql.identifier('users')} (id, type, name, revision, revision_timestamp, create_timestamp)
|
|
310
|
-
VALUES (${userId}, 'guest', 'Guest User', 1, now(), now())
|
|
311
|
-
`);
|
|
312
|
-
// Attempt to insert admin pointing to that user (mismatched type 'admin' vs 'guest')
|
|
313
|
-
const query = database.execute(sql `
|
|
314
|
-
INSERT INTO ${sql.identifier(schema)}.${sql.identifier('admins')} (id, type, role)
|
|
315
|
-
VALUES (${userId}, 'admin', 'Admin Role')
|
|
316
|
-
`);
|
|
317
|
-
await expect(query).rejects.toThrow();
|
|
318
|
-
});
|
|
319
|
-
test('should support nested inheritance', async () => {
|
|
320
|
-
const manager = new Manager();
|
|
321
|
-
manager.name = 'Big Boss';
|
|
322
|
-
manager.employeeId = 'EMP001';
|
|
323
|
-
manager.department = 'Executive';
|
|
324
|
-
const inserted = await managerRepository.insert(manager);
|
|
325
|
-
expect(inserted.name).toBe('Big Boss');
|
|
326
|
-
expect(inserted.employeeId).toBe('EMP001');
|
|
327
|
-
expect(inserted.department).toBe('Executive');
|
|
328
|
-
expect(inserted.type).toBe('manager');
|
|
329
|
-
// Verify DB state - all 3 tables should have rows
|
|
330
|
-
const { rows: [userRow] } = await database.execute(sql `SELECT * FROM ${sql.identifier(schema)}.${sql.identifier('users')} WHERE id = ${inserted.id}`);
|
|
331
|
-
expect(userRow['name']).toBe('Big Boss');
|
|
332
|
-
const { rows: [staffRow] } = await database.execute(sql `SELECT * FROM ${sql.identifier(schema)}.${sql.identifier('staff')} WHERE id = ${inserted.id}`);
|
|
333
|
-
expect(staffRow['employee_id']).toBe('EMP001');
|
|
334
|
-
const { rows: [managerRow] } = await database.execute(sql `SELECT * FROM ${sql.identifier(schema)}.${sql.identifier('managers')} WHERE id = ${inserted.id}`);
|
|
335
|
-
expect(managerRow['department']).toBe('Executive');
|
|
336
|
-
});
|
|
337
|
-
test('should rollback parent insert if child insert fails', async () => {
|
|
338
|
-
// Attempt to insert an admin with a missing role (should fail because of NOT NULL)
|
|
339
|
-
const invalidAdmin = new Admin();
|
|
340
|
-
invalidAdmin.name = 'Broken Admin';
|
|
341
|
-
// role is missing
|
|
342
|
-
await expect(adminRepository.insert(invalidAdmin)).rejects.toThrow();
|
|
343
|
-
// Verify that NO row was created in the users table
|
|
344
|
-
const { rows } = await database.execute(sql `SELECT * FROM ${sql.identifier(schema)}.${sql.identifier('users')}`);
|
|
345
|
-
expect(rows).toHaveLength(0);
|
|
346
|
-
});
|
|
347
|
-
test('should count and check existence polymorphically', async () => {
|
|
348
|
-
await adminRepository.insert(Object.assign(new Admin(), { name: 'A1', role: 'R1' }));
|
|
349
|
-
await guestRepository.insert(Object.assign(new Guest(), { name: 'G1', permissions: 'P1' }));
|
|
350
|
-
expect(await userRepository.count()).toBe(2);
|
|
351
|
-
expect(await userRepository.hasByQuery({ name: 'A1' })).toBe(true);
|
|
352
|
-
expect(await userRepository.hasByQuery({ name: 'G1' })).toBe(true);
|
|
353
|
-
});
|
|
354
|
-
test('should load many by IDs polymorphically', async () => {
|
|
355
|
-
const a1 = await adminRepository.insert(Object.assign(new Admin(), { name: 'A1', role: 'R1' }));
|
|
356
|
-
const g1 = await guestRepository.insert(Object.assign(new Guest(), { name: 'G1', permissions: 'P1' }));
|
|
357
|
-
const results = await userRepository.loadMany([a1.id, g1.id], { includeSubclasses: true });
|
|
358
|
-
expect(results).toHaveLength(2);
|
|
359
|
-
expect(results.find((u) => u.id === a1.id)).toBeInstanceOf(Admin);
|
|
360
|
-
expect(results.find((u) => u.id === g1.id)).toBeInstanceOf(Guest);
|
|
361
|
-
});
|
|
362
|
-
test('should update many child entities', async () => {
|
|
363
|
-
const a1 = await adminRepository.insert(Object.assign(new Admin(), { name: 'A1', role: 'Old' }));
|
|
364
|
-
const a2 = await adminRepository.insert(Object.assign(new Admin(), { name: 'A2', role: 'Old' }));
|
|
365
|
-
await adminRepository.updateMany([a1.id, a2.id], { role: 'New' });
|
|
366
|
-
const results = await adminRepository.loadMany([a1.id, a2.id]);
|
|
367
|
-
expect(results[0].role).toBe('New');
|
|
368
|
-
expect(results[1].role).toBe('New');
|
|
369
|
-
});
|
|
370
|
-
test('should update nested inheritance fields', async () => {
|
|
371
|
-
const manager = Object.assign(new Manager(), { name: 'Boss', employeeId: 'E1', department: 'D1' });
|
|
372
|
-
const inserted = await managerRepository.insert(manager);
|
|
373
|
-
await managerRepository.update(inserted.id, { name: 'New Boss', employeeId: 'E2', department: 'D2' });
|
|
374
|
-
const updated = await managerRepository.load(inserted.id);
|
|
375
|
-
expect(updated.name).toBe('New Boss');
|
|
376
|
-
expect(updated.employeeId).toBe('E2');
|
|
377
|
-
expect(updated.department).toBe('D2');
|
|
378
|
-
});
|
|
379
|
-
test('should delete from nested inheritance tables', async () => {
|
|
380
|
-
const manager = Object.assign(new Manager(), { name: 'Boss', employeeId: 'E1', department: 'D1' });
|
|
381
|
-
const inserted = await managerRepository.insert(manager);
|
|
382
|
-
await managerRepository.hardDelete(inserted.id);
|
|
383
|
-
const { rows: userRows } = await database.execute(sql `SELECT * FROM ${sql.identifier(schema)}.${sql.identifier('users')} WHERE id = ${inserted.id}`);
|
|
384
|
-
const { rows: staffRows } = await database.execute(sql `SELECT * FROM ${sql.identifier(schema)}.${sql.identifier('staff')} WHERE id = ${inserted.id}`);
|
|
385
|
-
const { rows: managerRows } = await database.execute(sql `SELECT * FROM ${sql.identifier(schema)}.${sql.identifier('managers')} WHERE id = ${inserted.id}`);
|
|
386
|
-
expect(userRows).toHaveLength(0);
|
|
387
|
-
expect(staffRows).toHaveLength(0);
|
|
388
|
-
expect(managerRows).toHaveLength(0);
|
|
389
|
-
});
|
|
390
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|