Skip to content

Commit

Permalink
feat(helper): persistHierarchicalRootCount: true (#6478)
Browse files Browse the repository at this point in the history
* feat(helper): persistHierarchicalRootCount: true

BREAKING CHANGE: the default behaviour of the helper is now persistHierarchicalRootCount: true

* fix(options): remove persistHierarchicalRootCount option

It behaves as persistHierarchicalRootCount: true
  • Loading branch information
Haroenv committed Dec 20, 2024
1 parent 52c68ad commit 7e21b35
Show file tree
Hide file tree
Showing 11 changed files with 107 additions and 380 deletions.
1 change: 0 additions & 1 deletion packages/algoliasearch-helper/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1114,7 +1114,6 @@ declare namespace algoliasearchHelper {
* This is for internal use, e.g., avoiding caching in infinite hits, or delaying the display of these results.
*/
__isArtificial?: boolean | undefined;
persistHierarchicalRootCount?: boolean;
}

type ISearchResponse<T> = Omit<SearchResponse<T>, 'facets' | 'params'> &
Expand Down
42 changes: 6 additions & 36 deletions packages/algoliasearch-helper/src/SearchResults/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -240,11 +240,8 @@ function SearchResults(state, results, options) {
});

// Make every key of the result options reachable from the instance
var opts = defaultsPure(options, {
persistHierarchicalRootCount: false,
});
Object.keys(opts).forEach(function (key) {
self[key] = opts[key];
Object.keys(options || {}).forEach(function (key) {
self[key] = options[key];
});

/**
Expand Down Expand Up @@ -508,16 +505,10 @@ function SearchResults(state, results, options) {
return;
}

self.hierarchicalFacets[position][attributeIndex].data =
self.persistHierarchicalRootCount
? defaultsPure(
self.hierarchicalFacets[position][attributeIndex].data,
facetResults
)
: defaultsPure(
facetResults,
self.hierarchicalFacets[position][attributeIndex].data
);
self.hierarchicalFacets[position][attributeIndex].data = defaultsPure(
self.hierarchicalFacets[position][attributeIndex].data,
facetResults
);
} else {
position = disjunctiveFacetsIndices[dfacet];

Expand Down Expand Up @@ -589,28 +580,7 @@ function SearchResults(state, results, options) {
return;
}

// when we always get root levels, if the hits refinement is `beers > IPA` (count: 5),
// then the disjunctive values will be `beers` (count: 100),
// but we do not want to display
// | beers (100)
// > IPA (5)
// We want
// | beers (5)
// > IPA (5)
// @MAJOR: remove this legacy behaviour in next major version
var defaultData = {};

if (
currentRefinement.length > 0 &&
!self.persistHierarchicalRootCount
) {
var root = currentRefinement[0].split(separator)[0];
defaultData[root] =
self.hierarchicalFacets[position][attributeIndex].data[root];
}

self.hierarchicalFacets[position][attributeIndex].data = defaultsPure(
defaultData,
facetResults,
self.hierarchicalFacets[position][attributeIndex].data
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,6 @@ function getData() {
index: 'test_hotels-node',
hitsPerPage: 20,
nbHits: 4,
persistHierarchicalRootCount: false,
nbPages: 1,
page: 0,
params:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -751,12 +751,10 @@ test('getFacetValues(facetName) prefers the "main" facet result (disjunctive)',
expect(facetValues).toEqual(expected);
});

test('getFacetValues(facetName) prefers the "main" facet result (hierarchical) (persistHierarchicalRootCount: true)', function () {
test('getFacetValues(facetName) prefers the "main" facet result (hierarchical)', function () {
var data = require('./getFacetValues/hierarchical-non-exhaustive.json');
var searchParams = new SearchParameters(data.state);
var result = new SearchResults(searchParams, data.content.results, {
persistHierarchicalRootCount: true,
});
var result = new SearchResults(searchParams, data.content.results);

var facetValues = result.getFacetValues('brand').data;

Expand Down Expand Up @@ -792,45 +790,3 @@ test('getFacetValues(facetName) prefers the "main" facet result (hierarchical) (

expect(facetValues).toEqual(expected);
});

test('getFacetValues(facetName) prefers the "main" facet result (hierarchical) (persistHierarchicalRootCount: false)', function () {
var data = require('./getFacetValues/hierarchical-non-exhaustive.json');
var searchParams = new SearchParameters(data.state);
var result = new SearchResults(searchParams, data.content.results, {
persistHierarchicalRootCount: false,
});

var facetValues = result.getFacetValues('brand').data;

var expected = [
{
count: 50,
data: null,
isRefined: true,
name: 'Apple',
escapedValue: 'Apple',
path: 'Apple',
exhaustive: true,
},
{
count: 551,
data: null,
isRefined: false,
name: 'Insignia™',
escapedValue: 'Insignia™',
path: 'Insignia™',
exhaustive: true,
},
{
count: 551,
data: null,
isRefined: false,
name: 'Samsung',
escapedValue: 'Samsung',
path: 'Samsung',
exhaustive: true,
},
];

expect(facetValues).toEqual(expected);
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
var algoliasearchHelper = require('../../../index');
var SearchParameters = require('../../../src/SearchParameters');

test('searchOnce should call the algolia client according to the number of refinements and call callback with no error and with results when no error', function (done) {
test('searchOnce should call the algolia client according to the number of refinements and call callback with no error and with results when no error', async function () {
var testData = require('../../datasets/SearchParameters/search.dataset')();

var client = {
Expand All @@ -21,76 +21,72 @@ test('searchOnce should call the algolia client according to the number of refin
.addDisjunctiveFacetRefinement('city', 'Paris')
.addDisjunctiveFacetRefinement('city', 'New York');

helper.searchOnce(parameters, function (err, data) {
expect(err).toBe(null);

// shame deepclone, to remove any associated methods coming from the results
expect(JSON.parse(JSON.stringify(data))).toEqual(
JSON.parse(JSON.stringify(testData.responseHelper))
);

var cityValues = data.getFacetValues('city');
var expectedCityValues = [
{ name: 'Paris', escapedValue: 'Paris', count: 3, isRefined: true },
{ name: 'New York', escapedValue: 'New York', count: 1, isRefined: true },
{
name: 'San Francisco',
escapedValue: 'San Francisco',
count: 1,
isRefined: false,
},
];

expect(cityValues).toEqual(expectedCityValues);

var cityValuesCustom = data.getFacetValues('city', {
sortBy: ['count:asc', 'name:asc'],
});
var expectedCityValuesCustom = [
{ name: 'New York', escapedValue: 'New York', count: 1, isRefined: true },
{
name: 'San Francisco',
escapedValue: 'San Francisco',
count: 1,
isRefined: false,
},
{ name: 'Paris', escapedValue: 'Paris', count: 3, isRefined: true },
];

expect(cityValuesCustom).toEqual(expectedCityValuesCustom);

var cityValuesFn = data.getFacetValues('city', {
sortBy: function (a, b) {
return a.count - b.count;
},
});
var expectedCityValuesFn = [
{ name: 'New York', escapedValue: 'New York', count: 1, isRefined: true },
{
name: 'San Francisco',
escapedValue: 'San Francisco',
count: 1,
isRefined: false,
},
{ name: 'Paris', escapedValue: 'Paris', count: 3, isRefined: true },
];

expect(cityValuesFn).toEqual(expectedCityValuesFn);

expect(client.search).toHaveBeenCalledTimes(1);

var queries = client.search.mock.calls[0][0];
for (var i = 0; i < queries.length; i++) {
var query = queries[i];
expect(query.query).toBeUndefined();
expect(query.params.query).toBeUndefined();
}

done();
const { content } = await helper.searchOnce(parameters);

// shame deepclone, to remove any associated methods coming from the results
expect(JSON.parse(JSON.stringify(content))).toEqual(
JSON.parse(JSON.stringify(testData.responseHelper))
);

var cityValues = content.getFacetValues('city');
var expectedCityValues = [
{ name: 'Paris', escapedValue: 'Paris', count: 3, isRefined: true },
{ name: 'New York', escapedValue: 'New York', count: 1, isRefined: true },
{
name: 'San Francisco',
escapedValue: 'San Francisco',
count: 1,
isRefined: false,
},
];

expect(cityValues).toEqual(expectedCityValues);

var cityValuesCustom = content.getFacetValues('city', {
sortBy: ['count:asc', 'name:asc'],
});
var expectedCityValuesCustom = [
{ name: 'New York', escapedValue: 'New York', count: 1, isRefined: true },
{
name: 'San Francisco',
escapedValue: 'San Francisco',
count: 1,
isRefined: false,
},
{ name: 'Paris', escapedValue: 'Paris', count: 3, isRefined: true },
];

expect(cityValuesCustom).toEqual(expectedCityValuesCustom);

var cityValuesFn = content.getFacetValues('city', {
sortBy: function (a, b) {
return a.count - b.count;
},
});
var expectedCityValuesFn = [
{ name: 'New York', escapedValue: 'New York', count: 1, isRefined: true },
{
name: 'San Francisco',
escapedValue: 'San Francisco',
count: 1,
isRefined: false,
},
{ name: 'Paris', escapedValue: 'Paris', count: 3, isRefined: true },
];

expect(cityValuesFn).toEqual(expectedCityValuesFn);

expect(client.search).toHaveBeenCalledTimes(1);

var queries = client.search.mock.calls[0][0];
for (var i = 0; i < queries.length; i++) {
var query = queries[i];
expect(query.query).toBeUndefined();
expect(query.params.query).toBeUndefined();
}
});

test('searchOnce should call the algolia client according to the number of refinements and call callback with error and no results when error', function (done) {
test('searchOnce should call the algolia client according to the number of refinements and call callback with error and no results when error', async function () {
var error = { message: 'error' };
var client = {
search: jest.fn().mockImplementationOnce(function () {
Expand All @@ -107,19 +103,14 @@ test('searchOnce should call the algolia client according to the number of refin
.addDisjunctiveFacetRefinement('city', 'Paris')
.addDisjunctiveFacetRefinement('city', 'New York');

helper.searchOnce(parameters, function (err, data) {
expect(err).toBe(error);
expect(data).toBe(null);

expect(client.search).toHaveBeenCalledTimes(1);
await expect(() => helper.searchOnce(parameters)).rejects.toEqual(error);

var queries = client.search.mock.calls[0][0];
for (var i = 0; i < queries.length; i++) {
var query = queries[i];
expect(query.query).toBeUndefined();
expect(query.params.query).toBeUndefined();
}
expect(client.search).toHaveBeenCalledTimes(1);

done();
});
var queries = client.search.mock.calls[0][0];
for (var i = 0; i < queries.length; i++) {
var query = queries[i];
expect(query.query).toBeUndefined();
expect(query.params.query).toBeUndefined();
}
});
Loading

0 comments on commit 7e21b35

Please sign in to comment.