@expo/entity-database-adapter-knex 0.54.0 → 0.57.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/build/src/AuthorizationResultBasedKnexEntityLoader.d.ts +279 -0
- package/build/src/AuthorizationResultBasedKnexEntityLoader.js +127 -0
- package/build/src/AuthorizationResultBasedKnexEntityLoader.js.map +1 -0
- package/build/src/BasePostgresEntityDatabaseAdapter.d.ts +150 -0
- package/build/src/BasePostgresEntityDatabaseAdapter.js +119 -0
- package/build/src/BasePostgresEntityDatabaseAdapter.js.map +1 -0
- package/build/src/BaseSQLQueryBuilder.d.ts +61 -0
- package/build/src/BaseSQLQueryBuilder.js +87 -0
- package/build/src/BaseSQLQueryBuilder.js.map +1 -0
- package/build/src/EnforcingKnexEntityLoader.d.ts +124 -0
- package/build/src/EnforcingKnexEntityLoader.js +166 -0
- package/build/src/EnforcingKnexEntityLoader.js.map +1 -0
- package/build/src/KnexEntityLoaderFactory.d.ts +25 -0
- package/build/src/KnexEntityLoaderFactory.js +39 -0
- package/build/src/KnexEntityLoaderFactory.js.map +1 -0
- package/build/src/PaginationStrategy.d.ts +30 -0
- package/build/src/PaginationStrategy.js +35 -0
- package/build/src/PaginationStrategy.js.map +1 -0
- package/build/src/PostgresEntity.d.ts +25 -0
- package/build/src/PostgresEntity.js +39 -0
- package/build/src/PostgresEntity.js.map +1 -0
- package/build/src/PostgresEntityDatabaseAdapter.d.ts +12 -5
- package/build/src/PostgresEntityDatabaseAdapter.js +32 -11
- package/build/src/PostgresEntityDatabaseAdapter.js.map +1 -1
- package/build/src/PostgresEntityDatabaseAdapterProvider.d.ts +9 -0
- package/build/src/PostgresEntityDatabaseAdapterProvider.js +5 -1
- package/build/src/PostgresEntityDatabaseAdapterProvider.js.map +1 -1
- package/build/src/ReadonlyPostgresEntity.d.ts +25 -0
- package/build/src/ReadonlyPostgresEntity.js +39 -0
- package/build/src/ReadonlyPostgresEntity.js.map +1 -0
- package/build/src/SQLOperator.d.ts +261 -0
- package/build/src/SQLOperator.js +464 -0
- package/build/src/SQLOperator.js.map +1 -0
- package/build/src/index.d.ts +15 -0
- package/build/src/index.js +15 -0
- package/build/src/index.js.map +1 -1
- package/build/src/internal/EntityKnexDataManager.d.ts +147 -0
- package/build/src/internal/EntityKnexDataManager.js +453 -0
- package/build/src/internal/EntityKnexDataManager.js.map +1 -0
- package/build/src/internal/getKnexDataManager.d.ts +3 -0
- package/build/src/internal/getKnexDataManager.js +19 -0
- package/build/src/internal/getKnexDataManager.js.map +1 -0
- package/build/src/internal/getKnexEntityLoaderFactory.d.ts +3 -0
- package/build/src/internal/getKnexEntityLoaderFactory.js +11 -0
- package/build/src/internal/getKnexEntityLoaderFactory.js.map +1 -0
- package/build/src/internal/utilityTypes.d.ts +5 -0
- package/build/src/internal/utilityTypes.js +5 -0
- package/build/src/internal/utilityTypes.js.map +1 -0
- package/build/src/internal/weakMaps.d.ts +9 -0
- package/build/src/internal/weakMaps.js +20 -0
- package/build/src/internal/weakMaps.js.map +1 -0
- package/build/src/knexLoader.d.ts +18 -0
- package/build/src/knexLoader.js +31 -0
- package/build/src/knexLoader.js.map +1 -0
- package/package.json +6 -5
- package/src/AuthorizationResultBasedKnexEntityLoader.ts +538 -0
- package/src/BasePostgresEntityDatabaseAdapter.ts +317 -0
- package/src/BaseSQLQueryBuilder.ts +114 -0
- package/src/EnforcingKnexEntityLoader.ts +271 -0
- package/src/KnexEntityLoaderFactory.ts +130 -0
- package/src/PaginationStrategy.ts +32 -0
- package/src/PostgresEntity.ts +118 -0
- package/src/PostgresEntityDatabaseAdapter.ts +78 -24
- package/src/PostgresEntityDatabaseAdapterProvider.ts +11 -1
- package/src/ReadonlyPostgresEntity.ts +115 -0
- package/src/SQLOperator.ts +603 -0
- package/src/__integration-tests__/EntityCreationUtils-test.ts +25 -31
- package/src/__integration-tests__/PostgresEntityIntegration-test.ts +3192 -330
- package/src/__integration-tests__/PostgresEntityQueryContextProvider-test.ts +7 -7
- package/src/__testfixtures__/PostgresTestEntity.ts +17 -3
- package/src/__tests__/AuthorizationResultBasedKnexEntityLoader-test.ts +1167 -0
- package/src/__tests__/BasePostgresEntityDatabaseAdapter-test.ts +160 -0
- package/src/__tests__/EnforcingKnexEntityLoader-test.ts +384 -0
- package/src/__tests__/EntityFields-test.ts +1 -1
- package/src/__tests__/PostgresEntity-test.ts +172 -0
- package/src/__tests__/ReadonlyEntity-test.ts +32 -0
- package/src/__tests__/SQLOperator-test.ts +831 -0
- package/src/__tests__/fixtures/StubPostgresDatabaseAdapter.ts +302 -0
- package/src/__tests__/fixtures/StubPostgresDatabaseAdapterProvider.ts +17 -0
- package/src/__tests__/fixtures/TestEntity.ts +131 -0
- package/src/__tests__/fixtures/TestPaginationEntity.ts +107 -0
- package/src/__tests__/fixtures/createUnitTestPostgresEntityCompanionProvider.ts +42 -0
- package/src/index.ts +15 -0
- package/src/internal/EntityKnexDataManager.ts +832 -0
- package/src/internal/__tests__/EntityKnexDataManager-test.ts +378 -0
- package/src/internal/__tests__/weakMaps-test.ts +25 -0
- package/src/internal/getKnexDataManager.ts +43 -0
- package/src/internal/getKnexEntityLoaderFactory.ts +60 -0
- package/src/internal/utilityTypes.ts +11 -0
- package/src/internal/weakMaps.ts +19 -0
- package/src/knexLoader.ts +110 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { EntityQueryContext, FieldTransformerMap } from '@expo/entity';
|
|
2
|
+
import { describe, expect, it } from '@jest/globals';
|
|
3
|
+
import { instance, mock } from 'ts-mockito';
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
BasePostgresEntityDatabaseAdapter,
|
|
7
|
+
TableFieldMultiValueEqualityCondition,
|
|
8
|
+
TableFieldSingleValueEqualityCondition,
|
|
9
|
+
} from '../BasePostgresEntityDatabaseAdapter';
|
|
10
|
+
import { testEntityConfiguration, TestFields } from './fixtures/TestEntity';
|
|
11
|
+
|
|
12
|
+
class TestEntityDatabaseAdapter extends BasePostgresEntityDatabaseAdapter<
|
|
13
|
+
TestFields,
|
|
14
|
+
'customIdField'
|
|
15
|
+
> {
|
|
16
|
+
private readonly fetchResults: object[];
|
|
17
|
+
private readonly fetchOneResult: object | null;
|
|
18
|
+
private readonly insertResults: object[];
|
|
19
|
+
private readonly updateResults: object[];
|
|
20
|
+
private readonly fetchEqualityConditionResults: object[];
|
|
21
|
+
private readonly fetchRawWhereResults: object[];
|
|
22
|
+
private readonly fetchSQLFragmentResults: object[];
|
|
23
|
+
private readonly deleteCount: number;
|
|
24
|
+
|
|
25
|
+
constructor({
|
|
26
|
+
fetchResults = [],
|
|
27
|
+
fetchOneResult = null,
|
|
28
|
+
insertResults = [],
|
|
29
|
+
updateResults = [],
|
|
30
|
+
fetchEqualityConditionResults = [],
|
|
31
|
+
fetchRawWhereResults = [],
|
|
32
|
+
fetchSQLFragmentResults = [],
|
|
33
|
+
deleteCount = 0,
|
|
34
|
+
}: {
|
|
35
|
+
fetchResults?: object[];
|
|
36
|
+
fetchOneResult?: object | null;
|
|
37
|
+
insertResults?: object[];
|
|
38
|
+
updateResults?: object[];
|
|
39
|
+
fetchEqualityConditionResults?: object[];
|
|
40
|
+
fetchRawWhereResults?: object[];
|
|
41
|
+
fetchSQLFragmentResults?: object[];
|
|
42
|
+
deleteCount?: number;
|
|
43
|
+
}) {
|
|
44
|
+
super(testEntityConfiguration);
|
|
45
|
+
this.fetchResults = fetchResults;
|
|
46
|
+
this.fetchOneResult = fetchOneResult;
|
|
47
|
+
this.insertResults = insertResults;
|
|
48
|
+
this.updateResults = updateResults;
|
|
49
|
+
this.fetchEqualityConditionResults = fetchEqualityConditionResults;
|
|
50
|
+
this.fetchRawWhereResults = fetchRawWhereResults;
|
|
51
|
+
this.fetchSQLFragmentResults = fetchSQLFragmentResults;
|
|
52
|
+
this.deleteCount = deleteCount;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
protected getFieldTransformerMap(): FieldTransformerMap {
|
|
56
|
+
return new Map();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
protected async fetchManyWhereInternalAsync(
|
|
60
|
+
_queryInterface: any,
|
|
61
|
+
_tableName: string,
|
|
62
|
+
_tableColumns: readonly string[],
|
|
63
|
+
_tableTuples: (readonly any[])[],
|
|
64
|
+
): Promise<object[]> {
|
|
65
|
+
return this.fetchResults;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
protected async fetchOneWhereInternalAsync(
|
|
69
|
+
_queryInterface: any,
|
|
70
|
+
_tableName: string,
|
|
71
|
+
_tableColumns: readonly string[],
|
|
72
|
+
_tableTuple: readonly any[],
|
|
73
|
+
): Promise<object | null> {
|
|
74
|
+
return this.fetchOneResult;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
protected async fetchManyByRawWhereClauseInternalAsync(
|
|
78
|
+
_queryInterface: any,
|
|
79
|
+
_tableName: string,
|
|
80
|
+
_rawWhereClause: string,
|
|
81
|
+
_bindings: object | any[],
|
|
82
|
+
): Promise<object[]> {
|
|
83
|
+
return this.fetchRawWhereResults;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
protected async fetchManyBySQLFragmentInternalAsync(
|
|
87
|
+
_queryInterface: any,
|
|
88
|
+
_tableName: string,
|
|
89
|
+
_sqlFragment: any,
|
|
90
|
+
): Promise<object[]> {
|
|
91
|
+
return this.fetchSQLFragmentResults;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
protected async fetchManyByFieldEqualityConjunctionInternalAsync(
|
|
95
|
+
_queryInterface: any,
|
|
96
|
+
_tableName: string,
|
|
97
|
+
_tableFieldSingleValueEqualityOperands: TableFieldSingleValueEqualityCondition[],
|
|
98
|
+
_tableFieldMultiValueEqualityOperands: TableFieldMultiValueEqualityCondition[],
|
|
99
|
+
): Promise<object[]> {
|
|
100
|
+
return this.fetchEqualityConditionResults;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
protected async insertInternalAsync(
|
|
104
|
+
_queryInterface: any,
|
|
105
|
+
_tableName: string,
|
|
106
|
+
_object: object,
|
|
107
|
+
): Promise<object[]> {
|
|
108
|
+
return this.insertResults;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
protected async updateInternalAsync(
|
|
112
|
+
_queryInterface: any,
|
|
113
|
+
_tableName: string,
|
|
114
|
+
_tableIdField: string,
|
|
115
|
+
_id: any,
|
|
116
|
+
_object: object,
|
|
117
|
+
): Promise<object[]> {
|
|
118
|
+
return this.updateResults;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
protected async deleteInternalAsync(
|
|
122
|
+
_queryInterface: any,
|
|
123
|
+
_tableName: string,
|
|
124
|
+
_tableIdField: string,
|
|
125
|
+
_id: any,
|
|
126
|
+
): Promise<number> {
|
|
127
|
+
return this.deleteCount;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
describe(BasePostgresEntityDatabaseAdapter, () => {
|
|
132
|
+
describe('get paginationMaxPageSize', () => {
|
|
133
|
+
it('returns the default paginationMaxPageSize (undefined)', () => {
|
|
134
|
+
const adapter = new TestEntityDatabaseAdapter({});
|
|
135
|
+
expect(adapter.paginationMaxPageSize).toBe(undefined);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
describe('fetchManyByFieldEqualityConjunction', () => {
|
|
140
|
+
it('transforms object', async () => {
|
|
141
|
+
const queryContext = instance(mock(EntityQueryContext));
|
|
142
|
+
const adapter = new TestEntityDatabaseAdapter({
|
|
143
|
+
fetchEqualityConditionResults: [{ string_field: 'hello' }],
|
|
144
|
+
});
|
|
145
|
+
const results = await adapter.fetchManyByFieldEqualityConjunctionAsync(queryContext, [], {});
|
|
146
|
+
expect(results).toEqual([{ stringField: 'hello' }]);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
describe('fetchManyWithRawWhereClause', () => {
|
|
151
|
+
it('transforms object', async () => {
|
|
152
|
+
const queryContext = instance(mock(EntityQueryContext));
|
|
153
|
+
const adapter = new TestEntityDatabaseAdapter({
|
|
154
|
+
fetchRawWhereResults: [{ string_field: 'hello' }],
|
|
155
|
+
});
|
|
156
|
+
const results = await adapter.fetchManyByRawWhereClauseAsync(queryContext, 'hello', [], {});
|
|
157
|
+
expect(results).toEqual([{ stringField: 'hello' }]);
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
});
|
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
import { EntityConstructionUtils, EntityQueryContext, IEntityMetricsAdapter } from '@expo/entity';
|
|
2
|
+
import { result } from '@expo/results';
|
|
3
|
+
import { describe, expect, it } from '@jest/globals';
|
|
4
|
+
import { anything, instance, mock, when } from 'ts-mockito';
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
AuthorizationResultBasedKnexEntityLoader,
|
|
8
|
+
AuthorizationResultBasedSQLQueryBuilder,
|
|
9
|
+
} from '../AuthorizationResultBasedKnexEntityLoader';
|
|
10
|
+
import { EnforcingKnexEntityLoader } from '../EnforcingKnexEntityLoader';
|
|
11
|
+
import { PaginationStrategy } from '../PaginationStrategy';
|
|
12
|
+
import { sql } from '../SQLOperator';
|
|
13
|
+
import { EntityKnexDataManager } from '../internal/EntityKnexDataManager';
|
|
14
|
+
|
|
15
|
+
describe(EnforcingKnexEntityLoader, () => {
|
|
16
|
+
describe('loadFirstByFieldEqualityConjunction', () => {
|
|
17
|
+
it('throws when result is unsuccessful', async () => {
|
|
18
|
+
const nonEnforcingKnexEntityLoaderMock = mock(
|
|
19
|
+
AuthorizationResultBasedKnexEntityLoader<any, any, any, any, any, any>,
|
|
20
|
+
);
|
|
21
|
+
const rejection = new Error();
|
|
22
|
+
when(
|
|
23
|
+
nonEnforcingKnexEntityLoaderMock.loadFirstByFieldEqualityConjunctionAsync(
|
|
24
|
+
anything(),
|
|
25
|
+
anything(),
|
|
26
|
+
),
|
|
27
|
+
).thenResolve(result(rejection));
|
|
28
|
+
const nonEnforcingKnexEntityLoader = instance(nonEnforcingKnexEntityLoaderMock);
|
|
29
|
+
const enforcingKnexEntityLoader = new EnforcingKnexEntityLoader(
|
|
30
|
+
nonEnforcingKnexEntityLoader,
|
|
31
|
+
instance(mock(EntityQueryContext)),
|
|
32
|
+
instance(mock(EntityKnexDataManager)),
|
|
33
|
+
instance(mock<IEntityMetricsAdapter>()),
|
|
34
|
+
instance(mock(EntityConstructionUtils)),
|
|
35
|
+
);
|
|
36
|
+
await expect(
|
|
37
|
+
enforcingKnexEntityLoader.loadFirstByFieldEqualityConjunctionAsync(anything(), anything()),
|
|
38
|
+
).rejects.toThrow(rejection);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('returns value when result is successful', async () => {
|
|
42
|
+
const nonEnforcingKnexEntityLoaderMock = mock(
|
|
43
|
+
AuthorizationResultBasedKnexEntityLoader<any, any, any, any, any, any>,
|
|
44
|
+
);
|
|
45
|
+
const resolved = {};
|
|
46
|
+
when(
|
|
47
|
+
nonEnforcingKnexEntityLoaderMock.loadFirstByFieldEqualityConjunctionAsync(
|
|
48
|
+
anything(),
|
|
49
|
+
anything(),
|
|
50
|
+
),
|
|
51
|
+
).thenResolve(result(resolved));
|
|
52
|
+
const nonEnforcingKnexEntityLoader = instance(nonEnforcingKnexEntityLoaderMock);
|
|
53
|
+
const enforcingKnexEntityLoader = new EnforcingKnexEntityLoader(
|
|
54
|
+
nonEnforcingKnexEntityLoader,
|
|
55
|
+
instance(mock(EntityQueryContext)),
|
|
56
|
+
instance(mock(EntityKnexDataManager)),
|
|
57
|
+
instance(mock<IEntityMetricsAdapter>()),
|
|
58
|
+
instance(mock(EntityConstructionUtils)),
|
|
59
|
+
);
|
|
60
|
+
await expect(
|
|
61
|
+
enforcingKnexEntityLoader.loadFirstByFieldEqualityConjunctionAsync(anything(), anything()),
|
|
62
|
+
).resolves.toEqual(resolved);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('returns null when the query is successful but no rows match', async () => {
|
|
66
|
+
const nonEnforcingKnexEntityLoaderMock = mock(
|
|
67
|
+
AuthorizationResultBasedKnexEntityLoader<any, any, any, any, any, any>,
|
|
68
|
+
);
|
|
69
|
+
when(
|
|
70
|
+
nonEnforcingKnexEntityLoaderMock.loadFirstByFieldEqualityConjunctionAsync(
|
|
71
|
+
anything(),
|
|
72
|
+
anything(),
|
|
73
|
+
),
|
|
74
|
+
).thenResolve(null);
|
|
75
|
+
const nonEnforcingKnexEntityLoader = instance(nonEnforcingKnexEntityLoaderMock);
|
|
76
|
+
const enforcingKnexEntityLoader = new EnforcingKnexEntityLoader(
|
|
77
|
+
nonEnforcingKnexEntityLoader,
|
|
78
|
+
instance(mock(EntityQueryContext)),
|
|
79
|
+
instance(mock(EntityKnexDataManager)),
|
|
80
|
+
instance(mock<IEntityMetricsAdapter>()),
|
|
81
|
+
instance(mock(EntityConstructionUtils)),
|
|
82
|
+
);
|
|
83
|
+
await expect(
|
|
84
|
+
enforcingKnexEntityLoader.loadFirstByFieldEqualityConjunctionAsync(anything(), anything()),
|
|
85
|
+
).resolves.toBeNull();
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
describe('loadManyByFieldEqualityConjunction', () => {
|
|
90
|
+
it('throws when result is unsuccessful', async () => {
|
|
91
|
+
const nonEnforcingKnexEntityLoaderMock = mock(
|
|
92
|
+
AuthorizationResultBasedKnexEntityLoader<any, any, any, any, any, any>,
|
|
93
|
+
);
|
|
94
|
+
const rejection = new Error();
|
|
95
|
+
when(
|
|
96
|
+
nonEnforcingKnexEntityLoaderMock.loadManyByFieldEqualityConjunctionAsync(
|
|
97
|
+
anything(),
|
|
98
|
+
anything(),
|
|
99
|
+
),
|
|
100
|
+
).thenResolve([result(rejection)]);
|
|
101
|
+
const nonEnforcingKnexEntityLoader = instance(nonEnforcingKnexEntityLoaderMock);
|
|
102
|
+
const enforcingKnexEntityLoader = new EnforcingKnexEntityLoader(
|
|
103
|
+
nonEnforcingKnexEntityLoader,
|
|
104
|
+
instance(mock(EntityQueryContext)),
|
|
105
|
+
instance(mock(EntityKnexDataManager)),
|
|
106
|
+
instance(mock<IEntityMetricsAdapter>()),
|
|
107
|
+
instance(mock(EntityConstructionUtils)),
|
|
108
|
+
);
|
|
109
|
+
await expect(
|
|
110
|
+
enforcingKnexEntityLoader.loadManyByFieldEqualityConjunctionAsync(anything(), anything()),
|
|
111
|
+
).rejects.toThrow(rejection);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('returns value when result is successful', async () => {
|
|
115
|
+
const nonEnforcingKnexEntityLoaderMock = mock(
|
|
116
|
+
AuthorizationResultBasedKnexEntityLoader<any, any, any, any, any, any>,
|
|
117
|
+
);
|
|
118
|
+
const resolved = {};
|
|
119
|
+
when(
|
|
120
|
+
nonEnforcingKnexEntityLoaderMock.loadManyByFieldEqualityConjunctionAsync(
|
|
121
|
+
anything(),
|
|
122
|
+
anything(),
|
|
123
|
+
),
|
|
124
|
+
).thenResolve([result(resolved)]);
|
|
125
|
+
const nonEnforcingKnexEntityLoader = instance(nonEnforcingKnexEntityLoaderMock);
|
|
126
|
+
const enforcingKnexEntityLoader = new EnforcingKnexEntityLoader(
|
|
127
|
+
nonEnforcingKnexEntityLoader,
|
|
128
|
+
instance(mock(EntityQueryContext)),
|
|
129
|
+
instance(mock(EntityKnexDataManager)),
|
|
130
|
+
instance(mock<IEntityMetricsAdapter>()),
|
|
131
|
+
instance(mock(EntityConstructionUtils)),
|
|
132
|
+
);
|
|
133
|
+
await expect(
|
|
134
|
+
enforcingKnexEntityLoader.loadManyByFieldEqualityConjunctionAsync(anything(), anything()),
|
|
135
|
+
).resolves.toEqual([resolved]);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
describe('loadManyByRawWhereClause', () => {
|
|
140
|
+
it('throws when result is unsuccessful', async () => {
|
|
141
|
+
const nonEnforcingKnexEntityLoaderMock = mock(
|
|
142
|
+
AuthorizationResultBasedKnexEntityLoader<any, any, any, any, any, any>,
|
|
143
|
+
);
|
|
144
|
+
const rejection = new Error();
|
|
145
|
+
when(
|
|
146
|
+
nonEnforcingKnexEntityLoaderMock.loadManyByRawWhereClauseAsync(
|
|
147
|
+
anything(),
|
|
148
|
+
anything(),
|
|
149
|
+
anything(),
|
|
150
|
+
),
|
|
151
|
+
).thenResolve([result(rejection)]);
|
|
152
|
+
const nonEnforcingKnexEntityLoader = instance(nonEnforcingKnexEntityLoaderMock);
|
|
153
|
+
const enforcingKnexEntityLoader = new EnforcingKnexEntityLoader(
|
|
154
|
+
nonEnforcingKnexEntityLoader,
|
|
155
|
+
instance(mock(EntityQueryContext)),
|
|
156
|
+
instance(mock(EntityKnexDataManager)),
|
|
157
|
+
instance(mock<IEntityMetricsAdapter>()),
|
|
158
|
+
instance(mock(EntityConstructionUtils)),
|
|
159
|
+
);
|
|
160
|
+
await expect(
|
|
161
|
+
enforcingKnexEntityLoader.loadManyByRawWhereClauseAsync(anything(), anything(), anything()),
|
|
162
|
+
).rejects.toThrow(rejection);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('returns value when result is successful', async () => {
|
|
166
|
+
const nonEnforcingKnexEntityLoaderMock = mock(
|
|
167
|
+
AuthorizationResultBasedKnexEntityLoader<any, any, any, any, any, any>,
|
|
168
|
+
);
|
|
169
|
+
const resolved = {};
|
|
170
|
+
when(
|
|
171
|
+
nonEnforcingKnexEntityLoaderMock.loadManyByRawWhereClauseAsync(
|
|
172
|
+
anything(),
|
|
173
|
+
anything(),
|
|
174
|
+
anything(),
|
|
175
|
+
),
|
|
176
|
+
).thenResolve([result(resolved)]);
|
|
177
|
+
const nonEnforcingKnexEntityLoader = instance(nonEnforcingKnexEntityLoaderMock);
|
|
178
|
+
const enforcingKnexEntityLoader = new EnforcingKnexEntityLoader(
|
|
179
|
+
nonEnforcingKnexEntityLoader,
|
|
180
|
+
instance(mock(EntityQueryContext)),
|
|
181
|
+
instance(mock(EntityKnexDataManager)),
|
|
182
|
+
instance(mock<IEntityMetricsAdapter>()),
|
|
183
|
+
instance(mock(EntityConstructionUtils)),
|
|
184
|
+
);
|
|
185
|
+
await expect(
|
|
186
|
+
enforcingKnexEntityLoader.loadManyByRawWhereClauseAsync(anything(), anything(), anything()),
|
|
187
|
+
).resolves.toEqual([resolved]);
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
describe('loadManyBySQL', () => {
|
|
192
|
+
it('throws when result is unsuccessful', async () => {
|
|
193
|
+
const nonEnforcingKnexEntityLoaderMock = mock(
|
|
194
|
+
AuthorizationResultBasedKnexEntityLoader<any, any, any, any, any, any>,
|
|
195
|
+
);
|
|
196
|
+
const rejection = new Error('Authorization failed');
|
|
197
|
+
|
|
198
|
+
const queryBuilderMock = mock(
|
|
199
|
+
AuthorizationResultBasedSQLQueryBuilder<any, any, any, any, any, any>,
|
|
200
|
+
);
|
|
201
|
+
when(queryBuilderMock.executeAsync()).thenResolve([result(rejection)]);
|
|
202
|
+
const queryBuilder = instance(queryBuilderMock);
|
|
203
|
+
|
|
204
|
+
when(nonEnforcingKnexEntityLoaderMock.loadManyBySQL(anything(), anything())).thenReturn(
|
|
205
|
+
queryBuilder,
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
const nonEnforcingKnexEntityLoader = instance(nonEnforcingKnexEntityLoaderMock);
|
|
209
|
+
const enforcingKnexEntityLoader = new EnforcingKnexEntityLoader(
|
|
210
|
+
nonEnforcingKnexEntityLoader,
|
|
211
|
+
instance(mock(EntityQueryContext)),
|
|
212
|
+
instance(mock(EntityKnexDataManager)),
|
|
213
|
+
instance(mock<IEntityMetricsAdapter>()),
|
|
214
|
+
instance(mock(EntityConstructionUtils)),
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
const enforcingQueryBuilder = enforcingKnexEntityLoader.loadManyBySQL(sql`1=1`);
|
|
218
|
+
await expect(enforcingQueryBuilder.executeAsync()).rejects.toThrow(rejection);
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it('returns value when result is successful', async () => {
|
|
222
|
+
const nonEnforcingKnexEntityLoaderMock = mock(
|
|
223
|
+
AuthorizationResultBasedKnexEntityLoader<any, any, any, any, any, any>,
|
|
224
|
+
);
|
|
225
|
+
const entity1 = { id: '1', name: 'Entity 1' };
|
|
226
|
+
const entity2 = { id: '2', name: 'Entity 2' };
|
|
227
|
+
|
|
228
|
+
const queryBuilderMock = mock(
|
|
229
|
+
AuthorizationResultBasedSQLQueryBuilder<any, any, any, any, any, any>,
|
|
230
|
+
);
|
|
231
|
+
when(queryBuilderMock.executeAsync()).thenResolve([result(entity1), result(entity2)]);
|
|
232
|
+
const queryBuilder = instance(queryBuilderMock);
|
|
233
|
+
|
|
234
|
+
when(nonEnforcingKnexEntityLoaderMock.loadManyBySQL(anything(), anything())).thenReturn(
|
|
235
|
+
queryBuilder,
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
const nonEnforcingKnexEntityLoader = instance(nonEnforcingKnexEntityLoaderMock);
|
|
239
|
+
const enforcingKnexEntityLoader = new EnforcingKnexEntityLoader(
|
|
240
|
+
nonEnforcingKnexEntityLoader,
|
|
241
|
+
instance(mock(EntityQueryContext)),
|
|
242
|
+
instance(mock(EntityKnexDataManager)),
|
|
243
|
+
instance(mock<IEntityMetricsAdapter>()),
|
|
244
|
+
instance(mock(EntityConstructionUtils)),
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
const enforcingQueryBuilder = enforcingKnexEntityLoader.loadManyBySQL(sql`1=1`);
|
|
248
|
+
await expect(enforcingQueryBuilder.executeAsync()).resolves.toEqual([entity1, entity2]);
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
describe('loadPageAsync', () => {
|
|
253
|
+
it('throws when result is unsuccessful', async () => {
|
|
254
|
+
const queryContext = instance(mock(EntityQueryContext));
|
|
255
|
+
const knexDataManagerMock = mock<EntityKnexDataManager<any, any>>(EntityKnexDataManager);
|
|
256
|
+
const constructionUtilsMock =
|
|
257
|
+
mock<EntityConstructionUtils<any, any, any, any, any, any>>(EntityConstructionUtils);
|
|
258
|
+
const rejection = new Error('Entity not authorized');
|
|
259
|
+
|
|
260
|
+
// Mock the data manager to return a connection with field objects
|
|
261
|
+
when(knexDataManagerMock.loadPageAsync(anything(), anything())).thenResolve({
|
|
262
|
+
edges: [
|
|
263
|
+
{
|
|
264
|
+
cursor: 'cursor1',
|
|
265
|
+
node: { id: '1', name: 'Entity 1' },
|
|
266
|
+
},
|
|
267
|
+
],
|
|
268
|
+
pageInfo: {
|
|
269
|
+
hasNextPage: false,
|
|
270
|
+
hasPreviousPage: false,
|
|
271
|
+
startCursor: 'cursor1',
|
|
272
|
+
endCursor: 'cursor1',
|
|
273
|
+
},
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
// Mock constructionUtils to throw when constructing entities
|
|
277
|
+
when(constructionUtilsMock.constructAndAuthorizeEntityAsync(anything())).thenResolve(
|
|
278
|
+
result(rejection),
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
const enforcingKnexEntityLoader = new EnforcingKnexEntityLoader(
|
|
282
|
+
instance(mock(AuthorizationResultBasedKnexEntityLoader<any, any, any, any, any, any>)),
|
|
283
|
+
queryContext,
|
|
284
|
+
instance(knexDataManagerMock),
|
|
285
|
+
instance(mock<IEntityMetricsAdapter>()),
|
|
286
|
+
instance(constructionUtilsMock),
|
|
287
|
+
);
|
|
288
|
+
|
|
289
|
+
await expect(
|
|
290
|
+
enforcingKnexEntityLoader.loadPageAsync({
|
|
291
|
+
first: 10,
|
|
292
|
+
pagination: {
|
|
293
|
+
strategy: PaginationStrategy.STANDARD,
|
|
294
|
+
orderBy: [],
|
|
295
|
+
},
|
|
296
|
+
}),
|
|
297
|
+
).rejects.toThrow(rejection);
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
it('returns value when result is successful', async () => {
|
|
301
|
+
const queryContext = instance(mock(EntityQueryContext));
|
|
302
|
+
const knexDataManagerMock = mock<EntityKnexDataManager<any, any>>(EntityKnexDataManager);
|
|
303
|
+
const constructionUtilsMock =
|
|
304
|
+
mock<EntityConstructionUtils<any, any, any, any, any, any>>(EntityConstructionUtils);
|
|
305
|
+
const entity1 = { id: '1', name: 'Entity 1', getID: () => '1' };
|
|
306
|
+
const entity2 = { id: '2', name: 'Entity 2', getID: () => '2' };
|
|
307
|
+
|
|
308
|
+
when(knexDataManagerMock.loadPageAsync(anything(), anything())).thenResolve({
|
|
309
|
+
edges: [
|
|
310
|
+
{
|
|
311
|
+
cursor: 'cursor1',
|
|
312
|
+
node: { id: '1', name: 'Entity 1' },
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
cursor: 'cursor2',
|
|
316
|
+
node: { id: '2', name: 'Entity 2' },
|
|
317
|
+
},
|
|
318
|
+
],
|
|
319
|
+
pageInfo: {
|
|
320
|
+
hasNextPage: true,
|
|
321
|
+
hasPreviousPage: false,
|
|
322
|
+
startCursor: 'cursor1',
|
|
323
|
+
endCursor: 'cursor2',
|
|
324
|
+
},
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
when(constructionUtilsMock.constructAndAuthorizeEntityAsync(anything())).thenCall(
|
|
328
|
+
async (fieldObject: any) => {
|
|
329
|
+
if (fieldObject.id === '1') {
|
|
330
|
+
return result(entity1);
|
|
331
|
+
} else if (fieldObject.id === '2') {
|
|
332
|
+
return result(entity2);
|
|
333
|
+
}
|
|
334
|
+
throw new Error('Unexpected field object');
|
|
335
|
+
},
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
const enforcingKnexEntityLoader = new EnforcingKnexEntityLoader(
|
|
339
|
+
instance(mock(AuthorizationResultBasedKnexEntityLoader<any, any, any, any, any, any>)),
|
|
340
|
+
queryContext,
|
|
341
|
+
instance(knexDataManagerMock),
|
|
342
|
+
instance(mock<IEntityMetricsAdapter>()),
|
|
343
|
+
instance(constructionUtilsMock),
|
|
344
|
+
);
|
|
345
|
+
|
|
346
|
+
const connection = await enforcingKnexEntityLoader.loadPageAsync({
|
|
347
|
+
first: 10,
|
|
348
|
+
pagination: {
|
|
349
|
+
strategy: PaginationStrategy.STANDARD,
|
|
350
|
+
orderBy: [],
|
|
351
|
+
},
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
expect(connection.edges).toHaveLength(2);
|
|
355
|
+
expect(connection.edges[0]).toEqual({
|
|
356
|
+
cursor: 'cursor1',
|
|
357
|
+
node: entity1,
|
|
358
|
+
});
|
|
359
|
+
expect(connection.edges[1]).toEqual({
|
|
360
|
+
cursor: 'cursor2',
|
|
361
|
+
node: entity2,
|
|
362
|
+
});
|
|
363
|
+
expect(connection.pageInfo).toEqual({
|
|
364
|
+
hasNextPage: true,
|
|
365
|
+
hasPreviousPage: false,
|
|
366
|
+
startCursor: 'cursor1',
|
|
367
|
+
endCursor: 'cursor2',
|
|
368
|
+
});
|
|
369
|
+
});
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
it('has the same method names as AuthorizationResultBasedKnexEntityLoader', () => {
|
|
373
|
+
const enforcingKnexLoaderProperties = Object.getOwnPropertyNames(
|
|
374
|
+
EnforcingKnexEntityLoader.prototype,
|
|
375
|
+
);
|
|
376
|
+
const nonEnforcingKnexLoaderProperties = Object.getOwnPropertyNames(
|
|
377
|
+
AuthorizationResultBasedKnexEntityLoader.prototype,
|
|
378
|
+
);
|
|
379
|
+
|
|
380
|
+
// The knex loaders don't have the internal validation methods that regular loaders have,
|
|
381
|
+
// so we just check that all methods match without any exclusions
|
|
382
|
+
expect(enforcingKnexLoaderProperties).toEqual(nonEnforcingKnexLoaderProperties);
|
|
383
|
+
});
|
|
384
|
+
});
|
|
@@ -4,7 +4,7 @@ import { BigIntField, JSONArrayField, MaybeJSONArrayField } from '../EntityField
|
|
|
4
4
|
|
|
5
5
|
describeFieldTestCase(
|
|
6
6
|
new JSONArrayField({ columnName: 'wat' }),
|
|
7
|
-
[[[1, 2]]
|
|
7
|
+
[[[1, 2]], [['hello']]],
|
|
8
8
|
[1, 'hello'],
|
|
9
9
|
);
|
|
10
10
|
describeFieldTestCase(
|