Skip to content

Commit 23a56d3

Browse files
committed
feat: add missing disableErrors to globals and sdk operations
1 parent 77f96a4 commit 23a56d3

10 files changed

Lines changed: 196 additions & 29 deletions

File tree

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export type GlobalFindOneArgs = {
2525
*/
2626
data?: Record<string, unknown>
2727
depth?: number
28+
disableErrors?: boolean
2829
draft?: boolean
2930
globalConfig: SanitizedGlobalConfig
3031
includeLockStatus?: boolean
@@ -42,6 +43,7 @@ export const findOneOperation = async <T extends Record<string, unknown>>(
4243
const {
4344
slug,
4445
depth,
46+
disableErrors,
4547
draft: replaceWithVersion = false,
4648
flattenLocales,
4749
globalConfig,
@@ -79,11 +81,14 @@ export const findOneOperation = async <T extends Record<string, unknown>>(
7981
let accessResult!: AccessResult
8082

8183
if (!overrideAccess) {
82-
accessResult = await executeAccess({ req }, globalConfig.access.read)
84+
accessResult = await executeAccess({ disableErrors, req }, globalConfig.access.read)
8385
}
8486

8587
if (accessResult === false) {
86-
throw new NotFound(req.t)
88+
if (!disableErrors) {
89+
throw new NotFound(req.t)
90+
}
91+
return null!
8792
}
8893

8994
const select = sanitizeSelect({

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ export type Options<TSlug extends GlobalSlug, TSelect extends SelectType> = {
3636
* [Control auto-population](https://payloadcms.com/docs/queries/depth) of nested relationship and upload fields.
3737
*/
3838
depth?: number
39+
/**
40+
* When set to `true`, errors will not be thrown.
41+
*/
42+
disableErrors?: boolean
3943
/**
4044
* Whether the document should be queried from the versions table/collection or not. [More](https://payloadcms.com/docs/versions/drafts#draft-api)
4145
*/
@@ -97,6 +101,7 @@ export async function findOneGlobalLocal<
97101
slug: globalSlug,
98102
data,
99103
depth,
104+
disableErrors,
100105
draft = false,
101106
flattenLocales,
102107
includeLockStatus,
@@ -116,6 +121,7 @@ export async function findOneGlobalLocal<
116121
slug: globalSlug as string,
117122
data,
118123
depth,
124+
disableErrors,
119125
draft,
120126
flattenLocales,
121127
globalConfig,

packages/sdk/src/collections/count.ts

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ export type CountOptions<T extends PayloadGeneratedTypes, TSlug extends Collecti
88
* the Collection slug to operate against.
99
*/
1010
collection: TSlug
11+
/**
12+
* When set to `true`, errors will not be thrown.
13+
*/
14+
disableErrors?: boolean
1115
/**
1216
* Specify [locale](https://payloadcms.com/docs/configuration/localization) for any returned documents.
1317
*/
@@ -23,12 +27,24 @@ export async function count<T extends PayloadGeneratedTypes, TSlug extends Colle
2327
options: CountOptions<T, TSlug>,
2428
init?: RequestInit,
2529
): Promise<{ totalDocs: number }> {
26-
const response = await sdk.request({
27-
args: options,
28-
init,
29-
method: 'GET',
30-
path: `/${options.collection}/count`,
31-
})
30+
try {
31+
const response = await sdk.request({
32+
args: options,
33+
init,
34+
method: 'GET',
35+
path: `/${options.collection}/count`,
36+
})
37+
38+
if (response.ok) {
39+
return response.json()
40+
} else {
41+
throw new Error()
42+
}
43+
} catch {
44+
if (options.disableErrors) {
45+
return { totalDocs: 0 }
46+
}
3247

33-
return response.json()
48+
throw new Error(`Error counting documents in ${options.collection}`)
49+
}
3450
}

packages/sdk/src/collections/find.ts

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ export type FindOptions<
2323
* [Control auto-population](https://payloadcms.com/docs/queries/depth) of nested relationship and upload fields.
2424
*/
2525
depth?: number
26+
/**
27+
* When set to `true`, errors will not be thrown.
28+
*/
29+
disableErrors?: boolean
2630
/**
2731
* Whether the documents should be queried from the versions table/collection or not. [More](https://payloadcms.com/docs/versions/drafts#draft-api)
2832
*/
@@ -94,12 +98,34 @@ export async function find<
9498
options: FindOptions<T, TSlug, TSelect>,
9599
init?: RequestInit,
96100
): Promise<PaginatedDocs<TransformCollectionWithSelect<T, TSlug, TSelect>>> {
97-
const response = await sdk.request({
98-
args: options,
99-
init,
100-
method: 'GET',
101-
path: `/${options.collection}`,
102-
})
101+
try {
102+
const response = await sdk.request({
103+
args: options,
104+
init,
105+
method: 'GET',
106+
path: `/${options.collection}`,
107+
})
108+
109+
if (response.ok) {
110+
return response.json()
111+
} else {
112+
throw new Error()
113+
}
114+
} catch {
115+
if (options.disableErrors) {
116+
return {
117+
docs: [],
118+
hasNextPage: false,
119+
hasPrevPage: false,
120+
limit: 0,
121+
page: 1,
122+
pagingCounter: 1,
123+
prevPage: null,
124+
totalDocs: 0,
125+
totalPages: 1,
126+
}
127+
}
103128

104-
return response.json()
129+
throw new Error(`Error retrieving documents from ${options.collection}`)
130+
}
105131
}

packages/sdk/src/globals/findOne.ts

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { SelectType } from 'payload'
1+
import type { ApplyDisableErrors, SelectType } from 'payload'
22

33
import type { PayloadSDK } from '../index.js'
44
import type {
@@ -14,11 +14,18 @@ export type FindGlobalOptions<
1414
T extends PayloadGeneratedTypes,
1515
TSlug extends GlobalSlug<T>,
1616
TSelect extends SelectType,
17+
// TODO 4.0: place TDisableErrors above TSelect to match with other operations
18+
TDisableErrors extends boolean,
1719
> = {
1820
/**
1921
* [Control auto-population](https://payloadcms.com/docs/queries/depth) of nested relationship and upload fields.
2022
*/
2123
depth?: number
24+
/**
25+
* When set to `true`, errors will not be thrown.
26+
* `null` will be returned instead, if the document was not found.
27+
*/
28+
disableErrors?: TDisableErrors
2229
/**
2330
* Whether the document should be queried from the versions table/collection or not. [More](https://payloadcms.com/docs/versions/drafts#draft-api)
2431
*/
@@ -49,17 +56,31 @@ export async function findGlobal<
4956
T extends PayloadGeneratedTypes,
5057
TSlug extends GlobalSlug<T>,
5158
TSelect extends SelectFromGlobalSlug<T, TSlug>,
59+
TDisableErrors extends boolean = boolean,
5260
>(
5361
sdk: PayloadSDK<T>,
54-
options: FindGlobalOptions<T, TSlug, TSelect>,
62+
options: FindGlobalOptions<T, TSlug, TSelect, TDisableErrors>,
5563
init?: RequestInit,
56-
): Promise<TransformGlobalWithSelect<T, TSlug, TSelect>> {
57-
const response = await sdk.request({
58-
args: options,
59-
init,
60-
method: 'GET',
61-
path: `/globals/${options.slug}`,
62-
})
64+
): Promise<ApplyDisableErrors<TransformGlobalWithSelect<T, TSlug, TSelect>, TDisableErrors>> {
65+
try {
66+
const response = await sdk.request({
67+
args: options,
68+
init,
69+
method: 'GET',
70+
path: `/globals/${options.slug}`,
71+
})
72+
73+
if (response.ok) {
74+
return response.json()
75+
} else {
76+
throw new Error()
77+
}
78+
} catch {
79+
if (options.disableErrors) {
80+
// @ts-expect-error generic nullable
81+
return null
82+
}
6383

64-
return response.json()
84+
throw new Error(`Error retrieving global ${options.slug}`)
85+
}
6586
}

packages/sdk/src/index.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -209,10 +209,14 @@ export class PayloadSDK<T extends PayloadGeneratedTypes = PayloadGeneratedTypes>
209209
return findByID(this, options, init)
210210
}
211211

212-
findGlobal<TSlug extends GlobalSlug<T>, TSelect extends SelectFromGlobalSlug<T, TSlug>>(
213-
options: FindGlobalOptions<T, TSlug, TSelect>,
212+
findGlobal<
213+
TSlug extends GlobalSlug<T>,
214+
TSelect extends SelectFromGlobalSlug<T, TSlug>,
215+
TDisableErrors extends boolean,
216+
>(
217+
options: FindGlobalOptions<T, TSlug, TSelect, TDisableErrors>,
214218
init?: RequestInit,
215-
): Promise<TransformGlobalWithSelect<T, TSlug, TSelect>> {
219+
): Promise<ApplyDisableErrors<TransformGlobalWithSelect<T, TSlug, TSelect>, TDisableErrors>> {
216220
return findGlobal(this, options, init)
217221
}
218222

test/collections-rest/int.spec.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1754,6 +1754,19 @@ describe('collections-rest', () => {
17541754
payload.findByID({ collection: 'posts', id, disableErrors: true }),
17551755
).resolves.toBeNull()
17561756
})
1757+
1758+
it('find should support disableErrors: true', async () => {
1759+
const res = await payload.find({ collection: 'posts', disableErrors: true })
1760+
1761+
expect(res.docs).toHaveLength(0)
1762+
expect(res.totalDocs).toBe(0)
1763+
})
1764+
1765+
it('count should support disableErrors: true', async () => {
1766+
const res = await payload.count({ collection: 'posts', disableErrors: true })
1767+
1768+
expect(res.totalDocs).toEqual(0)
1769+
})
17571770
})
17581771

17591772
describe('Custom endpoints', () => {

test/globals/int.spec.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,15 @@ describe('globals', () => {
195195
expect(hasAccess.title).toBeDefined()
196196
})
197197

198+
it('should return null when finding non-existent global with disableErrors: true', async () => {
199+
const doc = await payload.findGlobal({
200+
slug,
201+
disableErrors: true,
202+
})
203+
204+
expect(doc).toBeNull()
205+
})
206+
198207
it('should get globals with defaultValues populated before first creation', async () => {
199208
const defaultValueGlobal = await payload.findGlobal({
200209
slug: defaultValueSlug,

test/sdk/int.spec.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,17 @@ describe('@payloadcms/sdk', () => {
5757
await payload.delete({ collection: 'posts', where: { id: { in: ids } } })
5858
})
5959

60+
it('should execute find with disableErrors: true', async () => {
61+
const result = await sdk.find({
62+
collection: 'posts',
63+
where: { id: { equals: 'non-existent-id' } },
64+
disableErrors: true,
65+
})
66+
67+
expect(result.docs).toHaveLength(0)
68+
expect(result.totalDocs).toBe(0)
69+
})
70+
6071
it('should execute findVersions', async () => {
6172
const result = await sdk.findVersions({
6273
collection: 'posts',
@@ -93,6 +104,16 @@ describe('@payloadcms/sdk', () => {
93104
expect(result.id).toBe(version.id)
94105
})
95106

107+
it('should execute findVersionByID with disableErrors: true', async () => {
108+
const result = await sdk.findVersionByID({
109+
collection: 'posts',
110+
id: 'non-existent-version-id',
111+
disableErrors: true,
112+
})
113+
114+
expect(result).toBeNull()
115+
})
116+
96117
it('should execute create', async () => {
97118
const result = await sdk.create({ collection: 'posts', data: { text: 'text' } })
98119

@@ -113,6 +134,15 @@ describe('@payloadcms/sdk', () => {
113134
expect(result.totalDocs).toBe(1)
114135
})
115136

137+
it('should execute count with disableErrors: true', async () => {
138+
const result = await sdk.count({
139+
collection: 'posts',
140+
where: { id: { equals: 'non-existent-id' } },
141+
disableErrors: true,
142+
})
143+
expect(result.totalDocs).toBe(0)
144+
})
145+
116146
it('should execute update (by ID)', async () => {
117147
const result = await sdk.update({
118148
collection: 'posts',
@@ -195,6 +225,14 @@ describe('@payloadcms/sdk', () => {
195225
expect(result.text).toBe('some-global')
196226
})
197227

228+
it('should execute findGlobal with disableErrors: true', async () => {
229+
const result = await sdk.findGlobal({
230+
slug: 'non-existent-global',
231+
disableErrors: true,
232+
})
233+
expect(result).toBeNull()
234+
})
235+
198236
it('should execute findGlobalVersions', async () => {
199237
const result = await sdk.findGlobalVersions({
200238
slug: 'global',
@@ -215,6 +253,16 @@ describe('@payloadcms/sdk', () => {
215253
expect(result.id).toBe(version.id)
216254
})
217255

256+
it('should execute findGlobalVersionByID with disableErrors: true', async () => {
257+
const result = await sdk.findGlobalVersionByID({
258+
id: 'non-existent-version-id',
259+
slug: 'global',
260+
disableErrors: true,
261+
})
262+
263+
expect(result).toBeNull()
264+
})
265+
218266
it('should execute updateGlobal', async () => {
219267
const result = await sdk.updateGlobal({ slug: 'global', data: { text: 'some-updated-global' } })
220268
expect(result.text).toBe('some-updated-global')

test/versions/int.spec.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,16 @@ describe('Versions', () => {
209209
expect(version.id).toStrictEqual(versionID)
210210
})
211211

212+
it('should return null when finding non-existent version via ID with disableErrors: true', async () => {
213+
const res = await payload.findVersionByID({
214+
collection: autosaveCollectionSlug,
215+
id: 'non-existent',
216+
disableErrors: true,
217+
})
218+
219+
expect(res).toBeNull()
220+
})
221+
212222
it('should allow a version to save locales properly', async () => {
213223
const englishTitle = 'Title in EN'
214224
const spanishTitle = 'Title in ES'
@@ -2212,6 +2222,15 @@ describe('Versions', () => {
22122222
expect(version_1_deleted).toBeFalsy()
22132223
})
22142224

2225+
it('should count global versions with disableErrors: true', async () => {
2226+
const res = await payload.countGlobalVersions({
2227+
global: 'draft-unlimited-global',
2228+
disableErrors: true,
2229+
})
2230+
2231+
expect(res.totalDocs).toEqual(0)
2232+
})
2233+
22152234
it('findGlobalVersions - pagination should work correctly', async () => {
22162235
for (let i = 0; i < 100; i++) {
22172236
await payload.updateGlobal({ slug: 'draft-unlimited-global', data: { title: 'title' } })

0 commit comments

Comments
 (0)