Skip to content

Instantly share code, notes, and snippets.

@btaillon-coveo
Last active November 18, 2022 19:45
Show Gist options
  • Save btaillon-coveo/92aa59e6922f4582c9f5ff2af350a68f to your computer and use it in GitHub Desktop.
Save btaillon-coveo/92aa59e6922f4582c9f5ff2af350a68f to your computer and use it in GitHub Desktop.
JSUI folding like Headless
/**
* @typedef IQueryResult
* @property {IQueryResult[]} [childResults]
* @property {IQueryResult} [parentResult]
* @property {{ foldingcollection?: string, foldingparent?: string, foldingchild?: string, source: string }} raw
*/
/**
* @param {IQueryResult} parent
* @param {IQueryResult[]} results
* @param {string} [resolvedAncestors]
* @returns {IQueryResult[]}
*/
function resolveChildrenFromFields(
parent,
results,
resolvedAncestors = []
) {
const sourceChildValue = parent.raw.foldingchild;
if (!sourceChildValue) {
return [];
}
if (resolvedAncestors.indexOf(sourceChildValue) !== -1) {
return [];
}
return results
.filter((result) => {
const isSameResultAsSource =
result.raw.foldingchild === parent.raw.foldingchild;
const isChildOfSource =
result.raw.foldingparent === sourceChildValue;
return isChildOfSource && !isSameResultAsSource;
})
.map((result) => ({
...result,
parentResult: undefined,
childResults: resolveChildrenFromFields(result, results, [
...resolvedAncestors,
sourceChildValue,
]),
}));
}
/**
* @param {T | undefined} value1
* @param {T | undefined} value2
* @template T
*/
function areDefinedAndEqual(
value1,
value2
) {
return (value1 || value2) !== undefined && value1 === value2;
}
/**
* @param {IQueryResult[]} results
*/
function resolveRootFromFields(
results
) {
return results.find((result) => {
const hasNoParent = result.raw.foldingparent === undefined;
const isParentOfItself = areDefinedAndEqual(
result.raw.foldingparent,
result.raw.foldingchild
);
return hasNoParent || isParentOfItself;
});
}
/**
* @param {IQueryResult} result
* @returns {IQueryResult[]}
*/
function getChildResultsRecursively(result) {
if (!result.childResults) {
return [];
}
return result.childResults.flatMap((childResult) => [
childResult,
...getChildResultsRecursively(childResult),
]);
}
/**
* @param {T[]} arr
* @param {(value: T, index: number) => string} getIdentifier
* @returns {T[]}
* @template T
*/
function removeDuplicates(
arr,
getIdentifier
) {
return Object.values(
arr.reduce(
(existingValues, value, index) => ({
...existingValues,
[getIdentifier(value, index)]: value,
}),
{}
)
);
}
/**
* @param {IQueryResult} relevantResult
*/
function getAllIncludedResultsFrom(relevantResult) {
const foldedResults = getChildResultsRecursively(relevantResult);
const parentResults = [relevantResult, ...foldedResults]
.filter((result) => result.parentResult)
.map((result) => result.parentResult);
const resultsInCollection = removeDuplicates(
[relevantResult, ...foldedResults, ...parentResults],
(result) => result.uniqueId
);
return resultsInCollection;
}
/**
* @param {IQueryResult} relevantResult
* @returns {IQueryResult}
*/
function foldResultWithFields(
relevantResult
) {
const resultsInCollection = getAllIncludedResultsFrom(relevantResult);
const resultToUseAsRoot =
resolveRootFromFields(resultsInCollection);
if (!resultToUseAsRoot) {
console.warn(`Could not find the root for:`, relevantResult);
return relevantResult;
}
return {
...resultToUseAsRoot,
parentResult: undefined,
childResults: resolveChildrenFromFields(
resultToUseAsRoot,
resultsInCollection
),
};
}
/**
* @param {IQueryResult} result
* @returns {IQueryResult}
* @export
*/
function getResult(result) {
if (result.raw.source === 'University') {
return foldResultWithFields(result);
}
return Coveo.Folding.defaultGetResult(result);
}
/**
* Usage:
* ```js
* Coveo.init(
* searchInterface,
* {
* Folding: {
* getResult
* }
* }
* );
* ```
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment