# Querystring & filter helpers The router includes powerful helpers for working with querystrings and filters in a reactive, type-safe way. ## Querystring helpers ### Basic setup Configure once in `main.js`: ```javascript import { configureQuerystring } from '@keenmate/svelte-spa-router/helpers/querystring' configureQuerystring({ arrayFormat: 'auto' // 'auto', 'repeat', or 'comma' }) ``` ### Using shared reactive querystring ```svelte handleSearch(e.target.value)} /> ``` ### Array format support The router automatically detects array formats: ```javascript // Auto-detect (default) - handles both formats // ?tags=foo&tags=bar → { tags: ['foo', 'bar'] } // ?tags=foo,bar,baz → { tags: ['foo', 'bar', 'baz'] } // Explicit repeat format configureQuerystring({ arrayFormat: 'repeat' }) // ?tags=foo&tags=bar // Explicit comma format configureQuerystring({ arrayFormat: 'comma' }) // ?tags=foo,bar,baz ``` ### Manual parsing (without configuration) ```javascript import { parseQuerystring, stringifyQuerystring } from '@keenmate/svelte-spa-router/helpers/querystring-helpers' // Parse const parsed = parseQuerystring('search=foo&tags=a,b,c', { arrayFormat: 'auto' }) // { search: 'foo', tags: ['a', 'b', 'c'] } // Stringify const qs = stringifyQuerystring({ search: 'foo', tags: ['a', 'b'] }, { arrayFormat: 'repeat' }) // 'search=foo&tags=a&tags=b' ``` ## Filter helpers The filter system supports both flat and structured filter modes for different API requirements. ### Flat mode (default) Each filter is a separate query parameter: ```javascript // main.js import { configureFilters } from '@keenmate/svelte-spa-router/helpers/filters' configureFilters({ mode: 'flat' }) ``` ```svelte ``` ### Structured mode (OData-style) Single filter parameter with custom syntax: ```javascript // main.js import { configureFilters } from '@keenmate/svelte-spa-router/helpers/filters' configureFilters({ mode: 'structured', paramName: '$filter', parse: (filterString) => { // Parse "displayName eq 'john' AND status eq 'active'" const parts = filterString.split(' AND ') const result = {} parts.forEach(part => { const [field, , value] = part.split(' ') result[field] = value.replace(/'/g, '') }) return result }, stringify: (filters) => { // Convert object to OData filter string return Object.entries(filters) .filter(([, v]) => v !== null && v !== undefined) .map(([k, v]) => `${k} eq '${v}'`) .join(' AND ') } }) ``` ```svelte ``` ### null vs undefined in filters ```javascript // undefined: Always removes the parameter await updateFilters({ search: undefined }) // Result: parameter removed from URL // null: Keeps parameter with empty value await updateFilters({ search: null }) // Result: ?search= // For querystring helpers, behavior is configurable: await updateQuerystring({ search: null }, { dropNull: true }) // Removes it (default) await updateQuerystring({ search: null }, { dropNull: false }) // Keeps as ?search=null ```