From 8e450296c2dcfe47ad5095eb5693a0375d0c6dc4 Mon Sep 17 00:00:00 2001 From: David Brooke <38883189+dmbrooke@users.noreply.github.com> Date: Tue, 22 Aug 2023 15:50:20 -0400 Subject: [PATCH] Apply suggestions, improve UTs https://coveord.atlassian.net/browse/KIT-2684 --- ...less-core-search-parameter-manager.test.ts | 5 ++- .../headless-core-search-parameter-manager.ts | 34 ++++++------------- .../search-parameter-serializer.test.ts | 11 +++++- .../search-parameter-serializer.ts | 25 ++++++++------ 4 files changed, 40 insertions(+), 35 deletions(-) diff --git a/packages/headless/src/controllers/core/search-parameter-manager/headless-core-search-parameter-manager.test.ts b/packages/headless/src/controllers/core/search-parameter-manager/headless-core-search-parameter-manager.test.ts index 91353388b58..f376339901a 100644 --- a/packages/headless/src/controllers/core/search-parameter-manager/headless-core-search-parameter-manager.test.ts +++ b/packages/headless/src/controllers/core/search-parameter-manager/headless-core-search-parameter-manager.test.ts @@ -293,7 +293,10 @@ describe('search parameter manager', () => { }); it('is possible to access every relevant search parameter using #state.parameters given a certain initial state', () => { - const facetValues = [buildMockFacetValueRequest({state: 'selected'})]; + const facetValues = [ + buildMockFacetValueRequest({state: 'selected'}), + buildMockFacetValueRequest({state: 'excluded'}), + ]; engine.state.facetSet = { author: buildMockFacetSlice({ request: buildMockFacetRequest({currentValues: facetValues}), diff --git a/packages/headless/src/controllers/core/search-parameter-manager/headless-core-search-parameter-manager.ts b/packages/headless/src/controllers/core/search-parameter-manager/headless-core-search-parameter-manager.ts index 8afb58225b3..665a86fcc0d 100644 --- a/packages/headless/src/controllers/core/search-parameter-manager/headless-core-search-parameter-manager.ts +++ b/packages/headless/src/controllers/core/search-parameter-manager/headless-core-search-parameter-manager.ts @@ -129,8 +129,8 @@ export function getCoreActiveSearchParameters( ...getQ(state), ...getTab(state), ...getSortCriteria(state), - ...getSelectedFacets(state), - ...getExcludedFacets(state), + ...getFacets(state, getSelectedValues, 'f'), + ...getFacets(state, getExcludedValues, 'fExcluded'), ...getCategoryFacets(state), ...getNumericFacets(state), ...getDateFacets(state), @@ -186,36 +186,24 @@ function getSortCriteria(state: Partial) { return shouldInclude ? {sortCriteria} : {}; } -function getSelectedFacets(state: Partial) { - if (state.facetSet === undefined) { - return {}; - } - - const f = Object.entries(state.facetSet) - .filter(([facetId]) => state.facetOptions?.facets[facetId]?.enabled ?? true) - .map(([facetId, {request}]) => { - const selectedValues = getSelectedValues(request.currentValues); - return selectedValues.length ? {[facetId]: selectedValues} : {}; - }) - .reduce((acc, obj) => ({...acc, ...obj}), {}); - - return Object.keys(f).length ? {f} : {}; -} - -function getExcludedFacets(state: Partial) { +function getFacets( + state: Partial, + valuesSelector: (currentValues: FacetValueRequest[]) => string[], + out: keyof SearchParameters +) { if (state.facetSet === undefined) { return {}; } - const fExcluded = Object.entries(state.facetSet) + const facets = Object.entries(state.facetSet) .filter(([facetId]) => state.facetOptions?.facets[facetId]?.enabled ?? true) .map(([facetId, {request}]) => { - const excludedValues = getExcludedValues(request.currentValues); - return excludedValues.length ? {[facetId]: excludedValues} : {}; + const facetValues = valuesSelector(request.currentValues); + return facetValues.length ? {[facetId]: facetValues} : {}; }) .reduce((acc, obj) => ({...acc, ...obj}), {}); - return Object.keys(fExcluded).length ? {fExcluded} : {}; + return Object.keys(facets).length ? {[out]: facets} : {}; } function getSelectedValues(values: FacetValueRequest[]) { diff --git a/packages/headless/src/features/search-parameters/search-parameter-serializer.test.ts b/packages/headless/src/features/search-parameters/search-parameter-serializer.test.ts index 1a4489c96e3..8716210e05d 100644 --- a/packages/headless/src/features/search-parameters/search-parameter-serializer.test.ts +++ b/packages/headless/src/features/search-parameters/search-parameter-serializer.test.ts @@ -478,6 +478,7 @@ describe('buildSearchParameterSerializer', () => { it('can serialize and deserialize all search parameters', () => { const f = {author: ['a', 'b']}; + const fExcluded = {source: ['a', 'b']}; const cf = {geography: ['a', 'b']}; const nf = { size: [buildNumericRange({start: 0, end: 10, state: 'selected'})], @@ -493,7 +494,15 @@ describe('buildSearchParameterSerializer', () => { }; const sf = {fileType: ['a', 'b']}; const af = {documenttype: ['s', 'sd']}; - const parameters = buildMockSearchParameters({f, cf, nf, df, sf, af}); + const parameters = buildMockSearchParameters({ + f, + cf, + nf, + df, + sf, + af, + fExcluded, + }); const {serialize, deserialize} = buildSearchParameterSerializer(); const serialized = serialize(parameters); diff --git a/packages/headless/src/features/search-parameters/search-parameter-serializer.ts b/packages/headless/src/features/search-parameters/search-parameter-serializer.ts index de7a76f78d8..d5e15fac1db 100644 --- a/packages/headless/src/features/search-parameters/search-parameter-serializer.ts +++ b/packages/headless/src/features/search-parameters/search-parameter-serializer.ts @@ -127,16 +127,16 @@ function serializeRangeFacets( function deserialize(fragment: string): SearchParameters { const parts = fragment.split(delimiter); - const keyValuePairs = parts + const test = parts .map((part) => splitOnFirstEqual(part)) - .map(preprocessObjectPairs) - .filter(isValidPair) - .map(cast); + .map(preprocessObjectPairs); + + const keyValuePairs = test.filter(isValidPair).map(cast); return keyValuePairs.reduce((acc: SearchParameters, pair) => { const [key, val] = pair; - if (keyHasObjectValue(key)) { + if (keyHasObjectValue(key) || isSpecificFacetKey(key)) { const mergedValues = {...acc[key], ...(val as object)}; return {...acc, [key]: mergedValues}; } @@ -154,7 +154,7 @@ function splitOnFirstEqual(str: string) { function preprocessObjectPairs(pair: string[]) { const [key, val] = pair; - const objectKey = /^(f|cf|nf|df|sf|af)-(.+)$/; + const objectKey = /^(f|fExcluded|cf|nf|df|sf|af)-(.+)$/; const result = objectKey.exec(key); if (!result) { @@ -289,7 +289,7 @@ function cast(pair: [K, string]): [K, unknown] { return [key, parseInt(value)]; } - if (keyHasObjectValue(key)) { + if (keyHasObjectValue(key) || isSpecificFacetKey(key)) { return [key, castUnknownObject(value)]; } @@ -307,10 +307,15 @@ function castUnknownObject(value: string) { return ret; } -function keyHasObjectValue( +function keyHasObjectValue(key: SearchParameterKey): key is 'af' | 'sf' { + const keys = ['af', 'sf']; + return keys.includes(key); +} + +function isSpecificFacetKey( key: SearchParameterKey -): key is 'f' | 'fExcluded' | 'cf' | 'nf' | 'df' | 'sf' | 'af' { - const keys = ['f', 'fExcluded', 'cf', 'nf', 'df', 'sf', 'af']; +): key is 'f' | 'cf' | 'df' | 'nf' | 'fExcluded' { + const keys = ['f', 'cf', 'df', 'nf', 'fExcluded']; return keys.includes(key); }