/// <summary> /// Visits the children of the UnaryExpression. /// </summary> /// <param name="node"> /// The expression to visit. /// </param> /// <returns> /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. /// </returns> protected override Expression VisitUnary(UnaryExpression node) { BooleanQuery boolQuery; switch (node.NodeType) { case ExpressionType.Not: if (node.Operand.NodeType == ExpressionType.MemberAccess) { // We're accessing a boolean member, and we want to match those where the field is false. MappedField field = Owner.GetMappedField((MemberExpression)node.Operand); Query query = MakeTermQuery(field, Expression.Constant(false)); queryStack.Push(query); return(node); } Visit(node.Operand); Debug.Assert(queryStack.Count >= 1, "The query stack must not be empty."); boolQuery = new BooleanQuery(); boolQuery.Add(new MatchAllDocsQuery(), Occur.MUST); boolQuery.Add(queryStack.Pop(), Occur.MUST_NOT); queryStack.Push(boolQuery); return(node); } return(base.VisitUnary(node)); }
/// <summary> /// Visits the children of the MethodCallExpression. /// </summary> /// <param name="node"> /// The expression to visit. /// </param> /// <returns> /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. /// </returns> protected override Expression VisitMethodCall(MethodCallExpression node) { if (node.Method.Name == "Equals" && 1 == node.Arguments.Count) { return(VisitBinary(Expression.MakeBinary(ExpressionType.Equal, node.Object, node.Arguments[0]))); } else if (node.Method.DeclaringType == typeof(QueryOperators)) { if (node.Method.Name == "InRange") { Expression targetField = node.Arguments[0]; if (!(targetField is MemberExpression)) { throw new NotSupportedException("The expression is not supported for IsInRange: " + targetField); } MappedField field = Owner.GetMappedField(targetField as MemberExpression); if (null == field) { throw new InvalidOperationException("The expression refers to a field which is not mapped: " + targetField); } Query query = MakeNumericRangeQuery( field, node.Arguments[1], node.Arguments[2], node.Arguments[3], node.Arguments[4]); queryStack.Push(query); return(node); } else if (node.Method.Name == "MatchesTerm") { Expression targetField = node.Arguments[0]; if (!(targetField is MemberExpression)) { throw new NotSupportedException("The expression is not supported for MatchesTerm: " + targetField); } MappedField field = Owner.GetMappedField(targetField as MemberExpression); if (null == field) { throw new InvalidOperationException("The expression refers to a field which is not mapped: " + targetField); } string term = node.Arguments[1].GetValue <string>(); Query query = new TermQuery(new Term(field.Name, term)); queryStack.Push(query); return(node); } } return(base.VisitMethodCall(node)); }
/// <summary> /// Makes a TermQuery for the given MappedField and expression. /// </summary> /// <param name="field"> /// The MappedField to create the query for. /// </param> /// <param name="term"> /// The constant to match in the query. /// </param> /// <returns> /// An instance of TermQuery. /// </returns> private static TermQuery MakeTermQuery(MappedField field, Expression term) { Debug.Assert(null != field, "The mapped field must not be null."); Debug.Assert(null != term, "The term must not be null."); Term tm; switch (field.Type) { case MappedField.FieldType.Float: { BytesRef bytes = new BytesRef(NumericUtils.BUF_SIZE_INT64); long l = NumericUtils.DoubleToSortableInt64(field.GetValueFromExpression <float>(term)); NumericUtils.Int64ToPrefixCoded(l, 0, bytes); tm = new Term(field.Name, bytes); break; } case MappedField.FieldType.Double: { BytesRef bytes = new BytesRef(NumericUtils.BUF_SIZE_INT64); long l = NumericUtils.DoubleToSortableInt64(field.GetValueFromExpression <double>(term)); NumericUtils.Int64ToPrefixCoded(l, 0, bytes); tm = new Term(field.Name, bytes); break; } case MappedField.FieldType.Short: case MappedField.FieldType.Int: { BytesRef bytes = new BytesRef(NumericUtils.BUF_SIZE_INT32); NumericUtils.Int32ToPrefixCoded(field.GetValueFromExpression <int>(term), 0, bytes); tm = new Term(field.Name, bytes); break; } case MappedField.FieldType.Long: { BytesRef bytes = new BytesRef(NumericUtils.BUF_SIZE_INT64); NumericUtils.Int64ToPrefixCoded(field.GetValueFromExpression <long>(term), 0, bytes); tm = new Term(field.Name, bytes); break; } case MappedField.FieldType.String: { tm = new Term(field.Name, field.GetValueFromExpression <string>(term)); break; } default: throw new InvalidOperationException(String.Format( "Cannot make a TermQuery for field '{0}' of type {1}.", field.Name, field.Type)); } return(new TermQuery(tm)); }
/// <summary> /// Visits the children of the BinaryExpression. /// </summary> /// <param name="node"> /// The expression to visit. /// </param> /// <returns> /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. /// </returns> protected override Expression VisitBinary(BinaryExpression node) { Expression value = null; MappedField mappedField = null; BooleanQuery boolQuery; switch (node.NodeType) { case ExpressionType.Equal: mappedField = GetFieldAndConstant(node, out value); Debug.Assert(null != mappedField, "The mapped field must not be null."); Debug.Assert(null != value, "The value expression must not be null."); queryStack.Push(MakeTermQuery(mappedField, value)); return(node); case ExpressionType.NotEqual: VisitBinary(Expression.MakeBinary(ExpressionType.Equal, node.Left, node.Right)); Debug.Assert(queryStack.Count >= 1, "The query stack must not be empty."); boolQuery = new BooleanQuery(); boolQuery.Add(new MatchAllDocsQuery(), Occur.MUST); boolQuery.Add(queryStack.Pop(), Occur.MUST_NOT); queryStack.Push(boolQuery); return(node); case ExpressionType.AndAlso: Visit(node.Left); Visit(node.Right); Debug.Assert(queryStack.Count >= 2, "The query stack must have at least two queries."); boolQuery = new BooleanQuery(); boolQuery.Add(queryStack.Pop(), Occur.MUST); boolQuery.Add(queryStack.Pop(), Occur.MUST); queryStack.Push(boolQuery); return(node); case ExpressionType.OrElse: Visit(node.Left); Visit(node.Right); Debug.Assert(queryStack.Count >= 2, "The query stack must have at least two queries."); boolQuery = new BooleanQuery(); boolQuery.Add(queryStack.Pop(), Occur.SHOULD); boolQuery.Add(queryStack.Pop(), Occur.SHOULD); queryStack.Push(boolQuery); return(node); } throw new NotSupportedException(String.Format("Unsupported binary Expression: {0}", node)); }
/// <summary> /// Creates a new NumericRangeQuery for the given parameters. /// </summary> /// <param name="field"> /// The MappedField to create the query for. /// </param> /// <param name="min"> /// The Expression for the minimum value. /// </param> /// <param name="max"> /// The Expression for the maximum value. /// </param> /// <param name="minInclusive"> /// The Expression to determine whether or not the minimum value is inclusive. /// </param> /// <param name="maxInclusive"> /// The Expression to determine whether or not the maximum value is inclusive. /// </param> /// <returns> /// A Query which represents the NumericRangeQuery for the given parameters. /// </returns> private static Query MakeNumericRangeQuery(MappedField field, Expression min, Expression max, Expression minInclusive, Expression maxInclusive) { Debug.Assert(null != field, "The mapped field must not be null."); Debug.Assert(null != min, "The min expression must not be null."); Debug.Assert(null != max, "The max expression must not be null."); Debug.Assert(null != minInclusive, "The minInclusive expression must not be null."); Debug.Assert(null != maxInclusive, "The maxInclusive expression must not be null."); switch (field.Type) { case MappedField.FieldType.Float: return(NumericRangeQuery.NewFloatRange(field.Name, min.GetValue <float?>(), max.GetValue <float?>(), minInclusive.GetValue <bool>(), maxInclusive.GetValue <bool>())); case MappedField.FieldType.Double: return(NumericRangeQuery.NewDoubleRange(field.Name, min.GetValue <double?>(), max.GetValue <double?>(), minInclusive.GetValue <bool>(), maxInclusive.GetValue <bool>())); case MappedField.FieldType.Short: return(NumericRangeQuery.NewIntRange(field.Name, min.GetValue <short?>(), max.GetValue <short?>(), minInclusive.GetValue <bool>(), maxInclusive.GetValue <bool>())); case MappedField.FieldType.Int: return(NumericRangeQuery.NewIntRange(field.Name, min.GetValue <int?>(), max.GetValue <int?>(), minInclusive.GetValue <bool>(), maxInclusive.GetValue <bool>())); case MappedField.FieldType.Long: return(NumericRangeQuery.NewLongRange(field.Name, min.GetValue <long?>(), max.GetValue <long?>(), minInclusive.GetValue <bool>(), maxInclusive.GetValue <bool>())); default: throw new NotSupportedException(String.Format("Numeric Range Query is not supported for type '{0}'.", field.Type)); } }
/// <summary> /// Visits the children of the MemberExpression. /// </summary> /// <param name="node"> /// The expression to visit. /// </param> /// <returns> /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. /// </returns> protected override Expression VisitMember(MemberExpression node) { if (node.Type != typeof(bool)) { throw new NotSupportedException(String.Format("The expression is not supported: {0}.", node)); } MappedField field = Owner.GetMappedField(node); Query query = MakeTermQuery(field, Expression.Constant(true)); queryStack.Push(query); return(node); }
/// <summary> /// Visits the children of the MemberExpression. /// </summary> /// <param name="node"> /// The expression to visit. /// </param> /// <returns> /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. /// </returns> protected override Expression VisitMember(MemberExpression node) { MappedField mappedField = Owner.GetMappedField(node); if (null == mappedField) { throw new InvalidOperationException("The expression refers to a field which is not mapped: " + node); } SortFieldType fieldType; switch (mappedField.Type) { case MappedField.FieldType.Float: fieldType = SortFieldType.DOUBLE; break; case MappedField.FieldType.Double: fieldType = SortFieldType.DOUBLE; break; case MappedField.FieldType.Short: fieldType = SortFieldType.INT32; break; case MappedField.FieldType.Int: fieldType = SortFieldType.INT32; break; case MappedField.FieldType.Long: fieldType = SortFieldType.INT64; break; case MappedField.FieldType.String: fieldType = SortFieldType.STRING; break; default: Debug.Fail("The FieldType is not supported: " + mappedField.Type); throw new NotSupportedException("The FieldType is not supported: " + mappedField.Type); } sortField = new SortField(mappedField.Name, fieldType, sortDescending); return(node); }
/// <summary> /// Makes a TermQuery for the given MappedField and expression. /// </summary> /// <param name="field"> /// The MappedField to create the query for. /// </param> /// <param name="term"> /// The constant to match in the query. /// </param> /// <returns> /// An instance of TermQuery. /// </returns> private static TermQuery MakeTermQuery(MappedField field, Expression term) { Debug.Assert(null != field, "The mapped field must not be null."); Debug.Assert(null != term, "The term must not be null."); string queryTerm; switch (field.Type) { case MappedField.FieldType.Float: queryTerm = NumericUtils.FloatToPrefixCoded(field.GetValueFromExpression <float>(term)); break; case MappedField.FieldType.Double: queryTerm = NumericUtils.DoubleToPrefixCoded(field.GetValueFromExpression <double>(term)); break; case MappedField.FieldType.Short: queryTerm = NumericUtils.IntToPrefixCoded(field.GetValueFromExpression <short>(term)); break; case MappedField.FieldType.Int: queryTerm = NumericUtils.IntToPrefixCoded(field.GetValueFromExpression <int>(term)); break; case MappedField.FieldType.Long: queryTerm = NumericUtils.LongToPrefixCoded(field.GetValueFromExpression <long>(term)); break; case MappedField.FieldType.String: queryTerm = field.GetValueFromExpression <string>(term); break; default: throw new InvalidOperationException(String.Format( "Cannot make a TermQuery for field '{0}' of type {1}.", field.Name, field.Type)); } return(new TermQuery(new Term(field.Name, queryTerm))); }