@expo/entity-database-adapter-knex 0.42.0 → 0.44.0
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@expo/entity-database-adapter-knex",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.44.0",
|
|
4
4
|
"description": "Knex database adapter for @expo/entity",
|
|
5
5
|
"files": [
|
|
6
6
|
"build",
|
|
@@ -28,24 +28,24 @@
|
|
|
28
28
|
"author": "Expo",
|
|
29
29
|
"license": "MIT",
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@expo/entity": "^0.
|
|
31
|
+
"@expo/entity": "^0.44.0",
|
|
32
32
|
"knex": "^3.1.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@expo/entity-testing-utils": "^0.
|
|
35
|
+
"@expo/entity-testing-utils": "^0.44.0",
|
|
36
36
|
"@types/jest": "^29.5.14",
|
|
37
37
|
"@types/node": "^20.14.1",
|
|
38
38
|
"ctix": "^2.7.0",
|
|
39
|
-
"eslint": "^
|
|
40
|
-
"eslint-config-universe": "^
|
|
41
|
-
"eslint-plugin-tsdoc": "^0.
|
|
39
|
+
"eslint": "^9.26.0",
|
|
40
|
+
"eslint-config-universe": "^15.0.3",
|
|
41
|
+
"eslint-plugin-tsdoc": "^0.4.0",
|
|
42
42
|
"jest": "^29.7.0",
|
|
43
43
|
"pg": "8.14.1",
|
|
44
|
-
"prettier": "^3.
|
|
44
|
+
"prettier": "^3.5.3",
|
|
45
45
|
"prettier-plugin-organize-imports": "^4.1.0",
|
|
46
|
-
"ts-jest": "^29.3.
|
|
46
|
+
"ts-jest": "^29.3.2",
|
|
47
47
|
"ts-mockito": "^2.6.1",
|
|
48
48
|
"typescript": "^5.8.3"
|
|
49
49
|
},
|
|
50
|
-
"gitHead": "
|
|
50
|
+
"gitHead": "b9b09933e5a5b02037aa4688c5969705a29995c0"
|
|
51
51
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ViewerContext } from '@expo/entity';
|
|
1
|
+
import { TransactionalDataLoaderMode, ViewerContext } from '@expo/entity';
|
|
2
2
|
import { knex, Knex } from 'knex';
|
|
3
3
|
import nullthrows from 'nullthrows';
|
|
4
4
|
|
|
@@ -47,7 +47,7 @@ describe(PostgresEntityQueryContextProvider, () => {
|
|
|
47
47
|
.updateAsync();
|
|
48
48
|
|
|
49
49
|
// ensure the outer transaction is not aborted due to postgres error in inner transaction,
|
|
50
|
-
// in this case the error triggered is a unique constraint violation
|
|
50
|
+
// in this case the error triggered is a unique constraint violation from a conflict with the first entity created above
|
|
51
51
|
try {
|
|
52
52
|
await queryContext.runInNestedTransactionAsync(async (innerQueryContext) => {
|
|
53
53
|
const entity = await PostgresUniqueTestEntity.loader(
|
|
@@ -70,6 +70,360 @@ describe(PostgresEntityQueryContextProvider, () => {
|
|
|
70
70
|
expect(entityLoaded.getField('name')).toEqual('wat3');
|
|
71
71
|
});
|
|
72
72
|
|
|
73
|
+
test('dataloader consistency with nested transactions', async () => {
|
|
74
|
+
const vc1 = new ViewerContext(createKnexIntegrationTestEntityCompanionProvider(knexInstance));
|
|
75
|
+
|
|
76
|
+
// put it in local dataloader
|
|
77
|
+
const entity = await PostgresUniqueTestEntity.creator(vc1)
|
|
78
|
+
.setField('name', 'who')
|
|
79
|
+
.createAsync();
|
|
80
|
+
const entityLoaded = await PostgresUniqueTestEntity.loader(vc1).loadByIDAsync(entity.getID());
|
|
81
|
+
expect(entityLoaded.getField('name')).toEqual('who');
|
|
82
|
+
|
|
83
|
+
await vc1.runInTransactionForDatabaseAdaptorFlavorAsync('postgres', async (queryContext) => {
|
|
84
|
+
const entityLoadedOuter = await PostgresUniqueTestEntity.loader(vc1).loadByIDAsync(
|
|
85
|
+
entity.getID(),
|
|
86
|
+
);
|
|
87
|
+
expect(entityLoadedOuter.getField('name')).toEqual('who');
|
|
88
|
+
|
|
89
|
+
await queryContext.runInNestedTransactionAsync(async (innerQueryContext) => {
|
|
90
|
+
const entityLoadedInner = await PostgresUniqueTestEntity.loader(
|
|
91
|
+
vc1,
|
|
92
|
+
innerQueryContext,
|
|
93
|
+
).loadByIDAsync(entity.getID());
|
|
94
|
+
const updatedEntity = await PostgresUniqueTestEntity.updater(
|
|
95
|
+
entityLoadedInner,
|
|
96
|
+
innerQueryContext,
|
|
97
|
+
)
|
|
98
|
+
.setField('name', 'wat')
|
|
99
|
+
.updateAsync();
|
|
100
|
+
expect(updatedEntity.getField('name')).toEqual('wat');
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
const entityLoadedAfterNested = await PostgresUniqueTestEntity.loader(
|
|
104
|
+
vc1,
|
|
105
|
+
queryContext,
|
|
106
|
+
).loadByIDAsync(entity.getID());
|
|
107
|
+
expect(entityLoadedAfterNested.getField('name')).toEqual('wat');
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const entityLoadedAfterTransaction = await PostgresUniqueTestEntity.loader(vc1).loadByIDAsync(
|
|
111
|
+
entity.getID(),
|
|
112
|
+
);
|
|
113
|
+
expect(entityLoadedAfterTransaction.getField('name')).toEqual('wat');
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test('dataloader consistency with nested transactions that throw', async () => {
|
|
117
|
+
const vc1 = new ViewerContext(createKnexIntegrationTestEntityCompanionProvider(knexInstance));
|
|
118
|
+
|
|
119
|
+
// put it in local dataloader
|
|
120
|
+
const entity = await PostgresUniqueTestEntity.creator(vc1)
|
|
121
|
+
.setField('name', 'who')
|
|
122
|
+
.createAsync();
|
|
123
|
+
const entityLoaded = await PostgresUniqueTestEntity.loader(vc1).loadByIDAsync(entity.getID());
|
|
124
|
+
expect(entityLoaded.getField('name')).toEqual('who');
|
|
125
|
+
|
|
126
|
+
await vc1.runInTransactionForDatabaseAdaptorFlavorAsync('postgres', async (queryContext) => {
|
|
127
|
+
const entityLoadedOuter = await PostgresUniqueTestEntity.loader(vc1).loadByIDAsync(
|
|
128
|
+
entity.getID(),
|
|
129
|
+
);
|
|
130
|
+
expect(entityLoadedOuter.getField('name')).toEqual('who');
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
await queryContext.runInNestedTransactionAsync(async (innerQueryContext) => {
|
|
134
|
+
const entityLoadedInner = await PostgresUniqueTestEntity.loader(
|
|
135
|
+
vc1,
|
|
136
|
+
innerQueryContext,
|
|
137
|
+
).loadByIDAsync(entity.getID());
|
|
138
|
+
const updatedEntity = await PostgresUniqueTestEntity.updater(
|
|
139
|
+
entityLoadedInner,
|
|
140
|
+
innerQueryContext,
|
|
141
|
+
)
|
|
142
|
+
.setField('name', 'wat')
|
|
143
|
+
.updateAsync();
|
|
144
|
+
expect(updatedEntity.getField('name')).toEqual('wat');
|
|
145
|
+
throw new Error('wat');
|
|
146
|
+
});
|
|
147
|
+
} catch {}
|
|
148
|
+
|
|
149
|
+
const entityLoadedAfterNested = await PostgresUniqueTestEntity.loader(
|
|
150
|
+
vc1,
|
|
151
|
+
queryContext,
|
|
152
|
+
).loadByIDAsync(entity.getID());
|
|
153
|
+
expect(entityLoadedAfterNested.getField('name')).toEqual('who');
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
const entityLoadedAfterTransaction = await PostgresUniqueTestEntity.loader(vc1).loadByIDAsync(
|
|
157
|
+
entity.getID(),
|
|
158
|
+
);
|
|
159
|
+
expect(entityLoadedAfterTransaction.getField('name')).toEqual('who');
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test('dataloader consistency with concurrent loads outside of transaction', async () => {
|
|
163
|
+
const vc1 = new ViewerContext(createKnexIntegrationTestEntityCompanionProvider(knexInstance));
|
|
164
|
+
|
|
165
|
+
// put it in local dataloader
|
|
166
|
+
const entity = await PostgresUniqueTestEntity.creator(vc1)
|
|
167
|
+
.setField('name', 'who')
|
|
168
|
+
.createAsync();
|
|
169
|
+
const entityLoaded = await PostgresUniqueTestEntity.loader(vc1).loadByIDAsync(entity.getID());
|
|
170
|
+
expect(entityLoaded.getField('name')).toEqual('who');
|
|
171
|
+
|
|
172
|
+
let openBarrier1: () => void;
|
|
173
|
+
const barrier1 = new Promise<void>((resolve) => {
|
|
174
|
+
openBarrier1 = resolve;
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
let openBarrier2: () => void;
|
|
178
|
+
const barrier2 = new Promise<void>((resolve) => {
|
|
179
|
+
openBarrier2 = resolve;
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
await Promise.all([
|
|
183
|
+
vc1.runInTransactionForDatabaseAdaptorFlavorAsync('postgres', async (queryContext) => {
|
|
184
|
+
const entityLoadedOuter = await PostgresUniqueTestEntity.loader(vc1).loadByIDAsync(
|
|
185
|
+
entity.getID(),
|
|
186
|
+
);
|
|
187
|
+
expect(entityLoadedOuter.getField('name')).toEqual('who');
|
|
188
|
+
|
|
189
|
+
await queryContext.runInNestedTransactionAsync(async (innerQueryContext) => {
|
|
190
|
+
const entityLoadedInner = await PostgresUniqueTestEntity.loader(
|
|
191
|
+
vc1,
|
|
192
|
+
innerQueryContext,
|
|
193
|
+
).loadByIDAsync(entity.getID());
|
|
194
|
+
const updatedEntity = await PostgresUniqueTestEntity.updater(
|
|
195
|
+
entityLoadedInner,
|
|
196
|
+
innerQueryContext,
|
|
197
|
+
)
|
|
198
|
+
.setField('name', 'wat')
|
|
199
|
+
.updateAsync();
|
|
200
|
+
expect(updatedEntity.getField('name')).toEqual('wat');
|
|
201
|
+
const entityLoadedAfterUpdate = await PostgresUniqueTestEntity.loader(
|
|
202
|
+
vc1,
|
|
203
|
+
innerQueryContext,
|
|
204
|
+
).loadByIDAsync(entity.getID());
|
|
205
|
+
expect(entityLoadedAfterUpdate.getField('name')).toEqual('wat');
|
|
206
|
+
});
|
|
207
|
+
openBarrier1();
|
|
208
|
+
await barrier2;
|
|
209
|
+
}),
|
|
210
|
+
(async () => {
|
|
211
|
+
await barrier1;
|
|
212
|
+
|
|
213
|
+
const entityLoadedOutsideOfTransactionsBeforeNestedCommit =
|
|
214
|
+
await PostgresUniqueTestEntity.loader(vc1).loadByIDAsync(entity.getID());
|
|
215
|
+
expect(entityLoadedOutsideOfTransactionsBeforeNestedCommit.getField('name')).toEqual('who');
|
|
216
|
+
openBarrier2!();
|
|
217
|
+
})(),
|
|
218
|
+
]);
|
|
219
|
+
|
|
220
|
+
const entityLoadedAfterTransaction = await PostgresUniqueTestEntity.loader(vc1).loadByIDAsync(
|
|
221
|
+
entity.getID(),
|
|
222
|
+
);
|
|
223
|
+
expect(entityLoadedAfterTransaction.getField('name')).toEqual('wat');
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
test('consistent behavior with and without transactional dataloader for concurrent loads outside of nested transaction', async () => {
|
|
227
|
+
// Subtransactions are not supported in postgres. See #194 for more info.
|
|
228
|
+
// Instead, savepoints and rollbacks are used to simulate subtransactions, which results in non-isolated read semantics.
|
|
229
|
+
//
|
|
230
|
+
// This test tests the same behavior exists whether there is a dataloader or not in transactions, thus indicating that
|
|
231
|
+
// the dataloader invalidation is not the issue.
|
|
232
|
+
|
|
233
|
+
const runTest = async (
|
|
234
|
+
transactionalDataLoaderMode: TransactionalDataLoaderMode,
|
|
235
|
+
): Promise<void> => {
|
|
236
|
+
const vc1 = new ViewerContext(createKnexIntegrationTestEntityCompanionProvider(knexInstance));
|
|
237
|
+
await vc1.runInTransactionForDatabaseAdaptorFlavorAsync(
|
|
238
|
+
'postgres',
|
|
239
|
+
async (outerQueryContext) => {
|
|
240
|
+
// put it in local dataloader
|
|
241
|
+
const entity = await PostgresUniqueTestEntity.creator(vc1, outerQueryContext)
|
|
242
|
+
.setField('name', 'who')
|
|
243
|
+
.createAsync();
|
|
244
|
+
const entityLoaded = await PostgresUniqueTestEntity.loader(
|
|
245
|
+
vc1,
|
|
246
|
+
outerQueryContext,
|
|
247
|
+
).loadByIDAsync(entity.getID());
|
|
248
|
+
if (entityLoaded.getField('name') !== 'who') {
|
|
249
|
+
throw new Error('entity loaded wrong value');
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
let openBarrier1: () => void;
|
|
253
|
+
const barrier1 = new Promise<void>((resolve) => {
|
|
254
|
+
openBarrier1 = resolve;
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
let openBarrier2: () => void;
|
|
258
|
+
const barrier2 = new Promise<void>((resolve) => {
|
|
259
|
+
openBarrier2 = resolve;
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
await Promise.all([
|
|
263
|
+
outerQueryContext.runInNestedTransactionAsync(async (innerQueryContext) => {
|
|
264
|
+
const entityLoadedInner = await PostgresUniqueTestEntity.loader(
|
|
265
|
+
vc1,
|
|
266
|
+
innerQueryContext,
|
|
267
|
+
).loadByIDAsync(entity.getID());
|
|
268
|
+
const updatedEntity = await PostgresUniqueTestEntity.updater(
|
|
269
|
+
entityLoadedInner,
|
|
270
|
+
innerQueryContext,
|
|
271
|
+
)
|
|
272
|
+
.setField('name', 'wat')
|
|
273
|
+
.updateAsync();
|
|
274
|
+
if (updatedEntity.getField('name') !== 'wat') {
|
|
275
|
+
throw new Error('entity updated wrong value');
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const entityLoadedAfterUpdate = await PostgresUniqueTestEntity.loader(
|
|
279
|
+
vc1,
|
|
280
|
+
innerQueryContext,
|
|
281
|
+
).loadByIDAsync(entity.getID());
|
|
282
|
+
if (entityLoadedAfterUpdate.getField('name') !== 'wat') {
|
|
283
|
+
throw new Error('entity loaded wrong value after update');
|
|
284
|
+
}
|
|
285
|
+
openBarrier1();
|
|
286
|
+
await barrier2;
|
|
287
|
+
}),
|
|
288
|
+
(async () => {
|
|
289
|
+
await barrier1;
|
|
290
|
+
|
|
291
|
+
// if postgres supported nested transactions, this would read isolated from the nested transaction above
|
|
292
|
+
// but since it doesn't, this will read the updated value.
|
|
293
|
+
const entityLoadedInOuterTransactionBeforeNestedCommit =
|
|
294
|
+
await PostgresUniqueTestEntity.loader(vc1, outerQueryContext).loadByIDAsync(
|
|
295
|
+
entity.getID(),
|
|
296
|
+
);
|
|
297
|
+
if (entityLoadedInOuterTransactionBeforeNestedCommit.getField('name') !== 'who') {
|
|
298
|
+
throw new Error('outer transaction read wrong value');
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
openBarrier2!();
|
|
302
|
+
})(),
|
|
303
|
+
]);
|
|
304
|
+
|
|
305
|
+
const entityLoadedAfterTransaction = await PostgresUniqueTestEntity.loader(
|
|
306
|
+
vc1,
|
|
307
|
+
outerQueryContext,
|
|
308
|
+
).loadByIDAsync(entity.getID());
|
|
309
|
+
if (entityLoadedAfterTransaction.getField('name') !== 'wat') {
|
|
310
|
+
throw new Error('entity loaded wrong value after transaction');
|
|
311
|
+
}
|
|
312
|
+
},
|
|
313
|
+
{ transactionalDataLoaderMode },
|
|
314
|
+
);
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
await expect(runTest(TransactionalDataLoaderMode.DISABLED)).rejects.toThrow(
|
|
318
|
+
'outer transaction read wrong value',
|
|
319
|
+
);
|
|
320
|
+
await expect(runTest(TransactionalDataLoaderMode.ENABLED)).rejects.toThrow(
|
|
321
|
+
'outer transaction read wrong value',
|
|
322
|
+
);
|
|
323
|
+
await expect(runTest(TransactionalDataLoaderMode.ENABLED_BATCH_ONLY)).rejects.toThrow(
|
|
324
|
+
'outer transaction read wrong value',
|
|
325
|
+
);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
test('consistent behavior with and without transactional dataloader for concurrent mutations outside of nested transaction that reads', async () => {
|
|
329
|
+
// this test has a similar issue to the one above: absence of real nested transactions in postgres
|
|
330
|
+
// this should have the same behavior no matter if there is a dataloader or not in transactions
|
|
331
|
+
|
|
332
|
+
const runTest = async (
|
|
333
|
+
transactionalDataLoaderMode: TransactionalDataLoaderMode,
|
|
334
|
+
): Promise<void> => {
|
|
335
|
+
const vc1 = new ViewerContext(createKnexIntegrationTestEntityCompanionProvider(knexInstance));
|
|
336
|
+
await vc1.runInTransactionForDatabaseAdaptorFlavorAsync(
|
|
337
|
+
'postgres',
|
|
338
|
+
async (outerQueryContext) => {
|
|
339
|
+
// put it in local dataloader
|
|
340
|
+
const entity = await PostgresUniqueTestEntity.creator(vc1, outerQueryContext)
|
|
341
|
+
.setField('name', 'who')
|
|
342
|
+
.createAsync();
|
|
343
|
+
const entityLoaded = await PostgresUniqueTestEntity.loader(
|
|
344
|
+
vc1,
|
|
345
|
+
outerQueryContext,
|
|
346
|
+
).loadByIDAsync(entity.getID());
|
|
347
|
+
if (entityLoaded.getField('name') !== 'who') {
|
|
348
|
+
throw new Error('entity loaded wrong value');
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
let openBarrier1: () => void;
|
|
352
|
+
const barrier1 = new Promise<void>((resolve) => {
|
|
353
|
+
openBarrier1 = resolve;
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
let openBarrier2: () => void;
|
|
357
|
+
const barrier2 = new Promise<void>((resolve) => {
|
|
358
|
+
openBarrier2 = resolve;
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
await Promise.all([
|
|
362
|
+
(async () => {
|
|
363
|
+
await barrier1;
|
|
364
|
+
|
|
365
|
+
const entityLoadedOuterAgain = await PostgresUniqueTestEntity.loader(
|
|
366
|
+
vc1,
|
|
367
|
+
outerQueryContext,
|
|
368
|
+
).loadByIDAsync(entity.getID());
|
|
369
|
+
const updatedEntity = await PostgresUniqueTestEntity.updater(
|
|
370
|
+
entityLoadedOuterAgain,
|
|
371
|
+
outerQueryContext,
|
|
372
|
+
)
|
|
373
|
+
.setField('name', 'wat')
|
|
374
|
+
.updateAsync();
|
|
375
|
+
if (updatedEntity.getField('name') !== 'wat') {
|
|
376
|
+
throw new Error('entity updated wrong value');
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
openBarrier2!();
|
|
380
|
+
})(),
|
|
381
|
+
|
|
382
|
+
outerQueryContext.runInNestedTransactionAsync(async (innerQueryContext) => {
|
|
383
|
+
const entityLoadedInner = await PostgresUniqueTestEntity.loader(
|
|
384
|
+
vc1,
|
|
385
|
+
innerQueryContext,
|
|
386
|
+
).loadByIDAsync(entity.getID());
|
|
387
|
+
if (entityLoadedInner.getField('name') !== 'who') {
|
|
388
|
+
throw new Error('entity loaded inner wrong value 1');
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
openBarrier1();
|
|
392
|
+
await barrier2;
|
|
393
|
+
|
|
394
|
+
const entityLoadedInnerAgain = await PostgresUniqueTestEntity.loader(
|
|
395
|
+
vc1,
|
|
396
|
+
innerQueryContext,
|
|
397
|
+
).loadByIDAsync(entity.getID());
|
|
398
|
+
if (entityLoadedInnerAgain.getField('name') !== 'who') {
|
|
399
|
+
throw new Error('entity loaded inner wrong value 2');
|
|
400
|
+
}
|
|
401
|
+
}),
|
|
402
|
+
]);
|
|
403
|
+
|
|
404
|
+
const entityLoadedAfterTransaction = await PostgresUniqueTestEntity.loader(
|
|
405
|
+
vc1,
|
|
406
|
+
outerQueryContext,
|
|
407
|
+
).loadByIDAsync(entity.getID());
|
|
408
|
+
if (entityLoadedAfterTransaction.getField('name') !== 'wat') {
|
|
409
|
+
throw new Error('entity loaded wrong value after transaction');
|
|
410
|
+
}
|
|
411
|
+
},
|
|
412
|
+
{ transactionalDataLoaderMode },
|
|
413
|
+
);
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
await expect(runTest(TransactionalDataLoaderMode.DISABLED)).rejects.toThrow(
|
|
417
|
+
'entity loaded inner wrong value 2',
|
|
418
|
+
);
|
|
419
|
+
await expect(runTest(TransactionalDataLoaderMode.ENABLED)).rejects.toThrow(
|
|
420
|
+
'entity loaded inner wrong value 2',
|
|
421
|
+
);
|
|
422
|
+
await expect(runTest(TransactionalDataLoaderMode.ENABLED_BATCH_ONLY)).rejects.toThrow(
|
|
423
|
+
'entity loaded inner wrong value 2',
|
|
424
|
+
);
|
|
425
|
+
});
|
|
426
|
+
|
|
73
427
|
it('supports multi-nested transactions', async () => {
|
|
74
428
|
const vc1 = new ViewerContext(createKnexIntegrationTestEntityCompanionProvider(knexInstance));
|
|
75
429
|
|