/// <summary>
        ///     create greater than or equal expression ( operator ">=" or "=ge=" )
        /// </summary>
        /// <param name="parameter"></param>
        /// <param name="context"></param>
        /// <param name="jsonNamingPolicy"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static Expression <Func <T, bool> > GetGeExpression <T>(ParameterExpression parameter,
                                                                       RSqlQueryParser.ComparisonContext context,
                                                                       JsonNamingPolicy jsonNamingPolicy = null)
        {
            var expressionValue = GetSelector <T>(parameter, context, jsonNamingPolicy);

            if (!RSqlQueryGetValueHelper.IsLowerOrGreaterComparisonType(expressionValue.Property.PropertyType))
            {
                throw new ComparisonInvalidComparatorSelectionException(context);
            }

            var value = GetUniqueValue <T>(parameter, expressionValue, context, jsonNamingPolicy);

            var expression = value is ExpressionValue valueExp1
                ? valueExp1.Expression
                : Expression.Constant(value, expressionValue.Property.PropertyType);

            if (value is ExpressionValue valueExp2 &&
                valueExp2.Property.PropertyType != expressionValue.Property.PropertyType)
            {
                throw new ComparisonInvalidMatchTypeException(context);
            }

            return(Expression.Lambda <Func <T, bool> >(Expression.GreaterThanOrEqual(
                                                           expressionValue.Expression,
                                                           expression), parameter));
        }
        /// <summary>
        /// extract the unique value
        /// </summary>
        /// <param name="parameter"></param>
        /// <param name="expressionValue"></param>
        /// <param name="context"></param>
        /// <param name="jsonNamingPolicy"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        /// <exception cref="ComparisonNotEnoughArgumentException"></exception>
        /// <exception cref="ComparisonTooManyArgumentException"></exception>
        private static object GetUniqueValue <T>(ParameterExpression parameter, ExpressionValue expressionValue,
                                                 RSqlQueryParser.ComparisonContext context,
                                                 JsonNamingPolicy jsonNamingPolicy = null)
        {
            var value = context.arguments().value();

            if (value.Length > 1)
            {
                throw new ComparisonTooManyArgumentException(context);
            }

            return(RSqlQueryGetValueHelper.GetValue <T>(parameter, expressionValue, context, jsonNamingPolicy));
        }
        /// <summary>
        ///     create equal expression ( operator "==" or "=eq=" )
        /// </summary>
        /// <param name="parameter"></param>
        /// <param name="context"></param>
        /// <param name="jsonNamingPolicy"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static Expression <Func <T, bool> > GetEqExpression <T>(ParameterExpression parameter,
                                                                       RSqlQueryParser.ComparisonContext context,
                                                                       JsonNamingPolicy jsonNamingPolicy = null)
        {
            var expressionValue = GetSelector <T>(parameter, context, jsonNamingPolicy);

            if (!RSqlQueryGetValueHelper.IsEqualComparisonType(expressionValue.Property.PropertyType))
            {
                throw new ComparisonInvalidComparatorSelectionException(context);
            }

            var value      = GetUniqueValue <T>(parameter, expressionValue, context, jsonNamingPolicy);
            var expression = value is ExpressionValue valueExp1
                ? valueExp1.Expression
                : Expression.Constant(value, expressionValue.Property.PropertyType);

            if (value is ExpressionValue valueExp2 &&
                valueExp2.Property.PropertyType != expressionValue.Property.PropertyType)
            {
                throw new ComparisonInvalidMatchTypeException(context);
            }

            if (expressionValue.Property.PropertyType != typeof(string) || value is ExpressionValue)
            {
                return(Expression.Lambda <Func <T, bool> >(Expression.Equal(
                                                               expressionValue.Expression, expression
                                                               ), parameter));
            }

            var v = ((string)value).Replace(@"\*", MaskLk);

            if (v.IndexOf('*') != -1)
            {
                return(GetLkExpression <T>(parameter, context, jsonNamingPolicy));
            }

            value = v.Replace(MaskLk, "*");

            return(Expression.Lambda <Func <T, bool> >(Expression.Equal(
                                                           expressionValue.Expression,
                                                           Expression.Constant(value, expressionValue.Property.PropertyType)), parameter));
        }
        /// <summary>
        ///     create like expression
        /// </summary>
        /// <returns></returns>
        private static Expression <Func <T, bool> > GetLkExpression <T>(ParameterExpression parameter,
                                                                        RSqlQueryParser.ComparisonContext context,
                                                                        JsonNamingPolicy jsonNamingPolicy = null)
        {
            var expressionValue = GetSelector <T>(parameter, context, jsonNamingPolicy);
            var values          = RSqlQueryGetValueHelper.GetValues(expressionValue.Property.PropertyType, context.arguments());

            if (values.Count > 1)
            {
                throw new ComparisonTooManyArgumentException(context);
            }

            var criteria = Convert.ToString(values[0]) ?? string.Empty;
            var maskStar = "{" + Guid.NewGuid() + "}";

            criteria = criteria.Replace(@"\*", maskStar);
            MethodInfo method;

            if (!criteria.Contains('*'))
            {
                criteria += '*';
            }

            if (criteria.StartsWith("*", StringComparison.Ordinal) && criteria.EndsWith("*", StringComparison.Ordinal))
            {
                method = QueryReflectionHelper.MethodStringContains;
            }
            else if (criteria.StartsWith("*", StringComparison.Ordinal))
            {
                method = QueryReflectionHelper.MethodStringEndsWith;
            }
            else
            {
                method = QueryReflectionHelper.MethodStringStartsWith;
            }

            criteria = criteria.Replace("*", "").Replace(maskStar, "*");
            return(Expression.Lambda <Func <T, bool> >(Expression.Call(expressionValue.Expression,
                                                                       method,
                                                                       Expression.Constant(criteria, expressionValue.Property.PropertyType)), parameter));
        }
        /// <summary>
        ///     create is null expression ( operator "=is-null=" or "=nil=" )
        /// </summary>
        /// <param name="parameter"></param>
        /// <param name="context"></param>
        /// <param name="jsonNamingPolicy"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static Expression <Func <T, bool> > GetIsNullExpression <T>(ParameterExpression parameter,
                                                                           RSqlQueryParser.ComparisonContext context,
                                                                           JsonNamingPolicy jsonNamingPolicy = null)
        {
            var expressionValue = GetSelector <T>(parameter, context, jsonNamingPolicy);

            if (!RSqlQueryGetValueHelper.IsNullableComparisonType(expressionValue.Property.PropertyType))
            {
                throw new ComparisonInvalidComparatorSelectionException(context);
            }

            var values = RSqlQueryGetValueHelper.GetValues(typeof(bool), context.arguments());

            if (!values.Any())
            {
                throw new ComparisonNotEnoughArgumentException(context);
            }

            if (values.Count > 1)
            {
                throw new ComparisonTooManyArgumentException(context);
            }

            var result = Expression.Lambda <Func <T, bool> >(Expression.Equal(
                                                                 expressionValue.Expression,
                                                                 Expression.Constant(null, typeof(object))), parameter);

            if ((bool)values[0])
            {
                return(result);
            }

            var body = Expression.Not(result.Body);

            result = Expression.Lambda <Func <T, bool> >(body, parameter);
            return(result);
        }
 /// <summary>
 /// extract the multi value
 /// </summary>
 /// <param name="expressionValue"></param>
 /// <param name="context"></param>
 /// <returns></returns>
 /// <exception cref="ComparisonNotEnoughArgumentException"></exception>
 private static List <object> GetMultipleValue(ExpressionValue expressionValue,
                                               RSqlQueryParser.ComparisonContext context)
 {
     return(RSqlQueryGetValueHelper.GetValues(expressionValue.Property.PropertyType, context.arguments()));
 }