@tstdl/base 0.93.181 → 0.93.183
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 +8 -3
- 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 +13 -5
- 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,172 +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 { Integer, StringProperty } from '../../schema/index.js';
|
|
13
|
-
import { setupIntegrationTest } from '../../testing/index.js';
|
|
14
|
-
import { Table } from '../decorators.js';
|
|
15
|
-
import { Entity } from '../entity.js';
|
|
16
|
-
import { getRepository } from '../server/index.js';
|
|
17
|
-
describe('ORM Query Complex (Integration)', () => {
|
|
18
|
-
let injector;
|
|
19
|
-
let db;
|
|
20
|
-
let repo;
|
|
21
|
-
const schema = 'test_orm_query_complex';
|
|
22
|
-
let QueryEntity = class QueryEntity extends Entity {
|
|
23
|
-
tag;
|
|
24
|
-
score;
|
|
25
|
-
status;
|
|
26
|
-
};
|
|
27
|
-
__decorate([
|
|
28
|
-
StringProperty(),
|
|
29
|
-
__metadata("design:type", String)
|
|
30
|
-
], QueryEntity.prototype, "tag", void 0);
|
|
31
|
-
__decorate([
|
|
32
|
-
Integer(),
|
|
33
|
-
__metadata("design:type", Number)
|
|
34
|
-
], QueryEntity.prototype, "score", void 0);
|
|
35
|
-
__decorate([
|
|
36
|
-
StringProperty(),
|
|
37
|
-
__metadata("design:type", String)
|
|
38
|
-
], QueryEntity.prototype, "status", void 0);
|
|
39
|
-
QueryEntity = __decorate([
|
|
40
|
-
Table('query_entities', { schema })
|
|
41
|
-
], QueryEntity);
|
|
42
|
-
beforeAll(async () => {
|
|
43
|
-
({ injector, database: db } = await setupIntegrationTest({
|
|
44
|
-
orm: { schema },
|
|
45
|
-
}));
|
|
46
|
-
repo = injector.resolve(getRepository(QueryEntity));
|
|
47
|
-
await db.execute(sql `CREATE SCHEMA IF NOT EXISTS ${sql.identifier(schema)}`);
|
|
48
|
-
await db.execute(sql `DROP TABLE IF EXISTS ${sql.identifier(schema)}.${sql.identifier('query_entities')} CASCADE`);
|
|
49
|
-
await db.execute(sql `
|
|
50
|
-
CREATE TABLE ${sql.identifier(schema)}.${sql.identifier('query_entities')} (
|
|
51
|
-
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
52
|
-
tag TEXT NOT NULL,
|
|
53
|
-
score INTEGER NOT NULL,
|
|
54
|
-
status TEXT NOT NULL,
|
|
55
|
-
revision INTEGER NOT NULL,
|
|
56
|
-
revision_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
57
|
-
create_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
58
|
-
delete_timestamp TIMESTAMP WITH TIME ZONE,
|
|
59
|
-
attributes JSONB NOT NULL DEFAULT '{}'
|
|
60
|
-
)
|
|
61
|
-
`);
|
|
62
|
-
});
|
|
63
|
-
test('should support nested AND/OR logic', async () => {
|
|
64
|
-
await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('query_entities')} CASCADE`);
|
|
65
|
-
await repo.insertMany([
|
|
66
|
-
Object.assign(new QueryEntity(), { tag: 'A', score: 10, status: 'active' }),
|
|
67
|
-
Object.assign(new QueryEntity(), { tag: 'A', score: 20, status: 'inactive' }),
|
|
68
|
-
Object.assign(new QueryEntity(), { tag: 'B', score: 10, status: 'active' }),
|
|
69
|
-
Object.assign(new QueryEntity(), { tag: 'B', score: 20, status: 'inactive' }),
|
|
70
|
-
]);
|
|
71
|
-
// (Tag A AND Active) OR (Tag B AND Inactive)
|
|
72
|
-
const results = await repo.loadManyByQuery({
|
|
73
|
-
$or: [
|
|
74
|
-
{ $and: [{ tag: 'A' }, { status: 'active' }] },
|
|
75
|
-
{ $and: [{ tag: 'B' }, { status: 'inactive' }] },
|
|
76
|
-
],
|
|
77
|
-
});
|
|
78
|
-
expect(results).toHaveLength(2);
|
|
79
|
-
expect(results.some((r) => r.tag === 'A' && r.status === 'active')).toBe(true);
|
|
80
|
-
expect(results.some((r) => r.tag === 'B' && r.status === 'inactive')).toBe(true);
|
|
81
|
-
});
|
|
82
|
-
test('should support implicit AND', async () => {
|
|
83
|
-
await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('query_entities')} CASCADE`);
|
|
84
|
-
await repo.insert(Object.assign(new QueryEntity(), { tag: 'A', score: 10, status: 'active' }));
|
|
85
|
-
const results = await repo.loadManyByQuery({
|
|
86
|
-
tag: 'A',
|
|
87
|
-
score: 10,
|
|
88
|
-
status: 'active',
|
|
89
|
-
});
|
|
90
|
-
expect(results).toHaveLength(1);
|
|
91
|
-
});
|
|
92
|
-
test('should support NOT operator', async () => {
|
|
93
|
-
await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('query_entities')} CASCADE`);
|
|
94
|
-
await repo.insertMany([
|
|
95
|
-
Object.assign(new QueryEntity(), { tag: 'A', score: 10, status: 'active' }),
|
|
96
|
-
Object.assign(new QueryEntity(), { tag: 'B', score: 20, status: 'inactive' }),
|
|
97
|
-
]);
|
|
98
|
-
const results = await repo.loadManyByQuery({
|
|
99
|
-
tag: { $not: { $eq: 'A' } },
|
|
100
|
-
});
|
|
101
|
-
expect(results).toHaveLength(1);
|
|
102
|
-
expect(results[0].tag).toBe('B');
|
|
103
|
-
});
|
|
104
|
-
test('should support IN operator with empty array (should match nothing)', async () => {
|
|
105
|
-
await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('query_entities')} CASCADE`);
|
|
106
|
-
await repo.insert(Object.assign(new QueryEntity(), { tag: 'A', score: 10, status: 'active' }));
|
|
107
|
-
const results = await repo.loadManyByQuery({
|
|
108
|
-
tag: { $in: [] },
|
|
109
|
-
});
|
|
110
|
-
expect(results).toHaveLength(0);
|
|
111
|
-
});
|
|
112
|
-
test('should support NOT IN operator with empty array (should match everything)', async () => {
|
|
113
|
-
await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('query_entities')} CASCADE`);
|
|
114
|
-
await repo.insert(Object.assign(new QueryEntity(), { tag: 'A', score: 10, status: 'active' }));
|
|
115
|
-
const results = await repo.loadManyByQuery({
|
|
116
|
-
tag: { $nin: [] },
|
|
117
|
-
});
|
|
118
|
-
expect(results).toHaveLength(1);
|
|
119
|
-
});
|
|
120
|
-
test('should support REGEX operator', async () => {
|
|
121
|
-
await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('query_entities')} CASCADE`);
|
|
122
|
-
await repo.insertMany([
|
|
123
|
-
Object.assign(new QueryEntity(), { tag: 'apple', score: 10, status: '' }),
|
|
124
|
-
Object.assign(new QueryEntity(), { tag: 'banana', score: 10, status: '' }),
|
|
125
|
-
Object.assign(new QueryEntity(), { tag: 'apricot', score: 10, status: '' }),
|
|
126
|
-
]);
|
|
127
|
-
const results = await repo.loadManyByQuery({
|
|
128
|
-
tag: { $regex: '^ap' },
|
|
129
|
-
});
|
|
130
|
-
expect(results).toHaveLength(2); // apple, apricot
|
|
131
|
-
});
|
|
132
|
-
test('should support complex combination of logic and comparison', async () => {
|
|
133
|
-
await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('query_entities')} CASCADE`);
|
|
134
|
-
await repo.insertMany([
|
|
135
|
-
Object.assign(new QueryEntity(), { tag: 'A', score: 5, status: 'ok' }),
|
|
136
|
-
Object.assign(new QueryEntity(), { tag: 'A', score: 15, status: 'ok' }),
|
|
137
|
-
Object.assign(new QueryEntity(), { tag: 'A', score: 25, status: 'fail' }),
|
|
138
|
-
Object.assign(new QueryEntity(), { tag: 'B', score: 5, status: 'ok' }),
|
|
139
|
-
]);
|
|
140
|
-
// Tag A AND (Score > 10 AND Score < 20) AND Status != fail
|
|
141
|
-
const results = await repo.loadManyByQuery({
|
|
142
|
-
tag: 'A',
|
|
143
|
-
$and: [{ score: { $gt: 10 } }, { score: { $lt: 20 } }],
|
|
144
|
-
status: { $neq: 'fail' },
|
|
145
|
-
});
|
|
146
|
-
expect(results).toHaveLength(1);
|
|
147
|
-
expect(results[0].score).toBe(15);
|
|
148
|
-
});
|
|
149
|
-
test('should support NULL check', async () => {
|
|
150
|
-
await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('query_entities')} CASCADE`);
|
|
151
|
-
// Manually insert null status (violates NOT NULL usually, but let's assume nullable if we could change schema,
|
|
152
|
-
// but Entity defines it as string. We can query for null even if no rows can be null (result 0) OR if we use a nullable column).
|
|
153
|
-
// 'attributes' is JSONB and can be queried.
|
|
154
|
-
// But query-converter maps properties.
|
|
155
|
-
// Let's use a non-existent value for $eq which is different from null.
|
|
156
|
-
// But checking $eq: null generates IS NULL.
|
|
157
|
-
// Since our columns are NOT NULL, it should return empty.
|
|
158
|
-
await repo.insert(Object.assign(new QueryEntity(), { tag: 'A', score: 10, status: 'active' }));
|
|
159
|
-
const results = await repo.loadManyByQuery({
|
|
160
|
-
status: { $eq: null },
|
|
161
|
-
});
|
|
162
|
-
expect(results).toHaveLength(0);
|
|
163
|
-
});
|
|
164
|
-
test('should support NOT NULL check', async () => {
|
|
165
|
-
await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('query_entities')} CASCADE`);
|
|
166
|
-
await repo.insert(Object.assign(new QueryEntity(), { tag: 'A', score: 10, status: 'active' }));
|
|
167
|
-
const results = await repo.loadManyByQuery({
|
|
168
|
-
status: { $neq: null },
|
|
169
|
-
});
|
|
170
|
-
expect(results).toHaveLength(1);
|
|
171
|
-
});
|
|
172
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,131 +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 { PgDialect } from 'drizzle-orm/pg-core';
|
|
11
|
-
import { Integer, StringProperty } from '../../schema/index.js';
|
|
12
|
-
import { describe, expect, test } from 'vitest';
|
|
13
|
-
import { Table } from '../decorators.js';
|
|
14
|
-
import { Entity } from '../entity.js';
|
|
15
|
-
import { getColumnDefinitionsMap, getDrizzleTableFromType } from '../server/drizzle/schema-converter.js';
|
|
16
|
-
import { convertQuery } from '../server/query-converter.js';
|
|
17
|
-
describe('ORM Query Converter Complex', () => {
|
|
18
|
-
const dialect = new PgDialect();
|
|
19
|
-
let ComplexItem = class ComplexItem extends Entity {
|
|
20
|
-
name;
|
|
21
|
-
description;
|
|
22
|
-
value;
|
|
23
|
-
};
|
|
24
|
-
__decorate([
|
|
25
|
-
StringProperty(),
|
|
26
|
-
__metadata("design:type", String)
|
|
27
|
-
], ComplexItem.prototype, "name", void 0);
|
|
28
|
-
__decorate([
|
|
29
|
-
StringProperty(),
|
|
30
|
-
__metadata("design:type", String)
|
|
31
|
-
], ComplexItem.prototype, "description", void 0);
|
|
32
|
-
__decorate([
|
|
33
|
-
Integer(),
|
|
34
|
-
__metadata("design:type", Number)
|
|
35
|
-
], ComplexItem.prototype, "value", void 0);
|
|
36
|
-
ComplexItem = __decorate([
|
|
37
|
-
Table('complex_items', { schema: 'test' })
|
|
38
|
-
], ComplexItem);
|
|
39
|
-
const table = getDrizzleTableFromType(ComplexItem);
|
|
40
|
-
const colMap = getColumnDefinitionsMap(table);
|
|
41
|
-
test('should handle $tsvector with explicit weights', () => {
|
|
42
|
-
const q = {
|
|
43
|
-
$tsvector: {
|
|
44
|
-
fields: [['name', 'A'], ['description', 'B']],
|
|
45
|
-
query: 'search term',
|
|
46
|
-
language: 'english',
|
|
47
|
-
parser: 'websearch',
|
|
48
|
-
},
|
|
49
|
-
};
|
|
50
|
-
const condition = convertQuery(q, table, colMap);
|
|
51
|
-
const { sql, params } = dialect.sqlToQuery(condition);
|
|
52
|
-
expect(sql).toContain('setweight(to_tsvector($1, "test"."complex_items"."name"), \'A\')');
|
|
53
|
-
expect(sql).toContain('setweight(to_tsvector($2, "test"."complex_items"."description"), \'B\')');
|
|
54
|
-
expect(sql).toContain('websearch_to_tsquery($3, $4)');
|
|
55
|
-
expect(params).toEqual(['english', 'english', 'english', 'search term']);
|
|
56
|
-
});
|
|
57
|
-
test('should handle ParadeDB $parade match with tokenizer', () => {
|
|
58
|
-
const q = {
|
|
59
|
-
name: {
|
|
60
|
-
$parade: {
|
|
61
|
-
match: {
|
|
62
|
-
value: 'test',
|
|
63
|
-
tokenizer: { type: 'ngram', min_gram: 3, max_gram: 3 },
|
|
64
|
-
},
|
|
65
|
-
},
|
|
66
|
-
},
|
|
67
|
-
};
|
|
68
|
-
const condition = convertQuery(q, table, colMap);
|
|
69
|
-
const { sql, params } = dialect.sqlToQuery(condition);
|
|
70
|
-
// Tokenizer is supported via JSON object syntax
|
|
71
|
-
expect(sql).toContain('"test"."complex_items"."name" @@@ jsonb_build_object($1::text, jsonb_build_object($2::text, to_jsonb($3::text), $4::text, jsonb_build_object($5::text, to_jsonb($6::text), $7::text, to_jsonb($8::numeric), $9::text, to_jsonb($10::numeric))))::pdb.query');
|
|
72
|
-
expect(params).toEqual(['match', 'value', 'test', 'tokenizer', 'type', 'ngram', 'min_gram', 3, 'max_gram', 3]);
|
|
73
|
-
});
|
|
74
|
-
test('should handle ParadeDB $parade range', () => {
|
|
75
|
-
const q = {
|
|
76
|
-
value: {
|
|
77
|
-
$parade: {
|
|
78
|
-
range: {
|
|
79
|
-
lowerBound: { included: 10 },
|
|
80
|
-
upperBound: { excluded: 20 },
|
|
81
|
-
},
|
|
82
|
-
},
|
|
83
|
-
},
|
|
84
|
-
};
|
|
85
|
-
const condition = convertQuery(q, table, colMap);
|
|
86
|
-
const { sql, params } = dialect.sqlToQuery(condition);
|
|
87
|
-
// This should fall back to convertParadeComparisonQuery with recursive jsonb build
|
|
88
|
-
expect(sql).toContain('"test"."complex_items"."value" @@@ jsonb_build_object($1::text, jsonb_build_object($2::text, jsonb_build_object($3::text, to_jsonb($4::numeric)), $5::text, jsonb_build_object($6::text, to_jsonb($7::numeric))))::pdb.query');
|
|
89
|
-
expect(params).toEqual(['range', 'lower_bound', 'included', 10, 'upper_bound', 'excluded', 20]);
|
|
90
|
-
});
|
|
91
|
-
test('should handle ParadeDB $parade phrasePrefix', () => {
|
|
92
|
-
const q = {
|
|
93
|
-
name: {
|
|
94
|
-
$parade: {
|
|
95
|
-
phrasePrefix: { phrases: ['hello', 'wor'], maxExpansions: 10 },
|
|
96
|
-
},
|
|
97
|
-
},
|
|
98
|
-
};
|
|
99
|
-
const condition = convertQuery(q, table, colMap);
|
|
100
|
-
const { sql, params } = dialect.sqlToQuery(condition);
|
|
101
|
-
expect(sql).toContain('"test"."complex_items"."name" @@@ jsonb_build_object($1::text, jsonb_build_object($2::text, jsonb_build_array(to_jsonb($3::text), to_jsonb($4::text)), $5::text, to_jsonb($6::numeric)))::pdb.query');
|
|
102
|
-
expect(params).toEqual(['phrase_prefix', 'phrases', 'hello', 'wor', 'max_expansions', 10]);
|
|
103
|
-
});
|
|
104
|
-
test('should handle ParadeDB $parade regexPhrase', () => {
|
|
105
|
-
const q = {
|
|
106
|
-
name: {
|
|
107
|
-
$parade: {
|
|
108
|
-
regexPhrase: { regexes: ['he.*', 'wo.*'], slop: 1 },
|
|
109
|
-
},
|
|
110
|
-
},
|
|
111
|
-
};
|
|
112
|
-
const condition = convertQuery(q, table, colMap);
|
|
113
|
-
const { sql, params } = dialect.sqlToQuery(condition);
|
|
114
|
-
expect(sql).toContain('"test"."complex_items"."name" @@@ jsonb_build_object($1::text, jsonb_build_object($2::text, jsonb_build_array(to_jsonb($3::text), to_jsonb($4::text)), $5::text, to_jsonb($6::numeric)))::pdb.query');
|
|
115
|
-
expect(params).toEqual(['regex_phrase', 'regexes', 'he.*', 'wo.*', 'slop', 1]);
|
|
116
|
-
});
|
|
117
|
-
test('should handle ParadeDB top-level moreLikeThis', () => {
|
|
118
|
-
const q = {
|
|
119
|
-
$parade: {
|
|
120
|
-
moreLikeThis: {
|
|
121
|
-
keyValue: '123',
|
|
122
|
-
fields: ['name', 'description'],
|
|
123
|
-
},
|
|
124
|
-
},
|
|
125
|
-
};
|
|
126
|
-
const condition = convertQuery(q, table, colMap);
|
|
127
|
-
const { sql, params } = dialect.sqlToQuery(condition);
|
|
128
|
-
expect(sql).toContain('"test"."complex_items"."id" @@@ jsonb_build_object($1::text, jsonb_build_object($2::text, to_jsonb($3::text), $4::text, to_jsonb(ARRAY[$5, $6])))::pdb.query');
|
|
129
|
-
expect(params).toEqual(['more_like_this', 'key_value', '123', 'fields', 'name', 'description']);
|
|
130
|
-
});
|
|
131
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,123 +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 { describe, expect, test } from 'vitest';
|
|
11
|
-
import { eq, sql } from 'drizzle-orm';
|
|
12
|
-
import { getTableConfig, PgDialect } from 'drizzle-orm/pg-core';
|
|
13
|
-
import { StringProperty } from '../../schema/index.js';
|
|
14
|
-
import { Entity } from '../entity.js';
|
|
15
|
-
import { Column, Inheritance, ChildEntity, Table } from '../decorators.js';
|
|
16
|
-
import { getDrizzleTableFromType, getColumnDefinitionsMap } from '../server/drizzle/schema-converter.js';
|
|
17
|
-
import { convertQuery } from '../server/query-converter.js';
|
|
18
|
-
describe('ORM Query Converter (CTI)', () => {
|
|
19
|
-
test('should resolve columns to correct table in joined query', () => {
|
|
20
|
-
let BaseUser = class BaseUser extends Entity {
|
|
21
|
-
type;
|
|
22
|
-
name;
|
|
23
|
-
};
|
|
24
|
-
__decorate([
|
|
25
|
-
StringProperty(),
|
|
26
|
-
Column({ name: 'type' }),
|
|
27
|
-
__metadata("design:type", String)
|
|
28
|
-
], BaseUser.prototype, "type", void 0);
|
|
29
|
-
__decorate([
|
|
30
|
-
StringProperty(),
|
|
31
|
-
Column({ name: 'name' }),
|
|
32
|
-
__metadata("design:type", String)
|
|
33
|
-
], BaseUser.prototype, "name", void 0);
|
|
34
|
-
BaseUser = __decorate([
|
|
35
|
-
Table('users', { schema: 'test' }),
|
|
36
|
-
Inheritance({ strategy: 'joined', discriminatorColumn: 'type' })
|
|
37
|
-
], BaseUser);
|
|
38
|
-
let Admin = class Admin extends BaseUser {
|
|
39
|
-
role;
|
|
40
|
-
};
|
|
41
|
-
__decorate([
|
|
42
|
-
StringProperty(),
|
|
43
|
-
Column({ name: 'role' }),
|
|
44
|
-
__metadata("design:type", String)
|
|
45
|
-
], Admin.prototype, "role", void 0);
|
|
46
|
-
Admin = __decorate([
|
|
47
|
-
Table('admins', { schema: 'test' }),
|
|
48
|
-
ChildEntity('admin')
|
|
49
|
-
], Admin);
|
|
50
|
-
const parentTable = getDrizzleTableFromType(BaseUser);
|
|
51
|
-
const childTable = getDrizzleTableFromType(Admin);
|
|
52
|
-
const columnDefinitionsMap = getColumnDefinitionsMap(childTable);
|
|
53
|
-
const dialect = new PgDialect();
|
|
54
|
-
// Query on child property
|
|
55
|
-
const query1 = { role: 'super' };
|
|
56
|
-
const sql1 = convertQuery(query1, childTable, columnDefinitionsMap);
|
|
57
|
-
const sqlString1 = dialect.sqlToQuery(sql1).sql;
|
|
58
|
-
expect(sqlString1).toContain('"admins"."role" = $1');
|
|
59
|
-
// Query on parent property
|
|
60
|
-
const query2 = { name: 'admin' };
|
|
61
|
-
const sql2 = convertQuery(query2, childTable, columnDefinitionsMap);
|
|
62
|
-
const sqlString2 = dialect.sqlToQuery(sql2).sql;
|
|
63
|
-
expect(sqlString2).toContain('"users"."name" = $1');
|
|
64
|
-
expect(sqlString2).not.toContain('"admins"."name"');
|
|
65
|
-
});
|
|
66
|
-
test('should handle $regex with flags', () => {
|
|
67
|
-
let Item = class Item extends Entity {
|
|
68
|
-
name;
|
|
69
|
-
};
|
|
70
|
-
__decorate([
|
|
71
|
-
StringProperty(),
|
|
72
|
-
__metadata("design:type", String)
|
|
73
|
-
], Item.prototype, "name", void 0);
|
|
74
|
-
Item = __decorate([
|
|
75
|
-
Table('items', { schema: 'test' })
|
|
76
|
-
], Item);
|
|
77
|
-
const table = getDrizzleTableFromType(Item);
|
|
78
|
-
const colMap = getColumnDefinitionsMap(table);
|
|
79
|
-
const dialect = new PgDialect();
|
|
80
|
-
const q = convertQuery({ name: { $regex: { pattern: '^test', flags: 'i' } } }, table, colMap);
|
|
81
|
-
const sqlStr = dialect.sqlToQuery(q).sql;
|
|
82
|
-
expect(sqlStr).toContain('"items"."name" ~* $1');
|
|
83
|
-
});
|
|
84
|
-
test('should handle $nin (not in)', () => {
|
|
85
|
-
let Item = class Item extends Entity {
|
|
86
|
-
name;
|
|
87
|
-
};
|
|
88
|
-
__decorate([
|
|
89
|
-
StringProperty(),
|
|
90
|
-
__metadata("design:type", String)
|
|
91
|
-
], Item.prototype, "name", void 0);
|
|
92
|
-
Item = __decorate([
|
|
93
|
-
Table('items', { schema: 'test' })
|
|
94
|
-
], Item);
|
|
95
|
-
const table = getDrizzleTableFromType(Item);
|
|
96
|
-
const colMap = getColumnDefinitionsMap(table);
|
|
97
|
-
const dialect = new PgDialect();
|
|
98
|
-
const q = convertQuery({ name: { $nin: ['a', 'b'] } }, table, colMap);
|
|
99
|
-
const sqlStr = dialect.sqlToQuery(q).sql;
|
|
100
|
-
expect(sqlStr.toLowerCase()).toContain('"items"."name" not in ($1, $2)');
|
|
101
|
-
});
|
|
102
|
-
test('should handle logical $nor', () => {
|
|
103
|
-
let Item = class Item extends Entity {
|
|
104
|
-
name;
|
|
105
|
-
};
|
|
106
|
-
__decorate([
|
|
107
|
-
StringProperty(),
|
|
108
|
-
__metadata("design:type", String)
|
|
109
|
-
], Item.prototype, "name", void 0);
|
|
110
|
-
Item = __decorate([
|
|
111
|
-
Table('items', { schema: 'test' })
|
|
112
|
-
], Item);
|
|
113
|
-
const table = getDrizzleTableFromType(Item);
|
|
114
|
-
const colMap = getColumnDefinitionsMap(table);
|
|
115
|
-
const dialect = new PgDialect();
|
|
116
|
-
const q = convertQuery({ $nor: [{ name: 'a' }, { name: 'b' }] }, table, colMap);
|
|
117
|
-
const sqlStr = dialect.sqlToQuery(q).sql.toLowerCase();
|
|
118
|
-
expect(sqlStr).toContain('not');
|
|
119
|
-
expect(sqlStr).toContain('"items"."name" = $1');
|
|
120
|
-
expect(sqlStr).toContain('"items"."name" = $2');
|
|
121
|
-
expect(sqlStr).toContain('or');
|
|
122
|
-
});
|
|
123
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,189 +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 { Integer, StringProperty } from '../../schema/index.js';
|
|
13
|
-
import { setupIntegrationTest } from '../../testing/index.js';
|
|
14
|
-
import { toArrayAsync } from '../../utils/async-iterable-helpers/to-array.js';
|
|
15
|
-
import { Table } from '../decorators.js';
|
|
16
|
-
import { Entity } from '../entity.js';
|
|
17
|
-
import { getRepository } from '../server/index.js';
|
|
18
|
-
describe('ORM Repository Advanced (Integration)', () => {
|
|
19
|
-
let injector;
|
|
20
|
-
let db;
|
|
21
|
-
let repository;
|
|
22
|
-
const schema = 'test_orm_advanced';
|
|
23
|
-
let AdvancedEntity = class AdvancedEntity extends Entity {
|
|
24
|
-
name;
|
|
25
|
-
value;
|
|
26
|
-
};
|
|
27
|
-
__decorate([
|
|
28
|
-
StringProperty(),
|
|
29
|
-
__metadata("design:type", String)
|
|
30
|
-
], AdvancedEntity.prototype, "name", void 0);
|
|
31
|
-
__decorate([
|
|
32
|
-
Integer(),
|
|
33
|
-
__metadata("design:type", Number)
|
|
34
|
-
], AdvancedEntity.prototype, "value", void 0);
|
|
35
|
-
AdvancedEntity = __decorate([
|
|
36
|
-
Table('advanced_entities', { schema })
|
|
37
|
-
], AdvancedEntity);
|
|
38
|
-
beforeAll(async () => {
|
|
39
|
-
({ injector, database: db } = await setupIntegrationTest({
|
|
40
|
-
orm: { schema },
|
|
41
|
-
}));
|
|
42
|
-
repository = injector.resolve(getRepository(AdvancedEntity));
|
|
43
|
-
await db.execute(sql `CREATE SCHEMA IF NOT EXISTS ${sql.identifier(schema)}`);
|
|
44
|
-
await db.execute(sql `DROP TABLE IF EXISTS ${sql.identifier(schema)}.${sql.identifier('advanced_entities')} CASCADE`);
|
|
45
|
-
await db.execute(sql `
|
|
46
|
-
CREATE TABLE ${sql.identifier(schema)}.${sql.identifier('advanced_entities')} (
|
|
47
|
-
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
48
|
-
name TEXT NOT NULL,
|
|
49
|
-
value INTEGER NOT NULL,
|
|
50
|
-
revision INTEGER NOT NULL,
|
|
51
|
-
revision_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
52
|
-
create_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
53
|
-
delete_timestamp TIMESTAMP WITH TIME ZONE,
|
|
54
|
-
attributes JSONB NOT NULL DEFAULT '{}'
|
|
55
|
-
)
|
|
56
|
-
`);
|
|
57
|
-
});
|
|
58
|
-
test('should support loadManyCursor', async () => {
|
|
59
|
-
await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('advanced_entities')} CASCADE`);
|
|
60
|
-
const e1 = await repository.insert(Object.assign(new AdvancedEntity(), { name: 'E1', value: 1 }));
|
|
61
|
-
const e2 = await repository.insert(Object.assign(new AdvancedEntity(), { name: 'E2', value: 2 }));
|
|
62
|
-
const cursor = repository.loadManyCursor([e1.id, e2.id]);
|
|
63
|
-
const results = await toArrayAsync(cursor);
|
|
64
|
-
expect(results).toHaveLength(2);
|
|
65
|
-
expect(results.map((r) => r.name).sort()).toEqual(['E1', 'E2']);
|
|
66
|
-
});
|
|
67
|
-
test('should support loadAllCursor', async () => {
|
|
68
|
-
await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('advanced_entities')} CASCADE`);
|
|
69
|
-
await repository.insertMany([
|
|
70
|
-
Object.assign(new AdvancedEntity(), { name: 'E1', value: 1 }),
|
|
71
|
-
Object.assign(new AdvancedEntity(), { name: 'E2', value: 2 }),
|
|
72
|
-
]);
|
|
73
|
-
const cursor = repository.loadAllCursor();
|
|
74
|
-
const results = await toArrayAsync(cursor);
|
|
75
|
-
expect(results).toHaveLength(2);
|
|
76
|
-
});
|
|
77
|
-
test('should support countByQuery with various filters', async () => {
|
|
78
|
-
await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('advanced_entities')} CASCADE`);
|
|
79
|
-
await repository.insertMany([
|
|
80
|
-
Object.assign(new AdvancedEntity(), { name: 'A', value: 10 }),
|
|
81
|
-
Object.assign(new AdvancedEntity(), { name: 'B', value: 20 }),
|
|
82
|
-
Object.assign(new AdvancedEntity(), { name: 'C', value: 30 }),
|
|
83
|
-
]);
|
|
84
|
-
expect(await repository.countByQuery({ value: { $gt: 15 } })).toBe(2);
|
|
85
|
-
expect(await repository.countByQuery({ value: { $lt: 25 } })).toBe(2);
|
|
86
|
-
expect(await repository.countByQuery({ name: 'A' })).toBe(1);
|
|
87
|
-
});
|
|
88
|
-
test('should support has and hasByQuery', async () => {
|
|
89
|
-
await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('advanced_entities')} CASCADE`);
|
|
90
|
-
const e1 = await repository.insert(Object.assign(new AdvancedEntity(), { name: 'E1', value: 1 }));
|
|
91
|
-
expect(await repository.has(e1.id)).toBe(true);
|
|
92
|
-
expect(await repository.has('00000000-0000-0000-0000-000000000000')).toBe(false);
|
|
93
|
-
expect(await repository.hasByQuery({ name: 'E1' })).toBe(true);
|
|
94
|
-
expect(await repository.hasByQuery({ name: 'E2' })).toBe(false);
|
|
95
|
-
});
|
|
96
|
-
test('should support tryUpdate', async () => {
|
|
97
|
-
await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('advanced_entities')} CASCADE`);
|
|
98
|
-
const e1 = await repository.insert(Object.assign(new AdvancedEntity(), { name: 'E1', value: 1 }));
|
|
99
|
-
const updated = await repository.tryUpdate(e1.id, { name: 'E1-Updated' });
|
|
100
|
-
expect(updated.name).toBe('E1-Updated');
|
|
101
|
-
const missing = await repository.tryUpdate('00000000-0000-0000-0000-000000000000', { name: 'X' });
|
|
102
|
-
expect(missing).toBeUndefined();
|
|
103
|
-
});
|
|
104
|
-
test('should support tryUpdateByQuery', async () => {
|
|
105
|
-
await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('advanced_entities')} CASCADE`);
|
|
106
|
-
await repository.insert(Object.assign(new AdvancedEntity(), { name: 'E1', value: 1 }));
|
|
107
|
-
const updated = await repository.tryUpdateByQuery({ name: 'E1' }, { value: 100 });
|
|
108
|
-
expect(updated.value).toBe(100);
|
|
109
|
-
const missing = await repository.tryUpdateByQuery({ name: 'Missing' }, { value: 0 });
|
|
110
|
-
expect(missing).toBeUndefined();
|
|
111
|
-
});
|
|
112
|
-
test('should support insertIfNotExists', async () => {
|
|
113
|
-
await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('advanced_entities')} CASCADE`);
|
|
114
|
-
const e1 = await repository.insert(Object.assign(new AdvancedEntity(), { name: 'E1', value: 1 }));
|
|
115
|
-
// Conflict on ID
|
|
116
|
-
const conflict = await repository.insertIfNotExists('id', Object.assign(new AdvancedEntity(), { id: e1.id, name: 'Conflict', value: 2 }));
|
|
117
|
-
expect(conflict).toBeUndefined();
|
|
118
|
-
// No conflict
|
|
119
|
-
const success = await repository.insertIfNotExists('id', Object.assign(new AdvancedEntity(), { name: 'E2', value: 2 }));
|
|
120
|
-
expect(success).toBeDefined();
|
|
121
|
-
expect(success.name).toBe('E2');
|
|
122
|
-
});
|
|
123
|
-
test('should support pagination (limit/offset)', async () => {
|
|
124
|
-
await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('advanced_entities')} CASCADE`);
|
|
125
|
-
await repository.insertMany([
|
|
126
|
-
Object.assign(new AdvancedEntity(), { name: 'E1', value: 1 }),
|
|
127
|
-
Object.assign(new AdvancedEntity(), { name: 'E2', value: 2 }),
|
|
128
|
-
Object.assign(new AdvancedEntity(), { name: 'E3', value: 3 }),
|
|
129
|
-
]);
|
|
130
|
-
const p1 = await repository.loadAll({ limit: 2, order: { value: 'asc' } });
|
|
131
|
-
expect(p1).toHaveLength(2);
|
|
132
|
-
expect(p1[0].name).toBe('E1');
|
|
133
|
-
expect(p1[1].name).toBe('E2');
|
|
134
|
-
const p2 = await repository.loadAll({ limit: 2, offset: 2, order: { value: 'asc' } });
|
|
135
|
-
expect(p2).toHaveLength(1);
|
|
136
|
-
expect(p2[0].name).toBe('E3');
|
|
137
|
-
});
|
|
138
|
-
test('should support complex ordering', async () => {
|
|
139
|
-
await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('advanced_entities')} CASCADE`);
|
|
140
|
-
await repository.insertMany([
|
|
141
|
-
Object.assign(new AdvancedEntity(), { name: 'B', value: 10 }),
|
|
142
|
-
Object.assign(new AdvancedEntity(), { name: 'A', value: 20 }),
|
|
143
|
-
Object.assign(new AdvancedEntity(), { name: 'A', value: 10 }),
|
|
144
|
-
]);
|
|
145
|
-
const results = await repository.loadAll({
|
|
146
|
-
order: [
|
|
147
|
-
['name', 'asc'],
|
|
148
|
-
['value', 'desc'],
|
|
149
|
-
],
|
|
150
|
-
});
|
|
151
|
-
expect(results[0].name).toBe('A');
|
|
152
|
-
expect(results[0].value).toBe(20);
|
|
153
|
-
expect(results[1].name).toBe('A');
|
|
154
|
-
expect(results[1].value).toBe(10);
|
|
155
|
-
expect(results[2].name).toBe('B');
|
|
156
|
-
});
|
|
157
|
-
test('should return empty array for empty loadMany', async () => {
|
|
158
|
-
const results = await repository.loadMany([]);
|
|
159
|
-
expect(results).toEqual([]);
|
|
160
|
-
});
|
|
161
|
-
test('should fail on duplicate ID insert', async () => {
|
|
162
|
-
await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('advanced_entities')} CASCADE`);
|
|
163
|
-
const id = '00000000-0000-0000-0000-000000000001';
|
|
164
|
-
await repository.insert(Object.assign(new AdvancedEntity(), { id, name: 'E1', value: 1 }));
|
|
165
|
-
await expect(repository.insert(Object.assign(new AdvancedEntity(), { id, name: 'E2', value: 2 }))).rejects.toThrow();
|
|
166
|
-
});
|
|
167
|
-
test('should support explicit transaction usage', async () => {
|
|
168
|
-
await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('advanced_entities')} CASCADE`);
|
|
169
|
-
await repository.transaction(async (tx) => {
|
|
170
|
-
const txRepo = repository.withTransaction(tx);
|
|
171
|
-
await txRepo.insert(Object.assign(new AdvancedEntity(), { name: 'TxEntity', value: 100 }));
|
|
172
|
-
// Should be visible in tx
|
|
173
|
-
expect(await txRepo.count()).toBe(1);
|
|
174
|
-
});
|
|
175
|
-
// Should be committed
|
|
176
|
-
expect(await repository.count()).toBe(1);
|
|
177
|
-
});
|
|
178
|
-
test('should exclude soft-deleted entities by default', async () => {
|
|
179
|
-
await db.execute(sql `TRUNCATE TABLE ${sql.identifier(schema)}.${sql.identifier('advanced_entities')} CASCADE`);
|
|
180
|
-
const e1 = await repository.insert(Object.assign(new AdvancedEntity(), { name: 'E1', value: 1 }));
|
|
181
|
-
await repository.insert(Object.assign(new AdvancedEntity(), { name: 'E2', value: 2 }));
|
|
182
|
-
await repository.delete(e1.id);
|
|
183
|
-
const all = await repository.loadAll();
|
|
184
|
-
expect(all).toHaveLength(1);
|
|
185
|
-
expect(all[0].name).toBe('E2');
|
|
186
|
-
const withDeleted = await repository.loadManyByQuery({}, { withDeleted: true });
|
|
187
|
-
expect(withDeleted).toHaveLength(2);
|
|
188
|
-
});
|
|
189
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|