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; } } }
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); }
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; } } }
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)); }
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); }