| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.lucene.queryparser.flexible.standard.nodes; |
| |
| import java.util.ArrayList; |
| |
| import org.apache.lucene.queryparser.flexible.core.nodes.FieldValuePairQueryNode; |
| import org.apache.lucene.queryparser.flexible.core.nodes.FieldableNode; |
| import org.apache.lucene.queryparser.flexible.core.nodes.QueryNode; |
| import org.apache.lucene.queryparser.flexible.core.nodes.QueryNodeImpl; |
| import org.apache.lucene.queryparser.flexible.core.nodes.RangeQueryNode; |
| import org.apache.lucene.queryparser.flexible.core.parser.EscapeQuerySyntax; |
| import org.apache.lucene.queryparser.flexible.core.util.StringUtils; |
| |
| /** |
| * This class should be extended by nodes intending to represent range queries. |
| * |
| * @param <T> |
| * the type of the range query bounds (lower and upper) |
| */ |
| public class AbstractRangeQueryNode<T extends FieldValuePairQueryNode<?>> |
| extends QueryNodeImpl implements RangeQueryNode<FieldValuePairQueryNode<?>> { |
| |
| private boolean lowerInclusive, upperInclusive; |
| |
| /** |
| * Constructs an {@link AbstractRangeQueryNode}, it should be invoked only by |
| * its extenders. |
| */ |
| protected AbstractRangeQueryNode() { |
| setLeaf(false); |
| allocate(); |
| } |
| |
| /** |
| * Returns the field associated with this node. |
| * |
| * @return the field associated with this node |
| * |
| * @see FieldableNode |
| */ |
| @Override |
| public CharSequence getField() { |
| CharSequence field = null; |
| T lower = getLowerBound(); |
| T upper = getUpperBound(); |
| |
| if (lower != null) { |
| field = lower.getField(); |
| |
| } else if (upper != null) { |
| field = upper.getField(); |
| } |
| |
| return field; |
| |
| } |
| |
| /** |
| * Sets the field associated with this node. |
| * |
| * @param fieldName the field associated with this node |
| */ |
| @Override |
| public void setField(CharSequence fieldName) { |
| T lower = getLowerBound(); |
| T upper = getUpperBound(); |
| |
| if (lower != null) { |
| lower.setField(fieldName); |
| } |
| |
| if (upper != null) { |
| upper.setField(fieldName); |
| } |
| |
| } |
| |
| /** |
| * Returns the lower bound node. |
| * |
| * @return the lower bound node. |
| */ |
| @Override |
| @SuppressWarnings("unchecked") |
| public T getLowerBound() { |
| return (T) getChildren().get(0); |
| } |
| |
| /** |
| * Returns the upper bound node. |
| * |
| * @return the upper bound node. |
| */ |
| @Override |
| @SuppressWarnings("unchecked") |
| public T getUpperBound() { |
| return (T) getChildren().get(1); |
| } |
| |
| /** |
| * Returns whether the lower bound is inclusive or exclusive. |
| * |
| * @return <code>true</code> if the lower bound is inclusive, otherwise, <code>false</code> |
| */ |
| @Override |
| public boolean isLowerInclusive() { |
| return lowerInclusive; |
| } |
| |
| /** |
| * Returns whether the upper bound is inclusive or exclusive. |
| * |
| * @return <code>true</code> if the upper bound is inclusive, otherwise, <code>false</code> |
| */ |
| @Override |
| public boolean isUpperInclusive() { |
| return upperInclusive; |
| } |
| |
| /** |
| * Sets the lower and upper bounds. |
| * |
| * @param lower the lower bound, <code>null</code> if lower bound is open |
| * @param upper the upper bound, <code>null</code> if upper bound is open |
| * @param lowerInclusive <code>true</code> if the lower bound is inclusive, otherwise, <code>false</code> |
| * @param upperInclusive <code>true</code> if the upper bound is inclusive, otherwise, <code>false</code> |
| * |
| * @see #getLowerBound() |
| * @see #getUpperBound() |
| * @see #isLowerInclusive() |
| * @see #isUpperInclusive() |
| */ |
| public void setBounds(T lower, T upper, boolean lowerInclusive, |
| boolean upperInclusive) { |
| |
| if (lower != null && upper != null) { |
| String lowerField = StringUtils.toString(lower.getField()); |
| String upperField = StringUtils.toString(upper.getField()); |
| |
| if ((upperField != null || lowerField != null) |
| && ((upperField != null && !upperField.equals(lowerField)) || !lowerField |
| .equals(upperField))) { |
| throw new IllegalArgumentException( |
| "lower and upper bounds should have the same field name!"); |
| } |
| |
| this.lowerInclusive = lowerInclusive; |
| this.upperInclusive = upperInclusive; |
| |
| ArrayList<QueryNode> children = new ArrayList<>(2); |
| children.add(lower); |
| children.add(upper); |
| |
| set(children); |
| |
| } |
| |
| } |
| |
| @Override |
| public CharSequence toQueryString(EscapeQuerySyntax escapeSyntaxParser) { |
| StringBuilder sb = new StringBuilder(); |
| |
| T lower = getLowerBound(); |
| T upper = getUpperBound(); |
| |
| if (lowerInclusive) { |
| sb.append('['); |
| |
| } else { |
| sb.append('{'); |
| } |
| |
| if (lower != null) { |
| sb.append(lower.toQueryString(escapeSyntaxParser)); |
| |
| } else { |
| sb.append("..."); |
| } |
| |
| sb.append(' '); |
| |
| if (upper != null) { |
| sb.append(upper.toQueryString(escapeSyntaxParser)); |
| |
| } else { |
| sb.append("..."); |
| } |
| |
| if (upperInclusive) { |
| sb.append(']'); |
| |
| } else { |
| sb.append('}'); |
| } |
| |
| return sb.toString(); |
| |
| } |
| |
| @Override |
| public String toString() { |
| StringBuilder sb = new StringBuilder("<").append(getClass().getCanonicalName()); |
| sb.append(" lowerInclusive=").append(isLowerInclusive()); |
| sb.append(" upperInclusive=").append(isUpperInclusive()); |
| sb.append(">\n\t"); |
| sb.append(getUpperBound()).append("\n\t"); |
| sb.append(getLowerBound()).append("\n"); |
| sb.append("</").append(getClass().getCanonicalName()).append(">\n"); |
| |
| return sb.toString(); |
| |
| } |
| |
| } |