/* * 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(); } }