feat: sort support for payload.update operation (#11769)
Continuation of https://github.com/payloadcms/payload/pull/11768. This adds support for `sort` in `payload.update`. ## Example ```ts const { docs } = await payload.update({ collection: 'posts', data: { title: 'updated', }, limit: 5, sort: '-numberField', // <= new where: { id: { exists: true, }, }, }) ```
This commit is contained in:
@@ -14,13 +14,14 @@ import { updateOperation } from '../operations/update.js'
|
|||||||
|
|
||||||
export const updateHandler: PayloadHandler = async (req) => {
|
export const updateHandler: PayloadHandler = async (req) => {
|
||||||
const collection = getRequestCollection(req)
|
const collection = getRequestCollection(req)
|
||||||
const { depth, draft, limit, overrideLock, populate, select, where } = req.query as {
|
const { depth, draft, limit, overrideLock, populate, select, sort, where } = req.query as {
|
||||||
depth?: string
|
depth?: string
|
||||||
draft?: string
|
draft?: string
|
||||||
limit?: string
|
limit?: string
|
||||||
overrideLock?: string
|
overrideLock?: string
|
||||||
populate?: Record<string, unknown>
|
populate?: Record<string, unknown>
|
||||||
select?: Record<string, unknown>
|
select?: Record<string, unknown>
|
||||||
|
sort?: string
|
||||||
where?: Where
|
where?: Where
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,6 +35,7 @@ export const updateHandler: PayloadHandler = async (req) => {
|
|||||||
populate: sanitizePopulateParam(populate),
|
populate: sanitizePopulateParam(populate),
|
||||||
req,
|
req,
|
||||||
select: sanitizeSelectParam(select),
|
select: sanitizeSelectParam(select),
|
||||||
|
sort: typeof sort === 'string' ? sort.split(',') : undefined,
|
||||||
where,
|
where,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import type {
|
|||||||
PayloadRequest,
|
PayloadRequest,
|
||||||
PopulateType,
|
PopulateType,
|
||||||
SelectType,
|
SelectType,
|
||||||
|
Sort,
|
||||||
TransformCollectionWithSelect,
|
TransformCollectionWithSelect,
|
||||||
Where,
|
Where,
|
||||||
} from '../../../types/index.js'
|
} from '../../../types/index.js'
|
||||||
@@ -130,6 +131,12 @@ export type ByIDOptions<
|
|||||||
* Limit documents to update
|
* Limit documents to update
|
||||||
*/
|
*/
|
||||||
limit?: never
|
limit?: never
|
||||||
|
/**
|
||||||
|
* Sort the documents, can be a string or an array of strings
|
||||||
|
* @example '-createdAt' // Sort DESC by createdAt
|
||||||
|
* @example ['group', '-createdAt'] // sort by 2 fields, ASC group and DESC createdAt
|
||||||
|
*/
|
||||||
|
sort?: never
|
||||||
/**
|
/**
|
||||||
* A filter [query](https://payloadcms.com/docs/queries/overview)
|
* A filter [query](https://payloadcms.com/docs/queries/overview)
|
||||||
*/
|
*/
|
||||||
@@ -148,6 +155,12 @@ export type ManyOptions<
|
|||||||
* Limit documents to update
|
* Limit documents to update
|
||||||
*/
|
*/
|
||||||
limit?: number
|
limit?: number
|
||||||
|
/**
|
||||||
|
* Sort the documents, can be a string or an array of strings
|
||||||
|
* @example '-createdAt' // Sort DESC by createdAt
|
||||||
|
* @example ['group', '-createdAt'] // sort by 2 fields, ASC group and DESC createdAt
|
||||||
|
*/
|
||||||
|
sort?: Sort
|
||||||
/**
|
/**
|
||||||
* A filter [query](https://payloadcms.com/docs/queries/overview)
|
* A filter [query](https://payloadcms.com/docs/queries/overview)
|
||||||
*/
|
*/
|
||||||
@@ -205,6 +218,7 @@ async function updateLocal<
|
|||||||
publishSpecificLocale,
|
publishSpecificLocale,
|
||||||
select,
|
select,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
sort,
|
||||||
where,
|
where,
|
||||||
} = options
|
} = options
|
||||||
|
|
||||||
@@ -237,6 +251,7 @@ async function updateLocal<
|
|||||||
req,
|
req,
|
||||||
select,
|
select,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
sort,
|
||||||
where,
|
where,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import type { DeepPartial } from 'ts-essentials'
|
|||||||
import { status as httpStatus } from 'http-status'
|
import { status as httpStatus } from 'http-status'
|
||||||
|
|
||||||
import type { AccessResult } from '../../config/types.js'
|
import type { AccessResult } from '../../config/types.js'
|
||||||
import type { PayloadRequest, PopulateType, SelectType, Where } from '../../types/index.js'
|
import type { PayloadRequest, PopulateType, SelectType, Sort, Where } from '../../types/index.js'
|
||||||
import type {
|
import type {
|
||||||
BulkOperationResult,
|
BulkOperationResult,
|
||||||
Collection,
|
Collection,
|
||||||
@@ -26,6 +26,7 @@ import { killTransaction } from '../../utilities/killTransaction.js'
|
|||||||
import { sanitizeSelect } from '../../utilities/sanitizeSelect.js'
|
import { sanitizeSelect } from '../../utilities/sanitizeSelect.js'
|
||||||
import { buildVersionCollectionFields } from '../../versions/buildCollectionFields.js'
|
import { buildVersionCollectionFields } from '../../versions/buildCollectionFields.js'
|
||||||
import { appendVersionToQueryKey } from '../../versions/drafts/appendVersionToQueryKey.js'
|
import { appendVersionToQueryKey } from '../../versions/drafts/appendVersionToQueryKey.js'
|
||||||
|
import { getQueryDraftsSort } from '../../versions/drafts/getQueryDraftsSort.js'
|
||||||
import { updateDocument } from './utilities/update.js'
|
import { updateDocument } from './utilities/update.js'
|
||||||
import { buildAfterOperation } from './utils.js'
|
import { buildAfterOperation } from './utils.js'
|
||||||
|
|
||||||
@@ -45,6 +46,12 @@ export type Arguments<TSlug extends CollectionSlug> = {
|
|||||||
req: PayloadRequest
|
req: PayloadRequest
|
||||||
select?: SelectType
|
select?: SelectType
|
||||||
showHiddenFields?: boolean
|
showHiddenFields?: boolean
|
||||||
|
/**
|
||||||
|
* Sort the documents, can be a string or an array of strings
|
||||||
|
* @example '-createdAt' // Sort DESC by createdAt
|
||||||
|
* @example ['group', '-createdAt'] // sort by 2 fields, ASC group and DESC createdAt
|
||||||
|
*/
|
||||||
|
sort?: Sort
|
||||||
where: Where
|
where: Where
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,6 +103,7 @@ export const updateOperation = async <
|
|||||||
req,
|
req,
|
||||||
select: incomingSelect,
|
select: incomingSelect,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
sort,
|
||||||
where,
|
where,
|
||||||
} = args
|
} = args
|
||||||
|
|
||||||
@@ -147,6 +155,7 @@ export const updateOperation = async <
|
|||||||
locale,
|
locale,
|
||||||
pagination: false,
|
pagination: false,
|
||||||
req,
|
req,
|
||||||
|
sort: getQueryDraftsSort({ collectionConfig, sort }),
|
||||||
where: versionsWhere,
|
where: versionsWhere,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -158,6 +167,7 @@ export const updateOperation = async <
|
|||||||
locale,
|
locale,
|
||||||
pagination: false,
|
pagination: false,
|
||||||
req,
|
req,
|
||||||
|
sort,
|
||||||
where: fullWhere,
|
where: fullWhere,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1235,6 +1235,73 @@ describe('database', () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('ensure payload.update operation respects limit and sort', async () => {
|
||||||
|
await payload.db.deleteMany({
|
||||||
|
collection: postsSlug,
|
||||||
|
where: {
|
||||||
|
id: {
|
||||||
|
exists: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const numbers = Array.from({ length: 11 }, (_, i) => i)
|
||||||
|
|
||||||
|
// shuffle the numbers
|
||||||
|
numbers.sort(() => Math.random() - 0.5)
|
||||||
|
|
||||||
|
// create 11 documents numbered 0-10, but in random order
|
||||||
|
for (const i of numbers) {
|
||||||
|
await payload.create({
|
||||||
|
collection: postsSlug,
|
||||||
|
data: {
|
||||||
|
title: 'not updated',
|
||||||
|
number: i,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await payload.update({
|
||||||
|
collection: postsSlug,
|
||||||
|
data: {
|
||||||
|
title: 'updated',
|
||||||
|
},
|
||||||
|
limit: 5,
|
||||||
|
sort: 'number',
|
||||||
|
where: {
|
||||||
|
id: {
|
||||||
|
exists: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result?.docs.length).toBe(5)
|
||||||
|
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
expect(result?.docs?.[i]?.number).toBe(i)
|
||||||
|
expect(result?.docs?.[i]?.title).toBe('updated')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure all posts minus the one we don't want updated are updated
|
||||||
|
const { docs } = await payload.find({
|
||||||
|
collection: postsSlug,
|
||||||
|
depth: 0,
|
||||||
|
pagination: false,
|
||||||
|
sort: 'number',
|
||||||
|
where: {
|
||||||
|
title: {
|
||||||
|
equals: 'updated',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(docs).toHaveLength(5)
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
expect(docs?.[i]?.number).toBe(i)
|
||||||
|
expect(docs?.[i]?.title).toBe('updated')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
it('ensure updateMany respects limit and negative sort', async () => {
|
it('ensure updateMany respects limit and negative sort', async () => {
|
||||||
await payload.db.deleteMany({
|
await payload.db.deleteMany({
|
||||||
collection: postsSlug,
|
collection: postsSlug,
|
||||||
@@ -1302,6 +1369,73 @@ describe('database', () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('ensure payload.update operation respects limit and negative sort', async () => {
|
||||||
|
await payload.db.deleteMany({
|
||||||
|
collection: postsSlug,
|
||||||
|
where: {
|
||||||
|
id: {
|
||||||
|
exists: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const numbers = Array.from({ length: 11 }, (_, i) => i)
|
||||||
|
|
||||||
|
// shuffle the numbers
|
||||||
|
numbers.sort(() => Math.random() - 0.5)
|
||||||
|
|
||||||
|
// create 11 documents numbered 0-10, but in random order
|
||||||
|
for (const i of numbers) {
|
||||||
|
await payload.create({
|
||||||
|
collection: postsSlug,
|
||||||
|
data: {
|
||||||
|
title: 'not updated',
|
||||||
|
number: i,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await payload.update({
|
||||||
|
collection: postsSlug,
|
||||||
|
data: {
|
||||||
|
title: 'updated',
|
||||||
|
},
|
||||||
|
limit: 5,
|
||||||
|
sort: '-number',
|
||||||
|
where: {
|
||||||
|
id: {
|
||||||
|
exists: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result?.docs?.length).toBe(5)
|
||||||
|
|
||||||
|
for (let i = 10; i > 5; i--) {
|
||||||
|
expect(result?.docs?.[-i + 10]?.number).toBe(i)
|
||||||
|
expect(result?.docs?.[-i + 10]?.title).toBe('updated')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure all posts minus the one we don't want updated are updated
|
||||||
|
const { docs } = await payload.find({
|
||||||
|
collection: postsSlug,
|
||||||
|
depth: 0,
|
||||||
|
pagination: false,
|
||||||
|
sort: '-number',
|
||||||
|
where: {
|
||||||
|
title: {
|
||||||
|
equals: 'updated',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(docs).toHaveLength(5)
|
||||||
|
for (let i = 10; i > 5; i--) {
|
||||||
|
expect(docs?.[-i + 10]?.number).toBe(i)
|
||||||
|
expect(docs?.[-i + 10]?.title).toBe('updated')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
it('ensure updateMany correctly handles 0 limit', async () => {
|
it('ensure updateMany correctly handles 0 limit', async () => {
|
||||||
await payload.db.deleteMany({
|
await payload.db.deleteMany({
|
||||||
collection: postsSlug,
|
collection: postsSlug,
|
||||||
|
|||||||
Reference in New Issue
Block a user