private FilterOperatorType GetFilterOperator()

in src/Azure.IIoT.OpcUa.Publisher/src/Parser/FilterModelBuilder.cs [500:657]


        private FilterOperatorType GetFilterOperator(ParseTreeNode op, out bool negate,
            out Func<List<FilterOperandModel>, string?> validator)
        {
            negate = false;
            var opStr = op.FindTokenAndGetText();
            FilterOperatorType filterOp;
            switch (opStr.ToUpperInvariant())
            {
                case "NOT":
                case "!":
                    filterOp = FilterOperatorType.Not;
                    validator = l => ValidateExact(1, l);
                    break;
                case "=":
                case "==":
                    filterOp = FilterOperatorType.Equals;
                    validator = l => ValidateExact(2, l);
                    break;
                case ">":
                    filterOp = FilterOperatorType.GreaterThan;
                    validator = l => ValidateExact(2, l);
                    break;
                case "<":
                    filterOp = FilterOperatorType.LessThan;
                    validator = l => ValidateExact(2, l);
                    break;
                case ">=":
                    filterOp = FilterOperatorType.GreaterThan;
                    validator = l => ValidateExact(2, l);
                    break;
                case "<=":
                    filterOp = FilterOperatorType.LessThanOrEqual;
                    validator = l => ValidateExact(2, l);
                    break;
                case "LIKE":
                    filterOp = FilterOperatorType.Like;
                    validator = l => ValidateExact(2, l);
                    break;
                case "<>":
                case "!=":
                    negate = true;
                    filterOp = FilterOperatorType.Equals;
                    validator = l => ValidateExact(2, l);
                    break;
                case "!<":
                    negate = true;
                    filterOp = FilterOperatorType.LessThan;
                    validator = l => ValidateExact(2, l);
                    break;
                case "!>":
                    negate = true;
                    filterOp = FilterOperatorType.GreaterThan;
                    validator = l => ValidateExact(2, l);
                    break;
                case "AND":
                    filterOp = FilterOperatorType.And;
                    validator = l => ValidateExact(2, l, true);
                    break;
                case "OR":
                    filterOp = FilterOperatorType.Or;
                    validator = l => ValidateExact(2, l, true);
                    break;
                case "CAST":
                    filterOp = FilterOperatorType.Cast;
                    validator = l => ValidateExact(2, l);
                    break;
                case "&":
                    filterOp = FilterOperatorType.BitwiseAnd;
                    validator = l => ValidateExact(2, l);
                    break;
                case "|":
                    filterOp = FilterOperatorType.BitwiseOr;
                    validator = l => ValidateExact(2, l);
                    break;
                case "IN":
                    filterOp = FilterOperatorType.InList;
                    validator = l => ValidateMin(1, l);
                    break;
                case "BETWEEN":
                    filterOp = FilterOperatorType.Between;
                    validator = l => ValidateExact(3, l);
                    break;
                case "RELATEDTO":
                    filterOp = FilterOperatorType.RelatedTo;
                    validator = ValidateRelatedTo;
                    break;
                case "ISNULL":
                    filterOp = FilterOperatorType.IsNull;
                    validator = l => ValidateExact(1, l);
                    break;
                case "OFTYPE":
                    filterOp = FilterOperatorType.OfType;
                    validator = l => ValidateExact(1, l);
                    break;
                case "INVIEW":
                    filterOp = FilterOperatorType.InView;
                    validator = l => ValidateExact(1, l);
                    break;
                default:
                    throw ParserException.Create($"Operand {opStr} not supported",
                        _syntaxTree, op);
            }
            return filterOp;

            //
            // Generic expression validation. Validates the exact length of
            // provided operands.
            //
            string? ValidateExact(int exact, List<FilterOperandModel> operands,
                bool reverseOperands = false)
            {
                if (exact != operands.Count)
                {
                    return $"Operator {opStr} ({filterOp}) requires {exact} " +
                        $"operand(s) but only {operands.Count} provided.";
                }
                if (reverseOperands && operands.All(o => o.Index != null))
                {
                    //
                    // Call reverse on the operands to match the specification
                    // examples (validated in our tests)
                    //
                    operands.Reverse();
                }
                return null;
            }

            //
            // Special case related to, which can have 3-6 operands
            //
            string? ValidateRelatedTo(IList<FilterOperandModel> operands)
            {
                if (operands.Count < 3)
                {
                    return $"Operator {opStr} ({filterOp}) requires at least " +
                        $"3 operands, but {operands.Count} provided.";
                }
                if (operands.Count > 6)
                {
                    return $"Operator {opStr} ({filterOp}) requires at most " +
                        $"6 operands, but {operands.Count} provided.";
                }
                return null;
            }

            //
            // Validate minimum operands are provided.
            //
            string? ValidateMin(int min, IList<FilterOperandModel> operands)
            {
                if (operands.Count < min)
                {
                    return $"Operator {opStr} ({filterOp}) requires at least " +
                        $"{min} operand(s), but {operands.Count} provided.";
                }
                return null;
            }
        }