filter: action((state, { dataList, defaultFilter, customFilter }) => { if (!customFilter && !defaultFilter) { throw new Error(internalErrorMessage.invalidFilterParam); } const filterCache = { ...state.filterCache }; let filterResult = [...dataList]; if ( (defaultFilter && defaultFilter.filterValueList.length > 0) || customFilter ) { // Filter idea: // Filter based on the criteria // Store the result back in the temporary storage (cache) // Find the intersection of all the temporary result // => The result will satisfy all the filter criteria filterResult = dataList.filter((entry) => { if (customFilter) { return customFilter.filterHandler(entry); } if (!defaultFilter) { throw new Error(internalErrorMessage.invalidFilterParam); } const { filterKey, filterValueList, filterType } = defaultFilter; const toCompare = lodash.get(entry, filterKey); if (Array.isArray(toCompare)) { const intersection = lodash.intersectionWith( toCompare, filterValueList, lodash.isEqual ); switch (filterType) { case "matchSubset": // toCompare is the subset of filterValueList return intersection.length === toCompare.length; case "matchSuperset": // filterValueList is the subset of toCompare return intersection.length === filterValueList.length; case "matchExact": return ( intersection.length === toCompare.length && intersection.length === filterValueList.length ); default: case "matchOneOf": return intersection.length > 0; } } return ( filterValueList.findIndex((value) => lodash.isEqual(toCompare, value) ) >= 0 ); }); } filterCache[ customFilter?.customKey || (defaultFilter?.filterKey as string) ] = filterResult; // Intersect the result of every filter by in the cache state.filterResult = lodash.intersectionWith( ...Object.values(filterCache), lodash.isEqual ); // Reset the cache state.filterCache = filterCache; }), };