feat: sort by multiple fields (#8799)
This change adds support for sort with multiple fields in local API and REST API. Related discussion #2089 Co-authored-by: Dan Ribbens <dan.ribbens@gmail.com>
This commit is contained in:
committed by
GitHub
parent
6e919cc83a
commit
4d44c378ed
471
test/sort/int.spec.ts
Normal file
471
test/sort/int.spec.ts
Normal file
@@ -0,0 +1,471 @@
|
||||
import type { CollectionSlug, Payload } from 'payload'
|
||||
|
||||
import path from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
|
||||
import type { NextRESTClient } from '../helpers/NextRESTClient.js'
|
||||
|
||||
import { initPayloadInt } from '../helpers/initPayloadInt.js'
|
||||
|
||||
let payload: Payload
|
||||
let restClient: NextRESTClient
|
||||
|
||||
const filename = fileURLToPath(import.meta.url)
|
||||
const dirname = path.dirname(filename)
|
||||
|
||||
describe('Sort', () => {
|
||||
beforeAll(async () => {
|
||||
const initialized = await initPayloadInt(dirname)
|
||||
;({ payload, restClient } = initialized)
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
if (typeof payload.db.destroy === 'function') {
|
||||
await payload.db.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
describe('Local API', () => {
|
||||
beforeAll(async () => {
|
||||
await createData('posts', [
|
||||
{ text: 'Post 1', number: 1, number2: 10, group: { number: 100 } },
|
||||
{ text: 'Post 2', number: 2, number2: 10, group: { number: 200 } },
|
||||
{ text: 'Post 3', number: 3, number2: 5, group: { number: 150 } },
|
||||
{ text: 'Post 10', number: 10, number2: 5, group: { number: 200 } },
|
||||
{ text: 'Post 11', number: 11, number2: 20, group: { number: 150 } },
|
||||
{ text: 'Post 12', number: 12, number2: 20, group: { number: 100 } },
|
||||
])
|
||||
await createData('default-sort', [
|
||||
{ text: 'Post default-5 b', number: 5 },
|
||||
{ text: 'Post default-10', number: 10 },
|
||||
{ text: 'Post default-5 a', number: 5 },
|
||||
{ text: 'Post default-1', number: 1 },
|
||||
])
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await payload.delete({ collection: 'posts', where: {} })
|
||||
await payload.delete({ collection: 'default-sort', where: {} })
|
||||
})
|
||||
|
||||
describe('Default sort', () => {
|
||||
it('should sort posts by default definition in collection', async () => {
|
||||
const posts = await payload.find({
|
||||
collection: 'default-sort', // 'number,-text'
|
||||
})
|
||||
|
||||
expect(posts.docs.map((post) => post.text)).toEqual([
|
||||
'Post default-1',
|
||||
'Post default-5 b',
|
||||
'Post default-5 a',
|
||||
'Post default-10',
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe('Sinlge sort field', () => {
|
||||
it('should sort posts by text field', async () => {
|
||||
const posts = await payload.find({
|
||||
collection: 'posts',
|
||||
sort: 'text',
|
||||
})
|
||||
|
||||
expect(posts.docs.map((post) => post.text)).toEqual([
|
||||
'Post 1',
|
||||
'Post 10',
|
||||
'Post 11',
|
||||
'Post 12',
|
||||
'Post 2',
|
||||
'Post 3',
|
||||
])
|
||||
})
|
||||
|
||||
it('should sort posts by text field desc', async () => {
|
||||
const posts = await payload.find({
|
||||
collection: 'posts',
|
||||
sort: '-text',
|
||||
})
|
||||
|
||||
expect(posts.docs.map((post) => post.text)).toEqual([
|
||||
'Post 3',
|
||||
'Post 2',
|
||||
'Post 12',
|
||||
'Post 11',
|
||||
'Post 10',
|
||||
'Post 1',
|
||||
])
|
||||
})
|
||||
|
||||
it('should sort posts by number field', async () => {
|
||||
const posts = await payload.find({
|
||||
collection: 'posts',
|
||||
sort: 'number',
|
||||
})
|
||||
|
||||
expect(posts.docs.map((post) => post.text)).toEqual([
|
||||
'Post 1',
|
||||
'Post 2',
|
||||
'Post 3',
|
||||
'Post 10',
|
||||
'Post 11',
|
||||
'Post 12',
|
||||
])
|
||||
})
|
||||
|
||||
it('should sort posts by number field desc', async () => {
|
||||
const posts = await payload.find({
|
||||
collection: 'posts',
|
||||
sort: '-number',
|
||||
})
|
||||
|
||||
expect(posts.docs.map((post) => post.text)).toEqual([
|
||||
'Post 12',
|
||||
'Post 11',
|
||||
'Post 10',
|
||||
'Post 3',
|
||||
'Post 2',
|
||||
'Post 1',
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe('Sort by multiple fields', () => {
|
||||
it('should sort posts by multiple fields', async () => {
|
||||
const posts = await payload.find({
|
||||
collection: 'posts',
|
||||
sort: ['number2', 'number'],
|
||||
})
|
||||
|
||||
expect(posts.docs.map((post) => post.text)).toEqual([
|
||||
'Post 3', // 5, 3
|
||||
'Post 10', // 5, 10
|
||||
'Post 1', // 10, 1
|
||||
'Post 2', // 10, 2
|
||||
'Post 11', // 20, 11
|
||||
'Post 12', // 20, 12
|
||||
])
|
||||
})
|
||||
|
||||
it('should sort posts by multiple fields asc and desc', async () => {
|
||||
const posts = await payload.find({
|
||||
collection: 'posts',
|
||||
sort: ['number2', '-number'],
|
||||
})
|
||||
|
||||
expect(posts.docs.map((post) => post.text)).toEqual([
|
||||
'Post 10', // 5, 10
|
||||
'Post 3', // 5, 3
|
||||
'Post 2', // 10, 2
|
||||
'Post 1', // 10, 1
|
||||
'Post 12', // 20, 12
|
||||
'Post 11', // 20, 11
|
||||
])
|
||||
})
|
||||
|
||||
it('should sort posts by multiple fields with group', async () => {
|
||||
const posts = await payload.find({
|
||||
collection: 'posts',
|
||||
sort: ['-group.number', '-number'],
|
||||
})
|
||||
|
||||
expect(posts.docs.map((post) => post.text)).toEqual([
|
||||
'Post 10', // 200, 10
|
||||
'Post 2', // 200, 2
|
||||
'Post 11', // 150, 11
|
||||
'Post 3', // 150, 3
|
||||
'Post 12', // 100, 12
|
||||
'Post 1', // 100, 1
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe('Sort with drafts', () => {
|
||||
beforeAll(async () => {
|
||||
const testData1 = await payload.create({
|
||||
collection: 'drafts',
|
||||
data: { text: 'Post 1 draft', number: 10 },
|
||||
draft: true,
|
||||
})
|
||||
await payload.update({
|
||||
collection: 'drafts',
|
||||
id: testData1.id,
|
||||
data: { text: 'Post 1 draft updated', number: 20 },
|
||||
draft: true,
|
||||
})
|
||||
await payload.update({
|
||||
collection: 'drafts',
|
||||
id: testData1.id,
|
||||
data: { text: 'Post 1 draft updated', number: 30 },
|
||||
draft: true,
|
||||
})
|
||||
await payload.update({
|
||||
collection: 'drafts',
|
||||
id: testData1.id,
|
||||
data: { text: 'Post 1 published', number: 15 },
|
||||
draft: false,
|
||||
})
|
||||
const testData2 = await payload.create({
|
||||
collection: 'drafts',
|
||||
data: { text: 'Post 2 draft', number: 1 },
|
||||
draft: true,
|
||||
})
|
||||
await payload.update({
|
||||
collection: 'drafts',
|
||||
id: testData2.id,
|
||||
data: { text: 'Post 2 published', number: 2 },
|
||||
draft: false,
|
||||
})
|
||||
await payload.update({
|
||||
collection: 'drafts',
|
||||
id: testData2.id,
|
||||
data: { text: 'Post 2 newdraft', number: 100 },
|
||||
draft: true,
|
||||
})
|
||||
await payload.create({
|
||||
collection: 'drafts',
|
||||
data: { text: 'Post 3 draft', number: 3 },
|
||||
draft: true,
|
||||
})
|
||||
})
|
||||
|
||||
it('should sort latest without draft', async () => {
|
||||
const posts = await payload.find({
|
||||
collection: 'drafts',
|
||||
sort: 'number',
|
||||
draft: false,
|
||||
})
|
||||
|
||||
expect(posts.docs.map((post) => post.text)).toEqual([
|
||||
'Post 2 published', // 2
|
||||
'Post 3 draft', // 3
|
||||
'Post 1 published', // 15
|
||||
])
|
||||
})
|
||||
|
||||
it('should sort latest with draft', async () => {
|
||||
const posts = await payload.find({
|
||||
collection: 'drafts',
|
||||
sort: 'number',
|
||||
draft: true,
|
||||
})
|
||||
|
||||
expect(posts.docs.map((post) => post.text)).toEqual([
|
||||
'Post 3 draft', // 3
|
||||
'Post 1 published', // 15
|
||||
'Post 2 newdraft', // 100
|
||||
])
|
||||
})
|
||||
|
||||
it('should sort versions', async () => {
|
||||
const posts = await payload.findVersions({
|
||||
collection: 'drafts',
|
||||
sort: 'version.number',
|
||||
draft: false,
|
||||
})
|
||||
|
||||
expect(posts.docs.map((post) => post.version.text)).toEqual([
|
||||
'Post 2 draft', // 1
|
||||
'Post 2 published', // 2
|
||||
'Post 3 draft', // 3
|
||||
'Post 1 draft', // 10
|
||||
'Post 1 published', // 15
|
||||
'Post 1 draft updated', // 20
|
||||
'Post 1 draft updated', // 30
|
||||
'Post 2 newdraft', // 100
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe('Localized sort', () => {
|
||||
beforeAll(async () => {
|
||||
const testData1 = await payload.create({
|
||||
collection: 'localized',
|
||||
data: { text: 'Post 1 english', number: 10 },
|
||||
locale: 'en',
|
||||
})
|
||||
await payload.update({
|
||||
collection: 'localized',
|
||||
id: testData1.id,
|
||||
data: { text: 'Post 1 norsk', number: 20 },
|
||||
locale: 'nb',
|
||||
})
|
||||
const testData2 = await payload.create({
|
||||
collection: 'localized',
|
||||
data: { text: 'Post 2 english', number: 25 },
|
||||
locale: 'en',
|
||||
})
|
||||
await payload.update({
|
||||
collection: 'localized',
|
||||
id: testData2.id,
|
||||
data: { text: 'Post 2 norsk', number: 5 },
|
||||
locale: 'nb',
|
||||
})
|
||||
})
|
||||
|
||||
it('should sort localized field', async () => {
|
||||
const englishPosts = await payload.find({
|
||||
collection: 'localized',
|
||||
sort: 'number',
|
||||
locale: 'en',
|
||||
})
|
||||
|
||||
expect(englishPosts.docs.map((post) => post.text)).toEqual([
|
||||
'Post 1 english', // 10
|
||||
'Post 2 english', // 20
|
||||
])
|
||||
|
||||
const norwegianPosts = await payload.find({
|
||||
collection: 'localized',
|
||||
sort: 'number',
|
||||
locale: 'nb',
|
||||
})
|
||||
|
||||
expect(norwegianPosts.docs.map((post) => post.text)).toEqual([
|
||||
'Post 2 norsk', // 5
|
||||
'Post 1 norsk', // 25
|
||||
])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('REST API', () => {
|
||||
beforeAll(async () => {
|
||||
await createData('posts', [
|
||||
{ text: 'Post 1', number: 1, number2: 10 },
|
||||
{ text: 'Post 2', number: 2, number2: 10 },
|
||||
{ text: 'Post 3', number: 3, number2: 5 },
|
||||
{ text: 'Post 10', number: 10, number2: 5 },
|
||||
{ text: 'Post 11', number: 11, number2: 20 },
|
||||
{ text: 'Post 12', number: 12, number2: 20 },
|
||||
])
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await payload.delete({ collection: 'posts', where: {} })
|
||||
})
|
||||
|
||||
describe('Sinlge sort field', () => {
|
||||
it('should sort posts by text field', async () => {
|
||||
const res = await restClient
|
||||
.GET(`/posts`, {
|
||||
query: {
|
||||
sort: 'text',
|
||||
},
|
||||
})
|
||||
.then((res) => res.json())
|
||||
|
||||
expect(res.docs.map((post) => post.text)).toEqual([
|
||||
'Post 1',
|
||||
'Post 10',
|
||||
'Post 11',
|
||||
'Post 12',
|
||||
'Post 2',
|
||||
'Post 3',
|
||||
])
|
||||
})
|
||||
|
||||
it('should sort posts by text field desc', async () => {
|
||||
const res = await restClient
|
||||
.GET(`/posts`, {
|
||||
query: {
|
||||
sort: '-text',
|
||||
},
|
||||
})
|
||||
.then((res) => res.json())
|
||||
|
||||
expect(res.docs.map((post) => post.text)).toEqual([
|
||||
'Post 3',
|
||||
'Post 2',
|
||||
'Post 12',
|
||||
'Post 11',
|
||||
'Post 10',
|
||||
'Post 1',
|
||||
])
|
||||
})
|
||||
|
||||
it('should sort posts by number field', async () => {
|
||||
const res = await restClient
|
||||
.GET(`/posts`, {
|
||||
query: {
|
||||
sort: 'number',
|
||||
},
|
||||
})
|
||||
.then((res) => res.json())
|
||||
|
||||
expect(res.docs.map((post) => post.text)).toEqual([
|
||||
'Post 1',
|
||||
'Post 2',
|
||||
'Post 3',
|
||||
'Post 10',
|
||||
'Post 11',
|
||||
'Post 12',
|
||||
])
|
||||
})
|
||||
|
||||
it('should sort posts by number field desc', async () => {
|
||||
const res = await restClient
|
||||
.GET(`/posts`, {
|
||||
query: {
|
||||
sort: '-number',
|
||||
},
|
||||
})
|
||||
.then((res) => res.json())
|
||||
|
||||
expect(res.docs.map((post) => post.text)).toEqual([
|
||||
'Post 12',
|
||||
'Post 11',
|
||||
'Post 10',
|
||||
'Post 3',
|
||||
'Post 2',
|
||||
'Post 1',
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe('Sort by multiple fields', () => {
|
||||
it('should sort posts by multiple fields', async () => {
|
||||
const res = await restClient
|
||||
.GET(`/posts`, {
|
||||
query: {
|
||||
sort: 'number2,number',
|
||||
},
|
||||
})
|
||||
.then((res) => res.json())
|
||||
|
||||
expect(res.docs.map((post) => post.text)).toEqual([
|
||||
'Post 3', // 5, 3
|
||||
'Post 10', // 5, 10
|
||||
'Post 1', // 10, 1
|
||||
'Post 2', // 10, 2
|
||||
'Post 11', // 20, 11
|
||||
'Post 12', // 20, 12
|
||||
])
|
||||
})
|
||||
|
||||
it('should sort posts by multiple fields asc and desc', async () => {
|
||||
const res = await restClient
|
||||
.GET(`/posts`, {
|
||||
query: {
|
||||
sort: 'number2,-number',
|
||||
},
|
||||
})
|
||||
.then((res) => res.json())
|
||||
|
||||
expect(res.docs.map((post) => post.text)).toEqual([
|
||||
'Post 10', // 5, 10
|
||||
'Post 3', // 5, 3
|
||||
'Post 2', // 10, 2
|
||||
'Post 1', // 10, 1
|
||||
'Post 12', // 20, 12
|
||||
'Post 11', // 20, 11
|
||||
])
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
async function createData(collection: CollectionSlug, data: Record<string, any>[]) {
|
||||
for (const item of data) {
|
||||
await payload.create({ collection, data: item })
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user