Skip to content
This repository has been archived by the owner on Jul 11, 2023. It is now read-only.

Commit

Permalink
feat(getFacetValues): process facetOrdering
Browse files Browse the repository at this point in the history
  • Loading branch information
Haroenv committed Jun 9, 2021
1 parent 52939cd commit a620e5b
Show file tree
Hide file tree
Showing 4 changed files with 1,598 additions and 29 deletions.
134 changes: 108 additions & 26 deletions src/SearchResults/index.js
Expand Up @@ -659,20 +659,30 @@ function extractNormalizedFacetValues(results, attribute) {
}

/**
* Sort nodes of a hierarchical facet results
* Sort nodes of a hierarchical or disjunctive facet results
* @private
* @param {HierarchicalFacet} node node to upon which we want to apply the sort
* @param {function} sortFn
* @param {HierarchicalFacet|Array} node node to upon which we want to apply the sort
* @param {string[]} names attribute names
* @param {number} [level=0] current index in the names array
*/
function recSort(sortFn, node) {
function recSort(sortFn, node, names, level) {
level = level || 0;

if (Array.isArray(node)) {
return sortFn(node, names[level]);
}

if (!node.data || node.data.length === 0) {
return node;
}

var children = node.data.map(function(childNode) {
return recSort(sortFn, childNode);
return recSort(sortFn, childNode, names, level + 1);
});
var sortedChildren = sortFn(children);
var newNode = merge({}, node, {data: sortedChildren});
var sortedChildren = sortFn(children, names[level]);
var newNode = merge({}, node);
newNode.data = sortedChildren;
return newNode;
}

Expand All @@ -682,6 +692,66 @@ function vanillaSortFn(order, data) {
return data.sort(order);
}

/**
* @typedef FacetOrdering
* @type {Object}
* @property {string[]} [order]
* @property {'count' | 'alpha' | 'hidden'} [sortRemainingBy]
*/

/**
* Sorts facet arrays via their facet ordering
* @param {Array} facetValues the values
* @param {FacetOrdering} facetOrdering the ordering
* @returns {Array}
*/
function sortViaFacetOrdering(facetValues, facetOrdering) {
var pinnedFacets = [];
var unpinnedFacets = [];

var pinned = facetOrdering.order || [];
var reversePinned = pinned.reduce(function(acc, name, i) {
acc[name] = i;
return acc;
}, {});

facetValues.forEach(function(item) {
if (reversePinned[item.name] !== undefined) {
pinnedFacets[reversePinned[item.name]] = item;
} else {
unpinnedFacets.push(item);
}
});

var sortRemainingBy = facetOrdering.sortRemainingBy;
var ordering;
if (sortRemainingBy === 'hidden') {
return pinnedFacets;
} else if (sortRemainingBy === 'alpha') {
ordering = [['name'], ['asc']];
} else {
ordering = [['count'], ['desc']];
}

return pinnedFacets.concat(
orderBy(unpinnedFacets, ordering[0], ordering[1])
);
}

/**
* @param {SearchResults} results a results class (this)
* @param {string} attribute the attribute to retrieve ordering of
* @returns {FacetOrdering=}
*/
function getFacetOrdering(results, attribute) {
return (
results.renderingContent &&
results.renderingContent.facetOrdering &&
results.renderingContent.facetOrdering.values &&
results.renderingContent.facetOrdering.values[attribute]
);
}

/**
* Get a the list of values for a given facet attribute. Those values are sorted
* refinement first, descending count (bigger value on top), and name ascending
Expand All @@ -694,6 +764,9 @@ function vanillaSortFn(order, data) {
* might not be respected if you have facet values that are already refined.
* @param {string} attribute attribute name
* @param {object} opts configuration options.
* @param {boolean} [opts.facetOrdering=false]
* Force the use of facetOrdering from the result if a sortBy is present. If
* sortBy isn't present, facetOrdering will be used automatically.
* @param {Array.<string> | function} opts.sortBy
* When using strings, it consists of
* the name of the [FacetValue](#SearchResults.FacetValue) or the
Expand Down Expand Up @@ -735,28 +808,37 @@ SearchResults.prototype.getFacetValues = function(attribute, opts) {

var options = defaultsPure({}, opts, {sortBy: SearchResults.DEFAULT_SORT});

if (Array.isArray(options.sortBy)) {
var order = formatSort(options.sortBy, SearchResults.DEFAULT_SORT);
if (Array.isArray(facetValues)) {
return orderBy(facetValues, order[0], order[1]);
}
// If facetValues is not an array, it's an object thus a hierarchical facet object
return recSort(function(hierarchicalFacetValues) {
return orderBy(hierarchicalFacetValues, order[0], order[1]);
}, facetValues);
} else if (typeof options.sortBy === 'function') {
if (Array.isArray(facetValues)) {
return facetValues.sort(options.sortBy);
var results = this;
var attributes;
if (Array.isArray(facetValues)) {
attributes = [attribute];
} else {
var config = results._state.getHierarchicalFacetByName(facetValues.name);
attributes = config.attributes;
}

return recSort(function(data, facetName) {
// if no sortBy is given, attempt to sort based on facetOrdering
// if it is given, we still allow to sort via facet ordering first
if (!opts || !opts.sortBy || opts.facetOrdering) {
var facetOrdering = getFacetOrdering(results, facetName);
if (Boolean(facetOrdering)) {
return sortViaFacetOrdering(data, facetOrdering);
}
}
// If facetValues is not an array, it's an object thus a hierarchical facet object
return recSort(function(data) {

if (Array.isArray(options.sortBy)) {
var order = formatSort(options.sortBy, SearchResults.DEFAULT_SORT);

return orderBy(data, order[0], order[1]);
} else if (typeof options.sortBy === 'function') {
return vanillaSortFn(options.sortBy, data);
}, facetValues);
}
throw new Error(
'options.sortBy is optional but if defined it must be ' +
'either an array of string (predicates) or a sorting function'
);
}
throw new Error(
'options.sortBy is optional but if defined it must be ' +
'either an array of string (predicates) or a sorting function'
);
}, facetValues, attributes);
};

/**
Expand Down

0 comments on commit a620e5b

Please sign in to comment.