import { RecipeCollectionFilterItem } from './smart-collection-model'; import { Enum, isEnumType } from '../../library/enum'; import { DocumentQuery } from 'mongoose'; import { Recipe } from '../recipe'; export const RecipeFilterAttribute = Enum('TAG', 'INGREDIENT'); export type RecipeFilterAttribute = Enum; export const RecipeFilterAction = Enum( 'EQUAL', 'NOT_EQUAL', 'INCLUDE', 'NOT_INCLUDE' ); export type RecipeFilterAction = Enum; type RecipeFilterOptions = { [key in RecipeFilterAttribute]: { label: string; availableActions: RecipeFilterAction[]; }; }; export const recipeFilters: RecipeFilterOptions = { [RecipeFilterAttribute.TAG]: { label: 'Tags', availableActions: [RecipeFilterAction.EQUAL, RecipeFilterAction.INCLUDE], }, [RecipeFilterAttribute.INGREDIENT]: { label: 'Ingredients', availableActions: [RecipeFilterAction.INCLUDE], }, }; export function validateFilterItem(filter: RecipeCollectionFilterItem) { if (!isEnumType(RecipeFilterAttribute, filter.attribute)) { throw new Error(`${filter.attribute} is not a valide attribute type`); } if ( recipeFilters[filter.attribute].availableActions.indexOf(filter.action) < 0 ) { const availActions = recipeFilters[filter.attribute].availableActions.join( ' ' ); throw new Error( `${filter.action} is not a valid action for ${filter.attribute}. Must be one of ${availActions}` ); } return true; } export function buildFilterQuery( filters: RecipeCollectionFilterItem[], query: DocumentQuery ) { let filterQuery = query; filters.forEach(filter => { validateFilterItem(filter); switch (filter.attribute) { case RecipeFilterAttribute.TAG: filterQuery = filterByTag(filter, filterQuery); } }); return filterQuery; } // // Attribute Functions // function filterByTag( filter: RecipeCollectionFilterItem, query: DocumentQuery ) { switch (filter.action) { case RecipeFilterAction.INCLUDE: return query.where({ tags: { $all: filter.value.split(',') }, }); default: return query; } }