@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.
@@ -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<object[]>;
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
- return await wrapNativePostgresCallAsync(() => queryInterface.update(object).into(tableName).where(tableIdField, id).returning('*'));
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.62.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.62.0",
32
+ "@expo/entity": "^0.63.0",
33
33
  "knex": "^3.1.0"
34
34
  },
35
35
  "devDependencies": {
36
- "@expo/entity-testing-utils": "^0.62.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": "4965cc238882982e6315beca48a68679ed45456b"
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<object[]> {
261
- return await wrapNativePostgresCallAsync(() =>
262
- queryInterface.update(object).into(tableName).where(tableIdField, id).returning('*'),
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: object[];
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?: object[];
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<object[]> {
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<object[]> {
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 [objectCollection[objectIndex]];
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
  });