Skip to content

Commit 8bc9c11

Browse files
committed
fix: Use TSelectedFields for knex loader order by method
1 parent 273d1df commit 8bc9c11

5 files changed

Lines changed: 142 additions & 58 deletions

File tree

packages/entity-database-adapter-knex/src/AuthorizationResultBasedKnexEntityLoader.ts

Lines changed: 75 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,70 @@ import { Result } from '@expo/results';
1111
import {
1212
FieldEqualityCondition,
1313
isSingleValueFieldEqualityCondition,
14-
QuerySelectionModifiers,
15-
QuerySelectionModifiersWithOrderByFragment,
16-
QuerySelectionModifiersWithOrderByRaw,
14+
OrderByOrdering,
1715
} from './BasePostgresEntityDatabaseAdapter';
1816
import { BaseSQLQueryBuilder } from './BaseSQLQueryBuilder';
1917
import { SQLFragment } from './SQLOperator';
2018
import { EntityKnexDataManager } from './internal/EntityKnexDataManager';
2119

20+
export interface EntityLoaderOrderByClause<
21+
TFields extends Record<string, any>,
22+
TSelectedFields extends keyof TFields,
23+
> {
24+
/**
25+
* The field name to order by.
26+
*/
27+
fieldName: TSelectedFields;
28+
29+
/**
30+
* The OrderByOrdering to order by.
31+
*/
32+
order: OrderByOrdering;
33+
}
34+
35+
/**
36+
* SQL modifiers that only affect the selection but not the projection.
37+
*/
38+
export interface EntityLoaderQuerySelectionModifiers<
39+
TFields extends Record<string, any>,
40+
TSelectedFields extends keyof TFields,
41+
> {
42+
/**
43+
* Order the entities by specified columns and orders.
44+
*/
45+
orderBy?: readonly EntityLoaderOrderByClause<TFields, TSelectedFields>[];
46+
47+
/**
48+
* Skip the specified number of entities queried before returning.
49+
*/
50+
offset?: number;
51+
52+
/**
53+
* Limit the number of entities returned.
54+
*/
55+
limit?: number;
56+
}
57+
58+
export interface EntityLoaderQuerySelectionModifiersWithOrderByRaw<
59+
TFields extends Record<string, any>,
60+
TSelectedFields extends keyof TFields,
61+
> extends EntityLoaderQuerySelectionModifiers<TFields, TSelectedFields> {
62+
/**
63+
* Order the entities by a raw SQL `ORDER BY` clause.
64+
*/
65+
orderByRaw?: string;
66+
}
67+
68+
export interface EntityLoaderQuerySelectionModifiersWithOrderByFragment<
69+
TFields extends Record<string, any>,
70+
TSelectedFields extends keyof TFields,
71+
> extends EntityLoaderQuerySelectionModifiers<TFields, TSelectedFields> {
72+
/**
73+
* Order the entities by a SQL fragment `ORDER BY` clause.
74+
*/
75+
orderByFragment?: SQLFragment;
76+
}
77+
2278
/**
2379
* Authorization-result-based knex entity loader for non-data-loader-based load methods.
2480
* All loads through this loader are results (or null for some loader methods), where an
@@ -60,8 +116,11 @@ export class AuthorizationResultBasedKnexEntityLoader<
60116
*/
61117
async loadFirstByFieldEqualityConjunctionAsync<N extends keyof Pick<TFields, TSelectedFields>>(
62118
fieldEqualityOperands: FieldEqualityCondition<TFields, N>[],
63-
querySelectionModifiers: Omit<QuerySelectionModifiers<TFields>, 'limit'> &
64-
Required<Pick<QuerySelectionModifiers<TFields>, 'orderBy'>>,
119+
querySelectionModifiers: Omit<
120+
EntityLoaderQuerySelectionModifiers<TFields, TSelectedFields>,
121+
'limit'
122+
> &
123+
Required<Pick<EntityLoaderQuerySelectionModifiers<TFields, TSelectedFields>, 'orderBy'>>,
65124
): Promise<Result<TEntity> | null> {
66125
const results = await this.loadManyByFieldEqualityConjunctionAsync(fieldEqualityOperands, {
67126
...querySelectionModifiers,
@@ -76,7 +135,7 @@ export class AuthorizationResultBasedKnexEntityLoader<
76135
*/
77136
async loadManyByFieldEqualityConjunctionAsync<N extends keyof Pick<TFields, TSelectedFields>>(
78137
fieldEqualityOperands: FieldEqualityCondition<TFields, N>[],
79-
querySelectionModifiers: QuerySelectionModifiers<TFields> = {},
138+
querySelectionModifiers: EntityLoaderQuerySelectionModifiers<TFields, TSelectedFields> = {},
80139
): Promise<readonly Result<TEntity>[]> {
81140
for (const fieldEqualityOperand of fieldEqualityOperands) {
82141
const fieldValues = isSingleValueFieldEqualityCondition(fieldEqualityOperand)
@@ -101,7 +160,10 @@ export class AuthorizationResultBasedKnexEntityLoader<
101160
async loadManyByRawWhereClauseAsync(
102161
rawWhereClause: string,
103162
bindings: any[] | object,
104-
querySelectionModifiers: QuerySelectionModifiersWithOrderByRaw<TFields> = {},
163+
querySelectionModifiers: EntityLoaderQuerySelectionModifiersWithOrderByRaw<
164+
TFields,
165+
TSelectedFields
166+
> = {},
105167
): Promise<readonly Result<TEntity>[]> {
106168
const fieldObjects = await this.knexDataManager.loadManyByRawWhereClauseAsync(
107169
this.queryContext,
@@ -118,7 +180,10 @@ export class AuthorizationResultBasedKnexEntityLoader<
118180
*/
119181
loadManyBySQL(
120182
fragment: SQLFragment,
121-
modifiers: QuerySelectionModifiersWithOrderByFragment<TFields> = {},
183+
modifiers: EntityLoaderQuerySelectionModifiersWithOrderByFragment<
184+
TFields,
185+
TSelectedFields
186+
> = {},
122187
): AuthorizationResultBasedSQLQueryBuilder<
123188
TFields,
124189
TIDField,
@@ -153,7 +218,7 @@ export class AuthorizationResultBasedSQLQueryBuilder<
153218
TSelectedFields
154219
>,
155220
TSelectedFields extends keyof TFields,
156-
> extends BaseSQLQueryBuilder<TFields, Result<TEntity>> {
221+
> extends BaseSQLQueryBuilder<TFields, TSelectedFields, Result<TEntity>> {
157222
constructor(
158223
private readonly knexDataManager: EntityKnexDataManager<TFields, TIDField>,
159224
private readonly constructionUtils: EntityConstructionUtils<
@@ -166,7 +231,7 @@ export class AuthorizationResultBasedSQLQueryBuilder<
166231
>,
167232
private readonly queryContext: EntityQueryContext,
168233
sqlFragment: SQLFragment,
169-
modifiers: QuerySelectionModifiersWithOrderByFragment<TFields>,
234+
modifiers: EntityLoaderQuerySelectionModifiersWithOrderByFragment<TFields, TSelectedFields>,
170235
) {
171236
super(sqlFragment, modifiers);
172237
}

packages/entity-database-adapter-knex/src/BasePostgresEntityDatabaseAdapter.ts

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -75,24 +75,26 @@ export enum OrderByOrdering {
7575
DESCENDING = 'desc',
7676
}
7777

78+
export interface PostgresOrderByClause<TFields extends Record<string, any>> {
79+
/**
80+
* The field name to order by.
81+
*/
82+
fieldName: keyof TFields;
83+
84+
/**
85+
* The OrderByOrdering to order by.
86+
*/
87+
order: OrderByOrdering;
88+
}
89+
7890
/**
7991
* SQL modifiers that only affect the selection but not the projection.
8092
*/
81-
export interface QuerySelectionModifiers<TFields extends Record<string, any>> {
93+
export interface PostgresQuerySelectionModifiers<TFields extends Record<string, any>> {
8294
/**
8395
* Order the entities by specified columns and orders.
8496
*/
85-
orderBy?: {
86-
/**
87-
* The field name to order by.
88-
*/
89-
fieldName: keyof TFields;
90-
91-
/**
92-
* The OrderByOrdering to order by.
93-
*/
94-
order: OrderByOrdering;
95-
}[];
97+
orderBy?: readonly PostgresOrderByClause<TFields>[];
9698

9799
/**
98100
* Skip the specified number of entities queried before returning.
@@ -105,18 +107,18 @@ export interface QuerySelectionModifiers<TFields extends Record<string, any>> {
105107
limit?: number;
106108
}
107109

108-
export interface QuerySelectionModifiersWithOrderByRaw<
110+
export interface PostgresQuerySelectionModifiersWithOrderByRaw<
109111
TFields extends Record<string, any>,
110-
> extends QuerySelectionModifiers<TFields> {
112+
> extends PostgresQuerySelectionModifiers<TFields> {
111113
/**
112114
* Order the entities by a raw SQL `ORDER BY` clause.
113115
*/
114116
orderByRaw?: string;
115117
}
116118

117-
export interface QuerySelectionModifiersWithOrderByFragment<
119+
export interface PostgresQuerySelectionModifiersWithOrderByFragment<
118120
TFields extends Record<string, any>,
119-
> extends QuerySelectionModifiers<TFields> {
121+
> extends PostgresQuerySelectionModifiers<TFields> {
120122
/**
121123
* Order the entities by a SQL fragment `ORDER BY` clause.
122124
*/
@@ -159,7 +161,7 @@ export abstract class BasePostgresEntityDatabaseAdapter<
159161
async fetchManyByFieldEqualityConjunctionAsync<N extends keyof TFields>(
160162
queryContext: EntityQueryContext,
161163
fieldEqualityOperands: FieldEqualityCondition<TFields, N>[],
162-
querySelectionModifiers: QuerySelectionModifiers<TFields>,
164+
querySelectionModifiers: PostgresQuerySelectionModifiers<TFields>,
163165
): Promise<readonly Readonly<TFields>[]> {
164166
const tableFieldSingleValueOperands: TableFieldSingleValueEqualityCondition[] = [];
165167
const tableFieldMultipleValueOperands: TableFieldMultiValueEqualityCondition[] = [];
@@ -211,7 +213,7 @@ export abstract class BasePostgresEntityDatabaseAdapter<
211213
queryContext: EntityQueryContext,
212214
rawWhereClause: string,
213215
bindings: any[] | object,
214-
querySelectionModifiers: QuerySelectionModifiersWithOrderByRaw<TFields>,
216+
querySelectionModifiers: PostgresQuerySelectionModifiersWithOrderByRaw<TFields>,
215217
): Promise<readonly Readonly<TFields>[]> {
216218
const results = await this.fetchManyByRawWhereClauseInternalAsync(
217219
queryContext.getQueryInterface(),
@@ -245,7 +247,7 @@ export abstract class BasePostgresEntityDatabaseAdapter<
245247
async fetchManyBySQLFragmentAsync(
246248
queryContext: EntityQueryContext,
247249
sqlFragment: SQLFragment,
248-
querySelectionModifiers: QuerySelectionModifiersWithOrderByFragment<TFields>,
250+
querySelectionModifiers: PostgresQuerySelectionModifiersWithOrderByFragment<TFields>,
249251
): Promise<readonly Readonly<TFields>[]> {
250252
const results = await this.fetchManyBySQLFragmentInternalAsync(
251253
queryContext.getQueryInterface(),
@@ -267,7 +269,7 @@ export abstract class BasePostgresEntityDatabaseAdapter<
267269
): Promise<object[]>;
268270

269271
private convertToTableQueryModifiersWithOrderByRaw(
270-
querySelectionModifiers: QuerySelectionModifiersWithOrderByRaw<TFields>,
272+
querySelectionModifiers: PostgresQuerySelectionModifiersWithOrderByRaw<TFields>,
271273
): TableQuerySelectionModifiersWithOrderByRaw {
272274
return {
273275
...this.convertToTableQueryModifiers(querySelectionModifiers),
@@ -276,7 +278,7 @@ export abstract class BasePostgresEntityDatabaseAdapter<
276278
}
277279

278280
private convertToTableQueryModifiersWithOrderByFragment(
279-
querySelectionModifiers: QuerySelectionModifiersWithOrderByFragment<TFields>,
281+
querySelectionModifiers: PostgresQuerySelectionModifiersWithOrderByFragment<TFields>,
280282
): TableQuerySelectionModifiersWithOrderByFragment {
281283
return {
282284
...this.convertToTableQueryModifiers(querySelectionModifiers),
@@ -285,7 +287,7 @@ export abstract class BasePostgresEntityDatabaseAdapter<
285287
}
286288

287289
private convertToTableQueryModifiers(
288-
querySelectionModifiers: QuerySelectionModifiers<TFields>,
290+
querySelectionModifiers: PostgresQuerySelectionModifiers<TFields>,
289291
): TableQuerySelectionModifiers {
290292
const orderBy = querySelectionModifiers.orderBy;
291293
return {

packages/entity-database-adapter-knex/src/BaseSQLQueryBuilder.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,26 @@
11
import {
2-
OrderByOrdering,
3-
QuerySelectionModifiersWithOrderByFragment,
4-
} from './BasePostgresEntityDatabaseAdapter';
2+
EntityLoaderOrderByClause,
3+
EntityLoaderQuerySelectionModifiersWithOrderByFragment,
4+
} from './AuthorizationResultBasedKnexEntityLoader';
5+
import { OrderByOrdering } from './BasePostgresEntityDatabaseAdapter';
56
import { SQLFragment } from './SQLOperator';
67

78
/**
89
* Base SQL query builder that provides common functionality for building SQL queries.
910
*/
10-
export abstract class BaseSQLQueryBuilder<TFields extends Record<string, any>, TResultType> {
11+
export abstract class BaseSQLQueryBuilder<
12+
TFields extends Record<string, any>,
13+
TSelectedFields extends keyof TFields,
14+
TResultType,
15+
> {
1116
private executed = false;
1217

1318
constructor(
1419
private readonly sqlFragment: SQLFragment,
1520
private readonly modifiers: {
1621
limit?: number;
1722
offset?: number;
18-
orderBy?: { fieldName: keyof TFields; order: OrderByOrdering }[];
23+
orderBy?: readonly EntityLoaderOrderByClause<TFields, TSelectedFields>[];
1924
orderByFragment?: SQLFragment;
2025
},
2126
) {}
@@ -39,7 +44,7 @@ export abstract class BaseSQLQueryBuilder<TFields extends Record<string, any>, T
3944
/**
4045
* Order by a field. Can be called multiple times to add multiple order bys.
4146
*/
42-
orderBy(fieldName: keyof TFields, order: OrderByOrdering = OrderByOrdering.ASCENDING): this {
47+
orderBy(fieldName: TSelectedFields, order: OrderByOrdering = OrderByOrdering.ASCENDING): this {
4348
this.modifiers.orderBy = [...(this.modifiers.orderBy ?? []), { fieldName, order }];
4449
return this;
4550
}
@@ -71,7 +76,10 @@ export abstract class BaseSQLQueryBuilder<TFields extends Record<string, any>, T
7176
/**
7277
* Get the current modifiers as QuerySelectionModifiersWithOrderByFragment<TFields>
7378
*/
74-
protected getModifiers(): QuerySelectionModifiersWithOrderByFragment<TFields> {
79+
protected getModifiers(): EntityLoaderQuerySelectionModifiersWithOrderByFragment<
80+
TFields,
81+
TSelectedFields
82+
> {
7583
return this.modifiers;
7684
}
7785

packages/entity-database-adapter-knex/src/EnforcingKnexEntityLoader.ts

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { EntityPrivacyPolicy, ReadonlyEntity, ViewerContext } from '@expo/entity';
22

3-
import { AuthorizationResultBasedKnexEntityLoader } from './AuthorizationResultBasedKnexEntityLoader';
43
import {
5-
FieldEqualityCondition,
6-
QuerySelectionModifiers,
7-
QuerySelectionModifiersWithOrderByFragment,
8-
QuerySelectionModifiersWithOrderByRaw,
9-
} from './BasePostgresEntityDatabaseAdapter';
4+
AuthorizationResultBasedKnexEntityLoader,
5+
EntityLoaderQuerySelectionModifiers,
6+
EntityLoaderQuerySelectionModifiersWithOrderByFragment,
7+
EntityLoaderQuerySelectionModifiersWithOrderByRaw,
8+
} from './AuthorizationResultBasedKnexEntityLoader';
9+
import { FieldEqualityCondition } from './BasePostgresEntityDatabaseAdapter';
1010
import { BaseSQLQueryBuilder } from './BaseSQLQueryBuilder';
1111
import { SQLFragment } from './SQLOperator';
1212

@@ -52,8 +52,11 @@ export class EnforcingKnexEntityLoader<
5252
*/
5353
async loadFirstByFieldEqualityConjunctionAsync<N extends keyof Pick<TFields, TSelectedFields>>(
5454
fieldEqualityOperands: FieldEqualityCondition<TFields, N>[],
55-
querySelectionModifiers: Omit<QuerySelectionModifiers<TFields>, 'limit'> &
56-
Required<Pick<QuerySelectionModifiers<TFields>, 'orderBy'>>,
55+
querySelectionModifiers: Omit<
56+
EntityLoaderQuerySelectionModifiers<TFields, TSelectedFields>,
57+
'limit'
58+
> &
59+
Required<Pick<EntityLoaderQuerySelectionModifiers<TFields, TSelectedFields>, 'orderBy'>>,
5760
): Promise<TEntity | null> {
5861
const entityResult = await this.knexEntityLoader.loadFirstByFieldEqualityConjunctionAsync(
5962
fieldEqualityOperands,
@@ -74,7 +77,7 @@ export class EnforcingKnexEntityLoader<
7477
*/
7578
async loadManyByFieldEqualityConjunctionAsync<N extends keyof Pick<TFields, TSelectedFields>>(
7679
fieldEqualityOperands: FieldEqualityCondition<TFields, N>[],
77-
querySelectionModifiers: QuerySelectionModifiers<TFields> = {},
80+
querySelectionModifiers: EntityLoaderQuerySelectionModifiers<TFields, TSelectedFields> = {},
7881
): Promise<readonly TEntity[]> {
7982
const entityResults = await this.knexEntityLoader.loadManyByFieldEqualityConjunctionAsync(
8083
fieldEqualityOperands,
@@ -116,7 +119,10 @@ export class EnforcingKnexEntityLoader<
116119
async loadManyByRawWhereClauseAsync(
117120
rawWhereClause: string,
118121
bindings: any[] | object,
119-
querySelectionModifiers: QuerySelectionModifiersWithOrderByRaw<TFields> = {},
122+
querySelectionModifiers: EntityLoaderQuerySelectionModifiersWithOrderByRaw<
123+
TFields,
124+
TSelectedFields
125+
> = {},
120126
): Promise<readonly TEntity[]> {
121127
const entityResults = await this.knexEntityLoader.loadManyByRawWhereClauseAsync(
122128
rawWhereClause,
@@ -147,7 +153,10 @@ export class EnforcingKnexEntityLoader<
147153
*/
148154
loadManyBySQL(
149155
fragment: SQLFragment,
150-
modifiers: QuerySelectionModifiersWithOrderByFragment<TFields> = {},
156+
modifiers: EntityLoaderQuerySelectionModifiersWithOrderByFragment<
157+
TFields,
158+
TSelectedFields
159+
> = {},
151160
): EnforcingSQLQueryBuilder<
152161
TFields,
153162
TIDField,
@@ -177,7 +186,7 @@ export class EnforcingSQLQueryBuilder<
177186
TSelectedFields
178187
>,
179188
TSelectedFields extends keyof TFields,
180-
> extends BaseSQLQueryBuilder<TFields, TEntity> {
189+
> extends BaseSQLQueryBuilder<TFields, TSelectedFields, TEntity> {
181190
constructor(
182191
private readonly knexEntityLoader: AuthorizationResultBasedKnexEntityLoader<
183192
TFields,
@@ -188,7 +197,7 @@ export class EnforcingSQLQueryBuilder<
188197
TSelectedFields
189198
>,
190199
sqlFragment: SQLFragment,
191-
modifiers: QuerySelectionModifiersWithOrderByFragment<TFields>,
200+
modifiers: EntityLoaderQuerySelectionModifiersWithOrderByFragment<TFields, TSelectedFields>,
192201
) {
193202
super(sqlFragment, modifiers);
194203
}

0 commit comments

Comments
 (0)