private static IReadOnlyCollection <IFilter> And(IReadOnlyCollection <IFilter> left, IFilter right) { if (null == left) { throw new ArgumentNullException(nameof(left)); } if (null == right) { throw new ArgumentNullException(nameof(right)); } for (int index = 0; index < left.Count; index++) { IFilter leftFilter = left.ElementAt(index); FilterExpression.And(leftFilter, right); } return(left); }
private static void And(IFilter left, IFilter right) { if (null == left) { throw new ArgumentNullException(nameof(left)); } if (null == right) { throw new ArgumentNullException(nameof(right)); } if (null == left.AdditionalFilter) { left.AdditionalFilter = right; } else { FilterExpression.And(left.AdditionalFilter, right); } }
private static IReadOnlyCollection <IFilter> And(IFilter left, IReadOnlyCollection <IFilter> right) { List <IFilter> result = new List <IFilter>(); IFilter template = new Filter(left); for (int index = 0; index < right.Count; index++) { IFilter rightFilter = right.ElementAt(index); IFilter leftFilter; if (0 == index) { leftFilter = left; } else { leftFilter = new Filter(template); result.Add(leftFilter); } FilterExpression.And(leftFilter, rightFilter); } return(result); }
// 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); }