示例#1
0
                public override void VisitFieldToken(QueryExpression fieldName, QueryExpression value, BlittableJsonReaderObject parameters, OperatorType?operatorType)
                {
                    if (fieldName is MethodExpression me)
                    {
                        var methodType = QueryMethod.GetMethodType(me.Name);
                        switch (methodType)
                        {
                        case MethodType.Id:
                            if (value is ValueExpression ve)
                            {
                                var id = QueryBuilder.GetValue(_query, _metadata, parameters, ve);

                                Debug.Assert(id.Type == ValueTokenType.String || id.Type == ValueTokenType.Null);

                                AddId(id.Value?.ToString());
                            }
                            if (value is MethodExpression right)
                            {
                                var id = QueryBuilder.EvaluateMethod(_query, _metadata, _serverContext, _context, right, ref parameters);
                                if (id is ValueExpression v)
                                {
                                    AddId(v.Token);
                                }
                            }
                            break;
                        }
                    }
                }
示例#2
0
        private static QueryFieldName ExtractIndexFieldName(Query query, BlittableJsonReaderObject parameters, QueryExpression field, QueryMetadata metadata)
        {
            if (field is FieldExpression fe)
            {
                return(metadata.GetIndexFieldName(fe, parameters));
            }

            if (field is ValueExpression ve)
            {
                return(metadata.GetIndexFieldName(new QueryFieldName(ve.Token, false), parameters));
            }

            if (field is MethodExpression me)
            {
                var methodType = QueryMethod.GetMethodType(me.Name.Value);
                switch (methodType)
                {
                case MethodType.Id:
                    if (me.Arguments == null || me.Arguments.Count == 0)
                    {
                        return(QueryFieldName.DocumentId);
                    }
                    if (me.Arguments[0] is FieldExpression docAlias && docAlias.Compound.Count == 1 && docAlias.Compound[0].Equals(query.From.Alias))
                    {
                        return(QueryFieldName.DocumentId);
                    }
                    throw new InvalidQueryException("id() can only be used on the root query alias but got: " + me.Arguments[0], query.QueryText, parameters);

                case MethodType.Count:
                    if (me.Arguments == null || me.Arguments.Count == 0)
                    {
                        return(QueryFieldName.Count);
                    }
                    if (me.Arguments[0] is FieldExpression countAlias && countAlias.Compound.Count == 1 && countAlias.Compound[0].Equals(query.From.Alias))
                    {
                        return(QueryFieldName.Count);
                    }

                    throw new InvalidQueryException("count() can only be used on the root query alias but got: " + me.Arguments[0], query.QueryText, parameters);

                case MethodType.Sum:
                    if (me.Arguments != null && me.Arguments.Count == 1 &&
                        me.Arguments[0] is FieldExpression f &&
                        f.Compound.Count == 1)
                    {
                        return(new QueryFieldName(f.Compound[0], f.IsQuoted));
                    }

                    throw new InvalidQueryException("sum() must be called with a single field name, but was called: " + me, query.QueryText, parameters);

                default:
                    throw new InvalidQueryException("Method " + me.Name.Value + " cannot be used in an expression in this manner", query.QueryText, parameters);
                }
            }

            throw new InvalidQueryException("Expected field, got: " + field, query.QueryText, parameters);
        }
示例#3
0
                public override void VisitFieldToken(QueryExpression fieldName, QueryExpression value, BlittableJsonReaderObject parameters, OperatorType?operatorType)
                {
                    if (fieldName is MethodExpression me)
                    {
                        var methodType = QueryMethod.GetMethodType(me.Name);
                        switch (methodType)
                        {
                        case MethodType.Id:
                            if (value is ValueExpression ve)
                            {
                                var id = QueryBuilder.GetValue(_query, _metadata, parameters, ve);

                                Debug.Assert(id.Type == ValueTokenType.String);

                                AddId(id.Value.ToString());
                            }
                            else if (_metadata.FillIds != null)
                            {
                                AddId(_metadata.FillIds.EvaluateSingleMethod(_resultsRetriever, null).ToString());
                            }
                            break;
                        }
                    }
                }
示例#4
0
        private static Lucene.Net.Search.Query HandleSpatial(Query query, MethodExpression expression, QueryMetadata metadata, BlittableJsonReaderObject parameters,
                                                             MethodType spatialMethod, Func <string, SpatialField> getSpatialField)
        {
            string fieldName;

            if (metadata.IsDynamic == false)
            {
                fieldName = ExtractIndexFieldName(query, parameters, expression.Arguments[0], metadata);
            }
            else
            {
                var spatialExpression = (MethodExpression)expression.Arguments[0];
                fieldName = spatialExpression.GetText();
            }

            var shapeExpression = (MethodExpression)expression.Arguments[1];

            var distanceErrorPct = Constants.Documents.Indexing.Spatial.DefaultDistanceErrorPct;

            if (expression.Arguments.Count == 3)
            {
                var distanceErrorPctValue = GetValue(fieldName, query, metadata, parameters, (ValueExpression)expression.Arguments[2]);
                AssertValueIsNumber(fieldName, distanceErrorPctValue.Type);

                distanceErrorPct = Convert.ToDouble(distanceErrorPctValue.Value);
            }

            var spatialField = getSpatialField(fieldName);

            var methodName = shapeExpression.Name;
            var methodType = QueryMethod.GetMethodType(methodName);

            Shape shape = null;

            switch (methodType)
            {
            case MethodType.Circle:
                shape = HandleCircle(query, shapeExpression, metadata, parameters, fieldName, spatialField);
                break;

            case MethodType.Wkt:
                shape = HandleWkt(query, shapeExpression, metadata, parameters, fieldName, spatialField);
                break;

            default:
                QueryMethod.ThrowMethodNotSupported(methodType, metadata.QueryText, parameters);
                break;
            }

            Debug.Assert(shape != null);

            SpatialOperation operation = null;

            switch (spatialMethod)
            {
            case MethodType.Within:
                operation = SpatialOperation.IsWithin;
                break;

            case MethodType.Contains:
                operation = SpatialOperation.Contains;
                break;

            case MethodType.Disjoint:
                operation = SpatialOperation.IsDisjointTo;
                break;

            case MethodType.Intersects:
                operation = SpatialOperation.Intersects;
                break;

            default:
                QueryMethod.ThrowMethodNotSupported(spatialMethod, metadata.QueryText, parameters);
                break;
            }

            Debug.Assert(operation != null);

            var args = new SpatialArgs(operation, shape)
            {
                DistErrPct = distanceErrorPct
            };

            return(spatialField.Strategy.MakeQuery(args));
        }
示例#5
0
        private static Lucene.Net.Search.Query ToLuceneQuery(JsonOperationContext context, Query query, QueryExpression expression, QueryMetadata metadata,
                                                             BlittableJsonReaderObject parameters, Analyzer analyzer, Func <string, SpatialField> getSpatialField, bool exact = false)
        {
            if (expression == null)
            {
                return(new MatchAllDocsQuery());
            }

            if (expression is BinaryExpression where)
            {
                switch (where.Operator)
                {
                case OperatorType.Equal:
                case OperatorType.NotEqual:
                case OperatorType.GreaterThan:
                case OperatorType.LessThan:
                case OperatorType.LessThanEqual:
                case OperatorType.GreaterThanEqual:
                {
                    var fieldName = ExtractIndexFieldName(query, parameters, where.Left, metadata);
                    var(value, valueType) = GetValue(fieldName, query, metadata, parameters, where.Right);

                    var(luceneFieldName, fieldType, termType) = GetLuceneField(fieldName, valueType);

                    switch (fieldType)
                    {
                    case LuceneFieldType.String:
                        var valueAsString = GetValueAsString(value);


                        if (exact && metadata.IsDynamic)
                        {
                            luceneFieldName = AutoIndexField.GetExactAutoIndexFieldName(luceneFieldName);
                        }

                        switch (where.Operator)
                        {
                        case OperatorType.Equal:
                            return(LuceneQueryHelper.Equal(luceneFieldName, termType, valueAsString, exact));

                        case OperatorType.NotEqual:
                            return(LuceneQueryHelper.NotEqual(luceneFieldName, termType, valueAsString, exact));

                        case OperatorType.LessThan:
                            return(LuceneQueryHelper.LessThan(luceneFieldName, termType, valueAsString, exact));

                        case OperatorType.GreaterThan:
                            return(LuceneQueryHelper.GreaterThan(luceneFieldName, termType, valueAsString, exact));

                        case OperatorType.LessThanEqual:
                            return(LuceneQueryHelper.LessThanOrEqual(luceneFieldName, termType, valueAsString, exact));

                        case OperatorType.GreaterThanEqual:
                            return(LuceneQueryHelper.GreaterThanOrEqual(luceneFieldName, termType, valueAsString, exact));
                        }
                        break;

                    case LuceneFieldType.Long:
                        var valueAsLong = (long)value;

                        switch (where.Operator)
                        {
                        case OperatorType.Equal:
                            return(LuceneQueryHelper.Equal(luceneFieldName, termType, valueAsLong));

                        case OperatorType.NotEqual:
                            return(LuceneQueryHelper.NotEqual(luceneFieldName, termType, valueAsLong));

                        case OperatorType.LessThan:
                            return(LuceneQueryHelper.LessThan(luceneFieldName, termType, valueAsLong));

                        case OperatorType.GreaterThan:
                            return(LuceneQueryHelper.GreaterThan(luceneFieldName, termType, valueAsLong));

                        case OperatorType.LessThanEqual:
                            return(LuceneQueryHelper.LessThanOrEqual(luceneFieldName, termType, valueAsLong));

                        case OperatorType.GreaterThanEqual:
                            return(LuceneQueryHelper.GreaterThanOrEqual(luceneFieldName, termType, valueAsLong));
                        }
                        break;

                    case LuceneFieldType.Double:
                        var valueAsDouble = (double)value;

                        switch (where.Operator)
                        {
                        case OperatorType.Equal:
                            return(LuceneQueryHelper.Equal(luceneFieldName, termType, valueAsDouble));

                        case OperatorType.NotEqual:
                            return(LuceneQueryHelper.NotEqual(luceneFieldName, termType, valueAsDouble));

                        case OperatorType.LessThan:
                            return(LuceneQueryHelper.LessThan(luceneFieldName, termType, valueAsDouble));

                        case OperatorType.GreaterThan:
                            return(LuceneQueryHelper.GreaterThan(luceneFieldName, termType, valueAsDouble));

                        case OperatorType.LessThanEqual:
                            return(LuceneQueryHelper.LessThanOrEqual(luceneFieldName, termType, valueAsDouble));

                        case OperatorType.GreaterThanEqual:
                            return(LuceneQueryHelper.GreaterThanOrEqual(luceneFieldName, termType, valueAsDouble));
                        }
                        break;

                    default:
                        throw new ArgumentOutOfRangeException(nameof(fieldType), fieldType, null);
                    }

                    throw new NotSupportedException("Should not happen!");
                }

                case OperatorType.And:
                case OperatorType.AndNot:
                    var andPrefix = where.Operator == OperatorType.AndNot ? LucenePrefixOperator.Minus : LucenePrefixOperator.None;
                    return(LuceneQueryHelper.And(
                               ToLuceneQuery(context, query, where.Left, metadata, parameters, analyzer, getSpatialField, exact),
                               LucenePrefixOperator.None,
                               ToLuceneQuery(context, query, where.Right, metadata, parameters, analyzer, getSpatialField, exact),
                               andPrefix));

                case OperatorType.Or:
                case OperatorType.OrNot:
                    var orPrefix = where.Operator == OperatorType.OrNot ? LucenePrefixOperator.Minus : LucenePrefixOperator.None;
                    return(LuceneQueryHelper.Or(
                               ToLuceneQuery(context, query, where.Left, metadata, parameters, analyzer, getSpatialField, exact),
                               LucenePrefixOperator.None,
                               ToLuceneQuery(context, query, where.Right, metadata, parameters, analyzer, getSpatialField, exact),
                               orPrefix));
                }
            }
            if (expression is BetweenExpression be)
            {
                var fieldName = ExtractIndexFieldName(query, parameters, be.Source, metadata);
                var(valueFirst, valueFirstType) = GetValue(fieldName, query, metadata, parameters, be.Min);
                var(valueSecond, _)             = GetValue(fieldName, query, metadata, parameters, be.Max);

                var(luceneFieldName, fieldType, termType) = GetLuceneField(fieldName, valueFirstType);

                switch (fieldType)
                {
                case LuceneFieldType.String:
                    var valueFirstAsString  = GetValueAsString(valueFirst);
                    var valueSecondAsString = GetValueAsString(valueSecond);
                    return(LuceneQueryHelper.Between(luceneFieldName, termType, valueFirstAsString, valueSecondAsString, exact));

                case LuceneFieldType.Long:
                    var valueFirstAsLong  = (long)valueFirst;
                    var valueSecondAsLong = (long)valueSecond;
                    return(LuceneQueryHelper.Between(luceneFieldName, termType, valueFirstAsLong, valueSecondAsLong));

                case LuceneFieldType.Double:
                    var valueFirstAsDouble  = (double)valueFirst;
                    var valueSecondAsDouble = (double)valueSecond;
                    return(LuceneQueryHelper.Between(luceneFieldName, termType, valueFirstAsDouble, valueSecondAsDouble));

                default:
                    throw new ArgumentOutOfRangeException(nameof(fieldType), fieldType, null);
                }
            }
            if (expression is InExpression ie)
            {
                var            fieldName         = ExtractIndexFieldName(query, parameters, ie.Source, metadata);
                LuceneTermType termType          = LuceneTermType.Null;
                bool           hasGotTheRealType = false;

                if (ie.All)
                {
                    var allInQuery = new BooleanQuery();
                    foreach (var value in GetValuesForIn(context, query, ie, metadata, parameters, fieldName))
                    {
                        if (hasGotTheRealType == false)
                        {
                            // here we assume that all the values are of the same type
                            termType          = GetLuceneField(fieldName, value.Type).LuceneTermType;
                            hasGotTheRealType = true;
                        }
                        if (exact && metadata.IsDynamic)
                        {
                            fieldName = new QueryFieldName(AutoIndexField.GetExactAutoIndexFieldName(fieldName.Value), fieldName.IsQuoted);
                        }

                        allInQuery.Add(LuceneQueryHelper.Equal(fieldName, termType, value.Value, exact), Occur.MUST);
                    }

                    return(allInQuery);
                }
                var matches = new List <string>();
                foreach (var tuple in GetValuesForIn(context, query, ie, metadata, parameters, fieldName))
                {
                    if (hasGotTheRealType == false)
                    {
                        // we assume that the type of all the parameters is the same
                        termType          = GetLuceneField(fieldName, tuple.Type).LuceneTermType;
                        hasGotTheRealType = true;
                    }
                    matches.Add(LuceneQueryHelper.GetTermValue(tuple.Value, termType, exact));
                }

                return(new TermsMatchQuery(fieldName, matches));
            }
            if (expression is TrueExpression)
            {
                return(new MatchAllDocsQuery());
            }
            if (expression is MethodExpression me)
            {
                var methodName = me.Name.Value;
                var methodType = QueryMethod.GetMethodType(methodName);

                switch (methodType)
                {
                case MethodType.Search:
                    return(HandleSearch(query, me, metadata, parameters, analyzer));

                case MethodType.Boost:
                    return(HandleBoost(context, query, me, metadata, parameters, analyzer, getSpatialField, exact));

                case MethodType.StartsWith:
                    return(HandleStartsWith(query, me, metadata, parameters));

                case MethodType.EndsWith:
                    return(HandleEndsWith(query, me, metadata, parameters));

                case MethodType.Lucene:
                    return(HandleLucene(query, me, metadata, parameters, analyzer));

                case MethodType.Exists:
                    return(HandleExists(query, parameters, me, metadata));

                case MethodType.Exact:
                    return(HandleExact(context, query, me, metadata, parameters, analyzer, getSpatialField));

                case MethodType.Within:
                case MethodType.Contains:
                case MethodType.Disjoint:
                case MethodType.Intersects:
                    return(HandleSpatial(query, me, metadata, parameters, methodType, getSpatialField));

                default:
                    QueryMethod.ThrowMethodNotSupported(methodType, metadata.QueryText, parameters);
                    return(null);    // never hit
                }
            }

            throw new InvalidQueryException("Unable to understand query", query.QueryText, parameters);
        }