Example #1
0
        /// <summary>
        /// Removes redundancies in a filter to give simplest expression
        /// </summary>
        /// <typeparam name="TLeafNode"></typeparam>
        /// <param name="filter"></param>
        /// <returns></returns>
        public static IFilterNode <TLeafNode> Collapse <TLeafNode>(this IFilterNode <TLeafNode> filter)
            where TLeafNode : class, ILeafFilterNode
        {
            return(filter.Match(
                       combinationFilter =>
            {
                return combinationFilter.Operator.Match(
                    () =>
                {
                    var collapsedInnerFilters = combinationFilter.Filters.Select(f => f.Collapse())
                                                .ToList();

                    if (collapsedInnerFilters.Any(f => f.Equals(FilterNode <TLeafNode> .False)))
                    {
                        return FilterNode <TLeafNode> .False;
                    }

                    var nonTrivialFilters = collapsedInnerFilters.Where(f => !f.Equals(FilterNode <TLeafNode> .True));
                    var collapsedCombinationFilter = new CombinationFilter <TLeafNode>(nonTrivialFilters, combinationFilter.Operator);
                    return collapsedCombinationFilter.Filters.Count == 1
                                ? collapsedCombinationFilter.Filters.Single()
                                : collapsedCombinationFilter;
                },
                    () =>
                {
                    var collapsedInnerFilters = combinationFilter.Filters.Select(f => f.Collapse())
                                                .ToList();

                    if (collapsedInnerFilters.Any(f => f.Equals(FilterNode <TLeafNode> .True)))
                    {
                        return FilterNode <TLeafNode> .True;
                    }

                    var nonTrivialFilters = collapsedInnerFilters.Where(f => !f.Equals(FilterNode <TLeafNode> .False));
                    var collapsedCombinationFilter = new CombinationFilter <TLeafNode>(nonTrivialFilters, combinationFilter.Operator);
                    return collapsedCombinationFilter.Filters.Count == 1
                                ? collapsedCombinationFilter.Filters.Single()
                                : collapsedCombinationFilter;
                });
            },
                       invertedFilter =>
            {
                var collapsedInnerFilter = invertedFilter.FilterToInvert.Collapse();
                // If we have NOT(TRUE) then return FALSE or if we have NOT(FALSE) return TRUE.
                if (collapsedInnerFilter is ICombinationFilterNode <TLeafNode> combinationInner && combinationInner.Filters.Count == 0)
                {
                    return combinationInner.Operator.Match(() => FilterNode <TLeafNode> .False, () => FilterNode <TLeafNode> .True);
                }

                // If we have NOT(NOT(f)) just return f
                if (collapsedInnerFilter is IInvertedFilter <TLeafNode> invertedInner)
                {
                    return invertedInner.FilterToInvert;
                }

                return new InvertedFilter <TLeafNode>(collapsedInnerFilter);
            },
                       leafFilter => (IFilterNode <TLeafNode>)leafFilter)); // TODO: Figure out a way to remove this evil cast?
        }
Example #2
0
 /// <summary>
 /// 'Relaxes' a filter by relaxing each leaf of the filter according to <see cref="relaxFilterFunc"/>, or restricting
 /// inversions according to <see cref="restrictFilterFunc"/>.
 ///
 /// This is the inverse operation of <see cref="Restrict{TFilter}"/>.
 /// </summary>
 /// <param name="filter"></param>
 /// <param name="relaxFilterFunc">
 /// A function which takes a leaf node and relaxes it
 /// </param>
 /// <param name="restrictFilterFunc">
 /// A function which takes a leaf node and restricts it (i.e. the inverse operation of relax).
 /// </param>
 /// <returns></returns>
 public static IFilterNode <TFilter> Relax <TFilter>(
     this IFilterNode <TFilter> filter,
     Func <TFilter, IFilterNode <TFilter> > relaxFilterFunc,
     Func <TFilter, IFilterNode <TFilter> > restrictFilterFunc)
     where TFilter : IFilter
 => filter.Match(
     combinationFilterNode =>
 {
     var innerNodes = combinationFilterNode.Nodes.Select(f => Relax(f, relaxFilterFunc, restrictFilterFunc));
     return(innerNodes.Combine(combinationFilterNode.Operator));
 },
     invertedFilterNode => Restrict(invertedFilterNode.NodeToInvert, restrictFilterFunc, relaxFilterFunc).Invert(),
     leafFilterNode => relaxFilterFunc(leafFilterNode.Filter))
 .Collapse();
        /// <summary>
        /// 'Relaxes' a filter by relaxing each leaf of the filter according to <see cref="relaxFilterFunc"/>, or restricting
        /// inversions according to <see cref="restrictFilterFunc"/>.
        ///
        /// This is the inverse operation of <see cref="RestrictAsync{T}"/>.
        /// </summary>
        /// <param name="filter"></param>
        /// <param name="relaxFilterFunc">
        /// A function which takes a leaf node and relaxes it
        /// </param>
        /// <param name="restrictFilterFunc">
        /// A function which takes a leaf node and restricts it (i.e. the inverse operation of relax).
        /// </param>
        /// <returns></returns>
        public static async Task <IFilterNode <TFilter> > RelaxAsync <TFilter>(
            this IFilterNode <TFilter> filter,
            Func <TFilter, Task <IFilterNode <TFilter> > > relaxFilterFunc,
            Func <TFilter, Task <IFilterNode <TFilter> > > restrictFilterFunc)
            where TFilter : IFilter
        {
            var result = await filter.Match <Task <IFilterNode <TFilter> > >(
                async combinationFilterNode =>
            {
                var innerFilterNodeTasks = combinationFilterNode.Nodes.Select(f => RelaxAsync(f, relaxFilterFunc, restrictFilterFunc));
                var innerFilterNodes     = await Task.WhenAll(innerFilterNodeTasks).ConfigureAwait(false);
                return(innerFilterNodes.Combine(combinationFilterNode.Operator));
            },
                async invertedFilterNode => (await RestrictAsync(invertedFilterNode.NodeToInvert, restrictFilterFunc, relaxFilterFunc).ConfigureAwait(false)).Invert(),
                leafFilterNode => relaxFilterFunc(leafFilterNode.Filter))
                         .ConfigureAwait(false);

            return(result.Collapse());
        }