Skip to content

Commit

Permalink
feat: add support for returnQuery option, default to false (#545)
Browse files Browse the repository at this point in the history
  • Loading branch information
rexxars authored Feb 14, 2024
1 parent aebc569 commit dee015b
Show file tree
Hide file tree
Showing 7 changed files with 187 additions and 76 deletions.
26 changes: 26 additions & 0 deletions src/SanityClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,14 @@ import type {
QueryOptions,
QueryParams,
QueryWithoutParams,
RawQuerylessQueryResponse,
RawQueryResponse,
RawRequestOptions,
SanityDocument,
SanityDocumentStub,
SingleMutationResult,
UnfilteredResponseQueryOptions,
UnfilteredResponseWithoutQuery,
} from './types'
import {ObservableUsersClient, UsersClient} from './users/UsersClient'

Expand Down Expand Up @@ -160,6 +162,18 @@ export class ObservableSanityClient {
params: Q extends QueryWithoutParams ? QueryWithoutParams : Q,
options: UnfilteredResponseQueryOptions,
): Observable<RawQueryResponse<R>>
/**
* Perform a GROQ-query against the configured dataset.
*
* @param query - GROQ-query to perform
* @param params - Optional query parameters
* @param options - Request options
*/
fetch<R = Any, Q extends QueryWithoutParams | QueryParams = QueryParams>(
query: string,
params: Q extends QueryWithoutParams ? QueryWithoutParams : Q,
options: UnfilteredResponseWithoutQuery,
): Observable<RawQuerylessQueryResponse<R>>
fetch<R, Q>(
query: string,
params?: Q,
Expand Down Expand Up @@ -799,6 +813,18 @@ export class SanityClient {
params: Q extends QueryWithoutParams ? QueryWithoutParams : Q,
options: UnfilteredResponseQueryOptions,
): Promise<RawQueryResponse<R>>
/**
* Perform a GROQ-query against the configured dataset.
*
* @param query - GROQ-query to perform
* @param params - Optional query parameters
* @param options - Request options
*/
fetch<R = Any, Q extends QueryWithoutParams | QueryParams = QueryParams>(
query: string,
params: Q extends QueryWithoutParams ? QueryWithoutParams : Q,
options: UnfilteredResponseWithoutQuery,
): Promise<RawQuerylessQueryResponse<R>>
fetch<R, Q>(query: string, params?: Q, options?: QueryOptions): Promise<RawQueryResponse<R> | R> {
return lastValueFrom(
dataMethods._fetch<R, Q>(
Expand Down
13 changes: 12 additions & 1 deletion src/data/dataMethods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ export function _fetch<R, Q>(
const params = stega.enabled ? vercelStegaCleanAll(_params) : _params
const mapResponse =
options.filterResponse === false ? (res: Any) => res : (res: Any) => res.result

// Default to not returning the query, unless `filterResponse` is `false`,
// or `returnQuery` is explicitly set. `true` is the default in Content Lake, so skip if truthy
const returnQuery = options.filterResponse === false && options.returnQuery !== false

const {cache, next, ...opts} = {
// Opt out of setting a `signal` on an internal `fetch` if one isn't provided.
// This is necessary in React Server Components to avoid opting out of Request Memoization.
Expand All @@ -93,7 +98,13 @@ export function _fetch<R, Q>(
? {...opts, fetch: {cache, next}}
: opts

const $request = _dataRequest(client, httpRequest, 'query', {query, params}, reqOpts)
const $request = _dataRequest(
client,
httpRequest,
'query',
{query, params, options: {returnQuery}},
reqOpts,
)
return stega.enabled
? $request.pipe(
combineLatestWith(
Expand Down
5 changes: 4 additions & 1 deletion src/data/encodeQueryString.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const encodeQueryString = ({
}) => {
const searchParams = new URLSearchParams()
// We generally want tag at the start of the query string
const {tag, ...opts} = options
const {tag, returnQuery, ...opts} = options
// We're using `append` instead of `set` to support React Native: https://github.com/facebook/react-native/blob/1982c4722fcc51aa87e34cf562672ee4aff540f1/packages/react-native/Libraries/Blob/URL.js#L86-L88
if (tag) searchParams.append('tag', tag)
searchParams.append('query', query)
Expand All @@ -26,5 +26,8 @@ export const encodeQueryString = ({
if (value) searchParams.append(key, `${value}`)
}

// `returnQuery` is default `true`, so needs an explicit `false` handling
if (returnQuery === false) searchParams.append('returnQuery', 'false')

return `?${searchParams}`
}
29 changes: 28 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,8 @@ export interface QueryParams {
/** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */
resultSourceMap?: never
/** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */
returnQuery?: never
/** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */
signal?: never
/** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */
stega?: never
Expand Down Expand Up @@ -721,6 +723,7 @@ export interface ListenOptions {
export interface ResponseQueryOptions extends RequestOptions {
perspective?: ClientPerspective
resultSourceMap?: boolean | 'withKeyArraySelector'
returnQuery?: boolean
useCdn?: boolean
stega?: boolean | StegaConfig
// The `cache` and `next` options are specific to the Next.js App Router integration
Expand All @@ -736,10 +739,31 @@ export interface FilteredResponseQueryOptions extends ResponseQueryOptions {
/** @public */
export interface UnfilteredResponseQueryOptions extends ResponseQueryOptions {
filterResponse: false

/**
* When `filterResponse` is `false`, `returnQuery` also defaults to `true` for
* backwards compatibility (on the client side, not from the content lake API).
* Can also explicitly be set to `true`.
*/
returnQuery?: true
}

/**
* When using `filterResponse: false`, but you do not wish to receive back the query from
* the content lake API.
*
* @public
*/
export interface UnfilteredResponseWithoutQuery extends ResponseQueryOptions {
filterResponse: false
returnQuery: false
}

/** @public */
export type QueryOptions = FilteredResponseQueryOptions | UnfilteredResponseQueryOptions
export type QueryOptions =
| FilteredResponseQueryOptions
| UnfilteredResponseQueryOptions
| UnfilteredResponseWithoutQuery

/** @public */
export interface RawQueryResponse<R> {
Expand All @@ -749,6 +773,9 @@ export interface RawQueryResponse<R> {
resultSourceMap?: ContentSourceMap
}

/** @public */
export type RawQuerylessQueryResponse<R> = Omit<RawQueryResponse<R>, 'query'>

/** @internal */
export type BaseMutationOptions = RequestOptions & {
visibility?: 'sync' | 'async' | 'deferred'
Expand Down
15 changes: 14 additions & 1 deletion test-next/client.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
/// <reference types="next/types/global" />

import {createClient, QueryOptions, QueryParams, RawQueryResponse} from '@sanity/client'
import {
createClient,
type QueryOptions,
type QueryParams,
type RawQuerylessQueryResponse,
type RawQueryResponse,
} from '@sanity/client'
import {describe, expectTypeOf, test} from 'vitest'

describe('client.fetch', () => {
Expand Down Expand Up @@ -33,6 +39,13 @@ describe('client.fetch', () => {
{filterResponse: false, cache: 'force-cache', next: {revalidate: 60, tags: ['post']}},
),
).toMatchTypeOf<RawQueryResponse<any>>()
expectTypeOf(
await client.fetch(
'*[_type == $type]',
{type: 'post'},
{filterResponse: false, returnQuery: false},
),
).toMatchTypeOf<RawQuerylessQueryResponse<any>>()
})
test('generics', async () => {
expectTypeOf(
Expand Down
Loading

0 comments on commit dee015b

Please sign in to comment.