Skip to content

Commit 0696d40

Browse files
authored
feat: orderBy supports passing a handler as a field param (#9)
1 parent f45f371 commit 0696d40

File tree

5 files changed

+56
-19
lines changed

5 files changed

+56
-19
lines changed

src/query/Options.ts

+10-8
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { Model } from '../model/Model'
22
import { Query } from './Query'
33

4-
export interface Where<M extends Model, T extends keyof M> {
5-
field: WherePrimaryClosure<M> | T
6-
value: WhereSecondaryClosure<M, T> | M[T] | M[T][]
4+
export interface Where<M extends Model, K extends keyof M> {
5+
field: WherePrimaryClosure<M> | K
6+
value: WhereSecondaryClosure<M, K> | M[K] | M[K][]
77
boolean: 'and' | 'or'
88
}
99

@@ -13,16 +13,18 @@ export type WhereSecondaryClosure<M extends Model, K extends keyof M> = (
1313
value: M[K]
1414
) => boolean
1515

16-
export interface WhereGroup<M extends Model, T extends keyof M> {
17-
and?: Where<M, T>[]
18-
or?: Where<M, T>[]
16+
export interface WhereGroup<M extends Model, K extends keyof M> {
17+
and?: Where<M, K>[]
18+
or?: Where<M, K>[]
1919
}
2020

21-
export interface Order {
22-
field: string
21+
export interface Order<M extends Model> {
22+
field: OrderBy<M>
2323
direction: OrderDirection
2424
}
2525

26+
export type OrderBy<M extends Model> = string | ((model: M) => any)
27+
2628
export type OrderDirection = 'asc' | 'desc'
2729

2830
export interface EagerLoad {

src/query/Query.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
WherePrimaryClosure,
2424
WhereSecondaryClosure,
2525
Order,
26+
OrderBy,
2627
OrderDirection,
2728
EagerLoad,
2829
EagerLoadConstraint,
@@ -63,7 +64,7 @@ export class Query<M extends Model = Model> {
6364
/**
6465
* The orderings for the query.
6566
*/
66-
protected orders: Order[] = []
67+
protected orders: Order<M>[] = []
6768

6869
/**
6970
* The maximum number of records to return.
@@ -148,7 +149,7 @@ export class Query<M extends Model = Model> {
148149
/**
149150
* Add an "order by" clause to the query.
150151
*/
151-
orderBy(field: string, direction: OrderDirection = 'asc'): Query<M> {
152+
orderBy(field: OrderBy<M>, direction: OrderDirection = 'asc'): Query<M> {
152153
this.orders.push({ field, direction })
153154

154155
return this

src/repository/Repository.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import { Query } from '../query/Query'
77
import {
88
WherePrimaryClosure,
99
WhereSecondaryClosure,
10-
OrderDirection
10+
OrderDirection,
11+
OrderBy
1112
} from '../query/Options'
1213

1314
export class Repository<M extends Model = Model> {
@@ -119,7 +120,7 @@ export class Repository<M extends Model = Model> {
119120
/**
120121
* Add an "order by" clause to the query.
121122
*/
122-
orderBy(field: string, direction?: OrderDirection): Query<M> {
123+
orderBy(field: OrderBy<M>, direction?: OrderDirection): Query<M> {
123124
return this.query().orderBy(field, direction)
124125
}
125126

src/support/Utils.ts

+10-4
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export function orderBy<T>(
6060
): T[] {
6161
let index = -1
6262

63-
const result = collection.map((value) => {
63+
const result = collection.map<SortableArray<T>>((value) => {
6464
const criteria = iteratees.map((iteratee) => {
6565
return typeof iteratee === 'function' ? iteratee(value) : value[iteratee]
6666
})
@@ -88,9 +88,11 @@ function baseSortBy<T>(
8888
array.sort(comparer)
8989

9090
const newArray: T[] = []
91+
9192
while (length--) {
9293
newArray[length] = array[length].value
9394
}
95+
9496
return newArray
9597
}
9698

@@ -102,7 +104,11 @@ function baseSortBy<T>(
102104
* Otherwise, specify an order of "desc" for descending or "asc" for
103105
* ascending sort order of corresponding values.
104106
*/
105-
function compareMultiple(object: any, other: any, orders: string[]): number {
107+
function compareMultiple<T>(
108+
object: SortableArray<T>,
109+
other: SortableArray<T>,
110+
directions: string[]
111+
): number {
106112
let index = -1
107113

108114
const objCriteria = object.criteria
@@ -113,9 +119,9 @@ function compareMultiple(object: any, other: any, orders: string[]): number {
113119
const result = compareAscending(objCriteria[index], othCriteria[index])
114120

115121
if (result) {
116-
const order = orders[index]
122+
const direction = directions[index]
117123

118-
return result * (order === 'desc' ? -1 : 1)
124+
return result * (direction === 'desc' ? -1 : 1)
119125
}
120126
}
121127

test/feature/repository/retrieves_order_by.spec.ts

+30-3
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ describe('feature/repository/retrieves_order_by', () => {
1515
@Num(0) age!: number
1616
}
1717

18-
it('can sort the records by the `order by` clause', () => {
18+
it('can sort records using the `orderBy` modifier', () => {
1919
const store = createStore()
2020

2121
fillState(store, {
@@ -39,7 +39,7 @@ describe('feature/repository/retrieves_order_by', () => {
3939
assertModels(users, expected)
4040
})
4141

42-
it('can sort the records by "desc" order', () => {
42+
it('can sort records in descending order', () => {
4343
const store = createStore()
4444

4545
fillState(store, {
@@ -63,7 +63,7 @@ describe('feature/repository/retrieves_order_by', () => {
6363
assertModels(users, expected)
6464
})
6565

66-
it('can combine multiple orders', () => {
66+
it('can sort records by combining multiple `orderBy` modifiers', () => {
6767
const store = createStore()
6868

6969
fillState(store, {
@@ -90,4 +90,31 @@ describe('feature/repository/retrieves_order_by', () => {
9090
assertInstanceOf(users, User)
9191
assertModels(users, expected)
9292
})
93+
94+
it('can sort records by specifying a callback', () => {
95+
const store = createStore()
96+
97+
fillState(store, {
98+
users: {
99+
1: { id: 1, name: 'James', age: 40 },
100+
2: { id: 2, name: 'Andy', age: 30 },
101+
3: { id: 3, name: 'David', age: 20 }
102+
}
103+
})
104+
105+
const users = store
106+
.$repo(User)
107+
.orderBy((user) => user.age, 'desc')
108+
.get()
109+
110+
const expected = [
111+
{ id: 1, name: 'James', age: 40 },
112+
{ id: 2, name: 'Andy', age: 30 },
113+
{ id: 3, name: 'David', age: 20 }
114+
]
115+
116+
expect(users).toHaveLength(3)
117+
assertInstanceOf(users, User)
118+
assertModels(users, expected)
119+
})
93120
})

0 commit comments

Comments
 (0)