@expo/entity-database-adapter-knex 0.62.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/internal/EntityKnexDataManager.d.ts +0 -10
- package/build/src/internal/EntityKnexDataManager.js +0 -13
- package/package.json +4 -4
- 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/__integration-tests__/PostgresEntityIntegration-test.ts +43 -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 +0 -32
- package/src/internal/__tests__/EntityKnexDataManager-test.ts +1 -57
|
@@ -235,14 +235,6 @@ export declare class AuthorizationResultBasedKnexEntityLoader<TFields extends Re
|
|
|
235
235
|
* @returns array of entity results that match the query, where result error can be UnauthorizedError
|
|
236
236
|
*/
|
|
237
237
|
loadManyByFieldEqualityConjunctionAsync<N extends keyof Pick<TFields, TSelectedFields>>(fieldEqualityOperands: readonly FieldEqualityCondition<TFields, N>[], querySelectionModifiers?: EntityLoaderQuerySelectionModifiers<TFields, TSelectedFields>): Promise<readonly Result<TEntity>[]>;
|
|
238
|
-
/**
|
|
239
|
-
* Authorization-result-based version of the EnforcingKnexEntityLoader method by the same name.
|
|
240
|
-
* @returns array of entity results that match the query, where result error can be UnauthorizedError
|
|
241
|
-
* @throws Error when rawWhereClause or bindings are invalid
|
|
242
|
-
*
|
|
243
|
-
* @deprecated Use loadManyBySQL instead for safer value bindings and more flexible query building.
|
|
244
|
-
*/
|
|
245
|
-
loadManyByRawWhereClauseAsync(rawWhereClause: string, bindings: any[] | object, querySelectionModifiers?: EntityLoaderQuerySelectionModifiers<TFields, TSelectedFields>): Promise<readonly Result<TEntity>[]>;
|
|
246
238
|
/**
|
|
247
239
|
* Authorization-result-based version of the EnforcingKnexEntityLoader method by the same name.
|
|
248
240
|
* @returns SQL query builder for building and executing SQL queries that when executed returns entity results where result error can be UnauthorizedError.
|
|
@@ -43,17 +43,6 @@ export class AuthorizationResultBasedKnexEntityLoader {
|
|
|
43
43
|
const fieldObjects = await this.knexDataManager.loadManyByFieldEqualityConjunctionAsync(this.queryContext, fieldEqualityOperands, querySelectionModifiers);
|
|
44
44
|
return await this.constructionUtils.constructAndAuthorizeEntitiesArrayAsync(fieldObjects);
|
|
45
45
|
}
|
|
46
|
-
/**
|
|
47
|
-
* Authorization-result-based version of the EnforcingKnexEntityLoader method by the same name.
|
|
48
|
-
* @returns array of entity results that match the query, where result error can be UnauthorizedError
|
|
49
|
-
* @throws Error when rawWhereClause or bindings are invalid
|
|
50
|
-
*
|
|
51
|
-
* @deprecated Use loadManyBySQL instead for safer value bindings and more flexible query building.
|
|
52
|
-
*/
|
|
53
|
-
async loadManyByRawWhereClauseAsync(rawWhereClause, bindings, querySelectionModifiers = {}) {
|
|
54
|
-
const fieldObjects = await this.knexDataManager.loadManyByRawWhereClauseAsync(this.queryContext, rawWhereClause, bindings, querySelectionModifiers);
|
|
55
|
-
return await this.constructionUtils.constructAndAuthorizeEntitiesArrayAsync(fieldObjects);
|
|
56
|
-
}
|
|
57
46
|
/**
|
|
58
47
|
* Authorization-result-based version of the EnforcingKnexEntityLoader method by the same name.
|
|
59
48
|
* @returns SQL query builder for building and executing SQL queries that when executed returns entity results where result error can be UnauthorizedError.
|
|
@@ -126,17 +126,6 @@ export declare abstract class BasePostgresEntityDatabaseAdapter<TFields extends
|
|
|
126
126
|
*/
|
|
127
127
|
fetchManyByFieldEqualityConjunctionAsync<N extends keyof TFields>(queryContext: EntityQueryContext, fieldEqualityOperands: readonly FieldEqualityCondition<TFields, N>[], querySelectionModifiers: PostgresQuerySelectionModifiers<TFields>): Promise<readonly Readonly<TFields>[]>;
|
|
128
128
|
protected abstract fetchManyByFieldEqualityConjunctionInternalAsync(queryInterface: Knex, tableName: string, tableFieldSingleValueEqualityOperands: TableFieldSingleValueEqualityCondition[], tableFieldMultiValueEqualityOperands: TableFieldMultiValueEqualityCondition[], querySelectionModifiers: TableQuerySelectionModifiers<TFields>): Promise<object[]>;
|
|
129
|
-
/**
|
|
130
|
-
* Fetch many objects matching the raw WHERE clause.
|
|
131
|
-
*
|
|
132
|
-
* @param queryContext - query context with which to perform the fetch
|
|
133
|
-
* @param rawWhereClause - parameterized SQL WHERE clause with positional binding placeholders or named binding placeholders
|
|
134
|
-
* @param bindings - array of positional bindings or object of named bindings
|
|
135
|
-
* @param querySelectionModifiers - limit, offset, and orderBy for the query
|
|
136
|
-
* @returns array of objects matching the query
|
|
137
|
-
*/
|
|
138
|
-
fetchManyByRawWhereClauseAsync(queryContext: EntityQueryContext, rawWhereClause: string, bindings: any[] | object, querySelectionModifiers: PostgresQuerySelectionModifiers<TFields>): Promise<readonly Readonly<TFields>[]>;
|
|
139
|
-
protected abstract fetchManyByRawWhereClauseInternalAsync(queryInterface: Knex, tableName: string, rawWhereClause: string, bindings: object | any[], querySelectionModifiers: TableQuerySelectionModifiers<TFields>): Promise<object[]>;
|
|
140
129
|
/**
|
|
141
130
|
* Fetch many objects matching the SQL fragment.
|
|
142
131
|
*
|
|
@@ -60,19 +60,6 @@ export class BasePostgresEntityDatabaseAdapter extends EntityDatabaseAdapter {
|
|
|
60
60
|
const results = await this.fetchManyByFieldEqualityConjunctionInternalAsync(queryContext.getQueryInterface(), this.entityConfiguration.tableName, tableFieldSingleValueOperands, tableFieldMultipleValueOperands, this.convertToTableQueryModifiers(querySelectionModifiers));
|
|
61
61
|
return results.map((result) => transformDatabaseObjectToFields(this.entityConfiguration, this.fieldTransformerMap, result));
|
|
62
62
|
}
|
|
63
|
-
/**
|
|
64
|
-
* Fetch many objects matching the raw WHERE clause.
|
|
65
|
-
*
|
|
66
|
-
* @param queryContext - query context with which to perform the fetch
|
|
67
|
-
* @param rawWhereClause - parameterized SQL WHERE clause with positional binding placeholders or named binding placeholders
|
|
68
|
-
* @param bindings - array of positional bindings or object of named bindings
|
|
69
|
-
* @param querySelectionModifiers - limit, offset, and orderBy for the query
|
|
70
|
-
* @returns array of objects matching the query
|
|
71
|
-
*/
|
|
72
|
-
async fetchManyByRawWhereClauseAsync(queryContext, rawWhereClause, bindings, querySelectionModifiers) {
|
|
73
|
-
const results = await this.fetchManyByRawWhereClauseInternalAsync(queryContext.getQueryInterface(), this.entityConfiguration.tableName, rawWhereClause, bindings, this.convertToTableQueryModifiers(querySelectionModifiers));
|
|
74
|
-
return results.map((result) => transformDatabaseObjectToFields(this.entityConfiguration, this.fieldTransformerMap, result));
|
|
75
|
-
}
|
|
76
63
|
/**
|
|
77
64
|
* Fetch many objects matching the SQL fragment.
|
|
78
65
|
*
|
|
@@ -38,38 +38,6 @@ export declare class EnforcingKnexEntityLoader<TFields extends Record<string, an
|
|
|
38
38
|
* @returns entities matching the filters
|
|
39
39
|
*/
|
|
40
40
|
loadManyByFieldEqualityConjunctionAsync<N extends keyof Pick<TFields, TSelectedFields>>(fieldEqualityOperands: FieldEqualityCondition<TFields, N>[], querySelectionModifiers?: EntityLoaderQuerySelectionModifiers<TFields, TSelectedFields>): Promise<readonly TEntity[]>;
|
|
41
|
-
/**
|
|
42
|
-
* Load entities with a raw SQL WHERE clause.
|
|
43
|
-
*
|
|
44
|
-
* @example
|
|
45
|
-
* Load entities with SQL function
|
|
46
|
-
* ```typescript
|
|
47
|
-
* const entitiesWithJsonKey = await ExampleEntity.loader(vc)
|
|
48
|
-
* .loadManyByRawWhereClauseAsync(
|
|
49
|
-
* "json_column->>'key_name' = ?",
|
|
50
|
-
* ['value'],
|
|
51
|
-
* );
|
|
52
|
-
* ```
|
|
53
|
-
*
|
|
54
|
-
* @example
|
|
55
|
-
* Load entities with tuple matching
|
|
56
|
-
* ```typescript
|
|
57
|
-
* const entities = await ExampleEntity.loader(vc)
|
|
58
|
-
* .loadManyByRawWhereClauseAsync(
|
|
59
|
-
* '(column_1, column_2) IN ((?, ?), (?, ?))',
|
|
60
|
-
* [value1, value2, value3, value4],
|
|
61
|
-
* );
|
|
62
|
-
* ```
|
|
63
|
-
* @param rawWhereClause - SQL WHERE clause. Interpolated values should be specified as ?-placeholders or :key_name
|
|
64
|
-
* @param bindings - values to bind to the placeholders in the WHERE clause
|
|
65
|
-
* @param querySelectionModifiers - limit, offset, and orderBy for the query.
|
|
66
|
-
* @returns entities matching the WHERE clause
|
|
67
|
-
* @throws EntityNotAuthorizedError when viewer is not authorized to view one or more of the returned entities
|
|
68
|
-
* @throws Error when rawWhereClause or bindings are invalid
|
|
69
|
-
*
|
|
70
|
-
* @deprecated Use loadManyBySQL instead for safer value bindings and more flexible query building.
|
|
71
|
-
*/
|
|
72
|
-
loadManyByRawWhereClauseAsync(rawWhereClause: string, bindings: any[] | object, querySelectionModifiers?: EntityLoaderQuerySelectionModifiers<TFields, TSelectedFields>): Promise<readonly TEntity[]>;
|
|
73
41
|
/**
|
|
74
42
|
* Load entities using a SQL query builder. When executed, all queries will enforce authorization and throw if not authorized.
|
|
75
43
|
*
|
|
@@ -45,41 +45,6 @@ export class EnforcingKnexEntityLoader {
|
|
|
45
45
|
const entityResults = await this.knexEntityLoader.loadManyByFieldEqualityConjunctionAsync(fieldEqualityOperands, querySelectionModifiers);
|
|
46
46
|
return entityResults.map((result) => result.enforceValue());
|
|
47
47
|
}
|
|
48
|
-
/**
|
|
49
|
-
* Load entities with a raw SQL WHERE clause.
|
|
50
|
-
*
|
|
51
|
-
* @example
|
|
52
|
-
* Load entities with SQL function
|
|
53
|
-
* ```typescript
|
|
54
|
-
* const entitiesWithJsonKey = await ExampleEntity.loader(vc)
|
|
55
|
-
* .loadManyByRawWhereClauseAsync(
|
|
56
|
-
* "json_column->>'key_name' = ?",
|
|
57
|
-
* ['value'],
|
|
58
|
-
* );
|
|
59
|
-
* ```
|
|
60
|
-
*
|
|
61
|
-
* @example
|
|
62
|
-
* Load entities with tuple matching
|
|
63
|
-
* ```typescript
|
|
64
|
-
* const entities = await ExampleEntity.loader(vc)
|
|
65
|
-
* .loadManyByRawWhereClauseAsync(
|
|
66
|
-
* '(column_1, column_2) IN ((?, ?), (?, ?))',
|
|
67
|
-
* [value1, value2, value3, value4],
|
|
68
|
-
* );
|
|
69
|
-
* ```
|
|
70
|
-
* @param rawWhereClause - SQL WHERE clause. Interpolated values should be specified as ?-placeholders or :key_name
|
|
71
|
-
* @param bindings - values to bind to the placeholders in the WHERE clause
|
|
72
|
-
* @param querySelectionModifiers - limit, offset, and orderBy for the query.
|
|
73
|
-
* @returns entities matching the WHERE clause
|
|
74
|
-
* @throws EntityNotAuthorizedError when viewer is not authorized to view one or more of the returned entities
|
|
75
|
-
* @throws Error when rawWhereClause or bindings are invalid
|
|
76
|
-
*
|
|
77
|
-
* @deprecated Use loadManyBySQL instead for safer value bindings and more flexible query building.
|
|
78
|
-
*/
|
|
79
|
-
async loadManyByRawWhereClauseAsync(rawWhereClause, bindings, querySelectionModifiers = {}) {
|
|
80
|
-
const entityResults = await this.knexEntityLoader.loadManyByRawWhereClauseAsync(rawWhereClause, bindings, querySelectionModifiers);
|
|
81
|
-
return entityResults.map((result) => result.enforceValue());
|
|
82
|
-
}
|
|
83
48
|
/**
|
|
84
49
|
* Load entities using a SQL query builder. When executed, all queries will enforce authorization and throw if not authorized.
|
|
85
50
|
*
|
|
@@ -13,9 +13,10 @@ export declare class PostgresEntityDatabaseAdapter<TFields extends Record<string
|
|
|
13
13
|
protected fetchOneWhereInternalAsync(queryInterface: Knex, tableName: string, tableColumns: readonly string[], tableTuple: readonly any[]): Promise<object | null>;
|
|
14
14
|
private applyQueryModifiersToQuery;
|
|
15
15
|
protected fetchManyByFieldEqualityConjunctionInternalAsync(queryInterface: Knex, tableName: string, tableFieldSingleValueEqualityOperands: TableFieldSingleValueEqualityCondition[], tableFieldMultiValueEqualityOperands: TableFieldMultiValueEqualityCondition[], querySelectionModifiers: TableQuerySelectionModifiers<TFields>): Promise<object[]>;
|
|
16
|
-
protected fetchManyByRawWhereClauseInternalAsync(queryInterface: Knex, tableName: string, rawWhereClause: string, bindings: object | any[], querySelectionModifiers: TableQuerySelectionModifiers<TFields>): Promise<object[]>;
|
|
17
16
|
protected fetchManyBySQLFragmentInternalAsync(queryInterface: Knex, tableName: string, sqlFragment: SQLFragment<TFields>, querySelectionModifiers: TableQuerySelectionModifiers<TFields>): Promise<object[]>;
|
|
18
17
|
protected insertInternalAsync(queryInterface: Knex, tableName: string, object: object): Promise<object[]>;
|
|
19
|
-
protected updateInternalAsync(queryInterface: Knex, tableName: string, tableIdField: string, id: any, object: object): Promise<
|
|
18
|
+
protected updateInternalAsync(queryInterface: Knex, tableName: string, tableIdField: string, id: any, object: object): Promise<{
|
|
19
|
+
updatedRowCount: number;
|
|
20
|
+
}>;
|
|
20
21
|
protected deleteInternalAsync(queryInterface: Knex, tableName: string, tableIdField: string, id: any): Promise<number>;
|
|
21
22
|
}
|
|
@@ -133,11 +133,6 @@ export class PostgresEntityDatabaseAdapter extends BasePostgresEntityDatabaseAda
|
|
|
133
133
|
query = this.applyQueryModifiersToQuery(query, querySelectionModifiers);
|
|
134
134
|
return await wrapNativePostgresCallAsync(() => query);
|
|
135
135
|
}
|
|
136
|
-
async fetchManyByRawWhereClauseInternalAsync(queryInterface, tableName, rawWhereClause, bindings, querySelectionModifiers) {
|
|
137
|
-
let query = queryInterface.select().from(tableName).whereRaw(rawWhereClause, bindings);
|
|
138
|
-
query = this.applyQueryModifiersToQuery(query, querySelectionModifiers);
|
|
139
|
-
return await wrapNativePostgresCallAsync(() => query);
|
|
140
|
-
}
|
|
141
136
|
async fetchManyBySQLFragmentInternalAsync(queryInterface, tableName, sqlFragment, querySelectionModifiers) {
|
|
142
137
|
let query = queryInterface
|
|
143
138
|
.select()
|
|
@@ -150,7 +145,8 @@ export class PostgresEntityDatabaseAdapter extends BasePostgresEntityDatabaseAda
|
|
|
150
145
|
return await wrapNativePostgresCallAsync(() => queryInterface.insert(object).into(tableName).returning('*'));
|
|
151
146
|
}
|
|
152
147
|
async updateInternalAsync(queryInterface, tableName, tableIdField, id, object) {
|
|
153
|
-
|
|
148
|
+
const updatedRowCount = await wrapNativePostgresCallAsync(() => queryInterface.update(object).into(tableName).where(tableIdField, id));
|
|
149
|
+
return { updatedRowCount };
|
|
154
150
|
}
|
|
155
151
|
async deleteInternalAsync(queryInterface, tableName, tableIdField, id) {
|
|
156
152
|
return await wrapNativePostgresCallAsync(() => queryInterface.into(tableName).where(tableIdField, id).del());
|
|
@@ -88,16 +88,6 @@ export declare class EntityKnexDataManager<TFields extends Record<string, any>,
|
|
|
88
88
|
* @returns array of objects matching the query
|
|
89
89
|
*/
|
|
90
90
|
loadManyByFieldEqualityConjunctionAsync<N extends keyof TFields>(queryContext: EntityQueryContext, fieldEqualityOperands: readonly FieldEqualityCondition<TFields, N>[], querySelectionModifiers: PostgresQuerySelectionModifiers<TFields>): Promise<readonly Readonly<TFields>[]>;
|
|
91
|
-
/**
|
|
92
|
-
* Loads many objects matching the raw WHERE clause.
|
|
93
|
-
*
|
|
94
|
-
* @param queryContext - query context in which to perform the load
|
|
95
|
-
* @param rawWhereClause - parameterized SQL WHERE clause with positional binding placeholders or named binding placeholders
|
|
96
|
-
* @param bindings - array of positional bindings or object of named bindings
|
|
97
|
-
* @param querySelectionModifiers - limit, offset, orderBy, and orderByRaw for the query
|
|
98
|
-
* @returns array of objects matching the query
|
|
99
|
-
*/
|
|
100
|
-
loadManyByRawWhereClauseAsync(queryContext: EntityQueryContext, rawWhereClause: string, bindings: readonly any[] | object, querySelectionModifiers: PostgresQuerySelectionModifiers<TFields>): Promise<readonly Readonly<TFields>[]>;
|
|
101
91
|
loadManyBySQLFragmentAsync(queryContext: EntityQueryContext, sqlFragment: SQLFragment<TFields>, querySelectionModifiers: PostgresQuerySelectionModifiers<TFields>): Promise<readonly Readonly<TFields>[]>;
|
|
102
92
|
/**
|
|
103
93
|
* Load a page of objects using cursor-based pagination with unified pagination specification.
|
|
@@ -42,19 +42,6 @@ export class EntityKnexDataManager {
|
|
|
42
42
|
EntityKnexDataManager.validateOrderByClauses(querySelectionModifiers.orderBy);
|
|
43
43
|
return await timeAndLogLoadEventAsync(this.metricsAdapter, EntityMetricsLoadType.LOAD_MANY_EQUALITY_CONJUNCTION, this.entityClassName, queryContext)(this.databaseAdapter.fetchManyByFieldEqualityConjunctionAsync(queryContext, fieldEqualityOperands, querySelectionModifiers));
|
|
44
44
|
}
|
|
45
|
-
/**
|
|
46
|
-
* Loads many objects matching the raw WHERE clause.
|
|
47
|
-
*
|
|
48
|
-
* @param queryContext - query context in which to perform the load
|
|
49
|
-
* @param rawWhereClause - parameterized SQL WHERE clause with positional binding placeholders or named binding placeholders
|
|
50
|
-
* @param bindings - array of positional bindings or object of named bindings
|
|
51
|
-
* @param querySelectionModifiers - limit, offset, orderBy, and orderByRaw for the query
|
|
52
|
-
* @returns array of objects matching the query
|
|
53
|
-
*/
|
|
54
|
-
async loadManyByRawWhereClauseAsync(queryContext, rawWhereClause, bindings, querySelectionModifiers) {
|
|
55
|
-
EntityKnexDataManager.validateOrderByClauses(querySelectionModifiers.orderBy);
|
|
56
|
-
return await timeAndLogLoadEventAsync(this.metricsAdapter, EntityMetricsLoadType.LOAD_MANY_RAW, this.entityClassName, queryContext)(this.databaseAdapter.fetchManyByRawWhereClauseAsync(queryContext, rawWhereClause, bindings, querySelectionModifiers));
|
|
57
|
-
}
|
|
58
45
|
async loadManyBySQLFragmentAsync(queryContext, sqlFragment, querySelectionModifiers) {
|
|
59
46
|
EntityKnexDataManager.validateOrderByClauses(querySelectionModifiers.orderBy);
|
|
60
47
|
return await timeAndLogLoadEventAsync(this.metricsAdapter, EntityMetricsLoadType.LOAD_MANY_SQL, this.entityClassName, queryContext)(this.databaseAdapter.fetchManyBySQLFragmentAsync(queryContext, sqlFragment, querySelectionModifiers));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@expo/entity-database-adapter-knex",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.63.0",
|
|
4
4
|
"description": "Knex database adapter for @expo/entity",
|
|
5
5
|
"files": [
|
|
6
6
|
"build",
|
|
@@ -29,15 +29,15 @@
|
|
|
29
29
|
"license": "MIT",
|
|
30
30
|
"type": "module",
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@expo/entity": "^0.
|
|
32
|
+
"@expo/entity": "^0.63.0",
|
|
33
33
|
"knex": "^3.1.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@expo/entity-testing-utils": "^0.
|
|
36
|
+
"@expo/entity-testing-utils": "^0.63.0",
|
|
37
37
|
"@jest/globals": "30.3.0",
|
|
38
38
|
"pg": "8.20.0",
|
|
39
39
|
"ts-mockito": "2.6.1",
|
|
40
40
|
"typescript": "5.9.3"
|
|
41
41
|
},
|
|
42
|
-
"gitHead": "
|
|
42
|
+
"gitHead": "dbd1cc847952754acc0eb407165cbb7b8350d2df"
|
|
43
43
|
}
|
|
@@ -400,27 +400,6 @@ export class AuthorizationResultBasedKnexEntityLoader<
|
|
|
400
400
|
return await this.constructionUtils.constructAndAuthorizeEntitiesArrayAsync(fieldObjects);
|
|
401
401
|
}
|
|
402
402
|
|
|
403
|
-
/**
|
|
404
|
-
* Authorization-result-based version of the EnforcingKnexEntityLoader method by the same name.
|
|
405
|
-
* @returns array of entity results that match the query, where result error can be UnauthorizedError
|
|
406
|
-
* @throws Error when rawWhereClause or bindings are invalid
|
|
407
|
-
*
|
|
408
|
-
* @deprecated Use loadManyBySQL instead for safer value bindings and more flexible query building.
|
|
409
|
-
*/
|
|
410
|
-
async loadManyByRawWhereClauseAsync(
|
|
411
|
-
rawWhereClause: string,
|
|
412
|
-
bindings: any[] | object,
|
|
413
|
-
querySelectionModifiers: EntityLoaderQuerySelectionModifiers<TFields, TSelectedFields> = {},
|
|
414
|
-
): Promise<readonly Result<TEntity>[]> {
|
|
415
|
-
const fieldObjects = await this.knexDataManager.loadManyByRawWhereClauseAsync(
|
|
416
|
-
this.queryContext,
|
|
417
|
-
rawWhereClause,
|
|
418
|
-
bindings,
|
|
419
|
-
querySelectionModifiers,
|
|
420
|
-
);
|
|
421
|
-
return await this.constructionUtils.constructAndAuthorizeEntitiesArrayAsync(fieldObjects);
|
|
422
|
-
}
|
|
423
|
-
|
|
424
403
|
/**
|
|
425
404
|
* Authorization-result-based version of the EnforcingKnexEntityLoader method by the same name.
|
|
426
405
|
* @returns SQL query builder for building and executing SQL queries that when executed returns entity results where result error can be UnauthorizedError.
|
|
@@ -216,42 +216,6 @@ export abstract class BasePostgresEntityDatabaseAdapter<
|
|
|
216
216
|
querySelectionModifiers: TableQuerySelectionModifiers<TFields>,
|
|
217
217
|
): Promise<object[]>;
|
|
218
218
|
|
|
219
|
-
/**
|
|
220
|
-
* Fetch many objects matching the raw WHERE clause.
|
|
221
|
-
*
|
|
222
|
-
* @param queryContext - query context with which to perform the fetch
|
|
223
|
-
* @param rawWhereClause - parameterized SQL WHERE clause with positional binding placeholders or named binding placeholders
|
|
224
|
-
* @param bindings - array of positional bindings or object of named bindings
|
|
225
|
-
* @param querySelectionModifiers - limit, offset, and orderBy for the query
|
|
226
|
-
* @returns array of objects matching the query
|
|
227
|
-
*/
|
|
228
|
-
async fetchManyByRawWhereClauseAsync(
|
|
229
|
-
queryContext: EntityQueryContext,
|
|
230
|
-
rawWhereClause: string,
|
|
231
|
-
bindings: any[] | object,
|
|
232
|
-
querySelectionModifiers: PostgresQuerySelectionModifiers<TFields>,
|
|
233
|
-
): Promise<readonly Readonly<TFields>[]> {
|
|
234
|
-
const results = await this.fetchManyByRawWhereClauseInternalAsync(
|
|
235
|
-
queryContext.getQueryInterface(),
|
|
236
|
-
this.entityConfiguration.tableName,
|
|
237
|
-
rawWhereClause,
|
|
238
|
-
bindings,
|
|
239
|
-
this.convertToTableQueryModifiers(querySelectionModifiers),
|
|
240
|
-
);
|
|
241
|
-
|
|
242
|
-
return results.map((result) =>
|
|
243
|
-
transformDatabaseObjectToFields(this.entityConfiguration, this.fieldTransformerMap, result),
|
|
244
|
-
);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
protected abstract fetchManyByRawWhereClauseInternalAsync(
|
|
248
|
-
queryInterface: Knex,
|
|
249
|
-
tableName: string,
|
|
250
|
-
rawWhereClause: string,
|
|
251
|
-
bindings: object | any[],
|
|
252
|
-
querySelectionModifiers: TableQuerySelectionModifiers<TFields>,
|
|
253
|
-
): Promise<object[]>;
|
|
254
|
-
|
|
255
219
|
/**
|
|
256
220
|
* Fetch many objects matching the SQL fragment.
|
|
257
221
|
*
|
|
@@ -104,50 +104,6 @@ export class EnforcingKnexEntityLoader<
|
|
|
104
104
|
return entityResults.map((result) => result.enforceValue());
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
/**
|
|
108
|
-
* Load entities with a raw SQL WHERE clause.
|
|
109
|
-
*
|
|
110
|
-
* @example
|
|
111
|
-
* Load entities with SQL function
|
|
112
|
-
* ```typescript
|
|
113
|
-
* const entitiesWithJsonKey = await ExampleEntity.loader(vc)
|
|
114
|
-
* .loadManyByRawWhereClauseAsync(
|
|
115
|
-
* "json_column->>'key_name' = ?",
|
|
116
|
-
* ['value'],
|
|
117
|
-
* );
|
|
118
|
-
* ```
|
|
119
|
-
*
|
|
120
|
-
* @example
|
|
121
|
-
* Load entities with tuple matching
|
|
122
|
-
* ```typescript
|
|
123
|
-
* const entities = await ExampleEntity.loader(vc)
|
|
124
|
-
* .loadManyByRawWhereClauseAsync(
|
|
125
|
-
* '(column_1, column_2) IN ((?, ?), (?, ?))',
|
|
126
|
-
* [value1, value2, value3, value4],
|
|
127
|
-
* );
|
|
128
|
-
* ```
|
|
129
|
-
* @param rawWhereClause - SQL WHERE clause. Interpolated values should be specified as ?-placeholders or :key_name
|
|
130
|
-
* @param bindings - values to bind to the placeholders in the WHERE clause
|
|
131
|
-
* @param querySelectionModifiers - limit, offset, and orderBy for the query.
|
|
132
|
-
* @returns entities matching the WHERE clause
|
|
133
|
-
* @throws EntityNotAuthorizedError when viewer is not authorized to view one or more of the returned entities
|
|
134
|
-
* @throws Error when rawWhereClause or bindings are invalid
|
|
135
|
-
*
|
|
136
|
-
* @deprecated Use loadManyBySQL instead for safer value bindings and more flexible query building.
|
|
137
|
-
*/
|
|
138
|
-
async loadManyByRawWhereClauseAsync(
|
|
139
|
-
rawWhereClause: string,
|
|
140
|
-
bindings: any[] | object,
|
|
141
|
-
querySelectionModifiers: EntityLoaderQuerySelectionModifiers<TFields, TSelectedFields> = {},
|
|
142
|
-
): Promise<readonly TEntity[]> {
|
|
143
|
-
const entityResults = await this.knexEntityLoader.loadManyByRawWhereClauseAsync(
|
|
144
|
-
rawWhereClause,
|
|
145
|
-
bindings,
|
|
146
|
-
querySelectionModifiers,
|
|
147
|
-
);
|
|
148
|
-
return entityResults.map((result) => result.enforceValue());
|
|
149
|
-
}
|
|
150
|
-
|
|
151
107
|
/**
|
|
152
108
|
* Load entities using a SQL query builder. When executed, all queries will enforce authorization and throw if not authorized.
|
|
153
109
|
*
|
|
@@ -210,18 +210,6 @@ export class PostgresEntityDatabaseAdapter<
|
|
|
210
210
|
return await wrapNativePostgresCallAsync(() => query);
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
-
protected async fetchManyByRawWhereClauseInternalAsync(
|
|
214
|
-
queryInterface: Knex,
|
|
215
|
-
tableName: string,
|
|
216
|
-
rawWhereClause: string,
|
|
217
|
-
bindings: object | any[],
|
|
218
|
-
querySelectionModifiers: TableQuerySelectionModifiers<TFields>,
|
|
219
|
-
): Promise<object[]> {
|
|
220
|
-
let query = queryInterface.select().from(tableName).whereRaw(rawWhereClause, bindings);
|
|
221
|
-
query = this.applyQueryModifiersToQuery(query, querySelectionModifiers);
|
|
222
|
-
return await wrapNativePostgresCallAsync(() => query);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
213
|
protected async fetchManyBySQLFragmentInternalAsync(
|
|
226
214
|
queryInterface: Knex,
|
|
227
215
|
tableName: string,
|
|
@@ -257,10 +245,11 @@ export class PostgresEntityDatabaseAdapter<
|
|
|
257
245
|
tableIdField: string,
|
|
258
246
|
id: any,
|
|
259
247
|
object: object,
|
|
260
|
-
): Promise<
|
|
261
|
-
|
|
262
|
-
queryInterface.update(object).into(tableName).where(tableIdField, id)
|
|
248
|
+
): Promise<{ updatedRowCount: number }> {
|
|
249
|
+
const updatedRowCount = await wrapNativePostgresCallAsync(() =>
|
|
250
|
+
queryInterface.update(object).into(tableName).where(tableIdField, id),
|
|
263
251
|
);
|
|
252
|
+
return { updatedRowCount };
|
|
264
253
|
}
|
|
265
254
|
|
|
266
255
|
protected async deleteInternalAsync(
|
|
@@ -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 () => {
|
|
@@ -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>,
|
|
@@ -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
|
});
|