@tstdl/base 0.93.86 → 0.93.89
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/ai/genkit/helpers.d.ts +3 -1
- package/ai/genkit/helpers.js +3 -3
- package/api/server/gateway.d.ts +3 -0
- package/api/server/gateway.js +15 -4
- package/api/server/middlewares/catch-error.middleware.js +2 -4
- package/api/server/middlewares/cors.middleware.js +2 -3
- package/api/server/middlewares/csrf.middleware.d.ts +41 -0
- package/api/server/middlewares/csrf.middleware.js +108 -0
- package/api/server/middlewares/index.d.ts +1 -0
- package/api/server/middlewares/index.js +1 -0
- package/api/server/module.d.ts +8 -2
- package/api/server/module.js +14 -8
- package/api/server/tests/csrf.middleware.test.js +91 -0
- package/audit/drizzle/{0000_bored_stick.sql → 0000_lumpy_thunderball.sql} +3 -3
- package/audit/drizzle/meta/0000_snapshot.json +4 -4
- package/audit/drizzle/meta/_journal.json +2 -9
- package/audit/module.d.ts +4 -1
- package/audit/module.js +3 -2
- package/audit/schemas.d.ts +1 -1
- package/audit/types.d.ts +1 -1
- package/audit/types.js +1 -1
- package/authentication/client/authentication.service.d.ts +14 -1
- package/authentication/client/authentication.service.js +82 -23
- package/authentication/client/http-client.middleware.d.ts +6 -0
- package/authentication/client/http-client.middleware.js +36 -0
- package/authentication/client/module.js +8 -2
- package/authentication/models/service-account.model.d.ts +2 -2
- package/authentication/models/service-account.model.js +10 -5
- package/authentication/models/subject.model.d.ts +19 -5
- package/authentication/models/subject.model.js +25 -29
- package/authentication/models/system-account.model.d.ts +3 -2
- package/authentication/models/system-account.model.js +11 -5
- package/authentication/models/user.model.d.ts +2 -11
- package/authentication/models/user.model.js +5 -16
- package/authentication/server/authentication-api-request-token.provider.d.ts +0 -2
- package/authentication/server/authentication-api-request-token.provider.js +3 -11
- package/authentication/server/authentication.api-controller.d.ts +1 -2
- package/authentication/server/authentication.api-controller.js +8 -9
- package/authentication/server/authentication.audit.d.ts +3 -2
- package/authentication/server/authentication.service.d.ts +27 -1
- package/authentication/server/authentication.service.js +67 -18
- package/authentication/server/drizzle/{0000_normal_paper_doll.sql → 0000_soft_tag.sql} +25 -32
- package/authentication/server/drizzle/meta/0000_snapshot.json +180 -205
- package/authentication/server/drizzle/meta/_journal.json +2 -2
- package/authentication/server/helper.js +9 -2
- package/authentication/server/module.d.ts +4 -1
- package/authentication/server/module.js +9 -5
- package/authentication/server/schemas.d.ts +2 -1
- package/authentication/server/schemas.js +2 -2
- package/authentication/server/subject.service.d.ts +14 -8
- package/authentication/server/subject.service.js +86 -84
- package/authentication/tests/authentication-ancillary.service.test.d.ts +1 -0
- package/authentication/tests/authentication-ancillary.service.test.js +13 -0
- package/authentication/tests/authentication-secret-requirements.validator.test.d.ts +1 -0
- package/authentication/tests/authentication-secret-requirements.validator.test.js +29 -0
- package/authentication/tests/authentication.api-controller.test.d.ts +1 -0
- package/authentication/tests/authentication.api-controller.test.js +88 -0
- package/authentication/tests/authentication.api-request-token.provider.test.d.ts +1 -0
- package/authentication/tests/authentication.api-request-token.provider.test.js +48 -0
- package/authentication/tests/authentication.client-middleware.test.d.ts +1 -0
- package/authentication/tests/authentication.client-middleware.test.js +23 -0
- package/authentication/tests/authentication.client-service.test.d.ts +1 -0
- package/authentication/tests/authentication.client-service.test.js +70 -0
- package/authentication/tests/authentication.service.test.d.ts +1 -0
- package/authentication/tests/authentication.service.test.js +186 -0
- package/authentication/tests/authentication.test-ancillary-service.d.ts +9 -0
- package/authentication/tests/authentication.test-ancillary-service.js +27 -0
- package/authentication/tests/helper.test.d.ts +1 -0
- package/authentication/tests/helper.test.js +107 -0
- package/authentication/tests/secret-requirements.error.test.d.ts +1 -0
- package/authentication/tests/secret-requirements.error.test.js +14 -0
- package/authentication/tests/subject.service.test.d.ts +1 -0
- package/authentication/tests/subject.service.test.js +140 -0
- package/circuit-breaker/postgres/drizzle/meta/0000_snapshot.json +1 -1
- package/circuit-breaker/postgres/drizzle/meta/_journal.json +2 -2
- package/circuit-breaker/postgres/module.d.ts +7 -1
- package/circuit-breaker/postgres/module.js +8 -6
- package/circuit-breaker/tests/circuit-breaker.test.js +2 -22
- package/document-management/api/document-management.api.js +2 -6
- package/document-management/server/services/document-validation.service.js +6 -5
- package/document-management/server/services/document-workflow.service.js +5 -5
- package/document-management/service-models/document-folders.view-model.d.ts +5 -2
- package/document-management/service-models/document-folders.view-model.js +42 -9
- package/document-management/service-models/enriched/enriched-document-management-data.view.js +1 -1
- package/examples/document-management/main.js +4 -4
- package/http/client/adapters/undici.adapter.d.ts +7 -5
- package/http/client/adapters/undici.adapter.js +13 -10
- package/http/client/module.d.ts +3 -1
- package/http/client/module.js +8 -9
- package/http/server/http-server.d.ts +2 -0
- package/http/server/node/module.d.ts +6 -2
- package/http/server/node/module.js +6 -4
- package/http/server/node/node-http-server.d.ts +2 -0
- package/http/server/node/node-http-server.js +7 -0
- package/http/types.d.ts +1 -1
- package/key-value-store/postgres/module.d.ts +7 -1
- package/key-value-store/postgres/module.js +7 -3
- package/lock/postgres/lock.js +0 -1
- package/lock/postgres/module.d.ts +7 -1
- package/lock/postgres/module.js +9 -5
- package/logger/formatter.d.ts +2 -0
- package/logger/formatters/json.js +2 -2
- package/logger/formatters/pretty-print.js +8 -10
- package/logger/logger.d.ts +1 -1
- package/logger/logger.js +15 -12
- package/message-bus/local/module.d.ts +5 -2
- package/message-bus/local/module.js +5 -4
- package/module/module.d.ts +2 -1
- package/module/module.js +3 -0
- package/module/modules/web-server.module.d.ts +11 -6
- package/module/modules/web-server.module.js +15 -10
- package/orm/decorators.d.ts +24 -1
- package/orm/decorators.js +40 -4
- package/orm/index.d.ts +1 -1
- package/orm/index.js +1 -1
- package/orm/query/base.d.ts +17 -17
- package/orm/query/base.js +1 -1
- package/orm/repository.types.d.ts +46 -2
- package/orm/schemas/tsvector.js +1 -1
- package/orm/server/drizzle/schema-converter.d.ts +3 -1
- package/orm/server/drizzle/schema-converter.js +120 -14
- package/orm/server/index.d.ts +1 -0
- package/orm/server/index.js +1 -0
- package/orm/server/module.d.ts +4 -2
- package/orm/server/module.js +6 -5
- package/orm/server/query-converter.d.ts +6 -3
- package/orm/server/query-converter.js +33 -21
- package/orm/server/repository-config.d.ts +8 -0
- package/orm/server/repository-config.js +8 -0
- package/orm/server/repository.d.ts +117 -43
- package/orm/server/repository.js +758 -254
- package/orm/server/transaction.d.ts +4 -2
- package/orm/server/transaction.js +14 -5
- package/orm/server/transactional.d.ts +6 -2
- package/orm/server/transactional.js +39 -9
- package/orm/server/types.d.ts +2 -0
- package/orm/sqls/case-when.d.ts +25 -0
- package/orm/sqls/case-when.js +54 -0
- package/orm/sqls/index.d.ts +2 -0
- package/orm/sqls/index.js +2 -0
- package/orm/{sqls.d.ts → sqls/sqls.d.ts} +67 -19
- package/orm/{sqls.js → sqls/sqls.js} +116 -22
- package/orm/tests/data-types.test.d.ts +1 -0
- package/orm/tests/data-types.test.js +39 -0
- package/orm/tests/decorators.test.d.ts +1 -0
- package/orm/tests/decorators.test.js +77 -0
- package/orm/tests/encryption.test.d.ts +1 -0
- package/orm/tests/encryption.test.js +34 -0
- package/orm/tests/query-complex.test.d.ts +1 -0
- package/orm/tests/query-complex.test.js +203 -0
- package/orm/tests/query-converter-complex.test.d.ts +1 -0
- package/orm/tests/query-converter-complex.test.js +126 -0
- package/orm/tests/query-converter.test.d.ts +1 -0
- package/orm/tests/query-converter.test.js +123 -0
- package/orm/tests/repository-advanced.test.d.ts +1 -0
- package/orm/tests/repository-advanced.test.js +232 -0
- package/orm/tests/repository-attributes.test.d.ts +1 -0
- package/orm/tests/repository-attributes.test.js +99 -0
- package/orm/tests/repository-comprehensive.test.d.ts +1 -0
- package/orm/tests/repository-comprehensive.test.js +187 -0
- package/orm/tests/repository-coverage.test.d.ts +1 -0
- package/orm/tests/repository-coverage.test.js +303 -0
- package/orm/tests/repository-cti-complex.test.d.ts +1 -0
- package/orm/tests/repository-cti-complex.test.js +170 -0
- package/orm/tests/repository-cti-embedded.test.d.ts +1 -0
- package/orm/tests/repository-cti-embedded.test.js +188 -0
- package/orm/tests/repository-cti-extensive.test.d.ts +1 -0
- package/orm/tests/repository-cti-extensive.test.js +308 -0
- package/orm/tests/repository-cti-mapping.test.d.ts +1 -0
- package/orm/tests/repository-cti-mapping.test.js +121 -0
- package/orm/tests/repository-cti-search.test.d.ts +1 -0
- package/orm/tests/repository-cti-search.test.js +152 -0
- package/orm/tests/repository-cti-soft-delete.test.d.ts +1 -0
- package/orm/tests/repository-cti-soft-delete.test.js +115 -0
- package/orm/tests/repository-cti-transactions.test.d.ts +1 -0
- package/orm/tests/repository-cti-transactions.test.js +126 -0
- package/orm/tests/repository-cti-upsert-many.test.d.ts +1 -0
- package/orm/tests/repository-cti-upsert-many.test.js +127 -0
- package/orm/tests/repository-cti.test.d.ts +1 -0
- package/orm/tests/repository-cti.test.js +456 -0
- package/orm/tests/repository-edge-cases.test.d.ts +1 -0
- package/orm/tests/repository-edge-cases.test.js +216 -0
- package/orm/tests/repository-expiration.test.d.ts +1 -0
- package/orm/tests/repository-expiration.test.js +153 -0
- package/orm/tests/repository-extra-coverage.test.d.ts +1 -0
- package/orm/tests/repository-extra-coverage.test.js +546 -0
- package/orm/tests/repository-mapping.test.d.ts +1 -0
- package/orm/tests/repository-mapping.test.js +71 -0
- package/orm/tests/repository-regression.test.d.ts +1 -0
- package/orm/tests/repository-regression.test.js +330 -0
- package/orm/tests/repository-search-coverage.test.d.ts +1 -0
- package/orm/tests/repository-search-coverage.test.js +129 -0
- package/orm/tests/repository-search.test.d.ts +1 -0
- package/orm/tests/repository-search.test.js +116 -0
- package/orm/tests/repository-soft-delete.test.d.ts +1 -0
- package/orm/tests/repository-soft-delete.test.js +143 -0
- package/orm/tests/repository-transactions-nested.test.d.ts +1 -0
- package/orm/tests/repository-transactions-nested.test.js +202 -0
- package/orm/tests/repository-types.test.d.ts +1 -0
- package/orm/tests/repository-types.test.js +218 -0
- package/orm/tests/schema-converter.test.d.ts +1 -0
- package/orm/tests/schema-converter.test.js +81 -0
- package/orm/tests/schema-generation.test.d.ts +1 -0
- package/orm/tests/schema-generation.test.js +127 -0
- package/orm/tests/sql-helpers.test.d.ts +1 -0
- package/orm/tests/sql-helpers.test.js +67 -0
- package/orm/tests/transaction-safety.test.d.ts +1 -0
- package/orm/tests/transaction-safety.test.js +81 -0
- package/orm/tests/transactional.test.d.ts +1 -0
- package/orm/tests/transactional.test.js +224 -0
- package/orm/tests/utils.test.d.ts +1 -0
- package/orm/tests/utils.test.js +70 -0
- package/orm/utils.d.ts +7 -0
- package/orm/utils.js +26 -6
- package/package.json +12 -7
- package/pool/pool.js +1 -1
- package/rate-limit/index.d.ts +2 -0
- package/rate-limit/index.js +2 -0
- package/rate-limit/postgres/drizzle/0000_watery_rage.sql +7 -0
- package/{queue → rate-limit}/postgres/drizzle/meta/0000_snapshot.json +14 -39
- package/rate-limit/postgres/drizzle/meta/_journal.json +13 -0
- package/{queue → rate-limit}/postgres/drizzle.config.js +1 -1
- package/rate-limit/postgres/index.d.ts +4 -0
- package/rate-limit/postgres/index.js +4 -0
- package/rate-limit/postgres/module.d.ts +12 -0
- package/rate-limit/postgres/module.js +28 -0
- package/rate-limit/postgres/postgres-rate-limiter.d.ts +9 -0
- package/rate-limit/postgres/postgres-rate-limiter.js +56 -0
- package/rate-limit/postgres/rate-limit.model.d.ts +8 -0
- package/rate-limit/postgres/rate-limit.model.js +35 -0
- package/rate-limit/postgres/rate-limiter.provider.d.ts +6 -0
- package/rate-limit/postgres/rate-limiter.provider.js +21 -0
- package/rate-limit/postgres/schemas.d.ts +3 -0
- package/rate-limit/postgres/schemas.js +4 -0
- package/rate-limit/provider.d.ts +9 -0
- package/rate-limit/provider.js +2 -0
- package/rate-limit/rate-limiter.d.ts +35 -0
- package/rate-limit/rate-limiter.js +3 -0
- package/rate-limit/tests/postgres-rate-limiter.test.d.ts +1 -0
- package/rate-limit/tests/postgres-rate-limiter.test.js +92 -0
- package/signals/implementation/configure.d.ts +3 -0
- package/signals/implementation/configure.js +3 -0
- package/sse/data-stream-source.d.ts +1 -1
- package/sse/data-stream-source.js +6 -6
- package/task-queue/enqueue-batch.d.ts +17 -0
- package/task-queue/enqueue-batch.js +24 -0
- package/{queue → task-queue}/index.d.ts +1 -1
- package/{queue → task-queue}/index.js +1 -1
- package/task-queue/postgres/drizzle/0000_thin_black_panther.sql +74 -0
- package/task-queue/postgres/drizzle/meta/0000_snapshot.json +592 -0
- package/task-queue/postgres/drizzle/meta/_journal.json +13 -0
- package/task-queue/postgres/drizzle.config.d.ts +2 -0
- package/task-queue/postgres/drizzle.config.js +11 -0
- package/task-queue/postgres/index.d.ts +4 -0
- package/task-queue/postgres/index.js +4 -0
- package/task-queue/postgres/module.d.ts +12 -0
- package/task-queue/postgres/module.js +28 -0
- package/task-queue/postgres/schemas.d.ts +16 -0
- package/task-queue/postgres/schemas.js +8 -0
- package/task-queue/postgres/task-queue.d.ts +83 -0
- package/task-queue/postgres/task-queue.js +1054 -0
- package/task-queue/postgres/task-queue.provider.d.ts +7 -0
- package/{queue/postgres/queue.provider.js → task-queue/postgres/task-queue.provider.js} +8 -8
- package/task-queue/postgres/task.model.d.ts +39 -0
- package/task-queue/postgres/task.model.js +178 -0
- package/{queue → task-queue}/provider.d.ts +3 -3
- package/task-queue/provider.js +2 -0
- package/{queue → task-queue}/task-context.d.ts +7 -7
- package/{queue → task-queue}/task-context.js +8 -8
- package/{queue/queue.d.ts → task-queue/task-queue.d.ts} +128 -59
- package/task-queue/task-queue.js +200 -0
- package/task-queue/tests/complex.test.d.ts +1 -0
- package/task-queue/tests/complex.test.js +299 -0
- package/task-queue/tests/dependencies.test.d.ts +1 -0
- package/task-queue/tests/dependencies.test.js +174 -0
- package/task-queue/tests/queue.test.d.ts +1 -0
- package/task-queue/tests/queue.test.js +334 -0
- package/task-queue/tests/worker.test.d.ts +1 -0
- package/task-queue/tests/worker.test.js +163 -0
- package/test1.js +1 -1
- package/test4.js +2 -2
- package/unit-test/index.d.ts +1 -0
- package/unit-test/index.js +1 -0
- package/unit-test/integration-setup.d.ts +55 -0
- package/unit-test/integration-setup.js +182 -0
- package/utils/patterns.d.ts +3 -0
- package/utils/patterns.js +6 -1
- package/audit/drizzle/0001_previous_network.sql +0 -2
- package/audit/drizzle/meta/0001_snapshot.json +0 -195
- package/queue/enqueue-batch.d.ts +0 -17
- package/queue/enqueue-batch.js +0 -18
- package/queue/postgres/drizzle/0000_zippy_moondragon.sql +0 -11
- package/queue/postgres/drizzle/0001_certain_wild_pack.sql +0 -2
- package/queue/postgres/drizzle/0002_dear_meggan.sql +0 -2
- package/queue/postgres/drizzle/0003_tricky_venom.sql +0 -30
- package/queue/postgres/drizzle/meta/0001_snapshot.json +0 -103
- package/queue/postgres/drizzle/meta/0002_snapshot.json +0 -90
- package/queue/postgres/drizzle/meta/0003_snapshot.json +0 -288
- package/queue/postgres/drizzle/meta/_journal.json +0 -34
- package/queue/postgres/index.d.ts +0 -4
- package/queue/postgres/index.js +0 -4
- package/queue/postgres/module.d.ts +0 -9
- package/queue/postgres/module.js +0 -29
- package/queue/postgres/queue.d.ts +0 -60
- package/queue/postgres/queue.js +0 -681
- package/queue/postgres/queue.provider.d.ts +0 -7
- package/queue/postgres/schemas.d.ts +0 -14
- package/queue/postgres/schemas.js +0 -6
- package/queue/postgres/task.model.d.ts +0 -24
- package/queue/postgres/task.model.js +0 -115
- package/queue/provider.js +0 -2
- package/queue/queue.js +0 -131
- package/queue/tests/queue.test.js +0 -623
- package/test3.d.ts +0 -1
- package/test3.js +0 -47
- /package/{queue/tests/queue.test.d.ts → api/server/tests/csrf.middleware.test.d.ts} +0 -0
- /package/circuit-breaker/postgres/drizzle/{0000_hard_shocker.sql → 0000_cooing_korath.sql} +0 -0
- /package/{queue → rate-limit}/postgres/drizzle.config.d.ts +0 -0
|
@@ -0,0 +1,546 @@
|
|
|
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 { NotFoundError } from '../../errors/not-found.error.js';
|
|
11
|
+
import { Injector, runInInjectionContext } from '../../injector/index.js';
|
|
12
|
+
import { StringProperty } from '../../schema/index.js';
|
|
13
|
+
import { dropTables, setupIntegrationTest, truncateTables } from '../../unit-test/index.js';
|
|
14
|
+
import { toArrayAsync } from '../../utils/async-iterable-helpers/to-array.js';
|
|
15
|
+
import { sql } from 'drizzle-orm';
|
|
16
|
+
import { beforeAll, describe, expect, test } from 'vitest';
|
|
17
|
+
import { ChildEntity, Column, Inheritance, Table } from '../decorators.js';
|
|
18
|
+
import { BaseEntity, Entity } from '../entity.js';
|
|
19
|
+
import { Database } from '../server/index.js';
|
|
20
|
+
import { injectRepository } from '../server/repository.js';
|
|
21
|
+
import { ENCRYPTION_SECRET } from '../server/tokens.js';
|
|
22
|
+
describe('ORM Repository Extra Coverage', () => {
|
|
23
|
+
let injector;
|
|
24
|
+
let database;
|
|
25
|
+
const schema = 'test_orm_extra_coverage';
|
|
26
|
+
let BaseItem = class BaseItem extends Entity {
|
|
27
|
+
type;
|
|
28
|
+
name;
|
|
29
|
+
};
|
|
30
|
+
__decorate([
|
|
31
|
+
StringProperty(),
|
|
32
|
+
Column({ name: 'type' }),
|
|
33
|
+
__metadata("design:type", String)
|
|
34
|
+
], BaseItem.prototype, "type", void 0);
|
|
35
|
+
__decorate([
|
|
36
|
+
StringProperty(),
|
|
37
|
+
Column({ name: 'name' }),
|
|
38
|
+
__metadata("design:type", String)
|
|
39
|
+
], BaseItem.prototype, "name", void 0);
|
|
40
|
+
BaseItem = __decorate([
|
|
41
|
+
Table('items', { schema }),
|
|
42
|
+
Inheritance({ strategy: 'joined', discriminatorColumn: 'type' })
|
|
43
|
+
], BaseItem);
|
|
44
|
+
let PremiumItem = class PremiumItem extends BaseItem {
|
|
45
|
+
code;
|
|
46
|
+
};
|
|
47
|
+
__decorate([
|
|
48
|
+
StringProperty(),
|
|
49
|
+
Column({ name: 'code' }),
|
|
50
|
+
__metadata("design:type", String)
|
|
51
|
+
], PremiumItem.prototype, "code", void 0);
|
|
52
|
+
PremiumItem = __decorate([
|
|
53
|
+
Table('premium_items', { schema }),
|
|
54
|
+
ChildEntity('premium')
|
|
55
|
+
], PremiumItem);
|
|
56
|
+
let SimpleItem = class SimpleItem extends Entity {
|
|
57
|
+
label;
|
|
58
|
+
};
|
|
59
|
+
__decorate([
|
|
60
|
+
StringProperty(),
|
|
61
|
+
Column({ name: 'label' }),
|
|
62
|
+
__metadata("design:type", String)
|
|
63
|
+
], SimpleItem.prototype, "label", void 0);
|
|
64
|
+
SimpleItem = __decorate([
|
|
65
|
+
Table('simple_items', { schema })
|
|
66
|
+
], SimpleItem);
|
|
67
|
+
let PlainItem = class PlainItem extends BaseEntity {
|
|
68
|
+
description;
|
|
69
|
+
};
|
|
70
|
+
__decorate([
|
|
71
|
+
StringProperty(),
|
|
72
|
+
Column({ name: 'description' }),
|
|
73
|
+
__metadata("design:type", String)
|
|
74
|
+
], PlainItem.prototype, "description", void 0);
|
|
75
|
+
PlainItem = __decorate([
|
|
76
|
+
Table('plain_items', { schema })
|
|
77
|
+
], PlainItem);
|
|
78
|
+
beforeAll(async () => {
|
|
79
|
+
({ injector, database } = await setupIntegrationTest({ orm: { schema } }));
|
|
80
|
+
injector.register(ENCRYPTION_SECRET, { useValue: new Uint8Array(32).fill(1) });
|
|
81
|
+
await dropTables(database, schema, ['premium_items', 'items', 'simple_items', 'plain_items']);
|
|
82
|
+
await database.execute(sql `
|
|
83
|
+
CREATE TABLE ${sql.identifier(schema)}.${sql.identifier('items')} (
|
|
84
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
85
|
+
type TEXT NOT NULL,
|
|
86
|
+
name TEXT NOT NULL,
|
|
87
|
+
revision INTEGER NOT NULL,
|
|
88
|
+
revision_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
89
|
+
create_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
90
|
+
delete_timestamp TIMESTAMP WITH TIME ZONE,
|
|
91
|
+
attributes JSONB NOT NULL DEFAULT '{}',
|
|
92
|
+
UNIQUE (id, type)
|
|
93
|
+
)
|
|
94
|
+
`);
|
|
95
|
+
await database.execute(sql `
|
|
96
|
+
CREATE TABLE ${sql.identifier(schema)}.${sql.identifier('premium_items')} (
|
|
97
|
+
id UUID PRIMARY KEY,
|
|
98
|
+
type TEXT NOT NULL CHECK (type = 'premium'),
|
|
99
|
+
code TEXT NOT NULL,
|
|
100
|
+
FOREIGN KEY (id, type) REFERENCES ${sql.identifier(schema)}.${sql.identifier('items')} (id, type) ON DELETE CASCADE
|
|
101
|
+
)
|
|
102
|
+
`);
|
|
103
|
+
await database.execute(sql `
|
|
104
|
+
CREATE TABLE ${sql.identifier(schema)}.${sql.identifier('simple_items')} (
|
|
105
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
106
|
+
label TEXT NOT NULL UNIQUE,
|
|
107
|
+
revision INTEGER NOT NULL,
|
|
108
|
+
revision_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
109
|
+
create_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
110
|
+
delete_timestamp TIMESTAMP WITH TIME ZONE,
|
|
111
|
+
attributes JSONB NOT NULL DEFAULT '{}'
|
|
112
|
+
)
|
|
113
|
+
`);
|
|
114
|
+
await database.execute(sql `
|
|
115
|
+
CREATE TABLE ${sql.identifier(schema)}.${sql.identifier('plain_items')} (
|
|
116
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
117
|
+
description TEXT NOT NULL
|
|
118
|
+
)
|
|
119
|
+
`);
|
|
120
|
+
});
|
|
121
|
+
test.beforeEach(async () => {
|
|
122
|
+
await truncateTables(database, schema, ['premium_items', 'items', 'simple_items', 'plain_items']);
|
|
123
|
+
});
|
|
124
|
+
test('loadManyCursor should work', async () => {
|
|
125
|
+
await runInInjectionContext(injector, async () => {
|
|
126
|
+
const repository = injectRepository(SimpleItem);
|
|
127
|
+
const item = await repository.insert(Object.assign(new SimpleItem(), { label: 'Cursor Test' }));
|
|
128
|
+
const cursor = repository.loadManyCursor([item.id]);
|
|
129
|
+
const results = await toArrayAsync(cursor);
|
|
130
|
+
expect(results).toHaveLength(1);
|
|
131
|
+
expect(results[0].id).toBe(item.id);
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
test('loadAllCursor should work', async () => {
|
|
135
|
+
await runInInjectionContext(injector, async () => {
|
|
136
|
+
const repository = injectRepository(SimpleItem);
|
|
137
|
+
await repository.insert(Object.assign(new SimpleItem(), { label: 'All Cursor Test' }));
|
|
138
|
+
const cursor = repository.loadAllCursor();
|
|
139
|
+
const results = await toArrayAsync(cursor);
|
|
140
|
+
expect(results.length).toBeGreaterThan(0);
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
test('tryLoadByQuery with order option', async () => {
|
|
144
|
+
await runInInjectionContext(injector, async () => {
|
|
145
|
+
const repository = injectRepository(SimpleItem);
|
|
146
|
+
await repository.insert(Object.assign(new SimpleItem(), { label: 'A' }));
|
|
147
|
+
await repository.insert(Object.assign(new SimpleItem(), { label: 'B' }));
|
|
148
|
+
const item = await repository.tryLoadByQuery({}, { order: { label: 'desc' } });
|
|
149
|
+
expect(item.label).toBe('B');
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
test('insertManyIfNotExists with empty array', async () => {
|
|
153
|
+
await runInInjectionContext(injector, async () => {
|
|
154
|
+
const repository = injectRepository(SimpleItem);
|
|
155
|
+
const results = await repository.insertManyIfNotExists(['label'], []);
|
|
156
|
+
expect(results).toHaveLength(0);
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
test('insertManyIfNotExists with items', async () => {
|
|
160
|
+
await runInInjectionContext(injector, async () => {
|
|
161
|
+
const repository = injectRepository(SimpleItem);
|
|
162
|
+
const item = Object.assign(new SimpleItem(), { label: 'Unique' });
|
|
163
|
+
const results = await repository.insertManyIfNotExists(['label'], [item]);
|
|
164
|
+
expect(results).toHaveLength(1);
|
|
165
|
+
const results2 = await repository.insertManyIfNotExists(['label'], [item]);
|
|
166
|
+
expect(results2).toHaveLength(0);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
test('tryInsert returning entity', async () => {
|
|
170
|
+
await runInInjectionContext(injector, async () => {
|
|
171
|
+
const repository = injectRepository(SimpleItem);
|
|
172
|
+
const item = Object.assign(new SimpleItem(), { label: 'TryInsert' });
|
|
173
|
+
const inserted = await repository.tryInsert(item);
|
|
174
|
+
expect(inserted).toBeDefined();
|
|
175
|
+
expect(inserted.label).toBe('TryInsert');
|
|
176
|
+
const conflict = await repository.tryInsert(inserted); // Should conflict on ID
|
|
177
|
+
expect(conflict).toBeUndefined();
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
test('loadMany with empty array', async () => {
|
|
181
|
+
await runInInjectionContext(injector, async () => {
|
|
182
|
+
const repository = injectRepository(SimpleItem);
|
|
183
|
+
const results = await repository.loadMany([]);
|
|
184
|
+
expect(results).toHaveLength(0);
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
test('insertMany for non-CTI with empty array', async () => {
|
|
188
|
+
await runInInjectionContext(injector, async () => {
|
|
189
|
+
const repository = injectRepository(SimpleItem);
|
|
190
|
+
const results = await repository.insertMany([]);
|
|
191
|
+
expect(results).toHaveLength(0);
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
test('countByQuery returning count', async () => {
|
|
195
|
+
await runInInjectionContext(injector, async () => {
|
|
196
|
+
const repository = injectRepository(SimpleItem);
|
|
197
|
+
const initialCount = await repository.count();
|
|
198
|
+
await repository.insert(Object.assign(new SimpleItem(), { label: 'Count Test' }));
|
|
199
|
+
const newCount = await repository.count();
|
|
200
|
+
expect(newCount).toBe(initialCount + 1);
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
test('mapManyToColumns and mapManyToInsertColumns', async () => {
|
|
204
|
+
await runInInjectionContext(injector, async () => {
|
|
205
|
+
const repository = injectRepository(SimpleItem);
|
|
206
|
+
const item = Object.assign(new SimpleItem(), { label: 'Map Test' });
|
|
207
|
+
const cols = await repository.mapManyToColumns([item]);
|
|
208
|
+
expect(cols).toHaveLength(1);
|
|
209
|
+
expect(cols[0].label).toBe('Map Test');
|
|
210
|
+
const insertCols = await repository.mapManyToInsertColumns([item]);
|
|
211
|
+
expect(insertCols).toHaveLength(1);
|
|
212
|
+
expect(insertCols[0].label).toBe('Map Test');
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
test('tryUpsert on non-CTI returning undefined when condition fails', async () => {
|
|
216
|
+
await runInInjectionContext(injector, async () => {
|
|
217
|
+
const repository = injectRepository(SimpleItem);
|
|
218
|
+
const item = await repository.insert(Object.assign(new SimpleItem(), { label: 'Upsert Condition' }));
|
|
219
|
+
const conflictItem = Object.assign(new SimpleItem(), { id: item.id, label: 'Should Fail' });
|
|
220
|
+
const result = await repository.tryUpsert(['id'], conflictItem, undefined, { set: { label: 'Impossible' } });
|
|
221
|
+
expect(result).toBeUndefined();
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
test('tryUpdateByQuery on non-CTI', async () => {
|
|
225
|
+
await runInInjectionContext(injector, async () => {
|
|
226
|
+
const repository = injectRepository(SimpleItem);
|
|
227
|
+
const item = await repository.insert(Object.assign(new SimpleItem(), { label: 'UpdateByQuery' }));
|
|
228
|
+
const result = await repository.tryUpdateByQuery({ label: 'UpdateByQuery' }, { label: 'UpdatedByQuery' });
|
|
229
|
+
expect(result).toBeDefined();
|
|
230
|
+
expect(result.label).toBe('UpdatedByQuery');
|
|
231
|
+
const result2 = await repository.tryUpdateByQuery({ label: 'Ghost' }, { label: 'Buster' });
|
|
232
|
+
expect(result2).toBeUndefined();
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
test('tryDeleteByQuery on CTI', async () => {
|
|
236
|
+
await runInInjectionContext(injector, async () => {
|
|
237
|
+
const repository = injectRepository(PremiumItem);
|
|
238
|
+
const item = await repository.insert(Object.assign(new PremiumItem(), { name: 'DeleteMe', code: 'D1' }));
|
|
239
|
+
const result = await repository.tryDeleteByQuery({ name: 'DeleteMe' });
|
|
240
|
+
expect(result).toBeDefined();
|
|
241
|
+
expect(result.metadata.deleteTimestamp).not.toBeNull();
|
|
242
|
+
const result2 = await repository.tryDeleteByQuery({ name: 'Ghost' });
|
|
243
|
+
expect(result2).toBeUndefined();
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
test('getIdLimitQuery for update', async () => {
|
|
247
|
+
await runInInjectionContext(injector, async () => {
|
|
248
|
+
const repository = injectRepository(SimpleItem);
|
|
249
|
+
const query = repository.getIdLimitQuery({ label: 'Any' }).for('update');
|
|
250
|
+
expect(query).toBeDefined();
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
test('applySelect with distinct and distinctOn', async () => {
|
|
254
|
+
await runInInjectionContext(injector, async () => {
|
|
255
|
+
const repository = injectRepository(SimpleItem);
|
|
256
|
+
const q1 = repository.applySelect(database, true);
|
|
257
|
+
expect(q1).toBeDefined();
|
|
258
|
+
const q2 = repository.applySelect(database, ['label']);
|
|
259
|
+
expect(q2).toBeDefined();
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
test('mapToColumns and mapToInsertColumns', async () => {
|
|
263
|
+
await runInInjectionContext(injector, async () => {
|
|
264
|
+
const repository = injectRepository(SimpleItem);
|
|
265
|
+
const item = Object.assign(new SimpleItem(), { label: 'Map Single' });
|
|
266
|
+
const col = await repository.mapToColumns(item);
|
|
267
|
+
expect(col.label).toBe('Map Single');
|
|
268
|
+
const insertCol = await repository.mapToInsertColumns(item);
|
|
269
|
+
expect(insertCol.label).toBe('Map Single');
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
test('hasAll with duplicates and missing IDs', async () => {
|
|
273
|
+
await runInInjectionContext(injector, async () => {
|
|
274
|
+
const repository = injectRepository(SimpleItem);
|
|
275
|
+
const item = await repository.insert(Object.assign(new SimpleItem(), { label: 'HasAll' }));
|
|
276
|
+
expect(await repository.hasAll([item.id, item.id])).toBe(true);
|
|
277
|
+
expect(await repository.hasAll([item.id, '00000000-0000-0000-0000-000000000000'])).toBe(false);
|
|
278
|
+
expect(await repository.hasAll([])).toBe(false);
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
test('loadManyByQueryCursor should work', async () => {
|
|
282
|
+
await runInInjectionContext(injector, async () => {
|
|
283
|
+
const repository = injectRepository(SimpleItem);
|
|
284
|
+
await repository.insert(Object.assign(new SimpleItem(), { label: 'Many Cursor' }));
|
|
285
|
+
const cursor = repository.loadManyByQueryCursor({ label: 'Many Cursor' });
|
|
286
|
+
const results = await toArrayAsync(cursor);
|
|
287
|
+
expect(results).toHaveLength(1);
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
test('upsert (non-CTI) with wheres', async () => {
|
|
291
|
+
await runInInjectionContext(injector, async () => {
|
|
292
|
+
const repository = injectRepository(SimpleItem);
|
|
293
|
+
const item = await repository.insert(Object.assign(new SimpleItem(), { label: 'Upsert' }));
|
|
294
|
+
// This should succeed
|
|
295
|
+
const upserted = await repository.upsert(['label'], Object.assign(new SimpleItem(), { label: 'Upsert' }), { label: 'Upsert Updated' }, { set: { label: 'Upsert' } });
|
|
296
|
+
expect(upserted.label).toBe('Upsert Updated');
|
|
297
|
+
// This should fail to return a row due to condition
|
|
298
|
+
await expect(repository.upsert(['label'], Object.assign(new SimpleItem(), { label: 'Upsert Updated' }), { label: 'Should Not Happen' }, { set: { label: 'Wrong' } }))
|
|
299
|
+
.rejects.toThrow('upsert failed to return a row');
|
|
300
|
+
});
|
|
301
|
+
});
|
|
302
|
+
test('updateMany (non-CTI) with empty array', async () => {
|
|
303
|
+
await runInInjectionContext(injector, async () => {
|
|
304
|
+
const repository = injectRepository(SimpleItem);
|
|
305
|
+
expect(await repository.updateMany([], { label: 'None' })).toEqual([]);
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
test('hardDeleteByQuery throws NotFoundError', async () => {
|
|
309
|
+
await runInInjectionContext(injector, async () => {
|
|
310
|
+
const repository = injectRepository(SimpleItem);
|
|
311
|
+
await expect(repository.hardDeleteByQuery({ label: 'Ghost' })).rejects.toThrow('SimpleItem not found');
|
|
312
|
+
});
|
|
313
|
+
});
|
|
314
|
+
test('hardDeleteMany with empty array', async () => {
|
|
315
|
+
await runInInjectionContext(injector, async () => {
|
|
316
|
+
const repository = injectRepository(SimpleItem);
|
|
317
|
+
expect(await repository.hardDeleteMany([])).toEqual([]);
|
|
318
|
+
});
|
|
319
|
+
});
|
|
320
|
+
test('convertOrderBy with various inputs', async () => {
|
|
321
|
+
await runInInjectionContext(injector, async () => {
|
|
322
|
+
const repository = injectRepository(SimpleItem);
|
|
323
|
+
expect(repository.convertOrderBy('label')).toBeDefined();
|
|
324
|
+
expect(repository.convertOrderBy(['label', ['id', 'desc']])).toHaveLength(2);
|
|
325
|
+
expect(repository.convertOrderBy(sql `label`)).toHaveLength(1);
|
|
326
|
+
});
|
|
327
|
+
});
|
|
328
|
+
test('mapManyToEntity and mapToEntity with subclasses', async () => {
|
|
329
|
+
await runInInjectionContext(injector, async () => {
|
|
330
|
+
const repository = injectRepository(BaseItem);
|
|
331
|
+
const item = await injectRepository(PremiumItem).insert(Object.assign(new PremiumItem(), { name: 'P1', code: 'C1' }));
|
|
332
|
+
const polymorphic = await repository.load(item.id, { includeSubclasses: true });
|
|
333
|
+
expect(polymorphic).toBeInstanceOf(PremiumItem);
|
|
334
|
+
const rows = await database.execute(sql `SELECT * FROM ${sql.identifier(schema)}.${sql.identifier('items')} i LEFT JOIN ${sql.identifier(schema)}.${sql.identifier('premium_items')} p ON i.id = p.id`);
|
|
335
|
+
// We need to manually construct the polymorphic row structure if we want to test mapManyToEntity directly with subclasses
|
|
336
|
+
// But loadAll({ includeSubclasses: true }) already does this.
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
test('tryUpdateCTI with no changes', async () => {
|
|
340
|
+
await runInInjectionContext(injector, async () => {
|
|
341
|
+
const repository = injectRepository(PremiumItem);
|
|
342
|
+
const item = await repository.insert(Object.assign(new PremiumItem(), { name: 'NoChange', code: 'NC' }));
|
|
343
|
+
const updated = await repository.tryUpdate(item.id, {});
|
|
344
|
+
expect(updated.id).toBe(item.id);
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
test('tsvector search with various options', async () => {
|
|
348
|
+
await runInInjectionContext(injector, async () => {
|
|
349
|
+
const repository = injectRepository(SimpleItem);
|
|
350
|
+
await repository.insert(Object.assign(new SimpleItem(), { label: 'Search Item' }));
|
|
351
|
+
// score: false
|
|
352
|
+
const r1 = await repository.search({
|
|
353
|
+
query: { $tsvector: { fields: ['label'], query: 'Search' } },
|
|
354
|
+
score: false,
|
|
355
|
+
});
|
|
356
|
+
expect(r1[0].score).toBeUndefined();
|
|
357
|
+
// highlight variants
|
|
358
|
+
const r2 = await repository.search({
|
|
359
|
+
query: { $tsvector: { fields: ['label'], query: 'Search' } },
|
|
360
|
+
highlight: 'label',
|
|
361
|
+
});
|
|
362
|
+
expect(r2[0].highlight).toBeDefined();
|
|
363
|
+
const r3 = await repository.search({
|
|
364
|
+
query: { $tsvector: { fields: ['label'], query: 'Search' } },
|
|
365
|
+
highlight: { source: sql `label`, minWords: 5, maxWords: 10 },
|
|
366
|
+
});
|
|
367
|
+
expect(r3[0].highlight).toBeDefined();
|
|
368
|
+
// offset and limit
|
|
369
|
+
const r4 = await repository.search({
|
|
370
|
+
query: { $tsvector: { fields: ['label'], query: 'Search' } },
|
|
371
|
+
offset: 0,
|
|
372
|
+
limit: 1,
|
|
373
|
+
});
|
|
374
|
+
expect(r4).toHaveLength(1);
|
|
375
|
+
});
|
|
376
|
+
});
|
|
377
|
+
test('trigram search with rank: false', async () => {
|
|
378
|
+
await runInInjectionContext(injector, async () => {
|
|
379
|
+
const repository = injectRepository(SimpleItem);
|
|
380
|
+
await repository.insert(Object.assign(new SimpleItem(), { label: 'Trigram' }));
|
|
381
|
+
const results = await repository.search({
|
|
382
|
+
query: { $trigram: { fields: ['label'], query: 'Trigram' } },
|
|
383
|
+
rank: false,
|
|
384
|
+
});
|
|
385
|
+
expect(results).toHaveLength(1);
|
|
386
|
+
});
|
|
387
|
+
});
|
|
388
|
+
test('PlainItem (no metadata) operations', async () => {
|
|
389
|
+
await runInInjectionContext(injector, async () => {
|
|
390
|
+
const repository = injectRepository(PlainItem);
|
|
391
|
+
const item = await repository.insert(Object.assign(new PlainItem(), { description: 'Plain' }));
|
|
392
|
+
expect(repository.hasMetadata).toBe(false);
|
|
393
|
+
const deleted = await repository.delete(item.id);
|
|
394
|
+
expect(deleted.description).toBe('Plain');
|
|
395
|
+
const exists = await repository.has(item.id);
|
|
396
|
+
expect(exists).toBe(false);
|
|
397
|
+
});
|
|
398
|
+
});
|
|
399
|
+
test('convertOrderBy with object', async () => {
|
|
400
|
+
await runInInjectionContext(injector, async () => {
|
|
401
|
+
const repository = injectRepository(SimpleItem);
|
|
402
|
+
const order = repository.convertOrderBy({ label: 'desc' });
|
|
403
|
+
expect(order).toHaveLength(1);
|
|
404
|
+
});
|
|
405
|
+
});
|
|
406
|
+
test('tryHardDelete returning undefined', async () => {
|
|
407
|
+
await runInInjectionContext(injector, async () => {
|
|
408
|
+
const repository = injectRepository(SimpleItem);
|
|
409
|
+
const result = await repository.tryHardDelete('00000000-0000-0000-0000-000000000000');
|
|
410
|
+
expect(result).toBeUndefined();
|
|
411
|
+
});
|
|
412
|
+
});
|
|
413
|
+
test('tryHardDeleteByQuery returning undefined', async () => {
|
|
414
|
+
await runInInjectionContext(injector, async () => {
|
|
415
|
+
const repository = injectRepository(SimpleItem);
|
|
416
|
+
const result = await repository.tryHardDeleteByQuery({ label: 'Ghost' });
|
|
417
|
+
expect(result).toBeUndefined();
|
|
418
|
+
});
|
|
419
|
+
});
|
|
420
|
+
test('hardDeleteMany with empty array branch', async () => {
|
|
421
|
+
await runInInjectionContext(injector, async () => {
|
|
422
|
+
const repository = injectRepository(SimpleItem);
|
|
423
|
+
const results = await repository.hardDeleteMany([]);
|
|
424
|
+
expect(results).toEqual([]);
|
|
425
|
+
});
|
|
426
|
+
});
|
|
427
|
+
test('hardDeleteManyByQuery works', async () => {
|
|
428
|
+
await runInInjectionContext(injector, async () => {
|
|
429
|
+
const repository = injectRepository(SimpleItem);
|
|
430
|
+
await repository.insert(Object.assign(new SimpleItem(), { label: 'To Hard Delete' }));
|
|
431
|
+
const results = await repository.hardDeleteManyByQuery({ label: 'To Hard Delete' });
|
|
432
|
+
expect(results).toHaveLength(1);
|
|
433
|
+
});
|
|
434
|
+
});
|
|
435
|
+
test('applySelect with false (default)', async () => {
|
|
436
|
+
await runInInjectionContext(injector, async () => {
|
|
437
|
+
const repository = injectRepository(SimpleItem);
|
|
438
|
+
const q = repository.applySelect(database, undefined, false);
|
|
439
|
+
expect(q).toBeDefined();
|
|
440
|
+
});
|
|
441
|
+
});
|
|
442
|
+
test('load should throw NotFoundError', async () => {
|
|
443
|
+
await runInInjectionContext(injector, async () => {
|
|
444
|
+
const repository = injectRepository(SimpleItem);
|
|
445
|
+
await expect(repository.load('00000000-0000-0000-0000-000000000000')).rejects.toThrow(NotFoundError);
|
|
446
|
+
});
|
|
447
|
+
});
|
|
448
|
+
test('tsvector search with rank number', async () => {
|
|
449
|
+
await runInInjectionContext(injector, async () => {
|
|
450
|
+
const repository = injectRepository(SimpleItem);
|
|
451
|
+
await repository.insert(Object.assign(new SimpleItem(), { label: 'Rank' }));
|
|
452
|
+
const results = await repository.search({
|
|
453
|
+
query: { $tsvector: { fields: ['label'], query: 'Rank' } },
|
|
454
|
+
rank: { normalization: 1 }, // normalization
|
|
455
|
+
});
|
|
456
|
+
expect(results).toHaveLength(1);
|
|
457
|
+
});
|
|
458
|
+
});
|
|
459
|
+
test('encryptionSecret usage in getTransformContext', async () => {
|
|
460
|
+
await runInInjectionContext(injector, async () => {
|
|
461
|
+
await runInInjectionContext(injector, async () => {
|
|
462
|
+
const repository = injectRepository(SimpleItem);
|
|
463
|
+
const context = await repository.getTransformContext();
|
|
464
|
+
expect(context.encryptionKey).toBeDefined();
|
|
465
|
+
// Call it again to hit the cached branch
|
|
466
|
+
const context2 = await repository.getTransformContext();
|
|
467
|
+
expect(context2).toBe(context);
|
|
468
|
+
});
|
|
469
|
+
});
|
|
470
|
+
});
|
|
471
|
+
test('tsvector search with rank true/false', async () => {
|
|
472
|
+
await runInInjectionContext(injector, async () => {
|
|
473
|
+
const repository = injectRepository(SimpleItem);
|
|
474
|
+
await repository.insert(Object.assign(new SimpleItem(), { label: 'Rank' }));
|
|
475
|
+
await repository.search({
|
|
476
|
+
query: { $tsvector: { fields: ['label'], query: 'Rank' } },
|
|
477
|
+
rank: true,
|
|
478
|
+
});
|
|
479
|
+
await repository.search({
|
|
480
|
+
query: { $tsvector: { fields: ['label'], query: 'Rank' } },
|
|
481
|
+
rank: false,
|
|
482
|
+
});
|
|
483
|
+
});
|
|
484
|
+
});
|
|
485
|
+
test('trigram search with threshold', async () => {
|
|
486
|
+
await runInInjectionContext(injector, async () => {
|
|
487
|
+
const repository = injectRepository(SimpleItem);
|
|
488
|
+
await repository.insert(Object.assign(new SimpleItem(), { label: 'Trigram Threshold' }));
|
|
489
|
+
await database.execute(sql `SET pg_trgm.similarity_threshold = 0.1`);
|
|
490
|
+
const results = await repository.search({
|
|
491
|
+
query: { $trigram: { fields: ['label'], query: 'Trigram', threshold: 0.1 } },
|
|
492
|
+
});
|
|
493
|
+
expect(results).toHaveLength(1);
|
|
494
|
+
});
|
|
495
|
+
});
|
|
496
|
+
test('repository resolution inside transaction', async () => {
|
|
497
|
+
await database.transaction(async (transaction) => {
|
|
498
|
+
await runInInjectionContext(injector, async () => {
|
|
499
|
+
const repository = injectRepository(SimpleItem, transaction);
|
|
500
|
+
expect(repository).toBeDefined();
|
|
501
|
+
});
|
|
502
|
+
});
|
|
503
|
+
});
|
|
504
|
+
test('updateManyCTI with no matches', async () => {
|
|
505
|
+
await runInInjectionContext(injector, async () => {
|
|
506
|
+
const repository = injectRepository(PremiumItem);
|
|
507
|
+
const results = await repository.updateMany(['00000000-0000-0000-0000-000000000000'], { name: 'Ghost' });
|
|
508
|
+
expect(results).toEqual([]);
|
|
509
|
+
});
|
|
510
|
+
});
|
|
511
|
+
test('upsertMany on CTI with wheres and update object', async () => {
|
|
512
|
+
await runInInjectionContext(injector, async () => {
|
|
513
|
+
const repository = injectRepository(PremiumItem);
|
|
514
|
+
const item = await repository.insert(Object.assign(new PremiumItem(), { name: 'UpsertManyCTI', code: 'U1' }));
|
|
515
|
+
const conflictItem = Object.assign(new PremiumItem(), { id: item.id, name: 'UpsertManyCTI', code: 'U1' });
|
|
516
|
+
const results = await repository.upsertMany(['id'], [conflictItem], { name: 'UpsertManyCTI Updated', code: 'U2' }, { target: { name: 'UpsertManyCTI' } });
|
|
517
|
+
expect(results).toHaveLength(1);
|
|
518
|
+
expect(results[0].name).toBe('UpsertManyCTI Updated');
|
|
519
|
+
expect(results[0].code).toBe('U2');
|
|
520
|
+
});
|
|
521
|
+
});
|
|
522
|
+
test('updateManyCTI with no matches', async () => {
|
|
523
|
+
await runInInjectionContext(injector, async () => {
|
|
524
|
+
const repository = injectRepository(PremiumItem);
|
|
525
|
+
const results = await repository.updateMany(['00000000-0000-0000-0000-000000000000'], { name: 'Ghost' });
|
|
526
|
+
expect(results).toEqual([]);
|
|
527
|
+
});
|
|
528
|
+
});
|
|
529
|
+
test('upsertMany on CTI with wheres and update object', async () => {
|
|
530
|
+
await runInInjectionContext(injector, async () => {
|
|
531
|
+
const repository = injectRepository(PremiumItem);
|
|
532
|
+
const item = await repository.insert(Object.assign(new PremiumItem(), { name: 'UpsertManyCTI', code: 'U1' }));
|
|
533
|
+
const conflictItem = Object.assign(new PremiumItem(), { id: item.id, name: 'UpsertManyCTI', code: 'U1' });
|
|
534
|
+
const results = await repository.upsertMany(['id'], [conflictItem], { name: 'UpsertManyCTI Updated', code: 'U2' }, { target: { name: 'UpsertManyCTI' } });
|
|
535
|
+
expect(results).toHaveLength(1);
|
|
536
|
+
expect(results[0].name).toBe('UpsertManyCTI Updated');
|
|
537
|
+
expect(results[0].code).toBe('U2');
|
|
538
|
+
});
|
|
539
|
+
});
|
|
540
|
+
test('processExpirations with no expiration columns', async () => {
|
|
541
|
+
await runInInjectionContext(injector, async () => {
|
|
542
|
+
const repository = injectRepository(SimpleItem);
|
|
543
|
+
await repository.processExpirations(); // Should just return
|
|
544
|
+
});
|
|
545
|
+
});
|
|
546
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
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 { StringProperty } from '../../schema/index.js';
|
|
12
|
+
import { Entity } from '../entity.js';
|
|
13
|
+
import { Column, Inheritance, ChildEntity, Table } from '../decorators.js';
|
|
14
|
+
import { getRepository } from '../server/repository.js';
|
|
15
|
+
import { configureOrm } from '../server/index.js';
|
|
16
|
+
import { Injector, runInInjectionContext } from '../../injector/index.js';
|
|
17
|
+
describe('ORM Repository Mapping (CTI)', () => {
|
|
18
|
+
test('should flatten joined result when mapping child entity', async () => {
|
|
19
|
+
let BaseUser = class BaseUser extends Entity {
|
|
20
|
+
type;
|
|
21
|
+
name;
|
|
22
|
+
};
|
|
23
|
+
__decorate([
|
|
24
|
+
StringProperty(),
|
|
25
|
+
Column({ name: 'type' }),
|
|
26
|
+
__metadata("design:type", String)
|
|
27
|
+
], BaseUser.prototype, "type", void 0);
|
|
28
|
+
__decorate([
|
|
29
|
+
StringProperty(),
|
|
30
|
+
Column({ name: 'name' }),
|
|
31
|
+
__metadata("design:type", String)
|
|
32
|
+
], BaseUser.prototype, "name", void 0);
|
|
33
|
+
BaseUser = __decorate([
|
|
34
|
+
Table('users', { schema: 'test' }),
|
|
35
|
+
Inheritance({ strategy: 'joined', discriminatorColumn: 'type' })
|
|
36
|
+
], BaseUser);
|
|
37
|
+
let Admin = class Admin extends BaseUser {
|
|
38
|
+
role;
|
|
39
|
+
};
|
|
40
|
+
__decorate([
|
|
41
|
+
StringProperty(),
|
|
42
|
+
Column({ name: 'role' }),
|
|
43
|
+
__metadata("design:type", String)
|
|
44
|
+
], Admin.prototype, "role", void 0);
|
|
45
|
+
Admin = __decorate([
|
|
46
|
+
Table('admins', { schema: 'test' }),
|
|
47
|
+
ChildEntity('admin')
|
|
48
|
+
], Admin);
|
|
49
|
+
const injector = new Injector('Test');
|
|
50
|
+
configureOrm({
|
|
51
|
+
repositoryConfig: { schema: 'test' },
|
|
52
|
+
connection: { database: 'test' } // Mock config, we won't query DB
|
|
53
|
+
});
|
|
54
|
+
await runInInjectionContext(injector, async () => {
|
|
55
|
+
const repository = new (getRepository(Admin))();
|
|
56
|
+
// Simulate Drizzle joined result structure
|
|
57
|
+
const mockResult = {
|
|
58
|
+
users: { id: '123', type: 'admin', name: 'John Doe', revision: 1 },
|
|
59
|
+
admins: { id: '123', type: 'admin', role: 'super-admin' }
|
|
60
|
+
};
|
|
61
|
+
// Access private method for testing (using any cast)
|
|
62
|
+
const mappedEntity = await repository._mapToEntity(mockResult, {});
|
|
63
|
+
expect(mappedEntity).toBeInstanceOf(Admin);
|
|
64
|
+
expect(mappedEntity.id).toBe('123');
|
|
65
|
+
expect(mappedEntity.type).toBe('admin');
|
|
66
|
+
expect(mappedEntity.name).toBe('John Doe');
|
|
67
|
+
expect(mappedEntity.role).toBe('super-admin');
|
|
68
|
+
expect(mappedEntity.metadata.revision).toBe(1);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|