private Expression VisitRegexp(Expression left, Expression right)
        {
            var cm = ConstantMemberPair.Create(left, right);

            if (cm != null)
            {
                return(new CriteriaExpression(new RegexpCriteria(mapping.GetFieldName(prefix, cm.MemberExpression.Member), cm.ConstantExpression.Value.ToString())));
            }

            throw new NotSupportedException("Regexp must be between a Member and a Constant");
        }
        private Expression VisitContains(string methodName, Expression left, Expression right, TermsExecutionMode executionMode)
        {
            var cm = ConstantMemberPair.Create(left, right);

            if (cm != null)
            {
                var values = ((IEnumerable)cm.ConstantExpression.Value).Cast <object>().ToArray();
                return(new CriteriaExpression(TermsCriteria.Build(executionMode, mapping.GetFieldName(prefix, cm.MemberExpression.Member), cm.MemberExpression.Member, values)));
            }

            throw new NotSupportedException(methodName + " must be between a Member and a Constant");
        }
        Expression VisitContains(string methodName, Expression left, Expression right, TermsExecutionMode executionMode)
        {
            var cm = ConstantMemberPair.Create(left, right);

            if (cm != null && Mapping.TryGetFieldName(SourceType, cm.Expression, out string fieldName))
            {
                var values = ((IEnumerable)cm.ConstantExpression.Value).Cast <object>().ToArray();

                return(new CriteriaExpression(TermsCriteria.Build(executionMode, fieldName, cm.GetMemberFromExpression(), values)));
            }

            throw new NotSupportedException(methodName + " must be between a Member and a Constant");
        }
        private Expression VisitRange(ExpressionType t, Expression left, Expression right)
        {
            var cm = ConstantMemberPair.Create(left, right);

            if (cm == null)
            {
                throw new NotSupportedException("A range must consist of a constant and a member");
            }

            var member    = cm.MemberExpression.Member;
            var fieldName = mapping.GetFieldName(prefix, member);

            return(new CriteriaExpression(new RangeCriteria(fieldName, member, ExpressionTypeToRangeType(t), cm.ConstantExpression.Value)));
        }
        private Expression CreateExists(ConstantMemberPair cm, bool positiveTest)
        {
            var fieldName = mapping.GetFieldName(prefix, UnwrapNullableMethodExpression(cm.MemberExpression));
            var value     = cm.ConstantExpression.Value ?? false;

            if (value.Equals(positiveTest))
            {
                return(new CriteriaExpression(new ExistsCriteria(fieldName)));
            }

            if (value.Equals(!positiveTest))
            {
                return(new CriteriaExpression(new MissingCriteria(fieldName)));
            }

            throw new NotSupportedException("A null test Expression must have a member being compared to a bool or null");
        }
        private Expression VisitNotEqual(Expression left, Expression right)
        {
            var cm = ConstantMemberPair.Create(left, right);

            if (cm == null)
            {
                throw new NotSupportedException("A not-equal expression must consist of a constant and a member");
            }

            if (cm.IsNullTest)
            {
                return(CreateExists(cm, false));
            }

            var member    = cm.MemberExpression.Member;
            var fieldName = mapping.GetFieldName(prefix, member);

            return(new CriteriaExpression(NotCriteria.Create(TermsCriteria.Build(fieldName, member, cm.ConstantExpression.Value))));
        }
        private Expression VisitEquals(Expression left, Expression right)
        {
            var cm = ConstantMemberPair.Create(left, right);

            if (cm == null)
            {
                throw new NotSupportedException("Equality must be between a Member and a Constant");
            }

            if (cm.IsNullTest)
            {
                return(CreateExists(cm, true));
            }

            var member    = cm.MemberExpression.Member;
            var fieldName = mapping.GetFieldName(prefix, member);

            return(new CriteriaExpression(TermsCriteria.Build(fieldName, member, cm.ConstantExpression.Value)));
        }
        private Expression VisitRange(RangeComparison rangeComparison, Expression left, Expression right)
        {
            var inverted = left is ConstantExpression;
            var cm       = ConstantMemberPair.Create(left, right);

            if (cm == null)
            {
                throw new NotSupportedException("A {0} must test a constant against a member");
            }

            if (inverted)
            {
                rangeComparison = invertedRangeComparison[(int)rangeComparison];
            }

            var field = Mapping.GetFieldName(Prefix, cm.MemberExpression);

            return(new CriteriaExpression(new RangeCriteria(field, cm.MemberExpression.Member, rangeComparison, cm.ConstantExpression.Value)));
        }
        private Expression VisitNotEqual(Expression left, Expression right)
        {
            var booleanEquals = VisitCriteriaEquals(left, right, false);

            if (booleanEquals != null)
            {
                return(booleanEquals);
            }

            var cm = ConstantMemberPair.Create(left, right);

            if (cm == null)
            {
                throw new NotSupportedException("A not-equal expression must be between a constant and a member");
            }

            return(cm.IsNullTest
                ? CreateExists(cm, false)
                : new CriteriaExpression(NotCriteria.Create(new TermCriteria(Mapping.GetFieldName(Prefix, cm.MemberExpression), cm.MemberExpression.Member, cm.ConstantExpression.Value))));
        }
        private Expression VisitEquals(Expression left, Expression right)
        {
            var booleanEquals = VisitCriteriaEquals(left, right, true);

            if (booleanEquals != null)
            {
                return(booleanEquals);
            }

            var cm = ConstantMemberPair.Create(left, right);

            if (cm != null)
            {
                return(cm.IsNullTest
                    ? CreateExists(cm, true)
                    : new CriteriaExpression(new TermCriteria(Mapping.GetFieldName(Prefix, cm.MemberExpression), cm.MemberExpression.Member, cm.ConstantExpression.Value)));
            }

            throw new NotSupportedException("Equality must be between a Member and a Constant");
        }
        Expression VisitNotEqual(Expression left, Expression right)
        {
            var booleanEquals = VisitCriteriaEquals(left, right, false);

            if (booleanEquals != null)
            {
                return(booleanEquals);
            }

            var cm = ConstantMemberPair.Create(left, right);

            if (cm == null)
            {
                throw new NotSupportedException("A not-equal expression must be between a constant and a member");
            }

            return(cm.IsNullTest
                ? CreateExists(cm, false)
                : VisitCriteriaEqualsForFields(cm, false));
        }
        Expression VisitEquals(Expression left, Expression right)
        {
            var booleanEquals = VisitCriteriaEquals(left, right, true);

            if (booleanEquals != null)
            {
                return(booleanEquals);
            }

            var cm = ConstantMemberPair.Create(left, right);

            if (cm != null)
            {
                return(cm.IsNullTest
                    ? CreateExists(cm, true)
                    : VisitCriteriaEqualsForFields(cm));
            }

            throw new NotSupportedException("Equality must be between a Member and a Constant");
        }
        Expression VisitRange(RangeComparison rangeComparison, Expression left, Expression right)
        {
            var inverted = left is ConstantExpression;
            var cm       = ConstantMemberPair.Create(left, right);

            if (cm == null)
            {
                throw new NotSupportedException("A {0} must test a constant against a member");
            }

            if (inverted)
            {
                rangeComparison = invertedRangeComparison[(int)rangeComparison];
            }

            if (Mapping.TryGetFieldName(SourceType, cm.Expression, out string field))
            {
                return(new CriteriaExpression(new RangeCriteria(field, cm.GetMemberFromExpression(), rangeComparison, cm.ConstantExpression.Value)));
            }

            return(null);
        }
        Expression VisitCriteriaEqualsForFields(ConstantMemberPair constantMemberPair, bool equal = true)
        {
            if (Mapping.TryGetFieldName(SourceType, constantMemberPair.Expression, out string fieldName))
            {
                var propertyMappings = Mapping.ElasticPropertyMappings();

                ICriteria criteria;

                if (IsPropertyTypeText(fieldName, propertyMappings))
                {
                    if (propertyMappings.ContainsKey($"{fieldName}.keyword"))
                    {
                        fieldName = $"{fieldName}.keyword";
                        criteria  = new TermCriteria(fieldName,
                                                     constantMemberPair.GetMemberFromExpression(), constantMemberPair.ConstantExpression.Value);
                    }
                    else
                    {
                        criteria = new MatchCriteria(fieldName,
                                                     constantMemberPair.GetMemberFromExpression(), constantMemberPair.ConstantExpression.Value);
                    }
                }
                else
                {
                    criteria = new TermCriteria(fieldName,
                                                constantMemberPair.GetMemberFromExpression(), constantMemberPair.ConstantExpression.Value);
                }

                if (!equal)
                {
                    criteria = NotCriteria.Create(criteria);
                }
                return(new CriteriaExpression(criteria));
            }

            return(null);
        }