Skip to content

Commit 12d6d1a

Browse files
authored
fix: support an array as the orderBy value (#362)
1 parent f1efc96 commit 12d6d1a

6 files changed

Lines changed: 130 additions & 11 deletions

File tree

README.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,12 +200,12 @@ users.findMany((q) => q.where({ name: (name) => name.startsWith('J') }), {
200200
})
201201
```
202202

203-
You can sort by multiple criteria by providing them in the `orderBy` object:
203+
You can sort by multiple keys by listing them in the `orderBy` object:
204204

205205
```ts
206206
users.updateMany((q) => q.where({ name: (name) => name.startsWith('J') }), {
207207
data(user) {
208-
user.name = user.name.toUpperCase(),
208+
user.name = user.name.toUpperCase()
209209
},
210210
orderBy: {
211211
name: 'asc',
@@ -214,6 +214,14 @@ users.updateMany((q) => q.where({ name: (name) => name.startsWith('J') }), {
214214
})
215215
```
216216

217+
You can sort by an ordered list of criteria by passing an array to `orderBy`. Each entry is applied in sequence: the first entry determines the primary sort, and each subsequent entry breaks ties among records that compare equal under the preceding criteria.
218+
219+
```ts
220+
users.findMany(undefined, {
221+
orderBy: [{ age: 'asc' }, { name: 'desc' }]
222+
})
223+
```
224+
217225
## Relations
218226

219227
You can define relations by calling the `.defineRelations()` method on the collection.

src/sort.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,26 @@
11
import type { StandardSchemaV1 } from '@standard-schema/spec'
22
import { get } from 'es-toolkit/compat'
3-
import { toDeepEntries } from '#/src/utils.js'
3+
import { toDeepEntries, type PropertyPath } from '#/src/utils.js'
44

55
export type SortDirection = 'asc' | 'desc'
66

77
export interface SortOptions<Schema extends StandardSchemaV1> {
88
orderBy?: OrderBy<Schema>
99
}
1010

11-
type OrderBy<
11+
type OrderBy<Schema extends StandardSchemaV1> =
12+
| OrderByCriteria<Schema>
13+
| Array<OrderByCriteria<Schema>>
14+
15+
type OrderByCriteria<
1216
Schema extends StandardSchemaV1,
1317
T = StandardSchemaV1.InferOutput<Schema>,
1418
> =
1519
NonNullable<T> extends Array<infer V>
16-
? OrderBy<Schema, V>
20+
? OrderByCriteria<Schema, V>
1721
: NonNullable<T> extends Record<any, any>
1822
? {
19-
[K in keyof T]?: OrderBy<Schema, T[K]>
23+
[K in keyof T]?: OrderByCriteria<Schema, T[K]>
2024
}
2125
: SortDirection
2226

@@ -28,7 +32,13 @@ export function sortResults<Schema extends StandardSchemaV1>(
2832
return
2933
}
3034

31-
const criteria = toDeepEntries<SortDirection>(sortOptions.orderBy as any)
35+
const criteria: Array<[PropertyPath, SortDirection]> = Array.isArray(
36+
sortOptions.orderBy,
37+
)
38+
? sortOptions.orderBy.flatMap((entry) => {
39+
return toDeepEntries<SortDirection>(entry as any)
40+
})
41+
: toDeepEntries<SortDirection>(sortOptions.orderBy as any)
3242

3343
data.sort((left, right) => {
3444
for (const [path, sortDirection] of criteria) {

tests/sort.test.ts

Lines changed: 90 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const schema = z.object({
66
name: z.string(),
77
})
88

9-
it('sorts the find results by a single key (asc)', async () => {
9+
it('sorts the results by a single key (asc)', async () => {
1010
const users = new Collection({ schema })
1111

1212
await users.create({ id: 1, name: 'John' })
@@ -33,7 +33,7 @@ it('sorts the find results by a single key (asc)', async () => {
3333
])
3434
})
3535

36-
it('sorts the find results by a single key (desc)', async () => {
36+
it('sorts the results by a single key (desc)', async () => {
3737
const users = new Collection({ schema })
3838

3939
await users.create({ id: 1, name: 'John' })
@@ -60,7 +60,7 @@ it('sorts the find results by a single key (desc)', async () => {
6060
])
6161
})
6262

63-
it('sorts the find results by multiple keys (mixed)', async () => {
63+
it('sorts the results by multiple keys (mixed)', async () => {
6464
const users = new Collection({ schema })
6565
await users.create({ id: 1, name: 'John' })
6666
await users.create({ id: 2, name: 'Alice' })
@@ -89,7 +89,7 @@ it('sorts the find results by multiple keys (mixed)', async () => {
8989
])
9090
})
9191

92-
it('sorts the find results by a nested key', async () => {
92+
it('sorts the results by a nested key', async () => {
9393
const users = new Collection({
9494
schema: schema.extend({
9595
address: z.object({
@@ -121,3 +121,89 @@ it('sorts the find results by a nested key', async () => {
121121
{ id: 1, name: 'John', address: { street: 'C' } },
122122
])
123123
})
124+
125+
it('sorts the results by a list of sort criteria', async () => {
126+
const schema = z.object({
127+
id: z.number(),
128+
name: z.string(),
129+
age: z.number(),
130+
})
131+
132+
const users = new Collection({ schema })
133+
134+
await users.create({ id: 1, name: 'John', age: 32 })
135+
await users.create({ id: 2, name: 'Alice', age: 24 })
136+
await users.create({ id: 3, name: 'Bob', age: 41 })
137+
await users.create({ id: 4, name: 'Alice', age: 41 })
138+
139+
expect(
140+
users.findMany(undefined, {
141+
orderBy: [{ age: 'asc' }, { name: 'desc' }],
142+
}),
143+
).toEqual([
144+
{ id: 2, name: 'Alice', age: 24 },
145+
{ id: 1, name: 'John', age: 32 },
146+
{ id: 3, name: 'Bob', age: 41 },
147+
{ id: 4, name: 'Alice', age: 41 },
148+
])
149+
})
150+
151+
it('sorts by a relational property', async () => {
152+
const userSchema = z.object({
153+
id: z.number(),
154+
name: z.string(),
155+
get posts() {
156+
return z.array(postSchema)
157+
},
158+
})
159+
const postSchema = z.object({
160+
id: z.number(),
161+
title: z.string(),
162+
get author() {
163+
return userSchema.optional()
164+
},
165+
})
166+
167+
const users = new Collection({ schema: userSchema })
168+
const posts = new Collection({ schema: postSchema })
169+
170+
users.defineRelations(({ many }) => ({
171+
posts: many(posts),
172+
}))
173+
posts.defineRelations(({ one }) => ({
174+
author: one(users, { unique: true }),
175+
}))
176+
177+
const john = await users.create({
178+
id: 1,
179+
name: 'John',
180+
posts: await posts.createMany(2, (index) => ({
181+
id: index + 1,
182+
title: `Post ${index + 1}`,
183+
})),
184+
})
185+
186+
const alice = await users.create({
187+
id: 2,
188+
name: 'Alice',
189+
posts: await posts.createMany(2, (index) => ({
190+
id: index + 3,
191+
title: `Post ${index + 3}`,
192+
})),
193+
})
194+
195+
expect(
196+
posts.findMany(undefined, {
197+
orderBy: {
198+
author: {
199+
name: 'asc',
200+
},
201+
},
202+
}),
203+
).toEqual([
204+
{ id: 3, title: 'Post 3', author: alice },
205+
{ id: 4, title: 'Post 4', author: alice },
206+
{ id: 1, title: 'Post 1', author: john },
207+
{ id: 2, title: 'Post 2', author: john },
208+
])
209+
})

tests/types/delete-many.test-d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ it('supports sorting the results', () => {
6666
name?: SortDirection
6767
nested?: { key?: SortDirection }
6868
}
69+
| Array<{
70+
id?: SortDirection
71+
name?: SortDirection
72+
nested?: { key?: SortDirection }
73+
}>
6974
| undefined
7075
>()
7176
})

tests/types/find-many.test-d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,11 @@ it('supports sorting the results', () => {
117117
name?: SortDirection | undefined
118118
nested?: { key?: SortDirection | undefined }
119119
}
120+
| Array<{
121+
id?: SortDirection | undefined
122+
name?: SortDirection | undefined
123+
nested?: { key?: SortDirection | undefined }
124+
}>
120125
| undefined
121126
>()
122127
})

tests/types/update-many.test-d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,11 @@ it('supports sorting the results', () => {
109109
name?: SortDirection
110110
nested?: { key?: SortDirection }
111111
}
112+
| Array<{
113+
id?: SortDirection
114+
name?: SortDirection
115+
nested?: { key?: SortDirection }
116+
}>
112117
| undefined
113118
>()
114119
})

0 commit comments

Comments
 (0)