@travetto/model-query 8.0.3 → 8.0.5

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/README.md CHANGED
@@ -35,7 +35,13 @@ export interface ModelQuerySupport {
35
35
  * @param query The query to search for
36
36
  * @param failOnMany Should the query fail on more than one result found, defaults to true
37
37
  */
38
- queryOne<T extends ModelType>(cls: Class<T>, query: ModelQuery<T>, failOnMany?: boolean): Promise<T>;
38
+ getByQuery<T extends ModelType>(cls: Class<T>, query: ModelQuery<T>, failOnMany?: boolean): Promise<T>;
39
+ /**
40
+ * Find the count of matching documents by query.
41
+ * @param cls The model class
42
+ * @param query The query to count for
43
+ */
44
+ countByQuery<T extends ModelType>(cls: Class<T>, query: ModelQuery<T>): Promise<number>;
39
45
  }
40
46
  ```
41
47
 
@@ -122,35 +128,24 @@ export interface ModelQuerySuggestSupport extends ModelQuerySupport {
122
128
  ```
123
129
 
124
130
  ### Aggregate
125
- This contract provides the ability to run strongly-typed field-level aggregations (such as sum, avg, min, and max) on models with optional query filtering.
131
+ This contract provides the ability to run strongly-typed field-level statistics (such as min, max, count, avg, and sum) on models with optional query filtering.
126
132
 
127
133
  **Code: Query Aggregate**
128
134
  ```typescript
129
135
  export interface ModelQueryAggregateSupport extends ModelQuerySupport {
130
136
  /**
131
- * Run an aggregation on a field
137
+ * Run an aggregation on a comparable field.
138
+ * For numeric fields (number/bigint), returns count, min, max, avg, and sum.
139
+ * For date fields, returns count, min, and max.
132
140
  * @param modelClass The model class to aggregate
133
- * @param operation The operation to perform ('sum', 'avg', 'min', 'max')
134
141
  * @param field The field to aggregate on
135
142
  * @param query Additional query filtering
136
143
  */
137
- aggregateFieldByQuery<
138
- T extends ModelType,
139
- Op extends AggregateOperation,
140
- F extends (Op extends AggregateNumericOperation ? ValidNumericFields<T> : ValidComparableFields<T>)
141
- >(
144
+ aggregateFieldByQuery<T extends ModelType, const F extends ValidComparableFields<T>>(
142
145
  modelClass: Class<T>,
143
- operation: Op,
144
146
  field: F,
145
147
  query?: ModelQuery<T>
146
- ): Promise<AggregateResultType<T, F>>;
147
-
148
- /**
149
- * Find the count of matching documents by query.
150
- * @param cls The model class
151
- * @param query The query to count for
152
- */
153
- countByQuery<T extends ModelType>(cls: Class<T>, query: ModelQuery<T>): Promise<number>;
148
+ ): Promise<FieldAggregateResult<T, F>>;
154
149
  }
155
150
  ```
156
151
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/model-query",
3
- "version": "8.0.3",
3
+ "version": "8.0.5",
4
4
  "description": "Datastore abstraction for advanced query support.",
5
5
  "keywords": [
6
6
  "datastore",
@@ -2,13 +2,9 @@ import type { ModelType } from '@travetto/model';
2
2
  import type { Class } from '@travetto/runtime';
3
3
 
4
4
  import type { ModelQuery } from '../model/query.ts';
5
- import type { ValidComparableFields, ValidNumericFields } from '../model/where-clause.ts';
5
+ import type { ValidComparableFields } from '../model/where-clause.ts';
6
6
  import type { ModelQuerySupport } from './query.ts';
7
7
 
8
- export type AggregateNumericOperation = 'sum' | 'avg';
9
- export type AggregateComparableOperation = 'min' | 'max';
10
- export type AggregateOperation = AggregateNumericOperation | AggregateComparableOperation;
11
-
12
8
  export type PathType<T, Path extends string> = Path extends `${infer Head}.${infer Tail}`
13
9
  ? Head extends keyof T
14
10
  ? PathType<NonNullable<T[Head]> extends (infer Element)[] ? Element : NonNullable<T[Head]>, Tail>
@@ -20,36 +16,55 @@ export type PathType<T, Path extends string> = Path extends `${infer Head}.${inf
20
16
  : never;
21
17
 
22
18
  export type AggregateResultType<T, F extends string> = [PathType<T, F>] extends [never]
23
- ? number | Date | bigint | undefined
19
+ ? number | bigint | undefined
24
20
  : PathType<T, F> | undefined;
25
21
 
22
+ export type DateFieldAggregateResult = {
23
+ count: number;
24
+ min?: Date;
25
+ max?: Date;
26
+ };
27
+
28
+ export type NumberFieldAggregateResult = {
29
+ count: number;
30
+ min?: number;
31
+ max?: number;
32
+ avg?: number;
33
+ sum?: number;
34
+ };
35
+
36
+ export type BigIntFieldAggregateResult = {
37
+ count: number;
38
+ min?: bigint;
39
+ max?: bigint;
40
+ avg?: bigint;
41
+ sum?: bigint;
42
+ };
43
+
44
+ export type FieldAggregateResult<T, F extends string> = F extends any
45
+ ? NonNullable<PathType<T, F>> extends Date
46
+ ? DateFieldAggregateResult
47
+ : NonNullable<PathType<T, F>> extends bigint
48
+ ? BigIntFieldAggregateResult
49
+ : NumberFieldAggregateResult
50
+ : never;
51
+
26
52
  /**
27
53
  * The contract for a model service with aggregate support
28
54
  * @concrete
29
55
  */
30
56
  export interface ModelQueryAggregateSupport extends ModelQuerySupport {
31
57
  /**
32
- * Run an aggregation on a field
58
+ * Run an aggregation on a comparable field.
59
+ * For numeric fields (number/bigint), returns count, min, max, avg, and sum.
60
+ * For date fields, returns count, min, and max.
33
61
  * @param modelClass The model class to aggregate
34
- * @param operation The operation to perform ('sum', 'avg', 'min', 'max')
35
62
  * @param field The field to aggregate on
36
63
  * @param query Additional query filtering
37
64
  */
38
- aggregateFieldByQuery<
39
- T extends ModelType,
40
- Op extends AggregateOperation,
41
- F extends (Op extends AggregateNumericOperation ? ValidNumericFields<T> : ValidComparableFields<T>)
42
- >(
65
+ aggregateFieldByQuery<T extends ModelType, const F extends ValidComparableFields<T>>(
43
66
  modelClass: Class<T>,
44
- operation: Op,
45
67
  field: F,
46
68
  query?: ModelQuery<T>
47
- ): Promise<AggregateResultType<T, F>>;
48
-
49
- /**
50
- * Find the count of matching documents by query.
51
- * @param cls The model class
52
- * @param query The query to count for
53
- */
54
- countByQuery<T extends ModelType>(cls: Class<T>, query: ModelQuery<T>): Promise<number>;
69
+ ): Promise<FieldAggregateResult<T, F>>;
55
70
  }
@@ -20,5 +20,11 @@ export interface ModelQuerySupport {
20
20
  * @param query The query to search for
21
21
  * @param failOnMany Should the query fail on more than one result found, defaults to true
22
22
  */
23
- queryOne<T extends ModelType>(cls: Class<T>, query: ModelQuery<T>, failOnMany?: boolean): Promise<T>;
23
+ getByQuery<T extends ModelType>(cls: Class<T>, query: ModelQuery<T>, failOnMany?: boolean): Promise<T>;
24
+ /**
25
+ * Find the count of matching documents by query.
26
+ * @param cls The model class
27
+ * @param query The query to count for
28
+ */
29
+ countByQuery<T extends ModelType>(cls: Class<T>, query: ModelQuery<T>): Promise<number>;
24
30
  }
@@ -2,7 +2,8 @@ import type { ModelType } from '@travetto/model';
2
2
  import { castTo, type Class, hasFunction } from '@travetto/runtime';
3
3
  import { DataUtil, SchemaRegistryIndex } from '@travetto/schema';
4
4
 
5
- import type { AggregateOperation, AggregateResultType, ModelQueryAggregateSupport } from '../types/aggregate.ts';
5
+ import type { ValidComparableFields } from '../model/where-clause.ts';
6
+ import type { FieldAggregateResult, ModelQueryAggregateSupport, NumberFieldAggregateResult } from '../types/aggregate.ts';
6
7
 
7
8
  export class ModelQueryAggregateUtil {
8
9
  /**
@@ -11,19 +12,36 @@ export class ModelQueryAggregateUtil {
11
12
  static isSupported = hasFunction<ModelQueryAggregateSupport>('aggregateFieldByQuery');
12
13
 
13
14
  /**
14
- * Resolve and coerce the aggregate query result using DataUtil.coerceType
15
+ * Resolve and coerce aggregate query results
15
16
  * @param modelClass The model class being queried
16
- * @param operation The aggregate operation
17
17
  * @param field The field being aggregated
18
- * @param rawValue The raw result value from the datastore
18
+ * @param rawValues The raw result values from the datastore
19
19
  */
20
- static resolveResult<T extends ModelType, Op extends AggregateOperation, F extends string>(
20
+ static resolveAggregate<T extends ModelType, const F extends ValidComparableFields<T>>(
21
21
  modelClass: Class<T>,
22
- operation: Op,
23
22
  field: F,
24
- rawValue: unknown
25
- ): AggregateResultType<T, F> {
23
+ rawValues: Partial<Record<keyof NumberFieldAggregateResult, unknown>>
24
+ ): FieldAggregateResult<T, F> {
25
+ const count = Number(rawValues.count ?? 0);
26
+ if (count === 0) {
27
+ return castTo({ count: 0 });
28
+ }
26
29
  const leafFieldType = SchemaRegistryIndex.getNestedFieldConfig(modelClass, field)!.type;
27
- return castTo(DataUtil.coerceType(rawValue, leafFieldType, false) ?? undefined);
30
+
31
+ if (leafFieldType === Date) {
32
+ return castTo({
33
+ count,
34
+ min: DataUtil.coerceType(rawValues.min, leafFieldType, true),
35
+ max: DataUtil.coerceType(rawValues.max, leafFieldType, true)
36
+ });
37
+ }
38
+
39
+ return castTo({
40
+ count,
41
+ min: DataUtil.coerceType(rawValues.min, leafFieldType, true),
42
+ max: DataUtil.coerceType(rawValues.max, leafFieldType, true),
43
+ avg: DataUtil.coerceType(rawValues.avg, leafFieldType, true),
44
+ sum: DataUtil.coerceType(rawValues.sum, leafFieldType, true)
45
+ });
28
46
  }
29
47
  }
@@ -1,17 +1,60 @@
1
1
  import assert from 'node:assert';
2
2
 
3
- import type { ModelCrudSupport } from '@travetto/model';
3
+ import type { ModelCrudSupport, ModelType } from '@travetto/model';
4
4
  import { Suite, Test } from '@travetto/test';
5
5
 
6
6
  import { BaseModelSuite } from '@travetto/model/support/test/base.ts';
7
7
 
8
- import type { ModelQueryAggregateSupport } from '../../src/types/aggregate.ts';
9
- import { Aged, BigIntModel, Person } from './model.ts';
8
+ import type { DateFieldAggregateResult, ModelQueryAggregateSupport, NumberFieldAggregateResult } from '../../src/types/aggregate.ts';
9
+ import { Aged, BigIntModel, MultiFieldModel, Person } from './model.ts';
10
10
 
11
11
  @Suite()
12
12
  export abstract class ModelQueryAggregateSuite extends BaseModelSuite<ModelQueryAggregateSupport & ModelCrudSupport> {
13
- @Test('verify basic aggregations')
14
- async testAggregate() {
13
+ @Test('verify date field aggregate')
14
+ async testDateFieldAggregate() {
15
+ const service = await this.service;
16
+
17
+ const firstDate = new Date(2020, 0, 1);
18
+ const secondDate = new Date(2021, 0, 1);
19
+ const thirdDate = new Date(2022, 0, 1);
20
+
21
+ await this.saveAll(Aged, [
22
+ Aged.from({ createdAt: firstDate }),
23
+ Aged.from({ createdAt: secondDate }),
24
+ Aged.from({ createdAt: thirdDate })
25
+ ]);
26
+
27
+ const aggregate = await service.aggregateFieldByQuery(Aged, 'createdAt');
28
+ assert(aggregate.count === 3);
29
+ assert(aggregate.min instanceof Date);
30
+ assert(aggregate.min.getTime() === firstDate.getTime());
31
+ assert(aggregate.max instanceof Date);
32
+ assert(aggregate.max.getTime() === thirdDate.getTime());
33
+ }
34
+
35
+ @Test('verify model with multiple field types aggregate')
36
+ async testMultiFieldModelAggregate() {
37
+ const service = await this.service;
38
+ const now = new Date();
39
+ await this.saveAll(MultiFieldModel, [
40
+ MultiFieldModel.from({ createdAt: now, score: 10 }),
41
+ MultiFieldModel.from({ createdAt: now, score: 20 })
42
+ ]);
43
+
44
+ const dateStats = await service.aggregateFieldByQuery(MultiFieldModel, 'createdAt');
45
+ const dateCheck: DateFieldAggregateResult = dateStats;
46
+ assert(dateCheck.count === 2);
47
+ assert(dateCheck.min instanceof Date);
48
+
49
+ const numberStats = await service.aggregateFieldByQuery(MultiFieldModel, 'score');
50
+ const numberCheck: NumberFieldAggregateResult = numberStats;
51
+ assert(numberCheck.count === 2);
52
+ assert(numberCheck.min === 10);
53
+ assert(numberCheck.avg === 15);
54
+ }
55
+
56
+ @Test('verify field aggregate')
57
+ async testFieldAggregate() {
15
58
  const people = [
16
59
  Person.from({ name: 'Bob', age: 20, gender: 'm', address: { street1: '1st St' } }),
17
60
  Person.from({ name: 'Alice', age: 30, gender: 'f', address: { street1: '2nd St' } }),
@@ -23,67 +66,38 @@ export abstract class ModelQueryAggregateSuite extends BaseModelSuite<ModelQuery
23
66
  const saved = await this.saveAll(Person, people);
24
67
  assert(saved === 4);
25
68
 
26
- const sumResult = await service.aggregateFieldByQuery(Person, 'sum', 'age');
27
- assert(sumResult === 140);
28
-
29
- const averageResult = await service.aggregateFieldByQuery(Person, 'avg', 'age');
30
- assert(averageResult === 35);
31
-
32
- const minimumResult = await service.aggregateFieldByQuery(Person, 'min', 'age');
33
- assert(minimumResult === 20);
34
-
35
- const maximumResult = await service.aggregateFieldByQuery(Person, 'max', 'age');
36
- assert(maximumResult === 50);
69
+ const aggregate = await service.aggregateFieldByQuery(Person, 'age');
70
+ assert(aggregate.count === 4);
71
+ assert(aggregate.min === 20);
72
+ assert(aggregate.max === 50);
73
+ assert(aggregate.avg === 35);
74
+ assert(aggregate.sum === 140);
37
75
 
38
- // Filtered aggregations
39
- const filteredSumResult = await service.aggregateFieldByQuery(Person, 'sum', 'age', {
76
+ const filteredAggregate = await service.aggregateFieldByQuery(Person, 'age', {
40
77
  where: {
41
78
  age: { $gte: 30 }
42
79
  }
43
80
  });
44
- assert(filteredSumResult === 120);
81
+ assert(filteredAggregate.count === 3);
82
+ assert(filteredAggregate.min === 30);
83
+ assert(filteredAggregate.max === 50);
84
+ assert(filteredAggregate.avg === 40);
85
+ assert(filteredAggregate.sum === 120);
45
86
 
46
- const filteredAverageResult = await service.aggregateFieldByQuery(Person, 'avg', 'age', {
47
- where: {
48
- gender: 'f'
49
- }
50
- });
51
- assert(filteredAverageResult === 40);
52
-
53
- // No matches
54
- const noMatchResult = await service.aggregateFieldByQuery(Person, 'sum', 'age', {
87
+ const emptyAggregate = await service.aggregateFieldByQuery(Person, 'age', {
55
88
  where: {
56
89
  age: { $gt: 1000 }
57
90
  }
58
91
  });
59
- assert(noMatchResult === undefined);
60
- }
61
-
62
- @Test('verify date aggregations')
63
- async testDateAggregate() {
64
- const service = await this.service;
65
-
66
- const firstDate = new Date(2020, 0, 1);
67
- const secondDate = new Date(2021, 0, 1);
68
- const thirdDate = new Date(2022, 0, 1);
69
-
70
- await this.saveAll(Aged, [
71
- Aged.from({ createdAt: firstDate }),
72
- Aged.from({ createdAt: secondDate }),
73
- Aged.from({ createdAt: thirdDate })
74
- ]);
75
-
76
- const minimumDateResult = await service.aggregateFieldByQuery(Aged, 'min', 'createdAt');
77
- assert(minimumDateResult instanceof Date);
78
- assert(minimumDateResult.getTime() === firstDate.getTime());
79
-
80
- const maximumDateResult = await service.aggregateFieldByQuery(Aged, 'max', 'createdAt');
81
- assert(maximumDateResult instanceof Date);
82
- assert(maximumDateResult.getTime() === thirdDate.getTime());
92
+ assert(emptyAggregate.count === 0);
93
+ assert(emptyAggregate.min === undefined);
94
+ assert(emptyAggregate.max === undefined);
95
+ assert(emptyAggregate.avg === undefined);
96
+ assert(emptyAggregate.sum === undefined);
83
97
  }
84
98
 
85
- @Test('verify bigint aggregations')
86
- async testBigIntAggregate() {
99
+ @Test('verify bigint field aggregate')
100
+ async testBigIntFieldAggregate() {
87
101
  const service = await this.service;
88
102
 
89
103
  await this.saveAll(BigIntModel, [
@@ -92,16 +106,11 @@ export abstract class ModelQueryAggregateSuite extends BaseModelSuite<ModelQuery
92
106
  BigIntModel.from({ largeNumber: 300n })
93
107
  ]);
94
108
 
95
- const sumResult = await service.aggregateFieldByQuery(BigIntModel, 'sum', 'largeNumber');
96
- assert(sumResult === 600n);
97
-
98
- const minimumResult = await service.aggregateFieldByQuery(BigIntModel, 'min', 'largeNumber');
99
- assert(minimumResult === 100n);
100
-
101
- const maximumResult = await service.aggregateFieldByQuery(BigIntModel, 'max', 'largeNumber');
102
- assert(maximumResult === 300n);
103
-
104
- const averageResult = await service.aggregateFieldByQuery(BigIntModel, 'avg', 'largeNumber');
105
- assert(averageResult === 200n);
109
+ const aggregate = await service.aggregateFieldByQuery(BigIntModel, 'largeNumber');
110
+ assert(aggregate.count === 3);
111
+ assert(aggregate.min === 100n);
112
+ assert(aggregate.max === 300n);
113
+ assert(aggregate.avg === 200n);
114
+ assert(aggregate.sum === 600n);
106
115
  }
107
116
  }
@@ -74,6 +74,13 @@ export class Aged {
74
74
  createdAt: Date;
75
75
  }
76
76
 
77
+ @Model()
78
+ export class MultiFieldModel {
79
+ id: string;
80
+ createdAt: Date;
81
+ score: number;
82
+ }
83
+
77
84
  @Model()
78
85
  export class WithNestedLists {
79
86
  id: string;
@@ -18,9 +18,7 @@ import { ModelQueryFacetUtil } from '../../src/util/facet.ts';
18
18
  import { ModelQuerySuggestUtil } from '../../src/util/suggest.ts';
19
19
 
20
20
  @Suite()
21
- export abstract class ModelQueryPolymorphismSuite extends BaseModelSuite<
22
- ModelQuerySupport & ModelQueryAggregateSupport & ModelCrudSupport
23
- > {
21
+ export abstract class ModelQueryPolymorphismSuite extends BaseModelSuite<ModelQuerySupport & ModelCrudSupport> {
24
22
  @Test()
25
23
  async testQuery() {
26
24
  const svc = await this.service;
@@ -42,13 +40,13 @@ export abstract class ModelQueryPolymorphismSuite extends BaseModelSuite<
42
40
  assert((await svc.countByQuery(Doctor, { where: { name: 'bob' } })) === 1);
43
41
  assert((await svc.countByQuery(Engineer, { where: { name: 'bob' } })) === 0);
44
42
 
45
- assert((await svc.queryOne(Worker, { where: { name: 'bob' } })) instanceof Doctor);
46
- await assert.rejects(() => svc.queryOne(Firefighter, { where: { name: 'bob' } }), NotFoundError);
43
+ assert((await svc.getByQuery(Worker, { where: { name: 'bob' } })) instanceof Doctor);
44
+ await assert.rejects(() => svc.getByQuery(Firefighter, { where: { name: 'bob' } }), NotFoundError);
47
45
  }
48
46
 
49
47
  @Test({ skip: ModelQueryPolymorphismSuite.ifNot(ModelQueryCrudUtil.isSupported) })
50
48
  async testCrudQuery() {
51
- const svc: ModelQueryCrudSupport & ModelQueryAggregateSupport & ModelQuerySupport = castTo(await this.service);
49
+ const svc: ModelQueryCrudSupport & ModelQuerySupport = castTo(await this.service);
52
50
  const [doc, doc2, fire, eng] = [
53
51
  Doctor.from({ name: 'bob', specialty: 'feet' }),
54
52
  Doctor.from({ name: 'nob', specialty: 'eyes' }),
@@ -127,10 +125,11 @@ export abstract class ModelQueryPolymorphismSuite extends BaseModelSuite<
127
125
  await this.saveAll(Worker, [doctorOne, doctorTwo, firefighterOne, firefighterTwo]);
128
126
  assert((await this.getSize(Worker)) === 4);
129
127
 
130
- const sumFirehouse = await service.aggregateFieldByQuery(Firefighter, 'sum', 'firehouse');
131
- assert(sumFirehouse === 50);
132
-
133
- const averageFirehouse = await service.aggregateFieldByQuery(Firefighter, 'avg', 'firehouse');
134
- assert(averageFirehouse === 25);
128
+ const aggregate = await service.aggregateFieldByQuery(Firefighter, 'firehouse');
129
+ assert(aggregate.count === 2);
130
+ assert(aggregate.min === 20);
131
+ assert(aggregate.max === 30);
132
+ assert(aggregate.avg === 25);
133
+ assert(aggregate.sum === 50);
135
134
  }
136
135
  }
@@ -6,12 +6,11 @@ import { Suite, Test } from '@travetto/test';
6
6
 
7
7
  import { BaseModelSuite } from '@travetto/model/support/test/base.ts';
8
8
 
9
- import type { ModelQueryAggregateSupport } from '../../__index__.ts';
10
9
  import type { ModelQuerySupport } from '../../src/types/query.ts';
11
10
  import { Aged, Location, Names, Note, Person, PersonFamily, Recipe, SimpleList, WithNestedLists, WithNestedNestedLists } from './model.ts';
12
11
 
13
12
  @Suite()
14
- export abstract class ModelQuerySuite extends BaseModelSuite<ModelQuerySupport & ModelQueryAggregateSupport & ModelCrudSupport> {
13
+ export abstract class ModelQuerySuite extends BaseModelSuite<ModelQuerySupport & ModelCrudSupport> {
15
14
  supportsGeo = true;
16
15
 
17
16
  @Test()
@@ -33,10 +32,10 @@ export abstract class ModelQuerySuite extends BaseModelSuite<ModelQuerySupport &
33
32
 
34
33
  await this.saveAll(Person, people);
35
34
 
36
- const one = await svc.queryOne(Person, { where: { id: people[0].id } });
35
+ const one = await svc.getByQuery(Person, { where: { id: people[0].id } });
37
36
  assert(one.id === people[0].id);
38
37
 
39
- const one2 = await svc.queryOne(Person, { where: { id: { $eq: people[0].id } } });
38
+ const one2 = await svc.getByQuery(Person, { where: { id: { $eq: people[0].id } } });
40
39
  assert(one2.id === people[0].id);
41
40
 
42
41
  const none = await svc.countByQuery(Person, { where: { id: { $ne: people[0].id } } });
@@ -92,11 +91,11 @@ export abstract class ModelQuerySuite extends BaseModelSuite<ModelQuerySupport &
92
91
  )
93
92
  );
94
93
 
95
- await assert.rejects(() => service.queryOne(Person, { where: { gender: 'm' } }), /Invalid number of results/);
96
- await assert.rejects(() => service.queryOne(Person, { where: { gender: 'z' } }), NotFoundError);
97
- await assert.rejects(() => service.queryOne(Person, { where: { gender: 'z' } }), /No results found for query/);
98
- await assert.rejects(() => service.queryOne(Person, { where: { id: 'orange' } }), NotFoundError);
99
- await assert.rejects(() => service.queryOne(Person, { where: { id: 'orange' } }), /orange/);
94
+ await assert.rejects(() => service.getByQuery(Person, { where: { gender: 'm' } }), /Invalid number of results/);
95
+ await assert.rejects(() => service.getByQuery(Person, { where: { gender: 'z' } }), NotFoundError);
96
+ await assert.rejects(() => service.getByQuery(Person, { where: { gender: 'z' } }), /No results found for query/);
97
+ await assert.rejects(() => service.getByQuery(Person, { where: { id: 'orange' } }), NotFoundError);
98
+ await assert.rejects(() => service.getByQuery(Person, { where: { id: 'orange' } }), /orange/);
100
99
  }
101
100
 
102
101
  @Test('Verify array $in queries work properly')