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

Commit 8c7ff44

Browse files
authored
feat(getFacetValues): process facetOrdering (#822)
* feat(getFacetValues): process facetOrdering DX-2075 * fix: behave correctly on facetOrdering: false * pinned -> ordered * better description * simplify tests & code slightly
1 parent b3ee312 commit 8c7ff44

File tree

5 files changed

+1861
-30
lines changed

5 files changed

+1861
-30
lines changed

src/SearchResults/index.js

Lines changed: 114 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -659,20 +659,29 @@ function extractNormalizedFacetValues(results, attribute) {
659659
}
660660

661661
/**
662-
* Sort nodes of a hierarchical facet results
662+
* Sort nodes of a hierarchical or disjunctive facet results
663663
* @private
664-
* @param {HierarchicalFacet} node node to upon which we want to apply the sort
664+
* @param {function} sortFn
665+
* @param {HierarchicalFacet|Array} node node upon which we want to apply the sort
666+
* @param {string[]} names attribute names
667+
* @param {number} [level=0] current index in the names array
665668
*/
666-
function recSort(sortFn, node) {
669+
function recSort(sortFn, node, names, level) {
670+
level = level || 0;
671+
672+
if (Array.isArray(node)) {
673+
return sortFn(node, names[level]);
674+
}
675+
667676
if (!node.data || node.data.length === 0) {
668677
return node;
669678
}
670679

671680
var children = node.data.map(function(childNode) {
672-
return recSort(sortFn, childNode);
681+
return recSort(sortFn, childNode, names, level + 1);
673682
});
674-
var sortedChildren = sortFn(children);
675-
var newNode = merge({}, node, {data: sortedChildren});
683+
var sortedChildren = sortFn(children, names[level]);
684+
var newNode = defaultsPure({data: sortedChildren}, node);
676685
return newNode;
677686
}
678687

@@ -682,6 +691,70 @@ function vanillaSortFn(order, data) {
682691
return data.sort(order);
683692
}
684693

694+
/**
695+
* @typedef FacetOrdering
696+
* @type {Object}
697+
* @property {string[]} [order]
698+
* @property {'count' | 'alpha' | 'hidden'} [sortRemainingBy]
699+
*/
700+
701+
/**
702+
* Sorts facet arrays via their facet ordering
703+
* @param {Array} facetValues the values
704+
* @param {FacetOrdering} facetOrdering the ordering
705+
* @returns {Array}
706+
*/
707+
function sortViaFacetOrdering(facetValues, facetOrdering) {
708+
var orderedFacets = [];
709+
var remainingFacets = [];
710+
711+
var order = facetOrdering.order || [];
712+
/**
713+
* an object with the keys being the values in order, the values their index:
714+
* ['one', 'two'] -> { one: 0, two: 1 }
715+
*/
716+
var reverseOrder = order.reduce(function(acc, name, i) {
717+
acc[name] = i;
718+
return acc;
719+
}, {});
720+
721+
facetValues.forEach(function(item) {
722+
if (reverseOrder[item.name] !== undefined) {
723+
orderedFacets[reverseOrder[item.name]] = item;
724+
} else {
725+
remainingFacets.push(item);
726+
}
727+
});
728+
729+
var sortRemainingBy = facetOrdering.sortRemainingBy;
730+
var ordering;
731+
if (sortRemainingBy === 'hidden') {
732+
return orderedFacets;
733+
} else if (sortRemainingBy === 'alpha') {
734+
ordering = [['name'], ['asc']];
735+
} else {
736+
ordering = [['count'], ['desc']];
737+
}
738+
739+
return orderedFacets.concat(
740+
orderBy(remainingFacets, ordering[0], ordering[1])
741+
);
742+
}
743+
744+
/**
745+
* @param {SearchResults} results the search results class
746+
* @param {string} attribute the attribute to retrieve ordering of
747+
* @returns {FacetOrdering=}
748+
*/
749+
function getFacetOrdering(results, attribute) {
750+
return (
751+
results.renderingContent &&
752+
results.renderingContent.facetOrdering &&
753+
results.renderingContent.facetOrdering.values &&
754+
results.renderingContent.facetOrdering.values[attribute]
755+
);
756+
}
757+
685758
/**
686759
* Get a the list of values for a given facet attribute. Those values are sorted
687760
* refinement first, descending count (bigger value on top), and name ascending
@@ -694,6 +767,9 @@ function vanillaSortFn(order, data) {
694767
* might not be respected if you have facet values that are already refined.
695768
* @param {string} attribute attribute name
696769
* @param {object} opts configuration options.
770+
* @param {boolean} [opts.facetOrdering]
771+
* Force the use of facetOrdering from the result if a sortBy is present. If
772+
* sortBy isn't present, facetOrdering will be used automatically.
697773
* @param {Array.<string> | function} opts.sortBy
698774
* When using strings, it consists of
699775
* the name of the [FacetValue](#SearchResults.FacetValue) or the
@@ -733,30 +809,41 @@ SearchResults.prototype.getFacetValues = function(attribute, opts) {
733809
return undefined;
734810
}
735811

736-
var options = defaultsPure({}, opts, {sortBy: SearchResults.DEFAULT_SORT});
812+
var options = defaultsPure({}, opts, {
813+
sortBy: SearchResults.DEFAULT_SORT,
814+
// if no sortBy is given, attempt to sort based on facetOrdering
815+
// if it is given, we still allow to sort via facet ordering first
816+
facetOrdering: !(opts && opts.sortBy)
817+
});
737818

738-
if (Array.isArray(options.sortBy)) {
739-
var order = formatSort(options.sortBy, SearchResults.DEFAULT_SORT);
740-
if (Array.isArray(facetValues)) {
741-
return orderBy(facetValues, order[0], order[1]);
742-
}
743-
// If facetValues is not an array, it's an object thus a hierarchical facet object
744-
return recSort(function(hierarchicalFacetValues) {
745-
return orderBy(hierarchicalFacetValues, order[0], order[1]);
746-
}, facetValues);
747-
} else if (typeof options.sortBy === 'function') {
748-
if (Array.isArray(facetValues)) {
749-
return facetValues.sort(options.sortBy);
819+
var results = this;
820+
var attributes;
821+
if (Array.isArray(facetValues)) {
822+
attributes = [attribute];
823+
} else {
824+
var config = results._state.getHierarchicalFacetByName(facetValues.name);
825+
attributes = config.attributes;
826+
}
827+
828+
return recSort(function(data, facetName) {
829+
if (options.facetOrdering) {
830+
var facetOrdering = getFacetOrdering(results, facetName);
831+
if (Boolean(facetOrdering)) {
832+
return sortViaFacetOrdering(data, facetOrdering);
833+
}
750834
}
751-
// If facetValues is not an array, it's an object thus a hierarchical facet object
752-
return recSort(function(data) {
835+
836+
if (Array.isArray(options.sortBy)) {
837+
var order = formatSort(options.sortBy, SearchResults.DEFAULT_SORT);
838+
return orderBy(data, order[0], order[1]);
839+
} else if (typeof options.sortBy === 'function') {
753840
return vanillaSortFn(options.sortBy, data);
754-
}, facetValues);
755-
}
756-
throw new Error(
757-
'options.sortBy is optional but if defined it must be ' +
758-
'either an array of string (predicates) or a sorting function'
759-
);
841+
}
842+
throw new Error(
843+
'options.sortBy is optional but if defined it must be ' +
844+
'either an array of string (predicates) or a sorting function'
845+
);
846+
}, facetValues, attributes);
760847
};
761848

762849
/**

0 commit comments

Comments
 (0)