From b8dcc6f66a4d392f9f8d44ee4801150c3a513d57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Best?= Date: Wed, 30 Oct 2024 10:23:29 +0100 Subject: [PATCH] feat: Add support for urlKeys in cache (#725) * feat: Add support for urlKeys in cache This bridges the API gap for this feature, along with #720 which defines it for the serializer. * test: Add test case --- packages/docs/content/docs/server-side.mdx | 22 ++++++++++++ packages/nuqs/src/cache.test.ts | 42 ++++++++++++++++++++++ packages/nuqs/src/cache.ts | 8 +++-- 3 files changed, 70 insertions(+), 2 deletions(-) diff --git a/packages/docs/content/docs/server-side.mdx b/packages/docs/content/docs/server-side.mdx index bfd20833..2668abb6 100644 --- a/packages/docs/content/docs/server-side.mdx +++ b/packages/docs/content/docs/server-side.mdx @@ -128,3 +128,25 @@ export function Client() { // ... } ``` + +### Shorter search params keys + +Just like [`useQueryStates`](./batching#shorter-search-params-keys), you can +define a `urlKeys` object to map the variable names defined by the parser to +shorter keys in the URL. They will be translated on read and your codebase +can only refer to variable names that make sense for your domain or business logic. + +```ts title="searchParams.ts" +export const coordinatesParsers = { + // Use human-readable variable names throughout your codebase + latitude: parseAsFloat.withDefault(45.18), + longitude: parseAsFloat.withDefault(5.72) +} +export const coordinatesCache = createSearchParamsCache(coordinatesParsers, { + urlKeys: { + // Remap them to read from shorter keys in the URL + latitude: 'lat', + longitude: 'lng' + } +}) +``` diff --git a/packages/nuqs/src/cache.test.ts b/packages/nuqs/src/cache.test.ts index b7bb8a20..00346b9e 100644 --- a/packages/nuqs/src/cache.test.ts +++ b/packages/nuqs/src/cache.test.ts @@ -59,6 +59,48 @@ describe('cache', () => { // cache still works though expect(cache.all()).toBe(all) }) + + it('supports urlKeys', () => { + const cache = createSearchParamsCache( + { + string: parseAsString + }, + { + urlKeys: { + string: 'str' + } + } + ) + const parseOutput = cache.parse({ + str: 'this one is used', + string: 'not this one' + }) + expect(parseOutput.string).toBe('this one is used') + // @ts-expect-error - Making sure types & runtime are in sync + expect(parseOutput.str).toBeUndefined() + expect(cache.all().string).toBe('this one is used') + expect(cache.get('string')).toBe('this one is used') + }) + + it('supports partial urlKeys', () => { + const cache = createSearchParamsCache( + { + foo: parseAsString, + bar: parseAsString + }, + { + urlKeys: { + foo: 'f' + } + } + ) + const parseOutput = cache.parse({ + f: 'foo', + bar: 'bar' + }) + expect(parseOutput.foo).toBe('foo') + expect(parseOutput.bar).toBe('bar') + }) }) describe('compareSearchParams', () => { diff --git a/packages/nuqs/src/cache.ts b/packages/nuqs/src/cache.ts index 3329680c..df3df919 100644 --- a/packages/nuqs/src/cache.ts +++ b/packages/nuqs/src/cache.ts @@ -8,7 +8,10 @@ const $input: unique symbol = Symbol('Input') export function createSearchParamsCache< Parsers extends Record> ->(parsers: Parsers) { +>( + parsers: Parsers, + { urlKeys = {} }: { urlKeys?: Partial> } = {} +) { type Keys = keyof Parsers type ParsedSearchParams = { readonly [K in Keys]: inferParserType @@ -44,7 +47,8 @@ export function createSearchParamsCache< } for (const key in parsers) { const parser = parsers[key]! - c.searchParams[key] = parser.parseServerSide(searchParams[key]) + const urlKey = urlKeys[key] ?? key + c.searchParams[key] = parser.parseServerSide(searchParams[urlKey]) } c[$input] = searchParams return Object.freeze(c.searchParams) as ParsedSearchParams