Skip to content

Commit

Permalink
feat(stega): allow setting stega options on client.fetch (#427)
Browse files Browse the repository at this point in the history
  • Loading branch information
stipsan authored Dec 12, 2023
1 parent 7324a1e commit 144fc2d
Show file tree
Hide file tree
Showing 10 changed files with 490 additions and 187 deletions.
10 changes: 5 additions & 5 deletions package-lock.json

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

8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@sanity/client",
"version": "6.9.3",
"version": "6.9.4-canary.1",
"description": "Client for retrieving, creating and patching data from Sanity.io",
"keywords": [
"sanity",
Expand Down Expand Up @@ -142,7 +142,7 @@
"@types/node": "^20.8.8",
"@typescript-eslint/eslint-plugin": "^6.14.0",
"@typescript-eslint/parser": "^6.14.0",
"@vitest/coverage-v8": "^1.0.4",
"@vitest/coverage-v8": "1.0.4",
"eslint": "^8.55.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.0.1",
Expand All @@ -158,8 +158,8 @@
"sse-channel": "^4.0.0",
"terser": "^5.26.0",
"typescript": "^5.3.3",
"vitest": "^1.0.4",
"vitest-github-actions-reporter": "^0.11.1"
"vitest": "1.0.4",
"vitest-github-actions-reporter": "0.11.1"
},
"engines": {
"node": ">=14.18"
Expand Down
5 changes: 5 additions & 0 deletions src/data/dataMethods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ export function _fetch<R, Q extends QueryParams>(
params?: Q,
options: FilteredResponseQueryOptions | UnfilteredResponseQueryOptions = {},
): Observable<RawQueryResponse<R> | R> {
if ('stega' in options && options['stega'] !== undefined && options['stega'] !== false) {
throw new Error(
`It looks like you're using options meant for '@sanity/client/stega'. Make sure you're using the right import. Or set 'stega' in 'fetch' to 'false'.`,
)
}
const mapResponse =
options.filterResponse === false ? (res: Any) => res : (res: Any) => res.result
const {cache, next, ...opts} = {
Expand Down
27 changes: 20 additions & 7 deletions src/stega/SanityStegaClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@ import type {
RawQueryResponse,
UnfilteredResponseQueryOptions,
} from '../types'
import {defaultStegaConfig, initStegaConfig, splitConfig} from './config'
import {
defaultStegaConfig,
initStegaConfig,
splitConfig,
splitStegaConfigFromFetchOptions,
} from './config'
import {stegaEncodeSourceMap} from './stegaEncodeSourceMap'
import {ClientStegaConfig, InitializedClientStegaConfig, InitializedStegaConfig} from './types'

Expand Down Expand Up @@ -120,9 +125,13 @@ export class ObservableSanityStegaClient extends INTERNAL_DO_NOT_USE_DIRECTLY_Ob
fetch<R, Q extends QueryParams>(
query: string,
params?: Q,
options: FilteredResponseQueryOptions | UnfilteredResponseQueryOptions = {},
_options: FilteredResponseQueryOptions | UnfilteredResponseQueryOptions = {},
): Observable<RawQueryResponse<R> | R> {
if (!this.stegaConfig.enabled) {
const {stegaConfig, fetchOptions: options} = splitStegaConfigFromFetchOptions(
_options,
this.stegaConfig,
)
if (!stegaConfig.enabled) {
return super.fetch<R, Q>(query, params, options as Any)
}
const {filterResponse: originalFilterResponse = true} = options
Expand All @@ -138,7 +147,7 @@ export class ObservableSanityStegaClient extends INTERNAL_DO_NOT_USE_DIRECTLY_Ob
.pipe(
map((res: Any) => {
const {result: _result, resultSourceMap} = res as RawQueryResponse<R>
const result = stegaEncodeSourceMap(_result, resultSourceMap, this.stegaConfig)
const result = stegaEncodeSourceMap(_result, resultSourceMap, stegaConfig)
return originalFilterResponse ? result : {...res, result}
}),
)
Expand Down Expand Up @@ -253,9 +262,13 @@ export class SanityStegaClient extends INTERNAL_DO_NOT_USE_DIRECTLY_SanityClient
fetch<R, Q extends QueryParams>(
query: string,
params?: Q,
options: FilteredResponseQueryOptions | UnfilteredResponseQueryOptions = {},
_options: FilteredResponseQueryOptions | UnfilteredResponseQueryOptions = {},
): Promise<RawQueryResponse<R> | R> {
if (!this.stegaConfig.enabled) {
const {stegaConfig, fetchOptions: options} = splitStegaConfigFromFetchOptions(
_options,
this.stegaConfig,
)
if (!stegaConfig.enabled) {
return super.fetch<R, Q>(query, params, options as Any)
}
const {filterResponse: originalFilterResponse = true} = options
Expand All @@ -270,7 +283,7 @@ export class SanityStegaClient extends INTERNAL_DO_NOT_USE_DIRECTLY_SanityClient
)
.then((res: Any) => {
const {result: _result, resultSourceMap} = res as RawQueryResponse<R>
const result = stegaEncodeSourceMap(_result, resultSourceMap, this.stegaConfig)
const result = stegaEncodeSourceMap(_result, resultSourceMap, stegaConfig)
return originalFilterResponse ? result : {...res, result}
})
}
Expand Down
23 changes: 22 additions & 1 deletion src/stega/config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import type {ClientConfig} from '../types'
import type {
ClientConfig,
FilteredResponseQueryOptions,
UnfilteredResponseQueryOptions,
} from '../types'
import type {ClientStegaConfig, InitializedStegaConfig, StegaConfig} from './types'

export const defaultStegaConfig: StegaConfig = {
Expand Down Expand Up @@ -53,3 +57,20 @@ export const initStegaConfig = (

return newConfig
}

export function splitStegaConfigFromFetchOptions(
options: (FilteredResponseQueryOptions | UnfilteredResponseQueryOptions) & {
stega?: boolean | StegaConfig
},
initializedStegaConfig: InitializedStegaConfig,
): {
fetchOptions: FilteredResponseQueryOptions | UnfilteredResponseQueryOptions
stegaConfig: InitializedStegaConfig
} {
const {stega = {}, ...fetchOptions} = options
const stegaConfig = initStegaConfig(
typeof stega === 'boolean' ? {enabled: stega} : stega,
initializedStegaConfig,
)
return {fetchOptions, stegaConfig}
}
9 changes: 9 additions & 0 deletions src/stega/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,12 @@ export type Encoder = (context: {
resultPath: ContentSourceMapParsedPath
value: string
}) => string

// Extends the `client.fetch` call with a `stega` option
declare module '../types' {
/** @public */
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export interface ResponseQueryOptions<T = 'next'> extends RequestOptions {
stega?: boolean | StegaConfig
}
}
2 changes: 1 addition & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -663,7 +663,7 @@ export interface ListenOptions {
}

/** @public */
export type ResponseQueryOptions<T = 'next'> = RequestOptions & {
export interface ResponseQueryOptions<T = 'next'> extends RequestOptions {
perspective?: ClientPerspective
resultSourceMap?: boolean | 'withKeyArraySelector'
cache?: RequestInit['cache']
Expand Down
61 changes: 61 additions & 0 deletions test/client.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import {ContentSourceMap, createClient} from '@sanity/client'
import {describe, expectTypeOf, test} from 'vitest'

describe('client.fetch', () => {
const client = createClient({})
test('simple query', async () => {
expectTypeOf(client.fetch('*')).toMatchTypeOf<Promise<any>>()
expectTypeOf(client.fetch('*[_type == $type]', {type: 'post'})).toMatchTypeOf<Promise<any>>()
})
test('generics', async () => {
expectTypeOf(client.fetch<number>('count(*)')).toMatchTypeOf<Promise<number>>()
expectTypeOf(
client.fetch<number, {type: string}>('count(*[_type == $type])', {type: 'post'}),
).toMatchTypeOf<Promise<number>>()
// @ts-expect-error -- should fail
expectTypeOf(client.fetch<number, {type: string}>('count(*[_type == $type])')).toMatchTypeOf<
Promise<number>
>()
expectTypeOf(
// @ts-expect-error -- should fail
client.fetch<number, {type: string}>('count(*[_type == $type])', {_type: 'post'}),
).toMatchTypeOf<Promise<number>>()
})
test('filterResponse: false', async () => {
expectTypeOf(client.fetch<number>('count(*)', {}, {filterResponse: true})).toMatchTypeOf<
Promise<number>
>()
expectTypeOf(client.fetch<number>('count(*)', {}, {filterResponse: false})).toMatchTypeOf<
Promise<{
result: number
ms: number
query: string
resultSourceMap?: ContentSourceMap
}>
>()
expectTypeOf(
client.fetch<number, {type: string}>(
'count(*[_type == $type])',
{type: 'post'},
{filterResponse: true},
),
).toMatchTypeOf<Promise<number>>()
expectTypeOf(
client.fetch<number, {type: string}>(
'count(*[_type == $type])',
{type: 'post'},
{filterResponse: false},
),
).toMatchTypeOf<
Promise<{
result: number
ms: number
query: string
resultSourceMap?: ContentSourceMap
}>
>()
})
test('stega: false', async () => {
expectTypeOf(client.fetch('*', {}, {stega: false})).toMatchTypeOf<Promise<any>>()
})
})
59 changes: 59 additions & 0 deletions test/stega/client.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import {SanityClient} from '@sanity/client'
import {ContentSourceMap, createClient, SanityStegaClient} from '@sanity/client/stega'
import {describe, expectTypeOf, test} from 'vitest'

describe('client.fetch', () => {
const client: SanityClient | SanityStegaClient = createClient({})
test('simple query', async () => {
expectTypeOf(client.fetch('*')).toMatchTypeOf<Promise<any>>()
expectTypeOf(client.fetch('*[_type == $type]', {type: 'post'})).toMatchTypeOf<Promise<any>>()
})
test('generics', async () => {
expectTypeOf(client.fetch<number>('count(*)')).toMatchTypeOf<Promise<number>>()
expectTypeOf(
client.fetch<number, {type: string}>('count(*[_type == $type])', {type: 'post'}),
).toMatchTypeOf<Promise<number>>()
// @ts-expect-error -- should fail
expectTypeOf(client.fetch<number, {type: string}>('count(*[_type == $type])')).toMatchTypeOf<
Promise<number>
>()
expectTypeOf(
// @ts-expect-error -- should fail
client.fetch<number, {type: string}>('count(*[_type == $type])', {_type: 'post'}),
).toMatchTypeOf<Promise<number>>()
})
test('filterResponse: false', async () => {
expectTypeOf(client.fetch<number>('count(*)', {}, {filterResponse: true})).toMatchTypeOf<
Promise<number>
>()
expectTypeOf(client.fetch<number>('count(*)', {}, {filterResponse: false})).toMatchTypeOf<
Promise<{
result: number
ms: number
query: string
resultSourceMap?: ContentSourceMap
}>
>()
expectTypeOf(
client.fetch<number, {type: string}>(
'count(*[_type == $type])',
{type: 'post'},
{filterResponse: true},
),
).toMatchTypeOf<Promise<number>>()
expectTypeOf(
client.fetch<number, {type: string}>(
'count(*[_type == $type])',
{type: 'post'},
{filterResponse: false},
),
).toMatchTypeOf<
Promise<{
result: number
ms: number
query: string
resultSourceMap?: ContentSourceMap
}>
>()
})
})
Loading

0 comments on commit 144fc2d

Please sign in to comment.