Skip to content

Commit

Permalink
fix: support signal on getDocument(s) to cancel requests (#881)
Browse files Browse the repository at this point in the history
* fix: support `signal` on `getDocument(s)` to cancel requests

* chore: prerelease
  • Loading branch information
stipsan authored Aug 14, 2024
1 parent ebe840b commit 13d71bb
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 26 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@sanity/client",
"version": "6.21.2",
"version": "6.21.3-canary.0",
"description": "Client for retrieving, creating and patching data from Sanity.io",
"keywords": [
"sanity",
Expand Down
4 changes: 2 additions & 2 deletions src/SanityClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -900,7 +900,7 @@ export class SanityClient {
*/
getDocument<R extends Record<string, Any> = Record<string, Any>>(
id: string,
options?: {tag?: string},
options?: {signal?: AbortSignal; tag?: string},
): Promise<SanityDocument<R> | undefined> {
return lastValueFrom(dataMethods._getDocument<R>(this, this.#httpRequest, id, options))
}
Expand All @@ -916,7 +916,7 @@ export class SanityClient {
*/
getDocuments<R extends Record<string, Any> = Record<string, Any>>(
ids: string[],
options?: {tag?: string},
options?: {signal?: AbortSignal; tag?: string},
): Promise<(SanityDocument<R> | null)[]> {
return lastValueFrom(dataMethods._getDocuments<R>(this, this.#httpRequest, ids, options))
}
Expand Down
18 changes: 14 additions & 4 deletions src/data/dataMethods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,14 @@ export function _getDocument<R extends Record<string, Any>>(
client: ObservableSanityClient | SanityClient,
httpRequest: HttpRequest,
id: string,
opts: {tag?: string} = {},
opts: {signal?: AbortSignal; tag?: string} = {},
): Observable<SanityDocument<R> | undefined> {
const options = {uri: _getDataUrl(client, 'doc', id), json: true, tag: opts.tag}
const options = {
uri: _getDataUrl(client, 'doc', id),
json: true,
tag: opts.tag,
signal: opts.signal,
}
return _requestObservable<SanityDocument<R> | undefined>(client, httpRequest, options).pipe(
filter(isResponse),
map((event) => event.body.documents && event.body.documents[0]),
Expand All @@ -143,9 +148,14 @@ export function _getDocuments<R extends Record<string, Any>>(
client: ObservableSanityClient | SanityClient,
httpRequest: HttpRequest,
ids: string[],
opts: {tag?: string} = {},
opts: {signal?: AbortSignal; tag?: string} = {},
): Observable<(SanityDocument<R> | null)[]> {
const options = {uri: _getDataUrl(client, 'doc', ids.join(',')), json: true, tag: opts.tag}
const options = {
uri: _getDataUrl(client, 'doc', ids.join(',')),
json: true,
tag: opts.tag,
signal: opts.signal,
}
return _requestObservable<(SanityDocument<R> | null)[]>(client, httpRequest, options).pipe(
filter(isResponse),
map((event: Any) => {
Expand Down
90 changes: 73 additions & 17 deletions test/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -893,28 +893,84 @@ describe('client', async () => {
}
})

test.skipIf(isEdge || typeof globalThis.AbortController === 'undefined')(
describe.skipIf(isEdge || typeof globalThis.AbortController === 'undefined')(
'can cancel request with an abort controller signal',
async () => {
expect.assertions(2)
() => {
test('client.fetch', async () => {
expect.assertions(2)

nock(projectHost()).get(`/v1/data/query/foo?query=*`).delay(100).reply(200, {
ms: 123,
query: '*',
result: [],
nock(projectHost()).get(`/v1/data/query/foo?query=*`).delay(100).reply(200, {
ms: 123,
query: '*',
result: [],
})

const abortController = new AbortController()
const promise = getClient().fetch('*', {}, {signal: abortController.signal})
await new Promise((resolve) => setTimeout(resolve, 10))

try {
abortController.abort()
await promise
} catch (err: any) {
expect(err).toBeInstanceOf(Error)
expect(err.name, 'should throw AbortError').toBe('AbortError')
}
})
test('client.getDocument', async () => {
expect.assertions(2)

nock(projectHost())
.get('/v1/data/doc/foo/abc123dfg')
.delay(100)
.reply(200, {
ms: 123,
documents: [{_id: 'abc123dfg', mood: 'lax'}],
})

const abortController = new AbortController()
const promise = getClient().getDocument('abc123dfg', {signal: abortController.signal})
await new Promise((resolve) => setTimeout(resolve, 10))

try {
abortController.abort()
await promise
} catch (err: any) {
if (err.name === 'AssertionError') throw err
expect(err).toBeInstanceOf(Error)
expect(err.name, 'should throw AbortError').toBe('AbortError')
}
})

const abortController = new AbortController()
const fetch = getClient().fetch('*', {}, {signal: abortController.signal})
await new Promise((resolve) => setTimeout(resolve, 10))
test('client.getDocuments', async () => {
expect.assertions(2)

nock(projectHost())
.get('/v1/data/doc/foo/abc123dfg,abc321dfg')
.delay(100)
.reply(200, {
ms: 123,
documents: [
{_id: 'abc123dfg', mood: 'lax'},
{_id: 'abc321dfg', mood: 'tense'},
],
})

try {
abortController.abort()
await fetch
} catch (err: any) {
expect(err).toBeInstanceOf(Error)
expect(err.name, 'should throw AbortError').toBe('AbortError')
}
const abortController = new AbortController()
const promise = getClient().getDocuments(['abc123dfg', 'abc321dfg'], {
signal: abortController.signal,
})
await new Promise((resolve) => setTimeout(resolve, 10))

try {
abortController.abort()
await promise
} catch (err: any) {
if (err.name === 'AssertionError') throw err
expect(err).toBeInstanceOf(Error)
expect(err.name, 'should throw AbortError').toBe('AbortError')
}
})
},
)

Expand Down

0 comments on commit 13d71bb

Please sign in to comment.