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