diff --git a/packages/core/src/client/utils.ts b/packages/core/src/client/utils.ts index 8d5bb94..d60df42 100644 --- a/packages/core/src/client/utils.ts +++ b/packages/core/src/client/utils.ts @@ -7,33 +7,35 @@ import type { QueryParameters } from './types/types.ts' * - It will skip the key/value if value is `null` or `undefined` */ export function buildSearchParams(query: QueryParameters) { - if (!query) return + if (!query) return '' let stringified = '' - const append = ( - key: string, - value: string | number | boolean | null | undefined, - isArray = false, - ) => { - if (value === undefined || value === null) return - const encodedKey = encodeURIComponent(key) - const encodedValue = encodeURIComponent(value) - const keyValuePair = `${encodedKey}${isArray ? '[]' : ''}=${encodedValue}` + const append = (key: string, value?: string | number | boolean | null) => { + if (value === undefined || value === null) return - stringified += (stringified ? '&' : '?') + keyValuePair + stringified += + (stringified ? '&' : '?') + encodeURIComponent(key) + '=' + encodeURIComponent(value) } - for (const [key, value] of Object.entries(query)) { - if (!value) continue + const build = (obj: QueryParameters, prefix = '') => { + for (const [key, value] of Object.entries(obj)) { + if (value === undefined || value === null) continue - if (Array.isArray(value)) { - for (const v of value) append(key, v, true) - } else { - append(key, `${value}`) + const fullKey = prefix ? `${prefix}[${key}]` : key + + if (Array.isArray(value)) { + value.forEach((v) => append(`${fullKey}[]`, v)) + } else if (typeof value === 'object') { + build(value, fullKey) + } else { + append(fullKey, value) + } } } + build(query) + return stringified } diff --git a/packages/core/tests/client.spec.ts b/packages/core/tests/client.spec.ts index 3a38e6d..201ea4f 100644 --- a/packages/core/tests/client.spec.ts +++ b/packages/core/tests/client.spec.ts @@ -4,6 +4,7 @@ import { test } from '@japa/runner' import { createTuyau } from '../src/client/tuyau.ts' import { defaultRegistry as registry } from './fixtures/index.ts' import { TuyauHTTPError, TuyauNetworkError } from '../src/client/errors.ts' +import { buildSearchParams } from '../src/client/utils.ts' const createTestTuyau = (baseUrl: string = 'http://localhost:3333') => createTuyau({ baseUrl, registry }) @@ -429,3 +430,17 @@ test.group('Client | url', () => { assert.equal(r2.id, '1') }) }) + +test.group('Client | buildSearchParams', () => { + test('pass query params as nested object', async ({ assert }) => { + const queryParams = buildSearchParams({ + filter: { + // @ts-expect-error + name: { like: 'foo' }, + price: { gte: 1200 }, + }, + }) + + assert.equal(decodeURIComponent(queryParams), '?filter[name][like]=foo&filter[price][gte]=1200') + }) +}) \ No newline at end of file