@expo/entity-database-adapter-knex 0.61.0 → 0.63.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 +0 -8
- package/build/src/AuthorizationResultBasedKnexEntityLoader.js +0 -11
- package/build/src/BasePostgresEntityDatabaseAdapter.d.ts +0 -11
- package/build/src/BasePostgresEntityDatabaseAdapter.js +0 -13
- package/build/src/EnforcingKnexEntityLoader.d.ts +0 -32
- package/build/src/EnforcingKnexEntityLoader.js +0 -35
- package/build/src/PostgresEntityDatabaseAdapter.d.ts +3 -2
- package/build/src/PostgresEntityDatabaseAdapter.js +2 -6
- package/build/src/SQLOperator.d.ts +379 -31
- package/build/src/internal/EntityKnexDataManager.d.ts +0 -10
- package/build/src/internal/EntityKnexDataManager.js +3 -16
- package/package.json +5 -5
- package/src/AuthorizationResultBasedKnexEntityLoader.ts +0 -21
- package/src/BasePostgresEntityDatabaseAdapter.ts +0 -36
- package/src/EnforcingKnexEntityLoader.ts +0 -44
- package/src/PostgresEntityDatabaseAdapter.ts +4 -15
- package/src/SQLOperator.ts +449 -101
- package/src/__integration-tests__/PostgresEntityIntegration-test.ts +69 -116
- package/src/__tests__/AuthorizationResultBasedKnexEntityLoader-test.ts +0 -75
- package/src/__tests__/BasePostgresEntityDatabaseAdapter-test.ts +4 -28
- package/src/__tests__/EnforcingKnexEntityLoader-test.ts +0 -52
- package/src/__tests__/fixtures/StubPostgresDatabaseAdapter.ts +3 -13
- package/src/internal/EntityKnexDataManager.ts +6 -37
- package/src/internal/__tests__/EntityKnexDataManager-test.ts +1 -57
|
@@ -1085,6 +1085,49 @@ describe('postgres entity integration', () => {
|
|
|
1085
1085
|
expect(results.map((e) => e.getField('name'))).toEqual(['alpha', 'gamma', 'beta']);
|
|
1086
1086
|
});
|
|
1087
1087
|
|
|
1088
|
+
it('supports fieldFragment orderBy with entityField', async () => {
|
|
1089
|
+
const vc1 = new ViewerContext(createKnexIntegrationTestEntityCompanionProvider(knexInstance));
|
|
1090
|
+
|
|
1091
|
+
await enforceAsyncResult(
|
|
1092
|
+
PostgresTestEntity.creatorWithAuthorizationResults(vc1)
|
|
1093
|
+
.setField('name', 'alpha')
|
|
1094
|
+
.setField('hasACat', true)
|
|
1095
|
+
.createAsync(),
|
|
1096
|
+
);
|
|
1097
|
+
|
|
1098
|
+
await enforceAsyncResult(
|
|
1099
|
+
PostgresTestEntity.creatorWithAuthorizationResults(vc1)
|
|
1100
|
+
.setField('name', 'beta')
|
|
1101
|
+
.setField('hasACat', false)
|
|
1102
|
+
.createAsync(),
|
|
1103
|
+
);
|
|
1104
|
+
|
|
1105
|
+
await enforceAsyncResult(
|
|
1106
|
+
PostgresTestEntity.creatorWithAuthorizationResults(vc1)
|
|
1107
|
+
.setField('name', 'gamma')
|
|
1108
|
+
.setField('hasACat', true)
|
|
1109
|
+
.createAsync(),
|
|
1110
|
+
);
|
|
1111
|
+
|
|
1112
|
+
// Order by entityField references, which translate entity field names to DB column names
|
|
1113
|
+
const results = await PostgresTestEntity.knexLoader(
|
|
1114
|
+
vc1,
|
|
1115
|
+
).loadManyByFieldEqualityConjunctionAsync([], {
|
|
1116
|
+
orderBy: [
|
|
1117
|
+
{
|
|
1118
|
+
fieldFragment: sql`${entityField('hasACat')}`,
|
|
1119
|
+
order: OrderByOrdering.DESCENDING,
|
|
1120
|
+
},
|
|
1121
|
+
{
|
|
1122
|
+
fieldFragment: sql`${entityField('name')}`,
|
|
1123
|
+
order: OrderByOrdering.ASCENDING,
|
|
1124
|
+
},
|
|
1125
|
+
],
|
|
1126
|
+
});
|
|
1127
|
+
expect(results).toHaveLength(3);
|
|
1128
|
+
expect(results.map((e) => e.getField('name'))).toEqual(['alpha', 'gamma', 'beta']);
|
|
1129
|
+
});
|
|
1130
|
+
|
|
1088
1131
|
it('rejects fieldFragment containing trailing ASC or DESC', async () => {
|
|
1089
1132
|
const vc1 = new ViewerContext(createKnexIntegrationTestEntityCompanionProvider(knexInstance));
|
|
1090
1133
|
|
|
@@ -1165,122 +1208,6 @@ describe('postgres entity integration', () => {
|
|
|
1165
1208
|
});
|
|
1166
1209
|
});
|
|
1167
1210
|
|
|
1168
|
-
describe('raw where clause loading', () => {
|
|
1169
|
-
it('loads by raw where clause', async () => {
|
|
1170
|
-
const vc1 = new ViewerContext(createKnexIntegrationTestEntityCompanionProvider(knexInstance));
|
|
1171
|
-
await enforceAsyncResult(
|
|
1172
|
-
PostgresTestEntity.creatorWithAuthorizationResults(vc1)
|
|
1173
|
-
.setField('name', 'hello')
|
|
1174
|
-
.setField('hasACat', false)
|
|
1175
|
-
.setField('hasADog', true)
|
|
1176
|
-
.createAsync(),
|
|
1177
|
-
);
|
|
1178
|
-
|
|
1179
|
-
const results = await PostgresTestEntity.knexLoader(vc1).loadManyByRawWhereClauseAsync(
|
|
1180
|
-
'name = ?',
|
|
1181
|
-
['hello'],
|
|
1182
|
-
);
|
|
1183
|
-
|
|
1184
|
-
expect(results).toHaveLength(1);
|
|
1185
|
-
});
|
|
1186
|
-
|
|
1187
|
-
it('throws with invalid where clause', async () => {
|
|
1188
|
-
const vc1 = new ViewerContext(createKnexIntegrationTestEntityCompanionProvider(knexInstance));
|
|
1189
|
-
await enforceAsyncResult(
|
|
1190
|
-
PostgresTestEntity.creatorWithAuthorizationResults(vc1)
|
|
1191
|
-
.setField('name', 'hello')
|
|
1192
|
-
.setField('hasACat', false)
|
|
1193
|
-
.setField('hasADog', true)
|
|
1194
|
-
.createAsync(),
|
|
1195
|
-
);
|
|
1196
|
-
|
|
1197
|
-
await expect(
|
|
1198
|
-
PostgresTestEntity.knexLoader(vc1).loadManyByRawWhereClauseAsync('invalid_column = ?', [
|
|
1199
|
-
'hello',
|
|
1200
|
-
]),
|
|
1201
|
-
).rejects.toThrow();
|
|
1202
|
-
});
|
|
1203
|
-
|
|
1204
|
-
it('supports query modifiers', async () => {
|
|
1205
|
-
const vc1 = new ViewerContext(createKnexIntegrationTestEntityCompanionProvider(knexInstance));
|
|
1206
|
-
|
|
1207
|
-
await enforceAsyncResult(
|
|
1208
|
-
PostgresTestEntity.creatorWithAuthorizationResults(vc1)
|
|
1209
|
-
.setField('name', 'a')
|
|
1210
|
-
.setField('hasADog', true)
|
|
1211
|
-
.createAsync(),
|
|
1212
|
-
);
|
|
1213
|
-
|
|
1214
|
-
await enforceAsyncResult(
|
|
1215
|
-
PostgresTestEntity.creatorWithAuthorizationResults(vc1)
|
|
1216
|
-
.setField('name', 'b')
|
|
1217
|
-
.setField('hasADog', true)
|
|
1218
|
-
.createAsync(),
|
|
1219
|
-
);
|
|
1220
|
-
|
|
1221
|
-
await enforceAsyncResult(
|
|
1222
|
-
PostgresTestEntity.creatorWithAuthorizationResults(vc1)
|
|
1223
|
-
.setField('name', 'c')
|
|
1224
|
-
.setField('hasADog', true)
|
|
1225
|
-
.createAsync(),
|
|
1226
|
-
);
|
|
1227
|
-
|
|
1228
|
-
const results = await PostgresTestEntity.knexLoader(vc1).loadManyByRawWhereClauseAsync(
|
|
1229
|
-
'has_a_dog = ?',
|
|
1230
|
-
[true],
|
|
1231
|
-
{
|
|
1232
|
-
limit: 2,
|
|
1233
|
-
offset: 1,
|
|
1234
|
-
orderBy: [
|
|
1235
|
-
{
|
|
1236
|
-
fieldName: 'name',
|
|
1237
|
-
order: OrderByOrdering.ASCENDING,
|
|
1238
|
-
},
|
|
1239
|
-
],
|
|
1240
|
-
},
|
|
1241
|
-
);
|
|
1242
|
-
|
|
1243
|
-
expect(results).toHaveLength(2);
|
|
1244
|
-
expect(results.map((e) => e.getField('name'))).toEqual(['b', 'c']);
|
|
1245
|
-
|
|
1246
|
-
const resultsMultipleOrderBy = await PostgresTestEntity.knexLoader(
|
|
1247
|
-
vc1,
|
|
1248
|
-
).loadManyByRawWhereClauseAsync('has_a_dog = ?', [true], {
|
|
1249
|
-
orderBy: [
|
|
1250
|
-
{
|
|
1251
|
-
fieldName: 'hasADog',
|
|
1252
|
-
order: OrderByOrdering.ASCENDING,
|
|
1253
|
-
},
|
|
1254
|
-
{
|
|
1255
|
-
fieldName: 'name',
|
|
1256
|
-
order: OrderByOrdering.DESCENDING,
|
|
1257
|
-
},
|
|
1258
|
-
],
|
|
1259
|
-
});
|
|
1260
|
-
|
|
1261
|
-
expect(resultsMultipleOrderBy).toHaveLength(3);
|
|
1262
|
-
expect(resultsMultipleOrderBy.map((e) => e.getField('name'))).toEqual(['c', 'b', 'a']);
|
|
1263
|
-
|
|
1264
|
-
const resultsOrderByRaw = await PostgresTestEntity.knexLoader(
|
|
1265
|
-
vc1,
|
|
1266
|
-
).loadManyByRawWhereClauseAsync('has_a_dog = ?', [true], {
|
|
1267
|
-
orderBy: [
|
|
1268
|
-
{
|
|
1269
|
-
fieldFragment: sql`${entityField('hasADog')}`,
|
|
1270
|
-
order: OrderByOrdering.ASCENDING,
|
|
1271
|
-
},
|
|
1272
|
-
{
|
|
1273
|
-
fieldFragment: sql`${entityField('name')}`,
|
|
1274
|
-
order: OrderByOrdering.DESCENDING,
|
|
1275
|
-
},
|
|
1276
|
-
],
|
|
1277
|
-
});
|
|
1278
|
-
|
|
1279
|
-
expect(resultsOrderByRaw).toHaveLength(3);
|
|
1280
|
-
expect(resultsOrderByRaw.map((e) => e.getField('name'))).toEqual(['c', 'b', 'a']);
|
|
1281
|
-
});
|
|
1282
|
-
});
|
|
1283
|
-
|
|
1284
1211
|
describe('trigger transaction behavior', () => {
|
|
1285
1212
|
describe('create', () => {
|
|
1286
1213
|
it('rolls back transaction when trigger throws except afterCommit', async () => {
|
|
@@ -2196,6 +2123,32 @@ describe('postgres entity integration', () => {
|
|
|
2196
2123
|
},
|
|
2197
2124
|
}),
|
|
2198
2125
|
).rejects.toThrow("Cursor is missing required 'id' field.");
|
|
2126
|
+
|
|
2127
|
+
// Try with valid base64-encoded JSON that decodes to a non-object primitive
|
|
2128
|
+
const primitiveCursor = Buffer.from(JSON.stringify(12345)).toString('base64url');
|
|
2129
|
+
await expect(
|
|
2130
|
+
PostgresTestEntity.knexLoader(vc).loadPageAsync({
|
|
2131
|
+
first: 10,
|
|
2132
|
+
after: primitiveCursor,
|
|
2133
|
+
pagination: {
|
|
2134
|
+
strategy: PaginationStrategy.STANDARD,
|
|
2135
|
+
orderBy: [],
|
|
2136
|
+
},
|
|
2137
|
+
}),
|
|
2138
|
+
).rejects.toThrow("Cursor is missing required 'id' field.");
|
|
2139
|
+
|
|
2140
|
+
// Try with valid base64-encoded JSON string primitive
|
|
2141
|
+
const stringPrimitiveCursor = Buffer.from(JSON.stringify('hello')).toString('base64url');
|
|
2142
|
+
await expect(
|
|
2143
|
+
PostgresTestEntity.knexLoader(vc).loadPageAsync({
|
|
2144
|
+
first: 10,
|
|
2145
|
+
after: stringPrimitiveCursor,
|
|
2146
|
+
pagination: {
|
|
2147
|
+
strategy: PaginationStrategy.STANDARD,
|
|
2148
|
+
orderBy: [],
|
|
2149
|
+
},
|
|
2150
|
+
}),
|
|
2151
|
+
).rejects.toThrow("Cursor is missing required 'id' field.");
|
|
2199
2152
|
});
|
|
2200
2153
|
|
|
2201
2154
|
it('performs pagination with both loader types', async () => {
|
|
@@ -205,81 +205,6 @@ describe(AuthorizationResultBasedKnexEntityLoader, () => {
|
|
|
205
205
|
).once();
|
|
206
206
|
});
|
|
207
207
|
|
|
208
|
-
it('loads entities with loadManyByRawWhereClauseAsync', async () => {
|
|
209
|
-
const privacyPolicy = new TestEntityPrivacyPolicy();
|
|
210
|
-
const spiedPrivacyPolicy = spy(privacyPolicy);
|
|
211
|
-
const viewerContext = instance(mock(ViewerContext));
|
|
212
|
-
const privacyPolicyEvaluationContext =
|
|
213
|
-
instance(
|
|
214
|
-
mock<
|
|
215
|
-
EntityPrivacyPolicyEvaluationContext<
|
|
216
|
-
TestFields,
|
|
217
|
-
'customIdField',
|
|
218
|
-
ViewerContext,
|
|
219
|
-
TestEntity
|
|
220
|
-
>
|
|
221
|
-
>(),
|
|
222
|
-
);
|
|
223
|
-
const metricsAdapter = instance(mock<IEntityMetricsAdapter>());
|
|
224
|
-
const queryContext = instance(mock<EntityQueryContext>());
|
|
225
|
-
|
|
226
|
-
const knexDataManagerMock =
|
|
227
|
-
mock<EntityKnexDataManager<TestFields, 'customIdField'>>(EntityKnexDataManager);
|
|
228
|
-
when(
|
|
229
|
-
knexDataManagerMock.loadManyByRawWhereClauseAsync(
|
|
230
|
-
queryContext,
|
|
231
|
-
anything(),
|
|
232
|
-
anything(),
|
|
233
|
-
anything(),
|
|
234
|
-
),
|
|
235
|
-
).thenResolve([
|
|
236
|
-
{
|
|
237
|
-
customIdField: 'id',
|
|
238
|
-
stringField: 'huh',
|
|
239
|
-
intField: 4,
|
|
240
|
-
testIndexedField: '4',
|
|
241
|
-
dateField: new Date(),
|
|
242
|
-
nullableField: null,
|
|
243
|
-
},
|
|
244
|
-
]);
|
|
245
|
-
const knexDataManager = instance(knexDataManagerMock);
|
|
246
|
-
|
|
247
|
-
const constructionUtils = new EntityConstructionUtils(
|
|
248
|
-
viewerContext,
|
|
249
|
-
queryContext,
|
|
250
|
-
privacyPolicyEvaluationContext,
|
|
251
|
-
testEntityConfiguration,
|
|
252
|
-
TestEntity,
|
|
253
|
-
/* entitySelectedFields */ undefined,
|
|
254
|
-
privacyPolicy,
|
|
255
|
-
metricsAdapter,
|
|
256
|
-
);
|
|
257
|
-
const knexEntityLoader = new AuthorizationResultBasedKnexEntityLoader(
|
|
258
|
-
queryContext,
|
|
259
|
-
knexDataManager,
|
|
260
|
-
metricsAdapter,
|
|
261
|
-
constructionUtils,
|
|
262
|
-
);
|
|
263
|
-
|
|
264
|
-
const result = await knexEntityLoader.loadManyByRawWhereClauseAsync('id = ?', [1], {
|
|
265
|
-
orderBy: [{ fieldName: 'testIndexedField', order: OrderByOrdering.DESCENDING }],
|
|
266
|
-
});
|
|
267
|
-
expect(result).toHaveLength(1);
|
|
268
|
-
expect(result[0]).not.toBeNull();
|
|
269
|
-
expect(result[0]!.ok).toBe(true);
|
|
270
|
-
expect(result[0]!.enforceValue().getField('testIndexedField')).toEqual('4');
|
|
271
|
-
|
|
272
|
-
verify(
|
|
273
|
-
spiedPrivacyPolicy.authorizeReadAsync(
|
|
274
|
-
viewerContext,
|
|
275
|
-
queryContext,
|
|
276
|
-
privacyPolicyEvaluationContext,
|
|
277
|
-
anyOfClass(TestEntity),
|
|
278
|
-
anything(),
|
|
279
|
-
),
|
|
280
|
-
).once();
|
|
281
|
-
});
|
|
282
|
-
|
|
283
208
|
describe('loads entities with loadManyBySQL', () => {
|
|
284
209
|
it('returns entities with authorization results', async () => {
|
|
285
210
|
const privacyPolicy = new TestEntityPrivacyPolicy();
|
|
@@ -18,9 +18,8 @@ class TestEntityDatabaseAdapter extends BasePostgresEntityDatabaseAdapter<
|
|
|
18
18
|
private readonly fetchResults: object[];
|
|
19
19
|
private readonly fetchOneResult: object | null;
|
|
20
20
|
private readonly insertResults: object[];
|
|
21
|
-
private readonly updateResults:
|
|
21
|
+
private readonly updateResults: { updatedRowCount: number };
|
|
22
22
|
private readonly fetchEqualityConditionResults: object[];
|
|
23
|
-
private readonly fetchRawWhereResults: object[];
|
|
24
23
|
private readonly fetchSQLFragmentResults: object[];
|
|
25
24
|
private readonly deleteCount: number;
|
|
26
25
|
|
|
@@ -28,18 +27,16 @@ class TestEntityDatabaseAdapter extends BasePostgresEntityDatabaseAdapter<
|
|
|
28
27
|
fetchResults = [],
|
|
29
28
|
fetchOneResult = null,
|
|
30
29
|
insertResults = [],
|
|
31
|
-
updateResults =
|
|
30
|
+
updateResults = { updatedRowCount: 0 },
|
|
32
31
|
fetchEqualityConditionResults = [],
|
|
33
|
-
fetchRawWhereResults = [],
|
|
34
32
|
fetchSQLFragmentResults = [],
|
|
35
33
|
deleteCount = 0,
|
|
36
34
|
}: {
|
|
37
35
|
fetchResults?: object[];
|
|
38
36
|
fetchOneResult?: object | null;
|
|
39
37
|
insertResults?: object[];
|
|
40
|
-
updateResults?:
|
|
38
|
+
updateResults?: { updatedRowCount: number };
|
|
41
39
|
fetchEqualityConditionResults?: object[];
|
|
42
|
-
fetchRawWhereResults?: object[];
|
|
43
40
|
fetchSQLFragmentResults?: object[];
|
|
44
41
|
deleteCount?: number;
|
|
45
42
|
}) {
|
|
@@ -49,7 +46,6 @@ class TestEntityDatabaseAdapter extends BasePostgresEntityDatabaseAdapter<
|
|
|
49
46
|
this.insertResults = insertResults;
|
|
50
47
|
this.updateResults = updateResults;
|
|
51
48
|
this.fetchEqualityConditionResults = fetchEqualityConditionResults;
|
|
52
|
-
this.fetchRawWhereResults = fetchRawWhereResults;
|
|
53
49
|
this.fetchSQLFragmentResults = fetchSQLFragmentResults;
|
|
54
50
|
this.deleteCount = deleteCount;
|
|
55
51
|
}
|
|
@@ -76,15 +72,6 @@ class TestEntityDatabaseAdapter extends BasePostgresEntityDatabaseAdapter<
|
|
|
76
72
|
return this.fetchOneResult;
|
|
77
73
|
}
|
|
78
74
|
|
|
79
|
-
protected async fetchManyByRawWhereClauseInternalAsync(
|
|
80
|
-
_queryInterface: any,
|
|
81
|
-
_tableName: string,
|
|
82
|
-
_rawWhereClause: string,
|
|
83
|
-
_bindings: object | any[],
|
|
84
|
-
): Promise<object[]> {
|
|
85
|
-
return this.fetchRawWhereResults;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
75
|
protected async fetchManyBySQLFragmentInternalAsync(
|
|
89
76
|
_queryInterface: any,
|
|
90
77
|
_tableName: string,
|
|
@@ -116,7 +103,7 @@ class TestEntityDatabaseAdapter extends BasePostgresEntityDatabaseAdapter<
|
|
|
116
103
|
_tableIdField: string,
|
|
117
104
|
_id: any,
|
|
118
105
|
_object: object,
|
|
119
|
-
): Promise<
|
|
106
|
+
): Promise<{ updatedRowCount: number }> {
|
|
120
107
|
return this.updateResults;
|
|
121
108
|
}
|
|
122
109
|
|
|
@@ -148,15 +135,4 @@ describe(BasePostgresEntityDatabaseAdapter, () => {
|
|
|
148
135
|
expect(results).toEqual([{ stringField: 'hello' }]);
|
|
149
136
|
});
|
|
150
137
|
});
|
|
151
|
-
|
|
152
|
-
describe('fetchManyWithRawWhereClause', () => {
|
|
153
|
-
it('transforms object', async () => {
|
|
154
|
-
const queryContext = instance(mock(EntityQueryContext));
|
|
155
|
-
const adapter = new TestEntityDatabaseAdapter({
|
|
156
|
-
fetchRawWhereResults: [{ string_field: 'hello' }],
|
|
157
|
-
});
|
|
158
|
-
const results = await adapter.fetchManyByRawWhereClauseAsync(queryContext, 'hello', [], {});
|
|
159
|
-
expect(results).toEqual([{ stringField: 'hello' }]);
|
|
160
|
-
});
|
|
161
|
-
});
|
|
162
138
|
});
|
|
@@ -137,58 +137,6 @@ describe(EnforcingKnexEntityLoader, () => {
|
|
|
137
137
|
});
|
|
138
138
|
});
|
|
139
139
|
|
|
140
|
-
describe('loadManyByRawWhereClause', () => {
|
|
141
|
-
it('throws when result is unsuccessful', async () => {
|
|
142
|
-
const nonEnforcingKnexEntityLoaderMock = mock(
|
|
143
|
-
AuthorizationResultBasedKnexEntityLoader<any, any, any, any, any, any>,
|
|
144
|
-
);
|
|
145
|
-
const rejection = new Error();
|
|
146
|
-
when(
|
|
147
|
-
nonEnforcingKnexEntityLoaderMock.loadManyByRawWhereClauseAsync(
|
|
148
|
-
anything(),
|
|
149
|
-
anything(),
|
|
150
|
-
anything(),
|
|
151
|
-
),
|
|
152
|
-
).thenResolve([result(rejection)]);
|
|
153
|
-
const nonEnforcingKnexEntityLoader = instance(nonEnforcingKnexEntityLoaderMock);
|
|
154
|
-
const enforcingKnexEntityLoader = new EnforcingKnexEntityLoader(
|
|
155
|
-
nonEnforcingKnexEntityLoader,
|
|
156
|
-
instance(mock(EntityQueryContext)),
|
|
157
|
-
instance(mock(EntityKnexDataManager)),
|
|
158
|
-
instance(mock<IEntityMetricsAdapter>()),
|
|
159
|
-
instance(mock(EntityConstructionUtils)),
|
|
160
|
-
);
|
|
161
|
-
await expect(
|
|
162
|
-
enforcingKnexEntityLoader.loadManyByRawWhereClauseAsync(anything(), anything(), anything()),
|
|
163
|
-
).rejects.toThrow(rejection);
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
it('returns value when result is successful', async () => {
|
|
167
|
-
const nonEnforcingKnexEntityLoaderMock = mock(
|
|
168
|
-
AuthorizationResultBasedKnexEntityLoader<any, any, any, any, any, any>,
|
|
169
|
-
);
|
|
170
|
-
const resolved = {};
|
|
171
|
-
when(
|
|
172
|
-
nonEnforcingKnexEntityLoaderMock.loadManyByRawWhereClauseAsync(
|
|
173
|
-
anything(),
|
|
174
|
-
anything(),
|
|
175
|
-
anything(),
|
|
176
|
-
),
|
|
177
|
-
).thenResolve([result(resolved)]);
|
|
178
|
-
const nonEnforcingKnexEntityLoader = instance(nonEnforcingKnexEntityLoaderMock);
|
|
179
|
-
const enforcingKnexEntityLoader = new EnforcingKnexEntityLoader(
|
|
180
|
-
nonEnforcingKnexEntityLoader,
|
|
181
|
-
instance(mock(EntityQueryContext)),
|
|
182
|
-
instance(mock(EntityKnexDataManager)),
|
|
183
|
-
instance(mock<IEntityMetricsAdapter>()),
|
|
184
|
-
instance(mock(EntityConstructionUtils)),
|
|
185
|
-
);
|
|
186
|
-
await expect(
|
|
187
|
-
enforcingKnexEntityLoader.loadManyByRawWhereClauseAsync(anything(), anything(), anything()),
|
|
188
|
-
).resolves.toEqual([resolved]);
|
|
189
|
-
});
|
|
190
|
-
});
|
|
191
|
-
|
|
192
140
|
describe('loadManyBySQL', () => {
|
|
193
141
|
it('throws when result is unsuccessful', async () => {
|
|
194
142
|
const nonEnforcingKnexEntityLoaderMock = mock(
|
|
@@ -193,16 +193,6 @@ export class StubPostgresDatabaseAdapter<
|
|
|
193
193
|
return filteredObjects;
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
-
protected fetchManyByRawWhereClauseInternalAsync(
|
|
197
|
-
_queryInterface: any,
|
|
198
|
-
_tableName: string,
|
|
199
|
-
_rawWhereClause: string,
|
|
200
|
-
_bindings: object | any[],
|
|
201
|
-
_querySelectionModifiers: TableQuerySelectionModifiers<TFields>,
|
|
202
|
-
): Promise<object[]> {
|
|
203
|
-
throw new Error('Raw WHERE clauses not supported for StubDatabaseAdapter');
|
|
204
|
-
}
|
|
205
|
-
|
|
206
196
|
protected fetchManyBySQLFragmentInternalAsync(
|
|
207
197
|
_queryInterface: any,
|
|
208
198
|
_tableName: string,
|
|
@@ -254,7 +244,7 @@ export class StubPostgresDatabaseAdapter<
|
|
|
254
244
|
tableIdField: string,
|
|
255
245
|
id: any,
|
|
256
246
|
object: object,
|
|
257
|
-
): Promise<
|
|
247
|
+
): Promise<{ updatedRowCount: number }> {
|
|
258
248
|
// SQL does not support empty updates, mirror behavior here for better test simulation
|
|
259
249
|
if (Object.keys(object).length === 0) {
|
|
260
250
|
throw new Error(`Empty update (${tableIdField} = ${id})`);
|
|
@@ -269,14 +259,14 @@ export class StubPostgresDatabaseAdapter<
|
|
|
269
259
|
// SQL updates to a nonexistent row succeed but affect 0 rows,
|
|
270
260
|
// mirror that behavior here for better test simulation
|
|
271
261
|
if (objectIndex < 0) {
|
|
272
|
-
return
|
|
262
|
+
return { updatedRowCount: 0 };
|
|
273
263
|
}
|
|
274
264
|
|
|
275
265
|
objectCollection[objectIndex] = {
|
|
276
266
|
...objectCollection[objectIndex],
|
|
277
267
|
...object,
|
|
278
268
|
};
|
|
279
|
-
return
|
|
269
|
+
return { updatedRowCount: 1 };
|
|
280
270
|
}
|
|
281
271
|
|
|
282
272
|
protected async deleteInternalAsync(
|
|
@@ -190,38 +190,6 @@ export class EntityKnexDataManager<
|
|
|
190
190
|
);
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
-
/**
|
|
194
|
-
* Loads many objects matching the raw WHERE clause.
|
|
195
|
-
*
|
|
196
|
-
* @param queryContext - query context in which to perform the load
|
|
197
|
-
* @param rawWhereClause - parameterized SQL WHERE clause with positional binding placeholders or named binding placeholders
|
|
198
|
-
* @param bindings - array of positional bindings or object of named bindings
|
|
199
|
-
* @param querySelectionModifiers - limit, offset, orderBy, and orderByRaw for the query
|
|
200
|
-
* @returns array of objects matching the query
|
|
201
|
-
*/
|
|
202
|
-
async loadManyByRawWhereClauseAsync(
|
|
203
|
-
queryContext: EntityQueryContext,
|
|
204
|
-
rawWhereClause: string,
|
|
205
|
-
bindings: readonly any[] | object,
|
|
206
|
-
querySelectionModifiers: PostgresQuerySelectionModifiers<TFields>,
|
|
207
|
-
): Promise<readonly Readonly<TFields>[]> {
|
|
208
|
-
EntityKnexDataManager.validateOrderByClauses(querySelectionModifiers.orderBy);
|
|
209
|
-
|
|
210
|
-
return await timeAndLogLoadEventAsync(
|
|
211
|
-
this.metricsAdapter,
|
|
212
|
-
EntityMetricsLoadType.LOAD_MANY_RAW,
|
|
213
|
-
this.entityClassName,
|
|
214
|
-
queryContext,
|
|
215
|
-
)(
|
|
216
|
-
this.databaseAdapter.fetchManyByRawWhereClauseAsync(
|
|
217
|
-
queryContext,
|
|
218
|
-
rawWhereClause,
|
|
219
|
-
bindings,
|
|
220
|
-
querySelectionModifiers,
|
|
221
|
-
),
|
|
222
|
-
);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
193
|
async loadManyBySQLFragmentAsync(
|
|
226
194
|
queryContext: EntityQueryContext,
|
|
227
195
|
sqlFragment: SQLFragment<TFields>,
|
|
@@ -559,6 +527,7 @@ export class EntityKnexDataManager<
|
|
|
559
527
|
|
|
560
528
|
private decodeOpaqueCursor(cursor: string): TFields[TIDField] {
|
|
561
529
|
let parsedCursor: any;
|
|
530
|
+
|
|
562
531
|
try {
|
|
563
532
|
const decoded = Buffer.from(cursor, 'base64url').toString();
|
|
564
533
|
parsedCursor = JSON.parse(decoded);
|
|
@@ -569,13 +538,13 @@ export class EntityKnexDataManager<
|
|
|
569
538
|
);
|
|
570
539
|
}
|
|
571
540
|
|
|
572
|
-
if (
|
|
573
|
-
|
|
574
|
-
`Cursor is missing required 'id' field. Parsed cursor: ${JSON.stringify(parsedCursor)}`,
|
|
575
|
-
);
|
|
541
|
+
if (typeof parsedCursor === 'object' && 'id' in parsedCursor) {
|
|
542
|
+
return parsedCursor.id;
|
|
576
543
|
}
|
|
577
544
|
|
|
578
|
-
|
|
545
|
+
throw new EntityDatabaseAdapterPaginationCursorInvalidError(
|
|
546
|
+
`Cursor is missing required 'id' field. Parsed cursor: ${JSON.stringify(parsedCursor)}`,
|
|
547
|
+
);
|
|
579
548
|
}
|
|
580
549
|
|
|
581
550
|
private resolveSearchFieldToSQLFragment(
|
|
@@ -2,17 +2,7 @@ import type { EntityQueryContext, IEntityMetricsAdapter } from '@expo/entity';
|
|
|
2
2
|
import { EntityMetricsLoadType, NoOpEntityMetricsAdapter } from '@expo/entity';
|
|
3
3
|
import { StubQueryContextProvider } from '@expo/entity-testing-utils';
|
|
4
4
|
import { describe, expect, it } from '@jest/globals';
|
|
5
|
-
import {
|
|
6
|
-
anyNumber,
|
|
7
|
-
anyString,
|
|
8
|
-
anything,
|
|
9
|
-
deepEqual,
|
|
10
|
-
instance,
|
|
11
|
-
mock,
|
|
12
|
-
resetCalls,
|
|
13
|
-
verify,
|
|
14
|
-
when,
|
|
15
|
-
} from 'ts-mockito';
|
|
5
|
+
import { anyNumber, anything, deepEqual, instance, mock, verify, when } from 'ts-mockito';
|
|
16
6
|
|
|
17
7
|
import { OrderByOrdering } from '../../BasePostgresEntityDatabaseAdapter.ts';
|
|
18
8
|
import { PaginationStrategy } from '../../PaginationStrategy.ts';
|
|
@@ -110,14 +100,6 @@ describe(EntityKnexDataManager, () => {
|
|
|
110
100
|
nullableField: null,
|
|
111
101
|
},
|
|
112
102
|
]);
|
|
113
|
-
when(
|
|
114
|
-
databaseAdapterMock.fetchManyByRawWhereClauseAsync(
|
|
115
|
-
anything(),
|
|
116
|
-
anyString(),
|
|
117
|
-
anything(),
|
|
118
|
-
anything(),
|
|
119
|
-
),
|
|
120
|
-
).thenResolve([]);
|
|
121
103
|
|
|
122
104
|
const entityDataManager = new EntityKnexDataManager(
|
|
123
105
|
testEntityConfiguration,
|
|
@@ -148,21 +130,6 @@ describe(EntityKnexDataManager, () => {
|
|
|
148
130
|
),
|
|
149
131
|
).once();
|
|
150
132
|
|
|
151
|
-
resetCalls(metricsAdapterMock);
|
|
152
|
-
|
|
153
|
-
await entityDataManager.loadManyByRawWhereClauseAsync(queryContext, '', [], {});
|
|
154
|
-
verify(
|
|
155
|
-
metricsAdapterMock.logDataManagerLoadEvent(
|
|
156
|
-
deepEqual({
|
|
157
|
-
type: EntityMetricsLoadType.LOAD_MANY_RAW,
|
|
158
|
-
isInTransaction: false,
|
|
159
|
-
entityClassName: TestEntity.name,
|
|
160
|
-
duration: anyNumber(),
|
|
161
|
-
count: 0,
|
|
162
|
-
}),
|
|
163
|
-
),
|
|
164
|
-
).once();
|
|
165
|
-
|
|
166
133
|
verify(metricsAdapterMock.incrementDataManagerLoadCount(anything())).never();
|
|
167
134
|
});
|
|
168
135
|
|
|
@@ -190,14 +157,6 @@ describe(EntityKnexDataManager, () => {
|
|
|
190
157
|
nullableField: null,
|
|
191
158
|
},
|
|
192
159
|
]);
|
|
193
|
-
when(
|
|
194
|
-
databaseAdapterMock.fetchManyByRawWhereClauseAsync(
|
|
195
|
-
anything(),
|
|
196
|
-
anyString(),
|
|
197
|
-
anything(),
|
|
198
|
-
anything(),
|
|
199
|
-
),
|
|
200
|
-
).thenResolve([]);
|
|
201
160
|
|
|
202
161
|
const entityDataManager = new EntityKnexDataManager(
|
|
203
162
|
testEntityConfiguration,
|
|
@@ -229,21 +188,6 @@ describe(EntityKnexDataManager, () => {
|
|
|
229
188
|
),
|
|
230
189
|
).once();
|
|
231
190
|
|
|
232
|
-
resetCalls(metricsAdapterMock);
|
|
233
|
-
|
|
234
|
-
await entityDataManager.loadManyByRawWhereClauseAsync(queryContext, '', [], {});
|
|
235
|
-
verify(
|
|
236
|
-
metricsAdapterMock.logDataManagerLoadEvent(
|
|
237
|
-
deepEqual({
|
|
238
|
-
type: EntityMetricsLoadType.LOAD_MANY_RAW,
|
|
239
|
-
isInTransaction: true,
|
|
240
|
-
entityClassName: TestEntity.name,
|
|
241
|
-
duration: anyNumber(),
|
|
242
|
-
count: 0,
|
|
243
|
-
}),
|
|
244
|
-
),
|
|
245
|
-
).once();
|
|
246
|
-
|
|
247
191
|
verify(metricsAdapterMock.incrementDataManagerLoadCount(anything())).never();
|
|
248
192
|
});
|
|
249
193
|
});
|