Skip to content

Commit 49c9fa9

Browse files
fix: select in findByID with draft: true may return a wrong version (#14742)
Fixes #14589 This was caused by the fact that our `replacwWithDraftIfAvailable` function expects to have `createdAt` and `updatedAt` fields and when the user doesn't select `createdAt` and `updatedAt` fields the logic breaks. Now, specifically for this case we force to select those fields, however, you still won't receive `createdAt` and `updatedAt` fields to the final result if they weren't specified in `select`. --------- Co-authored-by: Jarrod Flesch <[email protected]>
1 parent d77af00 commit 49c9fa9

File tree

4 files changed

+59
-2
lines changed

4 files changed

+59
-2
lines changed

packages/payload/src/collections/operations/findByID.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { afterRead, type AfterReadArgs } from '../../fields/hooks/afterRead/inde
2424
import { validateQueryPaths } from '../../index.js'
2525
import { lockedDocumentsCollectionSlug } from '../../locked-documents/config.js'
2626
import { appendNonTrashedFilter } from '../../utilities/appendNonTrashedFilter.js'
27+
import { getSelectMode } from '../../utilities/getSelectMode.js'
2728
import { hasDraftsEnabled } from '../../utilities/getVersionsConfig.js'
2829
import { killTransaction } from '../../utilities/killTransaction.js'
2930
import { sanitizeSelect } from '../../utilities/sanitizeSelect.js'
@@ -152,6 +153,17 @@ export const findByIDOperation = async <
152153
// Find by ID
153154
// /////////////////////////////////////
154155

156+
let dbSelect = select
157+
158+
if (
159+
collectionConfig.versions?.drafts &&
160+
replaceWithVersion &&
161+
select &&
162+
getSelectMode(select) === 'include'
163+
) {
164+
dbSelect = { ...select, createdAt: true, updatedAt: true }
165+
}
166+
155167
const findOneArgs: FindOneArgs = {
156168
collection: collectionConfig.slug,
157169
draftsEnabled: replaceWithVersion,
@@ -160,7 +172,7 @@ export const findByIDOperation = async <
160172
req: {
161173
transactionID: req.transactionID,
162174
} as PayloadRequest,
163-
select,
175+
select: dbSelect,
164176
where: fullWhere,
165177
}
166178

packages/payload/src/globals/operations/findOne.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,11 +101,21 @@ export const findOneOperation = async <T extends Record<string, unknown>>(
101101
// Perform database operation
102102
// /////////////////////////////////////
103103

104+
let dbSelect = select
105+
106+
if (
107+
globalConfig.versions?.drafts &&
108+
replaceWithVersion &&
109+
select &&
110+
getSelectMode(select) === 'include'
111+
) {
112+
dbSelect = { ...select, createdAt: true, updatedAt: true }
113+
}
104114
const docFromDB = await req.payload.db.findGlobal({
105115
slug,
106116
locale: locale!,
107117
req,
108-
select,
118+
select: dbSelect,
109119
where: overrideAccess ? undefined : (accessResult as Where),
110120
})
111121

test/select/int.spec.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1635,6 +1635,39 @@ describe('Select', () => {
16351635
expect(doc.version.text).toBe(post.text)
16361636
})
16371637

1638+
it('should return a latest version with findByID and draft: true', async () => {
1639+
const doc = await payload.create({
1640+
collection: 'versioned-posts',
1641+
data: { text: 'draft-post', _status: 'draft' },
1642+
draft: true,
1643+
})
1644+
1645+
const res = await payload.findByID({
1646+
collection: 'versioned-posts',
1647+
id: doc.id,
1648+
draft: true,
1649+
select: { text: true },
1650+
})
1651+
expect(res.text).toBe('draft-post')
1652+
await payload.update({
1653+
collection: 'versioned-posts',
1654+
id: doc.id,
1655+
data: { text: 'published', _status: 'published' },
1656+
})
1657+
1658+
const res_2 = await payload.findByID({
1659+
collection: 'versioned-posts',
1660+
id: doc.id,
1661+
draft: true,
1662+
select: { text: true },
1663+
})
1664+
1665+
expect(res_2).toStrictEqual({
1666+
text: 'published',
1667+
id: res_2.id,
1668+
})
1669+
})
1670+
16381671
it('should create versions with complete data when updating with select', async () => {
16391672
// First, update the post with select to only return the id field
16401673
const updatedPost = await payload.update({

test/select/payload-types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,6 +1059,7 @@ export interface GlobalPost {
10591059
id: string;
10601060
text?: string | null;
10611061
number?: number | null;
1062+
_status?: ('draft' | 'published') | null;
10621063
updatedAt?: string | null;
10631064
createdAt?: string | null;
10641065
}
@@ -1086,6 +1087,7 @@ export interface ForceSelectGlobal {
10861087
export interface GlobalPostSelect<T extends boolean = true> {
10871088
text?: T;
10881089
number?: T;
1090+
_status?: T;
10891091
updatedAt?: T;
10901092
createdAt?: T;
10911093
globalType?: T;

0 commit comments

Comments
 (0)