@tstdl/base 0.93.162 → 0.93.164
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/gateway.d.ts +1 -0
- package/api/server/gateway.js +11 -4
- package/authentication/tests/authentication.api-controller.test.js +24 -0
- package/circuit-breaker/postgres/circuit-breaker.d.ts +0 -3
- package/circuit-breaker/postgres/circuit-breaker.js +9 -12
- package/circuit-breaker/tests/circuit-breaker.test.js +7 -2
- package/object-storage/s3/tests/s3.object-storage.integration.test.js +2 -2
- package/orm/tests/build-jsonb.test.js +5 -5
- package/orm/tests/query-converter-complex.test.js +5 -5
- package/orm/tests/repository-cti-complex.test.js +54 -73
- package/orm/tests/repository-cti-embedded.test.js +9 -19
- package/orm/tests/repository-cti-search.test.js +12 -23
- package/orm/tests/repository-edge-cases.test.js +81 -119
- package/orm/tests/repository-mapping.test.js +3 -9
- package/orm/tests/repository-search-coverage.test.js +52 -74
- package/orm/tests/repository-transactions-nested.test.js +96 -120
- package/orm/tests/transactional.test.js +5 -14
- package/package.json +11 -11
- package/task-queue/tests/optimization-edge-cases.test.js +11 -14
- package/task-queue/tests/queue.test.js +29 -2
- package/testing/README.md +23 -35
- package/testing/integration-setup.d.ts +54 -7
- package/testing/integration-setup.js +147 -21
|
@@ -8,18 +8,16 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
8
8
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
9
|
};
|
|
10
10
|
import { sql } from 'drizzle-orm';
|
|
11
|
-
import {
|
|
11
|
+
import { describe, expect } from 'vitest';
|
|
12
12
|
import { NotFoundError } from '../../errors/not-found.error.js';
|
|
13
|
-
import { Injector, runInInjectionContext } from '../../injector/index.js';
|
|
14
13
|
import { StringProperty } from '../../schema/index.js';
|
|
14
|
+
import { getIntegrationTest } from '../../testing/index.js';
|
|
15
15
|
import { ChildEntity, Column, Inheritance, Table } from '../decorators.js';
|
|
16
16
|
import { Entity } from '../entity.js';
|
|
17
|
-
import { configureOrm, Database } from '../server/index.js';
|
|
18
17
|
import { injectRepository } from '../server/repository.js';
|
|
18
|
+
const schema = 'test_orm_edge_cases';
|
|
19
|
+
const test = getIntegrationTest({ orm: { schema } });
|
|
19
20
|
describe('ORM Repository Edge Cases', () => {
|
|
20
|
-
let injector;
|
|
21
|
-
let db;
|
|
22
|
-
const schema = 'test_orm_edge_cases';
|
|
23
21
|
let BaseItem = class BaseItem extends Entity {
|
|
24
22
|
type;
|
|
25
23
|
name;
|
|
@@ -48,15 +46,7 @@ describe('ORM Repository Edge Cases', () => {
|
|
|
48
46
|
Table('derived_items', { schema }),
|
|
49
47
|
ChildEntity('derived')
|
|
50
48
|
], DerivedItem);
|
|
51
|
-
|
|
52
|
-
injector = new Injector('Test');
|
|
53
|
-
configureOrm({
|
|
54
|
-
repositoryConfig: { schema },
|
|
55
|
-
connection: {
|
|
56
|
-
host: '127.0.0.1', port: 5432, user: 'tstdl', password: 'wf7rq6glrk5jykne', database: 'tstdl',
|
|
57
|
-
},
|
|
58
|
-
});
|
|
59
|
-
db = injector.resolve(Database);
|
|
49
|
+
test.beforeEach(async ({ database: db }) => {
|
|
60
50
|
await db.execute(sql `CREATE SCHEMA IF NOT EXISTS ${sql.identifier(schema)}`);
|
|
61
51
|
await db.execute(sql `DROP TABLE IF EXISTS ${sql.identifier(schema)}.${sql.identifier('derived_items')} CASCADE`);
|
|
62
52
|
await db.execute(sql `DROP TABLE IF EXISTS ${sql.identifier(schema)}.${sql.identifier('base_items')} CASCADE`);
|
|
@@ -83,134 +73,106 @@ describe('ORM Repository Edge Cases', () => {
|
|
|
83
73
|
`);
|
|
84
74
|
});
|
|
85
75
|
test('should rollback transaction on insertMany failure', async () => {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
expect(count).toBe(0);
|
|
100
|
-
});
|
|
76
|
+
const repo = injectRepository(BaseItem);
|
|
77
|
+
const id = '00000000-0000-0000-0000-000000000001';
|
|
78
|
+
try {
|
|
79
|
+
await repo.insertMany([
|
|
80
|
+
Object.assign(new BaseItem(), { id, name: 'Success', type: 'base' }),
|
|
81
|
+
Object.assign(new BaseItem(), { id, name: 'Fail', type: 'base' }), // Duplicate ID
|
|
82
|
+
]);
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// Expected
|
|
86
|
+
}
|
|
87
|
+
const count = await repo.count();
|
|
88
|
+
expect(count).toBe(0);
|
|
101
89
|
});
|
|
102
90
|
test('should rollback transaction on updateMany failure', async () => {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
expect(item.name).toBe('Item 1');
|
|
118
|
-
});
|
|
91
|
+
const repo = injectRepository(BaseItem);
|
|
92
|
+
await repo.insert(Object.assign(new BaseItem(), { name: 'Item 1', type: 'base' }));
|
|
93
|
+
try {
|
|
94
|
+
await repo.transaction(async (tx) => {
|
|
95
|
+
const txRepo = repo.withTransaction(tx);
|
|
96
|
+
await txRepo.updateManyByQuery({}, { name: 'Updated' });
|
|
97
|
+
throw new Error('Rollback');
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
// Expected
|
|
102
|
+
}
|
|
103
|
+
const item = await repo.loadByQuery({ name: 'Item 1' });
|
|
104
|
+
expect(item.name).toBe('Item 1');
|
|
119
105
|
});
|
|
120
106
|
test('should throw on negative offset', async () => {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
await expect(repo.loadAll({ offset: -1 })).rejects.toThrow();
|
|
124
|
-
});
|
|
107
|
+
const repo = injectRepository(BaseItem);
|
|
108
|
+
await expect(repo.loadAll({ offset: -1 })).rejects.toThrow();
|
|
125
109
|
});
|
|
126
110
|
test('should fail when unique constraint is violated even if soft deleted', async () => {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
await expect(repo.insert(Object.assign(new BaseItem(), { id, name: 'B', type: 'base' }))).rejects.toThrow();
|
|
134
|
-
});
|
|
111
|
+
const repo = injectRepository(BaseItem);
|
|
112
|
+
const id = '00000000-0000-0000-0000-000000000002';
|
|
113
|
+
await repo.insert(Object.assign(new BaseItem(), { id, name: 'A', type: 'base' }));
|
|
114
|
+
await repo.delete(id);
|
|
115
|
+
// Attempt to insert same ID again (Unique violation)
|
|
116
|
+
await expect(repo.insert(Object.assign(new BaseItem(), { id, name: 'B', type: 'base' }))).rejects.toThrow();
|
|
135
117
|
});
|
|
136
|
-
test('should fail loading if child row is missing (data corruption)', async () => {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
expect(loadedBase.description).toBeNull();
|
|
152
|
-
});
|
|
118
|
+
test('should fail loading if child row is missing (data corruption)', async ({ database: db }) => {
|
|
119
|
+
const derivedRepo = injectRepository(DerivedItem);
|
|
120
|
+
const baseRepo = injectRepository(BaseItem);
|
|
121
|
+
const derived = await derivedRepo.insert(Object.assign(new DerivedItem(), { name: 'Derived', description: 'Desc' }));
|
|
122
|
+
// Manually delete child row
|
|
123
|
+
await db.execute(sql `DELETE FROM ${sql.identifier(schema)}.${sql.identifier('derived_items')} WHERE id = ${derived.id}`);
|
|
124
|
+
// Verify deletion
|
|
125
|
+
const { rows } = await db.execute(sql `SELECT * FROM ${sql.identifier(schema)}.${sql.identifier('derived_items')} WHERE id = ${derived.id}`);
|
|
126
|
+
expect(rows).toHaveLength(0);
|
|
127
|
+
// Child repo should fail because primary table row is missing
|
|
128
|
+
await expect(derivedRepo.load(derived.id)).rejects.toThrow(NotFoundError);
|
|
129
|
+
// Base repo should succeed (returning corrupted entity) because base row exists and it uses left join for subclasses
|
|
130
|
+
const loadedBase = await baseRepo.load(derived.id, { includeSubclasses: true });
|
|
131
|
+
expect(loadedBase).toBeInstanceOf(DerivedItem);
|
|
132
|
+
expect(loadedBase.description).toBeNull();
|
|
153
133
|
});
|
|
154
134
|
test('should throw NotFoundError when update target does not exist', async () => {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
await expect(repo.update('00000000-0000-0000-0000-000000000000', { name: 'New' })).rejects.toThrow(NotFoundError);
|
|
158
|
-
});
|
|
135
|
+
const repo = injectRepository(BaseItem);
|
|
136
|
+
await expect(repo.update('00000000-0000-0000-0000-000000000000', { name: 'New' })).rejects.toThrow(NotFoundError);
|
|
159
137
|
});
|
|
160
138
|
test('should throw NotFoundError when updateByQuery matches nothing', async () => {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
await expect(repo.updateByQuery({ name: 'Missing' }, { name: 'New' })).rejects.toThrow(NotFoundError);
|
|
164
|
-
});
|
|
139
|
+
const repo = injectRepository(BaseItem);
|
|
140
|
+
await expect(repo.updateByQuery({ name: 'Missing' }, { name: 'New' })).rejects.toThrow(NotFoundError);
|
|
165
141
|
});
|
|
166
142
|
test('should throw NotFoundError when delete target does not exist', async () => {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
await expect(repo.delete('00000000-0000-0000-0000-000000000000')).rejects.toThrow(NotFoundError);
|
|
170
|
-
});
|
|
143
|
+
const repo = injectRepository(BaseItem);
|
|
144
|
+
await expect(repo.delete('00000000-0000-0000-0000-000000000000')).rejects.toThrow(NotFoundError);
|
|
171
145
|
});
|
|
172
146
|
test('should throw NotFoundError when deleteByQuery matches nothing', async () => {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
await expect(repo.deleteByQuery({ name: 'Missing' })).rejects.toThrow(NotFoundError);
|
|
176
|
-
});
|
|
147
|
+
const repo = injectRepository(BaseItem);
|
|
148
|
+
await expect(repo.deleteByQuery({ name: 'Missing' })).rejects.toThrow(NotFoundError);
|
|
177
149
|
});
|
|
178
150
|
test('should throw NotFoundError when hardDelete target does not exist', async () => {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
await expect(repo.hardDelete('00000000-0000-0000-0000-000000000000')).rejects.toThrow(NotFoundError);
|
|
182
|
-
});
|
|
151
|
+
const repo = injectRepository(BaseItem);
|
|
152
|
+
await expect(repo.hardDelete('00000000-0000-0000-0000-000000000000')).rejects.toThrow(NotFoundError);
|
|
183
153
|
});
|
|
184
154
|
test('should throw NotFoundError when hardDeleteByQuery matches nothing', async () => {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
await expect(repo.hardDeleteByQuery({ name: 'Missing' })).rejects.toThrow(NotFoundError);
|
|
188
|
-
});
|
|
155
|
+
const repo = injectRepository(BaseItem);
|
|
156
|
+
await expect(repo.hardDeleteByQuery({ name: 'Missing' })).rejects.toThrow(NotFoundError);
|
|
189
157
|
});
|
|
190
158
|
test('should handle empty updates gracefully', async () => {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
expect(updated.name).toBe('EmptyUpdate');
|
|
197
|
-
});
|
|
159
|
+
const repo = injectRepository(BaseItem);
|
|
160
|
+
const item = await repo.insert(Object.assign(new BaseItem(), { name: 'EmptyUpdate', type: 'base' }));
|
|
161
|
+
const updated = await repo.update(item.id, {});
|
|
162
|
+
expect(updated.metadata.revision).toBeGreaterThan(item.metadata.revision);
|
|
163
|
+
expect(updated.name).toBe('EmptyUpdate');
|
|
198
164
|
});
|
|
199
165
|
test('should handle unknown properties in query gracefully (throw error)', async () => {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
await expect(repo.loadByQuery({ unknownProp: 'value' })).rejects.toThrow('Could not map property unknownProp');
|
|
203
|
-
});
|
|
166
|
+
const repo = injectRepository(BaseItem);
|
|
167
|
+
await expect(repo.loadByQuery({ unknownProp: 'value' })).rejects.toThrow('Could not map property unknownProp');
|
|
204
168
|
});
|
|
205
169
|
test('should prevent updating discriminator column via update', async () => {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
expect(reloaded.type).toBe('derived');
|
|
214
|
-
});
|
|
170
|
+
const repo = injectRepository(BaseItem);
|
|
171
|
+
const item = await repo.insert(Object.assign(new BaseItem(), { name: 'TypeCheck', type: 'base' }));
|
|
172
|
+
// Try to change type to 'derived'
|
|
173
|
+
await repo.update(item.id, { type: 'derived' });
|
|
174
|
+
const reloaded = await repo.load(item.id);
|
|
175
|
+
// It should change if not blocked
|
|
176
|
+
expect(reloaded.type).toBe('derived');
|
|
215
177
|
});
|
|
216
178
|
});
|
|
@@ -9,11 +9,10 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
9
9
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
10
|
};
|
|
11
11
|
import { describe, expect, test } from 'vitest';
|
|
12
|
-
import { Injector } from '../../injector/index.js';
|
|
13
12
|
import { StringProperty } from '../../schema/index.js';
|
|
13
|
+
import { setupIntegrationTest } from '../../testing/index.js';
|
|
14
14
|
import { ChildEntity, Column, Inheritance, Table } from '../decorators.js';
|
|
15
15
|
import { Entity } from '../entity.js';
|
|
16
|
-
import { configureOrm } from '../server/index.js';
|
|
17
16
|
import { getRepository } from '../server/repository.js';
|
|
18
17
|
describe('ORM Repository Mapping (CTI)', () => {
|
|
19
18
|
test('should flatten joined result when mapping child entity', async () => {
|
|
@@ -47,17 +46,12 @@ describe('ORM Repository Mapping (CTI)', () => {
|
|
|
47
46
|
Table('admins', { schema: 'test' }),
|
|
48
47
|
ChildEntity('admin')
|
|
49
48
|
], Admin);
|
|
50
|
-
const injector =
|
|
51
|
-
configureOrm({
|
|
52
|
-
repositoryConfig: { schema: 'test' },
|
|
53
|
-
connection: { database: 'test' }, // Mock config, we won't query DB
|
|
54
|
-
injector,
|
|
55
|
-
});
|
|
49
|
+
const { injector } = await setupIntegrationTest({ orm: { schema: 'test' } });
|
|
56
50
|
const repository = injector.resolve(getRepository(Admin));
|
|
57
51
|
// Simulate Drizzle joined result structure
|
|
58
52
|
const mockResult = {
|
|
59
53
|
users: { id: '123', type: 'admin', name: 'John Doe', revision: 1 },
|
|
60
|
-
admins: { id: '123', type: 'admin', role: 'super-admin' }
|
|
54
|
+
admins: { id: '123', type: 'admin', role: 'super-admin' },
|
|
61
55
|
};
|
|
62
56
|
// Access private method for testing (using any cast)
|
|
63
57
|
const mappedEntity = await repository._mapToEntity(mockResult, {});
|
|
@@ -7,18 +7,16 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
8
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
9
|
};
|
|
10
|
-
import { beforeAll, describe, expect, test } from 'vitest';
|
|
11
10
|
import { sql } from 'drizzle-orm';
|
|
11
|
+
import { describe, expect } from 'vitest';
|
|
12
12
|
import { StringProperty } from '../../schema/index.js';
|
|
13
|
-
import {
|
|
13
|
+
import { getIntegrationTest } from '../../testing/index.js';
|
|
14
14
|
import { Table } from '../decorators.js';
|
|
15
|
+
import { Entity } from '../entity.js';
|
|
15
16
|
import { injectRepository } from '../server/repository.js';
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
const schema = 'test_orm_search_coverage';
|
|
18
|
+
const test = getIntegrationTest({ orm: { schema } });
|
|
18
19
|
describe('ORM Repository Search Coverage', () => {
|
|
19
|
-
let injector;
|
|
20
|
-
let db;
|
|
21
|
-
const schema = 'test_orm_search_coverage';
|
|
22
20
|
let Document = class Document extends Entity {
|
|
23
21
|
content;
|
|
24
22
|
};
|
|
@@ -29,15 +27,7 @@ describe('ORM Repository Search Coverage', () => {
|
|
|
29
27
|
Document = __decorate([
|
|
30
28
|
Table('docs', { schema })
|
|
31
29
|
], Document);
|
|
32
|
-
|
|
33
|
-
injector = new Injector('TestSearchCoverage');
|
|
34
|
-
configureOrm({
|
|
35
|
-
repositoryConfig: { schema },
|
|
36
|
-
connection: {
|
|
37
|
-
host: '127.0.0.1', port: 5432, user: 'tstdl', password: 'wf7rq6glrk5jykne', database: 'tstdl',
|
|
38
|
-
},
|
|
39
|
-
});
|
|
40
|
-
db = injector.resolve(Database);
|
|
30
|
+
test.beforeEach(async ({ database: db }) => {
|
|
41
31
|
await db.execute(sql `CREATE SCHEMA IF NOT EXISTS ${sql.identifier(schema)}`);
|
|
42
32
|
await db.execute(sql `DROP TABLE IF EXISTS ${sql.identifier(schema)}.${sql.identifier('docs')} CASCADE`);
|
|
43
33
|
await db.execute(sql `CREATE EXTENSION IF NOT EXISTS pg_trgm`); // Enable trigram
|
|
@@ -54,76 +44,64 @@ describe('ORM Repository Search Coverage', () => {
|
|
|
54
44
|
`);
|
|
55
45
|
});
|
|
56
46
|
test('tsvector search with order function accessing score', async () => {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
order: (cols) => [[cols.score, 'desc']]
|
|
63
|
-
});
|
|
64
|
-
expect(results).toHaveLength(1);
|
|
47
|
+
const repository = injectRepository(Document);
|
|
48
|
+
await repository.insert(Object.assign(new Document(), { content: 'Apple Banana' }));
|
|
49
|
+
const results = await repository.search({
|
|
50
|
+
query: { $tsvector: { fields: ['content'], query: 'Apple' } },
|
|
51
|
+
order: (cols) => [[cols.score, 'desc']],
|
|
65
52
|
});
|
|
53
|
+
expect(results).toHaveLength(1);
|
|
66
54
|
});
|
|
67
55
|
test('trigram search basic', async () => {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
query: { $trigram: { fields: ['content'], query: 'Trigram' } },
|
|
73
|
-
});
|
|
74
|
-
expect(results).toHaveLength(1);
|
|
56
|
+
const repository = injectRepository(Document);
|
|
57
|
+
await repository.insert(Object.assign(new Document(), { content: 'Trigram Test' }));
|
|
58
|
+
const results = await repository.search({
|
|
59
|
+
query: { $trigram: { fields: ['content'], query: 'Trigram' } },
|
|
75
60
|
});
|
|
61
|
+
expect(results).toHaveLength(1);
|
|
76
62
|
});
|
|
77
|
-
test('trigram search with threshold (phrase)', async () => {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
query: { $trigram: { fields: ['content'], query: 'Phrase', type: 'phrase', threshold: 0.1 } },
|
|
85
|
-
});
|
|
86
|
-
expect(results).toHaveLength(1);
|
|
63
|
+
test('trigram search with threshold (phrase)', async ({ database: db }) => {
|
|
64
|
+
const repository = injectRepository(Document);
|
|
65
|
+
await repository.insert(Object.assign(new Document(), { content: 'Phrase Match' }));
|
|
66
|
+
// Set threshold to a value that allows matching (default is 0.3)
|
|
67
|
+
await db.execute(sql `SET pg_trgm.similarity_threshold = 0.1`);
|
|
68
|
+
const results = await repository.search({
|
|
69
|
+
query: { $trigram: { fields: ['content'], query: 'Phrase', type: 'phrase', threshold: 0.1 } },
|
|
87
70
|
});
|
|
71
|
+
expect(results).toHaveLength(1);
|
|
88
72
|
});
|
|
89
|
-
test('trigram search with threshold (word)', async () => {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
query: { $trigram: { fields: ['content'], query: 'Word', type: 'word', threshold: 0.1 } },
|
|
96
|
-
});
|
|
97
|
-
expect(results).toHaveLength(1);
|
|
73
|
+
test('trigram search with threshold (word)', async ({ database: db }) => {
|
|
74
|
+
const repository = injectRepository(Document);
|
|
75
|
+
await repository.insert(Object.assign(new Document(), { content: 'Word Match' }));
|
|
76
|
+
await db.execute(sql `SET pg_trgm.word_similarity_threshold = 0.1`);
|
|
77
|
+
const results = await repository.search({
|
|
78
|
+
query: { $trigram: { fields: ['content'], query: 'Word', type: 'word', threshold: 0.1 } },
|
|
98
79
|
});
|
|
80
|
+
expect(results).toHaveLength(1);
|
|
99
81
|
});
|
|
100
|
-
test('trigram search with threshold (strict-word)', async () => {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
query: { $trigram: { fields: ['content'], query: 'Strict', type: 'strict-word', threshold: 0.1 } },
|
|
107
|
-
});
|
|
108
|
-
expect(results).toHaveLength(1);
|
|
82
|
+
test('trigram search with threshold (strict-word)', async ({ database: db }) => {
|
|
83
|
+
const repository = injectRepository(Document);
|
|
84
|
+
await repository.insert(Object.assign(new Document(), { content: 'Strict Match' }));
|
|
85
|
+
await db.execute(sql `SET pg_trgm.strict_word_similarity_threshold = 0.1`);
|
|
86
|
+
const results = await repository.search({
|
|
87
|
+
query: { $trigram: { fields: ['content'], query: 'Strict', type: 'strict-word', threshold: 0.1 } },
|
|
109
88
|
});
|
|
89
|
+
expect(results).toHaveLength(1);
|
|
110
90
|
});
|
|
111
91
|
test('trigram search with order function', async () => {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
order: ({ score }) => [[score, 'desc']]
|
|
125
|
-
});
|
|
126
|
-
expect(results2).toHaveLength(1);
|
|
92
|
+
const repository = injectRepository(Document);
|
|
93
|
+
const results = await repository.search({
|
|
94
|
+
query: { $trigram: { fields: ['content'], query: 'Order' } },
|
|
95
|
+
order: ({ score }) => [[score, 'desc']],
|
|
96
|
+
});
|
|
97
|
+
// Even if no results, code path is exercised?
|
|
98
|
+
// No, order function is called only if query is executed.
|
|
99
|
+
// Insert something first
|
|
100
|
+
await repository.insert(Object.assign(new Document(), { content: 'Order Test' }));
|
|
101
|
+
const results2 = await repository.search({
|
|
102
|
+
query: { $trigram: { fields: ['content'], query: 'Order' } },
|
|
103
|
+
order: ({ score }) => [[score, 'desc']],
|
|
127
104
|
});
|
|
105
|
+
expect(results2).toHaveLength(1);
|
|
128
106
|
});
|
|
129
107
|
});
|