Skip to content

Commit

Permalink
feat: orderBy supports passing a handler as a field param (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
cuebit committed May 9, 2020
1 parent f45f371 commit 0696d40
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 19 deletions.
18 changes: 10 additions & 8 deletions src/query/Options.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Model } from '../model/Model'
import { Query } from './Query'

export interface Where<M extends Model, T extends keyof M> {
field: WherePrimaryClosure<M> | T
value: WhereSecondaryClosure<M, T> | M[T] | M[T][]
export interface Where<M extends Model, K extends keyof M> {
field: WherePrimaryClosure<M> | K
value: WhereSecondaryClosure<M, K> | M[K] | M[K][]
boolean: 'and' | 'or'
}

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

export interface WhereGroup<M extends Model, T extends keyof M> {
and?: Where<M, T>[]
or?: Where<M, T>[]
export interface WhereGroup<M extends Model, K extends keyof M> {
and?: Where<M, K>[]
or?: Where<M, K>[]
}

export interface Order {
field: string
export interface Order<M extends Model> {
field: OrderBy<M>
direction: OrderDirection
}

export type OrderBy<M extends Model> = string | ((model: M) => any)

export type OrderDirection = 'asc' | 'desc'

export interface EagerLoad {
Expand Down
5 changes: 3 additions & 2 deletions src/query/Query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
WherePrimaryClosure,
WhereSecondaryClosure,
Order,
OrderBy,
OrderDirection,
EagerLoad,
EagerLoadConstraint,
Expand Down Expand Up @@ -63,7 +64,7 @@ export class Query<M extends Model = Model> {
/**
* The orderings for the query.
*/
protected orders: Order[] = []
protected orders: Order<M>[] = []

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

return this
Expand Down
5 changes: 3 additions & 2 deletions src/repository/Repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import { Query } from '../query/Query'
import {
WherePrimaryClosure,
WhereSecondaryClosure,
OrderDirection
OrderDirection,
OrderBy
} from '../query/Options'

export class Repository<M extends Model = Model> {
Expand Down Expand Up @@ -119,7 +120,7 @@ export class Repository<M extends Model = Model> {
/**
* Add an "order by" clause to the query.
*/
orderBy(field: string, direction?: OrderDirection): Query<M> {
orderBy(field: OrderBy<M>, direction?: OrderDirection): Query<M> {
return this.query().orderBy(field, direction)
}

Expand Down
14 changes: 10 additions & 4 deletions src/support/Utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export function orderBy<T>(
): T[] {
let index = -1

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

const newArray: T[] = []

while (length--) {
newArray[length] = array[length].value
}

return newArray
}

Expand All @@ -102,7 +104,11 @@ function baseSortBy<T>(
* Otherwise, specify an order of "desc" for descending or "asc" for
* ascending sort order of corresponding values.
*/
function compareMultiple(object: any, other: any, orders: string[]): number {
function compareMultiple<T>(
object: SortableArray<T>,
other: SortableArray<T>,
directions: string[]
): number {
let index = -1

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

if (result) {
const order = orders[index]
const direction = directions[index]

return result * (order === 'desc' ? -1 : 1)
return result * (direction === 'desc' ? -1 : 1)
}
}

Expand Down
33 changes: 30 additions & 3 deletions test/feature/repository/retrieves_order_by.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ describe('feature/repository/retrieves_order_by', () => {
@Num(0) age!: number
}

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

fillState(store, {
Expand All @@ -39,7 +39,7 @@ describe('feature/repository/retrieves_order_by', () => {
assertModels(users, expected)
})

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

fillState(store, {
Expand All @@ -63,7 +63,7 @@ describe('feature/repository/retrieves_order_by', () => {
assertModels(users, expected)
})

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

fillState(store, {
Expand All @@ -90,4 +90,31 @@ describe('feature/repository/retrieves_order_by', () => {
assertInstanceOf(users, User)
assertModels(users, expected)
})

it('can sort records by specifying a callback', () => {
const store = createStore()

fillState(store, {
users: {
1: { id: 1, name: 'James', age: 40 },
2: { id: 2, name: 'Andy', age: 30 },
3: { id: 3, name: 'David', age: 20 }
}
})

const users = store
.$repo(User)
.orderBy((user) => user.age, 'desc')
.get()

const expected = [
{ id: 1, name: 'James', age: 40 },
{ id: 2, name: 'Andy', age: 30 },
{ id: 3, name: 'David', age: 20 }
]

expect(users).toHaveLength(3)
assertInstanceOf(users, User)
assertModels(users, expected)
})
})

0 comments on commit 0696d40

Please sign in to comment.