From 73c2a86ca1f42342b31dd2b232e220985de59369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Desboeufs?= Date: Thu, 13 Nov 2025 10:19:00 +0100 Subject: [PATCH] feat: pass filter arrays natively to addok API - Remove filter value concatenation with '+' separator - Pass array filter values directly to addok Python API - Simplify bridge.py by removing prepare_filters function - Merge formatFilterValue into validateFilters - Filter out empty arrays from validated filters - Update documentation to clarify new behavior --- README.md | 2 ++ lib/params.js | 38 +++++++++++++++++--------------------- test/params.js | 38 +++++++++++++------------------------- 3 files changed, 32 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index b3ef5af..84eea3e 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,8 @@ const params = { } ``` +**Note:** This requires addok to support array values in filters. Make sure your addok version supports the new filter API. + ### Reverse geocode ```js diff --git a/lib/params.js b/lib/params.js index 08c4869..6ee78f5 100644 --- a/lib/params.js +++ b/lib/params.js @@ -56,26 +56,6 @@ export function validateLonLat(lon, lat) { return [lon, lat] } -export function formatFilterValue(value) { - if (typeof value === 'string') { - return value - } - - if (Array.isArray(value)) { - // Validate that all elements are strings - for (const item of value) { - if (typeof item !== 'string') { - throw createError(400, 'filter values must be strings or arrays of strings') - } - } - - // Join with '+' separator for addok multi-value filters - return value.join('+') - } - - throw createError(400, 'filter values must be strings or arrays of strings') -} - export function validateFilters(filters) { if (typeof filters !== 'object' || Array.isArray(filters)) { throw createError(400, 'filters are not valid') @@ -84,7 +64,23 @@ export function validateFilters(filters) { const validatedFilters = {} for (const [key, value] of Object.entries(pickBy(filters))) { - validatedFilters[key] = formatFilterValue(value) + // Validate that value is either a string or an array of strings + if (typeof value === 'string') { + validatedFilters[key] = value + } else if (Array.isArray(value)) { + // Skip empty arrays + if (value.length === 0) { + continue + } + + if (!value.every(item => typeof item === 'string')) { + throw createError(400, 'filter values must be strings or arrays of strings') + } + + validatedFilters[key] = value + } else { + throw createError(400, 'filter values must be strings or arrays of strings') + } } return validatedFilters diff --git a/test/params.js b/test/params.js index c240e56..d141421 100644 --- a/test/params.js +++ b/test/params.js @@ -6,7 +6,6 @@ import { validateLimit, validateAutocomplete, validateLonLat, - formatFilterValue, validateFilters, validateParams } from '../lib/params.js' @@ -81,36 +80,17 @@ test('validateFilters', t => { t.throws(() => validateFilters('a'), {message: 'filters are not valid'}) }) -test('formatFilterValue', t => { - // String values (backward compatibility) - t.is(formatFilterValue('bar'), 'bar') - t.is(formatFilterValue('75001'), '75001') - - // Array values (new feature) - t.is(formatFilterValue(['bar', 'baz']), 'bar+baz') - t.is(formatFilterValue(['75001', '75002', '75003']), '75001+75002+75003') - t.is(formatFilterValue(['single']), 'single') - - // Empty array - t.is(formatFilterValue([]), '') - - // Invalid values - t.throws(() => formatFilterValue(123), {message: 'filter values must be strings or arrays of strings'}) - t.throws(() => formatFilterValue(['valid', 123]), {message: 'filter values must be strings or arrays of strings'}) - t.throws(() => formatFilterValue({foo: 'bar'}), {message: 'filter values must be strings or arrays of strings'}) -}) - test('validateFilters with array values', t => { // Single string values (backward compatibility) t.deepEqual(validateFilters({postcode: '75001'}), {postcode: '75001'}) - // Array values - t.deepEqual(validateFilters({postcode: ['75001', '75002']}), {postcode: '75001+75002'}) + // Array values - preserved as arrays + t.deepEqual(validateFilters({postcode: ['75001', '75002']}), {postcode: ['75001', '75002']}) t.deepEqual(validateFilters({ postcode: ['75001', '75002'], citycode: '75056' }), { - postcode: '75001+75002', + postcode: ['75001', '75002'], citycode: '75056' }) @@ -120,12 +100,20 @@ test('validateFilters with array values', t => { postcode: ['75001', '75002', '75003'] }), { type: 'street', - postcode: '75001+75002+75003' + postcode: ['75001', '75002', '75003'] }) + // Single item array + t.deepEqual(validateFilters({postcode: ['75001']}), {postcode: ['75001']}) + + // Empty array - should be ignored + t.deepEqual(validateFilters({postcode: []}), {}) + t.deepEqual(validateFilters({postcode: [], type: 'street'}), {type: 'street'}) + // Invalid filter values t.throws(() => validateFilters({postcode: 123}), {message: 'filter values must be strings or arrays of strings'}) t.throws(() => validateFilters({postcode: ['valid', 123]}), {message: 'filter values must be strings or arrays of strings'}) + t.throws(() => validateFilters({postcode: {foo: 'bar'}}), {message: 'filter values must be strings or arrays of strings'}) }) test('validateParams / all params', t => { @@ -157,7 +145,7 @@ test('validateParams / filters with array values', t => { }), { q: 'rue de la paix', filters: { - postcode: '75001+75002', + postcode: ['75001', '75002'], type: 'street' } })