Skip to content

Commit

Permalink
feat: add shouldCacheResult option
Browse files Browse the repository at this point in the history
  • Loading branch information
nkgentile committed Nov 3, 2024
1 parent 9017680 commit 323cc8e
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 49 deletions.
30 changes: 21 additions & 9 deletions package/src/context.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type {QueryStore} from '@sanity/react-loader'
import {CacheShort, WithCache} from '@shopify/hydrogen'
import {CacheShort, type WithCache} from '@shopify/hydrogen'
import groq from 'groq'
import {beforeEach, describe, expect, it, vi} from 'vitest'

Expand All @@ -25,9 +25,11 @@ let withCache = vi.hoisted<WithCache | null>(() => null)

vi.mock('@shopify/hydrogen', async (importOriginal) => {
const module = await importOriginal<typeof import('@shopify/hydrogen')>()
withCache = vi
.fn()
.mockImplementation(module.createWithCache({cache, waitUntil: () => Promise.resolve()}))
withCache = module.createWithCache({
cache,
waitUntil: () => Promise.resolve(),
request: new Request('https://example.com'),
})

return {
...module,
Expand All @@ -44,6 +46,8 @@ vi.mock('@sanity/react-loader', async (importOriginal) => {
}
})

const runWithCache = vi.spyOn(withCache!, 'run')

const client = createClient({projectId: 'my-project-id', dataset: 'my-dataset'})

const query = groq`true`
Expand Down Expand Up @@ -73,17 +77,25 @@ describe('the Sanity request context', () => {
})

await contextWithDefaultStrategy.loadQuery<boolean>(query, params)
expect(withCache).toHaveBeenCalledWith(hashedQuery, defaultStrategy, expect.any(Function))
expect(cache.put).toHaveBeenCalled()
expect(runWithCache).toHaveBeenNthCalledWith(
1,
expect.objectContaining({cacheKey: hashedQuery, cacheStrategy: defaultStrategy}),
expect.any(Function),
)
expect(cache.put).toHaveBeenCalledOnce()
})

it('queries should use the cache strategy passed in `loadQuery`', async () => {
const strategy = CacheShort()
await sanityContext.loadQuery<boolean>(query, params, {
hydrogen: {cache: strategy},
})
expect(withCache).toHaveBeenCalledWith(hashedQuery, strategy, expect.any(Function))
expect(cache.put).toHaveBeenCalled()
expect(runWithCache).toHaveBeenNthCalledWith(
1,
expect.objectContaining({cacheKey: hashedQuery, cacheStrategy: strategy}),
expect.any(Function),
)
expect(cache.put).toHaveBeenCalledOnce()
})
})

Expand Down Expand Up @@ -122,6 +134,6 @@ describe('when configured for preview', () => {
it(`shouldn't cache queries`, async () => {
await previewContext.loadQuery<boolean>(query)
expect(loadQuery).toHaveBeenCalledOnce()
expect(cache.put).not.toHaveBeenCalled()
expect(cache.put).not.toHaveBeenCalledOnce()
})
})
48 changes: 32 additions & 16 deletions package/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,18 @@ type HydrogenResponseQueryOptions = Omit<ResponseQueryOptions, 'next' | 'cache'>
hydrogen?: 'hydrogen' extends keyof RequestInit ? RequestInit['hydrogen'] : never
}

type LoadQueryOptions = Pick<
type LoadQueryOptions<T> = Pick<
HydrogenResponseQueryOptions,
'perspective' | 'hydrogen' | 'useCdn' | 'stega' | 'headers' | 'tag'
>
> & {
hydrogen?: {
/**
* Whether to cache the result of the query or not.
* @default () => true
*/
shouldCacheResult?: (value: QueryResponseInitial<T>) => boolean
}
}

export type SanityContext = {
/**
Expand All @@ -76,7 +84,7 @@ export type SanityContext = {
loadQuery<T = any>(
query: string,
params?: QueryParams,
options?: LoadQueryOptions,
options?: LoadQueryOptions<T>,
): Promise<QueryResponseInitial<T>>

client: SanityClient
Expand Down Expand Up @@ -125,7 +133,7 @@ export function createSanityContext(options: CreateSanityContextOptions): Sanity
async loadQuery<T>(
query: string,
params: QueryParams | QueryWithoutParams,
loaderOptions?: LoadQueryOptions,
loaderOptions?: LoadQueryOptions<T>,
): Promise<QueryResponseInitial<T>> {
// Don't store response if preview is enabled
const cacheStrategy =
Expand All @@ -134,20 +142,28 @@ export function createSanityContext(options: CreateSanityContextOptions): Sanity
: loaderOptions?.hydrogen?.cache || defaultStrategy || DEFAULT_CACHE_STRATEGY

const queryHash = await hashQuery(query, params)
const shouldCacheResult = loaderOptions?.hydrogen?.shouldCacheResult ?? (() => true)

return await (withCache
? withCache(queryHash, cacheStrategy, async ({addDebugData}) => {
if (process.env.NODE_ENV === 'development') {
// Name displayed in the subrequest profiler
const displayName = loaderOptions?.hydrogen?.debug?.displayName || 'query Sanity'

addDebugData({
displayName,
})
}

return await loadQuery<T>(query, params, loaderOptions)
})
? withCache.run(
{
cacheKey: queryHash,
cacheStrategy,
shouldCacheResult,
},
async ({addDebugData}) => {
if (process.env.NODE_ENV === 'development') {
// Name displayed in the subrequest profiler
const displayName = loaderOptions?.hydrogen?.debug?.displayName || 'query Sanity'

addDebugData({
displayName,
})
}

return await loadQuery<T>(query, params, loaderOptions)
},
)
: loadQuery<T>(query, params, loaderOptions))
},
client,
Expand Down
22 changes: 15 additions & 7 deletions package/src/loader.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ function waitUntil() {
return Promise.resolve()
}

type WithCache = ReturnType<typeof createWithCache>
const withCache: WithCache = vi.fn().mockImplementation(createWithCache({cache, waitUntil}))
const withCache = createWithCache({cache, waitUntil, request: new Request('https://example.com')})
const runWithCache = vi.spyOn(withCache, 'run')

const client = createClient({projectId: 'my-project-id', dataset: 'my-dataset'})

Expand Down Expand Up @@ -63,15 +63,23 @@ describe('the loader', () => {
})

await loaderWithDefaultStrategy.loadQuery<boolean>(query, params)
expect(withCache).toHaveBeenCalledWith(hashedQuery, strategy, expect.any(Function))
expect(cache.put).toHaveBeenCalled()
expect(runWithCache).toHaveBeenNthCalledWith(
1,
expect.objectContaining({cacheKey: hashedQuery, cacheStrategy: strategy}),
expect.any(Function),
)
expect(cache.put).toHaveBeenCalledOnce()
})

it('queries should use the cache strategy passed in `loadQuery`', async () => {
const strategy = CacheShort()
await loader.loadQuery<boolean>(query, params, {hydrogen: {cache: strategy}})
expect(withCache).toHaveBeenCalledWith(hashedQuery, strategy, expect.any(Function))
expect(cache.put).toHaveBeenCalled()
expect(runWithCache).toHaveBeenNthCalledWith(
1,
expect.objectContaining({cacheKey: hashedQuery, cacheStrategy: strategy}),
expect.any(Function),
)
expect(cache.put).toHaveBeenCalledOnce()
})
})

Expand Down Expand Up @@ -108,6 +116,6 @@ describe('when configured for preview', () => {
it(`shouldn't cache queries`, async () => {
await previewLoader.loadQuery<boolean>(query)
expect(loadQuery).toHaveBeenCalledOnce()
expect(cache.put).not.toHaveBeenCalled()
expect(cache.put).not.toHaveBeenCalledOnce()
})
})
51 changes: 34 additions & 17 deletions package/src/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,18 @@ type HydrogenResponseQueryOptions = Omit<ResponseQueryOptions, 'next' | 'cache'>
hydrogen?: 'hydrogen' extends keyof RequestInit ? RequestInit['hydrogen'] : never
}

type LoadQueryOptions = Pick<
type LoadQueryOptions<T> = Pick<
HydrogenResponseQueryOptions,
'perspective' | 'hydrogen' | 'useCdn' | 'stega' | 'headers' | 'tag'
>
> & {
hydrogen?: {
/**
* Whether to cache the result of the query or not.
* @default () => true
*/
shouldCacheResult?: (value: QueryResponseInitial<T>) => boolean
}
}

export type SanityLoader = {
/**
Expand All @@ -75,7 +83,7 @@ export type SanityLoader = {
loadQuery<T = any>(
query: string,
params?: QueryParams,
options?: LoadQueryOptions,
options?: LoadQueryOptions<T>,
): Promise<QueryResponseInitial<T>>

client: SanityClient
Expand Down Expand Up @@ -123,7 +131,7 @@ export function createSanityLoader(options: CreateSanityLoaderOptions): SanityLo
async loadQuery<T>(
query: string,
params: QueryParams | QueryWithoutParams,
loaderOptions?: LoadQueryOptions,
loaderOptions?: LoadQueryOptions<T>,
): Promise<QueryResponseInitial<T>> {
// Don't store response if preview is enabled
const cacheStrategy =
Expand All @@ -133,19 +141,28 @@ export function createSanityLoader(options: CreateSanityLoaderOptions): SanityLo

const queryHash = await hashQuery(query, params)

return await withCache(queryHash, cacheStrategy, async ({addDebugData}) => {
// eslint-disable-next-line no-process-env
if (process.env.NODE_ENV === 'development') {
// Name displayed in the subrequest profiler
const displayName = loaderOptions?.hydrogen?.debug?.displayName || 'query Sanity'

addDebugData({
displayName,
})
}

return await loadQuery<T>(query, params, loaderOptions)
})
const shouldCacheResult = loaderOptions?.hydrogen?.shouldCacheResult ?? (() => true)

return await withCache.run(
{
cacheKey: queryHash,
cacheStrategy,
shouldCacheResult,
},
async ({addDebugData}) => {
// eslint-disable-next-line no-process-env
if (process.env.NODE_ENV === 'development') {
// Name displayed in the subrequest profiler
const displayName = loaderOptions?.hydrogen?.debug?.displayName || 'query Sanity'

addDebugData({
displayName,
})
}

return await loadQuery<T>(query, params, loaderOptions)
},
)
},
client,
preview,
Expand Down

0 comments on commit 323cc8e

Please sign in to comment.