Example #1
0
        private void Initialize(System.Text.RegularExpressions.Group left, System.Text.RegularExpressions.Group @operator, System.Text.RegularExpressions.Group right)
        {
            if (null == left)
            {
                throw new ArgumentNullException(nameof(left));
            }

            if (null == @operator)
            {
                throw new ArgumentNullException(nameof(@operator));
            }

            if (null == right)
            {
                throw new ArgumentNullException(nameof(right));
            }

            if
            (
                !left.Success ||
                !right.Success ||
                string.IsNullOrEmpty(left.Value) ||
                string.IsNullOrEmpty(right.Value)
            )
            {
                string message =
                    CultureInfo.InvariantCulture +
                    "ExceptionInvalidFilterTemplate" +
                    this.Text;
                throw new InvalidOperationException(message);
            }

            this.attributePath = left.Value;

            if (!Enum.TryParse <ComparisonOperatorValue>(@operator.Value, out ComparisonOperatorValue comparisonOperatorValue))
            {
                string message =
                    CultureInfo.InvariantCulture +
                    "ExceptionInvalidFilterTemplate" +
                    this.Text;
                throw new InvalidOperationException(message);
            }
            this.Operator = comparisonOperatorValue;

            if (!FilterExpression.TryParse(right.Value, out string comparisonValue))
            {
                string message =
                    CultureInfo.InvariantCulture +
                    "ExceptionInvalidFilterTemplate" +
                    this.Text;
                throw new InvalidOperationException(message);
            }
            this.value = new ComparisonValue(comparisonValue, FilterExpression.Quote == right.Value[0]);

            int indexRemainder = right.Value.IndexOf(comparisonValue, StringComparison.Ordinal) + comparisonValue.Length;

            if (indexRemainder >= right.Value.Length)
            {
                return;
            }
            string remainder = right.Value.Substring(indexRemainder);
            int    indexAnd  = remainder.IndexOf(FilterExpression.LogicalOperatorAnd.Value, StringComparison.Ordinal);
            int    indexOr   = remainder.IndexOf(FilterExpression.LogicalOperatorOr.Value, StringComparison.Ordinal);
            int    indexNextFilter;
            int    indexLogicalOperator;

            if (indexAnd >= 0 && (indexOr < 0 || indexAnd < indexOr))
            {
                indexNextFilter      = indexAnd + FilterExpression.LogicalOperatorAnd.Value.Length;
                this.logicalOperator = LogicalOperatorValue.and;
                indexLogicalOperator = indexAnd;
            }
            else if (indexOr >= 0)
            {
                indexNextFilter      = indexOr + FilterExpression.LogicalOperatorOr.Value.Length;
                this.logicalOperator = LogicalOperatorValue.or;
                indexLogicalOperator = indexOr;
            }
            else
            {
                string tail = remainder.Trim().TrimEnd(FilterExpression.TrailingCharacters.Value);
                if (!string.IsNullOrWhiteSpace(tail))
                {
                    string message =
                        CultureInfo.InvariantCulture +
                        "ExceptionInvalidFilterTemplate" +
                        this.Text;
                    throw new InvalidOperationException(message);
                }
                else
                {
                    return;
                }
            }

            string nextExpression      = remainder.Substring(indexNextFilter);
            int    indexClosingBracket = remainder.IndexOf(FilterExpression.BracketClose, StringComparison.Ordinal);
            int    nextExpressionLevel;
            int    nextExpressionGroup;

            if (indexClosingBracket >= 0 && indexClosingBracket < indexLogicalOperator)
            {
                nextExpressionLevel = this.Level - 1;
                nextExpressionGroup = this.Group - 1;
            }
            else
            {
                nextExpressionLevel = this.Level;
                nextExpressionGroup = this.Group;
            }
            this.next          = new FilterExpression(nextExpression, nextExpressionGroup, nextExpressionLevel);
            this.next.Previous = this;
        }
Example #2
0
        public IReadOnlyCollection <IFilter> ToFilters()
        {
            IReadOnlyCollection <IFilter> result = new FilterExpression(this).Convert();

            return(result);
        }
Example #3
0
        // Convert the doubly-linked list into a collection of IFilter objects.
        // There are three cases that may be encountered as the conversion proceeds through the linked list of clauses.
        // Those cases are documented by comments below.
        private IReadOnlyCollection <IFilter> Convert()
        {
            List <IFilter> result     = new List <IFilter>();
            IFilter        thisFilter = this.ToFilter();

            result.Add(thisFilter);
            FilterExpression current = this.next;

            while (current != null)
            {
                if (this.Level == current.Level)
                {
                    // The current clause has the same level number as the initial clause,
                    // such as
                    // b eq 2
                    // in the expression
                    // a eq 1 and b eq 2.
                    IFilter filter = current.ToFilter();
                    switch (current.Previous.logicalOperator)
                    {
                    case LogicalOperatorValue.and:
                        IFilter left = result.Last();
                        FilterExpression.And(left, filter);
                        break;

                    case LogicalOperatorValue.or:
                        result.Add(filter);
                        break;

                    default:
                        string notSupported = Enum.GetName(typeof(LogicalOperatorValue), this.logicalOperator);
                        throw new NotSupportedException(notSupported);
                    }
                    current = current.next;
                }
                else if (this.Level > current.Level)
                {
                    // The current clause has a lower level number than the initial clause,
                    // such as
                    // c eq 3
                    // in the expression
                    // (a eq 1 and b eq 2) or c eq 3.
                    IReadOnlyCollection <IFilter> superiors = current.Convert();
                    switch (current.Previous.logicalOperator)
                    {
                    case LogicalOperatorValue.and:
                        IFilter superior = superiors.First();
                        result = FilterExpression.And(result, superior).ToList();
                        IReadOnlyCollection <IFilter> remainder = superiors.Skip(1).ToArray();
                        result.AddRange(remainder);
                        break;

                    case LogicalOperatorValue.or:
                        result.AddRange(superiors);
                        break;

                    default:
                        string notSupported = Enum.GetName(typeof(LogicalOperatorValue), this.logicalOperator);
                        throw new NotSupportedException(notSupported);
                    }
                    break;
                }
                else
                {
                    // The current clause has a higher level number than the initial clause,
                    // such as
                    // b eq 2
                    // in the expression
                    // a eq 1 and (b eq 2 or c eq 3) and (d eq 4 or e eq 5)
                    //
                    // In this case, the linked list is edited,
                    // so that
                    // c eq 3
                    // has no next link,
                    // while the next link of
                    // a eq 1
                    // refers to
                    // d eq 4.
                    // Thereby,
                    // b eq 2 or c eq 3
                    // can be converted to filters and combined with the filter composed from
                    // a eq 1,
                    // after which conversion will continue with the conversion of
                    // d eq 4.
                    // It is the change in group number between
                    // c eq 3
                    // and
                    // d eq 4
                    // that identifies the end of current group,
                    // despite the two clauses having the same level number.
                    //
                    // It is because of the editing of the linked list that the public method,
                    // ToFilters(),
                    // makes a copy of the linked list before initiating conversion;
                    // so that,
                    // ToFilters()
                    // can be called on a FilterExpression any number of times,
                    // to yield the same output.
                    FilterExpression subordinate = current;
                    while (current != null && this.Level < current.Level && subordinate.Group == current.Group)
                    {
                        current = current.next;
                    }
                    if (current != null)
                    {
                        current.Previous.next     = null;
                        subordinate.Previous.next = current;
                    }
                    IReadOnlyCollection <IFilter> subordinates = subordinate.Convert();
                    switch (subordinate.Previous.logicalOperator)
                    {
                    case LogicalOperatorValue.and:
                        IFilter superior = result.Last();
                        IReadOnlyCollection <IFilter> merged = FilterExpression.And(superior, subordinates);
                        result.AddRange(merged);
                        break;

                    case LogicalOperatorValue.or:
                        result.AddRange(subordinates);
                        break;

                    default:
                        string notSupported = Enum.GetName(typeof(LogicalOperatorValue), this.logicalOperator);
                        throw new NotSupportedException(notSupported);
                    }
                }
            }
            return(result);
        }