/**
* ============LICENSE_START=======================================================
* org.onap.aai
* ================================================================================
* Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
* Copyright © 2017-2018 Amdocs
* ================================================================================
* Licensed 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.
* ============LICENSE_END=========================================================
*/
package org.onap.aai.sa.searchdbabstraction.searchapi;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* This class represents a simple range query.
*
*
* A range query is composed of one or more operator/value pairs which define the upper and lower bounds of the range,
* and a field to apply the query to.
*
*
* Operators may be one of the following:
*
* - gt - Greater than.
* - gte - Greater than or equal to.
* - lt - Less than.
* - lte - Less than or equal to.
*
* Values may be either numeric values (Integer or Double) or Strings representing dates.
*
*
* The following examples illustrate a couple of variants of the range query:
*
*
*
*
* // A simple numeric range query:
* {
* "range": {
* "field": "fieldname",
* "gte": 5,
* "lte": 10
* }
* }
*
* // A simple date range query:
* {
* "range": {
* "field": "fieldname",
* "gt": "2016-10-06T00:00:00.558+03:00",
* "lt": "2016-10-06T23:59:59.558+03:00"
* }
* }
*
*/
public class RangeQuery {
/**
* The name of the field to apply the range query against.
*/
private String field;
/**
* The value of the field must be greater than this value to be a match.
* NOTE: Only one of 'gt' or 'gte' should be set on any single {@link RangeQuery} instance.
*/
private Object gt;
/**
* The value of the field must be greater than or equal to this value to be a match.
* NOTE: Only one of 'gt' or 'gte' should be set on any single {@link RangeQuery} instance.
*/
private Object gte;
/**
* The value of the field must be less than this value to be a match.
* NOTE: Only one of 'lt' or 'lte' should be set on any single {@link RangeQuery} instance.
*/
private Object lt;
/**
* The value of the field must be less than or equal to than this value to be a match.
* NOTE: Only one of 'lt' or 'lte' should be set on any single {@link RangeQuery} instance.
*/
private Object lte;
private String format;
@JsonProperty("time-zone")
private String timeZone;
public String getField() {
return field;
}
public void setField(String field) {
this.field = field;
}
public Object getGt() {
return gt;
}
public void setGt(Object gt) {
// It does not make sense to assign a value to both the 'greater than'
// and 'greater than or equal' operations, so make sure we are not
// trying to do that.
if (gte == null) {
// Make sure that we are not trying to mix both numeric and date
// type values in the same queries.
if (((lt != null) && !typesMatch(gt, lt)) || ((lte != null) && !typesMatch(gt, lte))) {
throw new IllegalArgumentException("Cannot mix date and numeric values in the same ranged query");
}
// If we made it here, then we're all good. Store the value.
this.gt = gt;
} else {
throw new IllegalArgumentException("Cannot assign both 'gt' and 'gte' fields in the same ranged query");
}
}
public Object getGte() {
return gte;
}
public void setGte(Object gte) {
// It does not make sense to assign a value to both the 'greater than'
// and 'greater than or equal' operations, so make sure we are not
// trying to do that.
if (gt == null) {
// Make sure that we are not trying to mix both numeric and date
// type values in the same queries.
if (((lt != null) && !typesMatch(gte, lt)) || ((lte != null) && !typesMatch(gte, lte))) {
throw new IllegalArgumentException("Cannot mix date and numeric values in the same ranged query");
}
// If we made it here, then we're all good. Store the value.
this.gte = gte;
} else {
throw new IllegalArgumentException("Cannot assign both 'gt' and 'gte' fields in the same ranged query");
}
}
public Object getLt() {
return lt;
}
public void setLt(Object lt) {
// It does not make sense to assign a value to both the 'less than'
// and 'less than or equal' operations, so make sure we are not
// trying to do that.
if (lte == null) {
// Make sure that we are not trying to mix both numeric and date
// type values in the same queries.
if (((gt != null) && !typesMatch(lt, gt)) || ((gte != null) && !typesMatch(lt, gte))) {
throw new IllegalArgumentException("Cannot mix date and numeric values in the same ranged query");
}
// If we made it here, then we're all good. Store the value.
this.lt = lt;
} else {
throw new IllegalArgumentException("Cannot assign both 'lt' and 'lte' fields in the same ranged query");
}
}
public Object getLte() {
return lte;
}
public void setLte(Object lte) {
// It does not make sense to assign a value to both the 'greater than'
// and 'greater than or equal' operations, so make sure we are not
// trying to do that.
if (lt == null) {
// Make sure that we are not trying to mix both numeric and date
// type values in the same queries.
if (((gt != null) && !typesMatch(lte, gt)) || ((gte != null) && !typesMatch(lte, gte))) {
throw new IllegalArgumentException("Cannot mix date and numeric values in the same ranged query");
}
// If we made it here, then we're all good. Store the value.
this.lte = lte;
} else {
throw new IllegalArgumentException("Cannot assign both 'lt' and 'lte' fields in the same ranged query");
}
}
public String getFormat() {
return format;
}
public void setFormat(String format) {
this.format = format;
}
public String getTimeZone() {
return timeZone;
}
public void setTimeZone(String timeZone) {
this.timeZone = timeZone;
}
/**
* This convenience method determines whether or not the supplied value needs to be enclosed in '"' characters when
* generating ElasticSearch compatible syntax.
*
* @param val - The value to check.
* @return - A string representation of the value for inclusion in an ElasticSearch syntax string.
*/
private String formatStringOrNumericVal(Object val) {
if (val instanceof String) {
return "\"" + val.toString() + "\"";
} else {
return val.toString();
}
}
/**
* This convenience method verifies that the supplied objects are of classes considered to be compatible for a
* ranged query.
*
* @param value1 - The first value to check.
* @param value2 - The second value to check.
* @return - True if the two objects are compatible for inclusion in the same ranged query, False, otherwise.
*/
boolean typesMatch(Object value1, Object value2) {
return ((value1 instanceof String) && (value2 instanceof String))
|| (!(value1 instanceof String) && !(value2 instanceof String));
}
/**
* This method returns a string which represents this query in syntax that is understandable by ElasticSearch and is
* suitable for inclusion in an ElasticSearch query string.
*
* @return - ElasticSearch syntax string.
*/
public String toElasticSearch() {
StringBuilder sb = new StringBuilder();
sb.append("{");
sb.append("\"range\": {");
sb.append("\"").append(field).append("\": {");
// We may have one or zero of 'greater than' or 'greater
// than or equal'
boolean needComma = false;
if (gte != null) {
sb.append("\"gte\": ").append(formatStringOrNumericVal(gte));
needComma = true;
} else if (gt != null) {
sb.append("\"gt\": ").append(formatStringOrNumericVal(gt));
needComma = true;
}
// We may have one or zero of 'less than' or 'less
// than or equal'
if (lte != null) {
if (needComma) {
sb.append(", ");
}
sb.append("\"lte\": ").append(formatStringOrNumericVal(lte));
} else if (lt != null) {
if (needComma) {
sb.append(", ");
}
sb.append("\"lt\": ").append(formatStringOrNumericVal(lt));
}
// Append the format specifier if one was provided.
if (format != null) {
sb.append(", \"format\": \"").append(format).append("\"");
}
// Append the time zone specifier if one was provided.
if (timeZone != null) {
sb.append(", \"time_zone\": \"").append(timeZone).append("\"");
}
sb.append("}");
sb.append("}");
sb.append("}");
return sb.toString();
}
@Override
public String toString() {
String str = "{ field: " + field + ", ";
if (gt != null) {
str += "gt: " + gt;
} else if (gte != null) {
str += "gte: " + gte;
}
if (lt != null) {
str += (((gt != null) || (gte != null)) ? ", " : "") + "lt: " + lt;
} else if (lte != null) {
str += (((gt != null) || (gte != null)) ? ", " : "") + "lte: " + lte;
}
str += "}";
return str;
}
}