Skip to content

Commit 0be9f1d

Browse files
committed
chore: move knex-specific loader logic out of EntityDataManager
1 parent fd886c7 commit 0be9f1d

10 files changed

Lines changed: 364 additions & 230 deletions

packages/entity/src/AuthorizationResultBasedKnexEntityLoader.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { EntityPrivacyPolicy } from './EntityPrivacyPolicy';
1111
import { EntityQueryContext } from './EntityQueryContext';
1212
import { ReadonlyEntity } from './ReadonlyEntity';
1313
import { ViewerContext } from './ViewerContext';
14-
import { EntityDataManager } from './internal/EntityDataManager';
14+
import { EntityKnexDataManager } from './internal/EntityKnexDataManager';
1515
import { IEntityMetricsAdapter } from './metrics/IEntityMetricsAdapter';
1616

1717
/**
@@ -36,7 +36,7 @@ export class AuthorizationResultBasedKnexEntityLoader<
3636
> {
3737
constructor(
3838
private readonly queryContext: EntityQueryContext,
39-
private readonly dataManager: EntityDataManager<TFields, TIDField>,
39+
private readonly knexDataManager: EntityKnexDataManager<TFields, TIDField>,
4040
protected readonly metricsAdapter: IEntityMetricsAdapter,
4141
public readonly utils: EntityLoaderUtils<
4242
TFields,
@@ -80,7 +80,7 @@ export class AuthorizationResultBasedKnexEntityLoader<
8080
this.utils.validateFieldAndValues(fieldEqualityOperand.fieldName, fieldValues);
8181
}
8282

83-
const fieldObjects = await this.dataManager.loadManyByFieldEqualityConjunctionAsync(
83+
const fieldObjects = await this.knexDataManager.loadManyByFieldEqualityConjunctionAsync(
8484
this.queryContext,
8585
fieldEqualityOperands,
8686
querySelectionModifiers,
@@ -98,7 +98,7 @@ export class AuthorizationResultBasedKnexEntityLoader<
9898
bindings: any[] | object,
9999
querySelectionModifiers: QuerySelectionModifiersWithOrderByRaw<TFields> = {},
100100
): Promise<readonly Result<TEntity>[]> {
101-
const fieldObjects = await this.dataManager.loadManyByRawWhereClauseAsync(
101+
const fieldObjects = await this.knexDataManager.loadManyByRawWhereClauseAsync(
102102
this.queryContext,
103103
rawWhereClause,
104104
bindings,

packages/entity/src/EntityCompanion.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ export class EntityCompanion<
8787
TEntity,
8888
TPrivacyPolicy,
8989
TSelectedFields
90-
>(this, tableDataCoordinator.dataManager, metricsAdapter);
90+
>(this, tableDataCoordinator.dataManager, tableDataCoordinator.knexDataManager, metricsAdapter);
9191
this.entityMutatorFactory = new EntityMutatorFactory(
9292
entityCompanionProvider,
9393
tableDataCoordinator.entityConfiguration,

packages/entity/src/KnexEntityLoaderFactory.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { EntityQueryContext } from './EntityQueryContext';
66
import { ReadonlyEntity } from './ReadonlyEntity';
77
import { ViewerContext } from './ViewerContext';
88
import { EntityDataManager } from './internal/EntityDataManager';
9+
import { EntityKnexDataManager } from './internal/EntityKnexDataManager';
910
import { IEntityMetricsAdapter } from './metrics/IEntityMetricsAdapter';
1011

1112
/**
@@ -35,6 +36,7 @@ export class KnexEntityLoaderFactory<
3536
TSelectedFields
3637
>,
3738
private readonly dataManager: EntityDataManager<TFields, TIDField>,
39+
private readonly knexDataManager: EntityKnexDataManager<TFields, TIDField>,
3840
protected readonly metricsAdapter: IEntityMetricsAdapter,
3941
) {}
4042

@@ -75,7 +77,7 @@ export class KnexEntityLoaderFactory<
7577

7678
return new AuthorizationResultBasedKnexEntityLoader(
7779
queryContext,
78-
this.dataManager,
80+
this.knexDataManager,
7981
this.metricsAdapter,
8082
utils,
8183
);

packages/entity/src/__tests__/AuthorizationResultBasedKnexEntityLoader-test.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { EntityPrivacyPolicyEvaluationContext } from '../EntityPrivacyPolicy';
99
import { ViewerContext } from '../ViewerContext';
1010
import { enforceResultsAsync } from '../entityUtils';
1111
import { EntityDataManager } from '../internal/EntityDataManager';
12+
import { EntityKnexDataManager } from '../internal/EntityKnexDataManager';
1213
import { ReadThroughEntityCache } from '../internal/ReadThroughEntityCache';
1314
import { IEntityMetricsAdapter } from '../metrics/IEntityMetricsAdapter';
1415
import { NoCacheStubCacheAdapterProvider } from '../utils/__testfixtures__/StubCacheAdapter';
@@ -90,6 +91,11 @@ describe(AuthorizationResultBasedKnexEntityLoader, () => {
9091
instance(mock<IEntityMetricsAdapter>()),
9192
TestEntity.name,
9293
);
94+
const knexDataManager = new EntityKnexDataManager(
95+
databaseAdapter,
96+
metricsAdapter,
97+
TestEntity.name,
98+
);
9399
const utils = new EntityLoaderUtils(
94100
viewerContext,
95101
queryContext,
@@ -103,7 +109,7 @@ describe(AuthorizationResultBasedKnexEntityLoader, () => {
103109
);
104110
const knexEntityLoader = new AuthorizationResultBasedKnexEntityLoader(
105111
queryContext,
106-
dataManager,
112+
knexDataManager,
107113
metricsAdapter,
108114
utils,
109115
);
@@ -205,6 +211,11 @@ describe(AuthorizationResultBasedKnexEntityLoader, () => {
205211
instance(mock<IEntityMetricsAdapter>()),
206212
TestEntity.name,
207213
);
214+
const knexDataManager = new EntityKnexDataManager(
215+
databaseAdapter,
216+
metricsAdapter,
217+
TestEntity.name,
218+
);
208219
const utils = new EntityLoaderUtils(
209220
viewerContext,
210221
queryContext,
@@ -218,7 +229,7 @@ describe(AuthorizationResultBasedKnexEntityLoader, () => {
218229
);
219230
const knexEntityLoader = new AuthorizationResultBasedKnexEntityLoader(
220231
queryContext,
221-
dataManager,
232+
knexDataManager,
222233
metricsAdapter,
223234
utils,
224235
);
@@ -271,9 +282,10 @@ describe(AuthorizationResultBasedKnexEntityLoader, () => {
271282
const metricsAdapter = instance(mock<IEntityMetricsAdapter>());
272283
const queryContext = new StubQueryContextProvider().getQueryContext();
273284

274-
const dataManagerMock = mock<EntityDataManager<TestFields, 'customIdField'>>(EntityDataManager);
285+
const knexDataManagerMock =
286+
mock<EntityKnexDataManager<TestFields, 'customIdField'>>(EntityKnexDataManager);
275287
when(
276-
dataManagerMock.loadManyByRawWhereClauseAsync(
288+
knexDataManagerMock.loadManyByRawWhereClauseAsync(
277289
queryContext,
278290
anything(),
279291
anything(),
@@ -289,6 +301,10 @@ describe(AuthorizationResultBasedKnexEntityLoader, () => {
289301
nullableField: null,
290302
},
291303
]);
304+
const knexDataManager = instance(knexDataManagerMock);
305+
306+
// Create a real dataManager for the EntityLoaderUtils
307+
const dataManagerMock = mock<EntityDataManager<TestFields, 'customIdField'>>(EntityDataManager);
292308
const dataManager = instance(dataManagerMock);
293309

294310
const utils = new EntityLoaderUtils(
@@ -304,7 +320,7 @@ describe(AuthorizationResultBasedKnexEntityLoader, () => {
304320
);
305321
const knexEntityLoader = new AuthorizationResultBasedKnexEntityLoader(
306322
queryContext,
307-
dataManager,
323+
knexDataManager,
308324
metricsAdapter,
309325
utils,
310326
);

packages/entity/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ export * from './internal/CompositeFieldHolder';
6464
export * from './internal/CompositeFieldValueMap';
6565
export * from './internal/EntityDataManager';
6666
export * from './internal/EntityFieldTransformationUtils';
67+
export * from './internal/EntityKnexDataManager';
6768
export * from './internal/EntityLoadInterfaces';
6869
export * from './internal/EntityTableDataCoordinator';
6970
export * from './internal/ReadThroughEntityCache';

packages/entity/src/internal/EntityDataManager.ts

Lines changed: 2 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
11
import DataLoader from 'dataloader';
22
import invariant from 'invariant';
33

4-
import {
5-
EntityDatabaseAdapter,
6-
FieldEqualityCondition,
7-
QuerySelectionModifiers,
8-
QuerySelectionModifiersWithOrderByRaw,
9-
} from '../EntityDatabaseAdapter';
4+
import { EntityDatabaseAdapter } from '../EntityDatabaseAdapter';
105
import {
116
EntityQueryContext,
127
EntityTransactionalQueryContext,
@@ -16,10 +11,7 @@ import { EntityQueryContextProvider } from '../EntityQueryContextProvider';
1611
import { partitionErrors } from '../entityUtils';
1712
import { IEntityLoadKey, IEntityLoadValue, LoadPair } from './EntityLoadInterfaces';
1813
import { ReadThroughEntityCache } from './ReadThroughEntityCache';
19-
import {
20-
timeAndLogLoadEventAsync,
21-
timeAndLogLoadMapEventAsync,
22-
} from '../metrics/EntityMetricsUtils';
14+
import { timeAndLogLoadMapEventAsync } from '../metrics/EntityMetricsUtils';
2315
import {
2416
EntityMetricsLoadType,
2517
IEntityMetricsAdapter,
@@ -251,64 +243,6 @@ export class EntityDataManager<
251243
return mapToReturn;
252244
}
253245

254-
/**
255-
* Loads many objects matching the conjunction of where clauses constructed from
256-
* specified field equality operands.
257-
*
258-
* @param queryContext - query context in which to perform the load
259-
* @param fieldEqualityOperands - list of field equality where clause operand specifications
260-
* @param querySelectionModifiers - limit, offset, and orderBy for the query
261-
* @returns array of objects matching the query
262-
*/
263-
async loadManyByFieldEqualityConjunctionAsync<N extends keyof TFields>(
264-
queryContext: EntityQueryContext,
265-
fieldEqualityOperands: FieldEqualityCondition<TFields, N>[],
266-
querySelectionModifiers: QuerySelectionModifiers<TFields>,
267-
): Promise<readonly Readonly<TFields>[]> {
268-
return await timeAndLogLoadEventAsync(
269-
this.metricsAdapter,
270-
EntityMetricsLoadType.LOAD_MANY_EQUALITY_CONJUNCTION,
271-
this.entityClassName,
272-
queryContext,
273-
)(
274-
this.databaseAdapter.fetchManyByFieldEqualityConjunctionAsync(
275-
queryContext,
276-
fieldEqualityOperands,
277-
querySelectionModifiers,
278-
),
279-
);
280-
}
281-
282-
/**
283-
* Loads many objects matching the raw WHERE clause.
284-
*
285-
* @param queryContext - query context in which to perform the load
286-
* @param rawWhereClause - parameterized SQL WHERE clause with positional binding placeholders or named binding placeholders
287-
* @param bindings - array of positional bindings or object of named bindings
288-
* @param querySelectionModifiers - limit, offset, orderBy, and orderByRaw for the query
289-
* @returns array of objects matching the query
290-
*/
291-
async loadManyByRawWhereClauseAsync(
292-
queryContext: EntityQueryContext,
293-
rawWhereClause: string,
294-
bindings: any[] | object,
295-
querySelectionModifiers: QuerySelectionModifiersWithOrderByRaw<TFields>,
296-
): Promise<readonly Readonly<TFields>[]> {
297-
return await timeAndLogLoadEventAsync(
298-
this.metricsAdapter,
299-
EntityMetricsLoadType.LOAD_MANY_RAW,
300-
this.entityClassName,
301-
queryContext,
302-
)(
303-
this.databaseAdapter.fetchManyByRawWhereClauseAsync(
304-
queryContext,
305-
rawWhereClause,
306-
bindings,
307-
querySelectionModifiers,
308-
),
309-
);
310-
}
311-
312246
private async invalidateOneAsync<
313247
TLoadKey extends IEntityLoadKey<TFields, TIDField, TSerializedLoadValue, TLoadValue>,
314248
TSerializedLoadValue,
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import {
2+
EntityDatabaseAdapter,
3+
FieldEqualityCondition,
4+
QuerySelectionModifiers,
5+
QuerySelectionModifiersWithOrderByRaw,
6+
} from '../EntityDatabaseAdapter';
7+
import { EntityQueryContext } from '../EntityQueryContext';
8+
import { timeAndLogLoadEventAsync } from '../metrics/EntityMetricsUtils';
9+
import { EntityMetricsLoadType, IEntityMetricsAdapter } from '../metrics/IEntityMetricsAdapter';
10+
11+
/**
12+
* A knex data manager is responsible for handling non-dataloader-based
13+
* database operations.
14+
*
15+
* @internal
16+
*/
17+
export class EntityKnexDataManager<
18+
TFields extends Record<string, any>,
19+
TIDField extends keyof TFields,
20+
> {
21+
constructor(
22+
private readonly databaseAdapter: EntityDatabaseAdapter<TFields, TIDField>,
23+
private readonly metricsAdapter: IEntityMetricsAdapter,
24+
private readonly entityClassName: string,
25+
) {}
26+
27+
/**
28+
* Loads many objects matching the conjunction of where clauses constructed from
29+
* specified field equality operands.
30+
*
31+
* @param queryContext - query context in which to perform the load
32+
* @param fieldEqualityOperands - list of field equality where clause operand specifications
33+
* @param querySelectionModifiers - limit, offset, and orderBy for the query
34+
* @returns array of objects matching the query
35+
*/
36+
async loadManyByFieldEqualityConjunctionAsync<N extends keyof TFields>(
37+
queryContext: EntityQueryContext,
38+
fieldEqualityOperands: FieldEqualityCondition<TFields, N>[],
39+
querySelectionModifiers: QuerySelectionModifiers<TFields>,
40+
): Promise<readonly Readonly<TFields>[]> {
41+
return await timeAndLogLoadEventAsync(
42+
this.metricsAdapter,
43+
EntityMetricsLoadType.LOAD_MANY_EQUALITY_CONJUNCTION,
44+
this.entityClassName,
45+
queryContext,
46+
)(
47+
this.databaseAdapter.fetchManyByFieldEqualityConjunctionAsync(
48+
queryContext,
49+
fieldEqualityOperands,
50+
querySelectionModifiers,
51+
),
52+
);
53+
}
54+
55+
/**
56+
* Loads many objects matching the raw WHERE clause.
57+
*
58+
* @param queryContext - query context in which to perform the load
59+
* @param rawWhereClause - parameterized SQL WHERE clause with positional binding placeholders or named binding placeholders
60+
* @param bindings - array of positional bindings or object of named bindings
61+
* @param querySelectionModifiers - limit, offset, orderBy, and orderByRaw for the query
62+
* @returns array of objects matching the query
63+
*/
64+
async loadManyByRawWhereClauseAsync(
65+
queryContext: EntityQueryContext,
66+
rawWhereClause: string,
67+
bindings: any[] | object,
68+
querySelectionModifiers: QuerySelectionModifiersWithOrderByRaw<TFields>,
69+
): Promise<readonly Readonly<TFields>[]> {
70+
return await timeAndLogLoadEventAsync(
71+
this.metricsAdapter,
72+
EntityMetricsLoadType.LOAD_MANY_RAW,
73+
this.entityClassName,
74+
queryContext,
75+
)(
76+
this.databaseAdapter.fetchManyByRawWhereClauseAsync(
77+
queryContext,
78+
rawWhereClause,
79+
bindings,
80+
querySelectionModifiers,
81+
),
82+
);
83+
}
84+
}

packages/entity/src/internal/EntityTableDataCoordinator.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { IEntityCacheAdapter } from '../IEntityCacheAdapter';
55
import { IEntityCacheAdapterProvider } from '../IEntityCacheAdapterProvider';
66
import { IEntityDatabaseAdapterProvider } from '../IEntityDatabaseAdapterProvider';
77
import { EntityDataManager } from './EntityDataManager';
8+
import { EntityKnexDataManager } from './EntityKnexDataManager';
89
import { ReadThroughEntityCache } from './ReadThroughEntityCache';
910
import { IEntityMetricsAdapter } from '../metrics/IEntityMetricsAdapter';
1011

@@ -22,6 +23,7 @@ export class EntityTableDataCoordinator<
2223
readonly databaseAdapter: EntityDatabaseAdapter<TFields, TIDField>;
2324
readonly cacheAdapter: IEntityCacheAdapter<TFields, TIDField>;
2425
readonly dataManager: EntityDataManager<TFields, TIDField>;
26+
readonly knexDataManager: EntityKnexDataManager<TFields, TIDField>;
2527

2628
constructor(
2729
readonly entityConfiguration: EntityConfiguration<TFields, TIDField>,
@@ -40,6 +42,11 @@ export class EntityTableDataCoordinator<
4042
metricsAdapter,
4143
entityClassName,
4244
);
45+
this.knexDataManager = new EntityKnexDataManager(
46+
this.databaseAdapter,
47+
metricsAdapter,
48+
entityClassName,
49+
);
4350
}
4451

4552
getQueryContextProvider(): EntityQueryContextProvider {

0 commit comments

Comments
 (0)