Skip to content

Commit

Permalink
feat(headless): support resultsMustMatch parameter on facet request (
Browse files Browse the repository at this point in the history
  • Loading branch information
y-lakhdar authored Sep 12, 2023
1 parent 6b5fb82 commit fe40054
Show file tree
Hide file tree
Showing 27 changed files with 96 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import {Schema, StringValue} from '@coveo/bueno';
import {
FacetResultsMustMatch,
facetResultsMustMatch,
} from '../../../../features/facets/facet-api/request';
import {
facetSortCriteria,
FacetSortCriterion,
Expand Down Expand Up @@ -62,6 +66,13 @@ export interface FacetOptions {
* @defaultValue `automatic`
*/
sortCriteria?: FacetSortCriterion;

/**
* The criterion to use for specifying how results must match the selected facet values.
*
* @defaultValue `atLeastOneValue`
*/
resultsMustMatch?: FacetResultsMustMatch;
}

export interface FacetSearchOptions {
Expand Down Expand Up @@ -90,5 +101,6 @@ export const facetOptionsSchema = new Schema<Required<FacetOptions>>({
injectionDepth,
numberOfValues,
sortCriteria: new StringValue({constrainTo: facetSortCriteria}),
resultsMustMatch: new StringValue({constrainTo: facetResultsMustMatch}),
facetSearch,
});
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ describe('facet', () => {
const action = registerFacet({
field: 'author',
sortCriteria: 'score',
resultsMustMatch: 'atLeastOneValue',
facetId,
filterFacetCount: true,
injectionDepth: 1000,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -481,10 +481,13 @@ export function buildCoreFacet(
);
const canShowMoreValues = response ? response.moreValuesAvailable : false;

const resultsMustMatch = request.resultsMustMatch;

return {
facetId,
values,
sortCriterion,
resultsMustMatch,
isLoading,
hasActiveValues,
canShowMoreValues,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export function buildCoreRangeFacet<
| undefined;

const sortCriterion = request.sortCriteria;
const resultsMustMatch = request.resultsMustMatch;
const values: R['values'] = response ? response.values : [];
const isLoading = isFacetLoadingResponseSelector(engine.state);
const enabled = getIsEnabled();
Expand All @@ -98,6 +99,7 @@ export function buildCoreRangeFacet<
facetId,
values,
sortCriterion,
resultsMustMatch,
hasActiveValues,
isLoading,
enabled,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import {
StringValue,
} from '@coveo/bueno';
import {CoreEngine} from '../../../../../app/engine';
import {
FacetResultsMustMatch,
facetResultsMustMatch,
} from '../../../../../features/facets/facet-api/request';
import {facetValueStates} from '../../../../../features/facets/facet-api/value';
import {
rangeFacetRangeAlgorithm,
Expand Down Expand Up @@ -99,6 +103,13 @@ export interface NumericFacetOptions {
*/
sortCriteria?: RangeFacetSortCriterion;

/**
* The criterion to use for specifying how results must match the selected facet values.
*
* @defaultValue `atLeastOneValue`
*/
resultsMustMatch?: FacetResultsMustMatch;

/**
* The algorithm that's used for generating the ranges of this facet when they aren't manually defined. The default value of `"even"` generates equally sized facet ranges across all of the results. The value `"equiprobable"` generates facet ranges which vary in size but have a more balanced number of results within each range.
*
Expand Down Expand Up @@ -127,6 +138,7 @@ export const numericFacetOptionsSchema = new Schema<
each: new RecordValue({values: numericRangeRequestDefinition}),
}),
sortCriteria: new StringValue({constrainTo: rangeFacetSortCriteria}),
resultsMustMatch: new StringValue({constrainTo: facetResultsMustMatch}),
rangeAlgorithm: new StringValue({constrainTo: rangeFacetRangeAlgorithm}),
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import {Schema, StringValue} from '@coveo/bueno';
import {
FacetResultsMustMatch,
facetResultsMustMatch,
} from '../../../features/facets/facet-api/request';
import {
facetSortCriteria,
FacetSortCriterion,
Expand Down Expand Up @@ -66,6 +70,13 @@ export interface FacetOptions {
*/
sortCriteria?: FacetSortCriterion;

/**
* The criterion to use for specifying how results must match the selected facet values.
*
* @defaultValue `atLeastOneValue`
*/
resultsMustMatch?: FacetResultsMustMatch;

/**
* Specifies an explicit list of `allowedValues` in the Search API request.
*
Expand Down Expand Up @@ -123,6 +134,7 @@ export const facetOptionsSchema = new Schema<Required<FacetOptions>>({
injectionDepth,
numberOfValues,
sortCriteria: new StringValue({constrainTo: facetSortCriteria}),
resultsMustMatch: new StringValue({constrainTo: facetResultsMustMatch}),
facetSearch,
allowedValues,
hasBreadcrumbs,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ describe('facet', () => {
const action = registerFacet({
field: 'author',
sortCriteria: 'score',
resultsMustMatch: 'atLeastOneValue',
facetId,
filterFacetCount: true,
injectionDepth: 1000,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {Schema, StringValue} from '@coveo/bueno';
import {facetResultsMustMatch} from '../../../../features/facets/facet-api/request';
import {facetSortCriteria} from '../../../../features/facets/facet-set/interfaces/request';
import {
facetId,
Expand Down Expand Up @@ -49,6 +50,7 @@ export const facetOptionsSchema = new Schema<Required<FacetOptions>>({
injectionDepth,
numberOfValues,
sortCriteria: new StringValue({constrainTo: facetSortCriteria}),
resultsMustMatch: new StringValue({constrainTo: facetResultsMustMatch}),
facetSearch,
allowedValues,
customSort,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ describe('facet', () => {
facetId,
field: 'author',
sortCriteria: 'score',
resultsMustMatch: 'atLeastOneValue',
facetSearch: {},
};

Expand All @@ -64,6 +65,7 @@ describe('facet', () => {
const action = registerFacet({
field: 'author',
sortCriteria: 'score',
resultsMustMatch: 'atLeastOneValue',
facetId,
filterFacetCount: true,
injectionDepth: 1000,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ describe('category facet slice', () => {
numberOfValues: 5,
preventAutoSelect: false,
sortCriteria: 'occurrences',
resultsMustMatch: 'atLeastOneValue',
delimitingCharacter: ';',
type: 'hierarchical',
basePath: [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ export const defaultCategoryFacetOptions: CategoryFacetOptionalParameters = {
sortCriteria: 'occurrences',
basePath: [],
filterByBasePath: true,
resultsMustMatch: 'atLeastOneValue',
};

function ensurePathAndReturnChildren(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ export type CategoryFacetOptionalParameters = Pick<
| 'sortCriteria'
| 'basePath'
| 'filterByBasePath'
| 'resultsMustMatch'
>;
14 changes: 14 additions & 0 deletions packages/headless/src/features/facets/facet-api/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ export interface BaseFacetRequest {
* @defaultValue `false`
*/
preventAutoSelect: boolean;

/**
* The criterion to use for specifying how results must match the selected facet values.
*
* @defaultValue `atLeastOneValue`
*/
resultsMustMatch: FacetResultsMustMatch;
}

export interface BaseFacetValueRequest {
Expand Down Expand Up @@ -105,6 +112,13 @@ export interface RangeAlgorithm<T extends 'even' | 'equiprobable'> {
rangeAlgorithm: T;
}

export type FacetResultsMustMatch = 'allValues' | 'atLeastOneValue';

export const facetResultsMustMatch: FacetResultsMustMatch[] = [
'allValues',
'atLeastOneValue',
];

export interface AllowedValues {
/**
* Specifies an explicit list of `allowedValues` in the Search API request.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
customSort,
} from '../../../controllers/core/facets/_common/facet-option-definitions';
import {validatePayload} from '../../../utils/validate-payload';
import {FacetResultsMustMatch} from '../facet-api/request';
import {facetIdDefinition} from '../generic/facet-actions-validation';
import {facetValueDefinition} from './facet-set-validate-payload';
import {FacetSortCriterion} from './interfaces/request';
Expand Down Expand Up @@ -87,6 +88,13 @@ export interface RegisterFacetActionCreatorPayload {
* The default value is `undefined`, and the facet values will be sorted using only the `sortCriteria`.
*/
customSort?: string[];

/**
* The criterion to use for specifying how results must match the selected facet values.
*
* @defaultValue `atLeastOneValue`
*/
resultsMustMatch?: FacetResultsMustMatch;
}

const facetRegistrationOptionsDefinition = {
Expand All @@ -96,6 +104,7 @@ const facetRegistrationOptionsDefinition = {
injectionDepth: new NumberValue({required: false, min: 0}),
numberOfValues: new NumberValue({required: false, min: 1}),
sortCriteria: new Value<FacetSortCriterion>({required: false}),
resultsMustMatch: new Value<FacetResultsMustMatch>({required: false}),
allowedValues: allowedValues,
customSort: customSort,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,15 +86,18 @@ describe('facet-set slice', () => {
numberOfValues: 8,
preventAutoSelect: false,
sortCriteria: 'automatic',
resultsMustMatch: 'atLeastOneValue',
};

expect(finalState[facetId]?.request).toEqual(expectedFacet);
});

it('registers a facet request with the passed optional values', () => {
const criterion = 'alphanumeric';
const matchCriterion = 'allValues';
const sortCriterion = 'alphanumeric';
const options = buildRegistrationOptions({
sortCriteria: criterion,
sortCriteria: sortCriterion,
resultsMustMatch: matchCriterion,
allowedValues: {type: 'simple', values: ['foo', 'bar']},
customSort: ['bar', 'buzz', 'foo'],
});
Expand All @@ -103,7 +106,8 @@ describe('facet-set slice', () => {
const finalState = facetSetReducer(state, action);
const {request: facetRequest} = finalState[options.facetId];

expect(facetRequest.sortCriteria).toBe(criterion);
expect(facetRequest.resultsMustMatch).toBe(matchCriterion);
expect(facetRequest.sortCriteria).toBe(sortCriterion);
expect(facetRequest.allowedValues?.values).toEqual(['foo', 'bar']);
expect(facetRequest.customSort).toEqual(['bar', 'buzz', 'foo']);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ export const defaultFacetOptions: FacetOptionalParameters = {
injectionDepth: 1000,
numberOfValues: 8,
sortCriteria: 'automatic',
resultsMustMatch: 'atLeastOneValue',
};

function buildFacetRequest(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import {FacetOptions} from '../../../../controllers/core/facets/facet/headless-c
export type FacetOptionalParameters = Required<
Pick<
FacetOptions,
'filterFacetCount' | 'injectionDepth' | 'numberOfValues' | 'sortCriteria'
| 'filterFacetCount'
| 'injectionDepth'
| 'numberOfValues'
| 'sortCriteria'
| 'resultsMustMatch'
>
>;
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ describe('date-facet-set slice', () => {
numberOfValues: 8,
preventAutoSelect: false,
sortCriteria: 'ascending',
resultsMustMatch: 'atLeastOneValue',
type: 'dateRange',
rangeAlgorithm: 'even',
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export type RangeFacetOptionalParameters = Pick<
| 'numberOfValues'
| 'sortCriteria'
| 'rangeAlgorithm'
| 'resultsMustMatch'
>;

export type ManualRangeFacetOptions<T extends RangeFacetRequest> =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ describe('range facet reducers', () => {
sortCriteria: 'ascending',
type: 'numericalRange',
rangeAlgorithm: 'even',
resultsMustMatch: 'atLeastOneValue',
...options,
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export const defaultRangeFacetOptions: RangeFacetOptionalParameters = {
numberOfValues: 8,
sortCriteria: 'ascending',
rangeAlgorithm: 'even',
resultsMustMatch: 'atLeastOneValue',
};

export function registerRangeFacet<T extends RangeFacetSlice>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ describe('numeric-facet-set slice', () => {
sortCriteria: 'ascending',
type: 'numericalRange',
rangeAlgorithm: 'even',
resultsMustMatch: 'atLeastOneValue',
});
});

Expand Down
1 change: 1 addition & 0 deletions packages/headless/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ export type {
FacetValueRequest,
FacetSortCriterion,
} from './features/facets/facet-set/interfaces/request';
export type {FacetResultsMustMatch} from './features/facets/facet-api/request';
export type {NumericRangeRequest} from './features/facets/range-facets/numeric-facet-set/interfaces/request';
export type {NumericFacetValue} from './features/facets/range-facets/numeric-facet-set/interfaces/response';
export type {AnyFacetValueRequest} from './features/facets/generic/interfaces/generic-facet-request';
Expand Down
1 change: 1 addition & 0 deletions packages/headless/src/test/mock-category-facet-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export function buildMockCategoryFacetRequest(
numberOfValues: 5,
preventAutoSelect: false,
sortCriteria: 'occurrences',
resultsMustMatch: 'atLeastOneValue',
type: 'hierarchical',
basePath: [],
filterByBasePath: false,
Expand Down
1 change: 1 addition & 0 deletions packages/headless/src/test/mock-date-facet-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export function buildMockDateFacetRequest(
numberOfValues: 8,
preventAutoSelect: false,
sortCriteria: 'ascending',
resultsMustMatch: 'atLeastOneValue',
type: 'dateRange',
rangeAlgorithm: 'even',
...config,
Expand Down
1 change: 1 addition & 0 deletions packages/headless/src/test/mock-facet-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export function buildMockFacetRequest(
numberOfValues: 8,
preventAutoSelect: false,
sortCriteria: 'score',
resultsMustMatch: 'atLeastOneValue',
type: 'specific',
...config,
};
Expand Down
1 change: 1 addition & 0 deletions packages/headless/src/test/mock-numeric-facet-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export function buildMockNumericFacetRequest(
numberOfValues: 8,
preventAutoSelect: false,
sortCriteria: 'ascending',
resultsMustMatch: 'atLeastOneValue',
type: 'numericalRange',
rangeAlgorithm: 'even',
...config,
Expand Down

0 comments on commit fe40054

Please sign in to comment.