io.objectbox.query.PropertyQuery Maven / Gradle / Ivy
Show all versions of objectbox-java Show documentation
/*
* Copyright 2017-2020 ObjectBox Ltd. All rights reserved.
*
* 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.
*/
package io.objectbox.query;
import io.objectbox.Property;
/**
* Query for a specific property; create using {@link Query#property(Property)}.
* Note: Property values do currently not consider any order defined for the main {@link Query} object
* (subject to change in a future version).
*/
@SuppressWarnings("WeakerAccess") // WeakerAccess: allow inner class access without accessor
public class PropertyQuery {
final Query> query;
final long queryHandle;
final Property> property;
final int propertyId;
boolean distinct;
boolean noCaseIfDistinct = true;
boolean enableNull;
boolean unique;
double nullValueDouble;
float nullValueFloat;
String nullValueString;
long nullValueLong;
PropertyQuery(Query> query, Property> property) {
this.query = query;
queryHandle = query.handle;
this.property = property;
propertyId = property.id;
}
native String[] nativeFindStrings(long handle, long cursorHandle, int propertyId, boolean distinct,
boolean distinctNoCase, boolean enableNull, String nullValue);
native long[] nativeFindLongs(long handle, long cursorHandle, int propertyId, boolean distinct, boolean enableNull,
long nullValue);
native int[] nativeFindInts(long handle, long cursorHandle, int propertyId, boolean distinct, boolean enableNull,
int nullValue);
native short[] nativeFindShorts(long handle, long cursorHandle, int propertyId, boolean distinct,
boolean enableNull, short nullValue);
native char[] nativeFindChars(long handle, long cursorHandle, int propertyId, boolean distinct, boolean enableNull,
char nullValue);
native byte[] nativeFindBytes(long handle, long cursorHandle, int propertyId, boolean distinct, boolean enableNull,
byte nullValue);
native float[] nativeFindFloats(long handle, long cursorHandle, int propertyId, boolean distinct,
boolean enableNull, float nullValue);
native double[] nativeFindDoubles(long handle, long cursorHandle, int propertyId, boolean distinct,
boolean enableNull, double nullValue);
native Object nativeFindNumber(long handle, long cursorHandle, int propertyId, boolean unique, boolean distinct,
boolean enableNull, long nullValue, float nullValueFloat, double nullValueDouble);
native String nativeFindString(long handle, long cursorHandle, int propertyId, boolean unique, boolean distinct,
boolean distinctCase, boolean enableNull, String nullValue);
native long nativeSum(long handle, long cursorHandle, int propertyId);
native double nativeSumDouble(long handle, long cursorHandle, int propertyId);
native long nativeMax(long handle, long cursorHandle, int propertyId);
native double nativeMaxDouble(long handle, long cursorHandle, int propertyId);
native long nativeMin(long handle, long cursorHandle, int propertyId);
native double nativeMinDouble(long handle, long cursorHandle, int propertyId);
native double nativeAvg(long handle, long cursorHandle, int propertyId);
native long nativeAvgLong(long handle, long cursorHandle, int propertyId);
native long nativeCount(long handle, long cursorHandle, int propertyId, boolean distinct);
/** Clears all values (e.g. distinct and null value). */
public PropertyQuery reset() {
distinct = false;
noCaseIfDistinct = true;
unique = false;
enableNull = false;
nullValueDouble = 0;
nullValueFloat = 0;
nullValueString = null;
nullValueLong = 0;
return this;
}
/**
* Only distinct values should be returned (e.g. 1,2,3 instead of 1,1,2,3,3,3).
*
* Note: strings default to case-insensitive comparision;
* to change that call {@link #distinct(QueryBuilder.StringOrder)}.
*/
public PropertyQuery distinct() {
distinct = true;
return this;
}
/**
* For string properties you can specify {@link io.objectbox.query.QueryBuilder.StringOrder#CASE_SENSITIVE} if you
* want to have case sensitive distinct values (e.g. returning "foo","Foo","FOO" instead of "foo").
*/
public PropertyQuery distinct(QueryBuilder.StringOrder stringOrder) {
if (property.type != String.class) {
throw new RuntimeException("Reserved for string properties, but got " + property);
}
distinct = true;
noCaseIfDistinct = stringOrder == QueryBuilder.StringOrder.CASE_INSENSITIVE;
return this;
}
/**
* For find methods returning single values, e.g. {@link #findInt()}, this will additional verify that the
* resulting value is unique.
* If there is any other resulting value resulting from this query, an exception will be thrown.
*
* Can be combined with {@link #distinct()}.
*
* Will be ignored for find methods returning multiple values, e.g. {@link #findInts()}.
*/
public PropertyQuery unique() {
unique = true;
return this;
}
/**
* By default, null values are not returned by find methods (primitive arrays cannot contains nulls).
* However, using this function, you can define an alternative value that will be returned for null values.
* E.g. -1 for ins/longs or "NULL" for strings.
*/
public PropertyQuery nullValue(Object nullValue) {
//noinspection ConstantConditions Annotation can not enforce non-null.
if (nullValue == null) {
throw new IllegalArgumentException("Null values are not allowed");
}
boolean isString = nullValue instanceof String;
boolean isNumber = nullValue instanceof Number;
if (!isString && !isNumber) {
throw new IllegalArgumentException("Unsupported value class: " + nullValue.getClass());
}
enableNull = true;
nullValueString = isString ? (String) nullValue : null;
boolean isFloat = nullValue instanceof Float;
nullValueFloat = isFloat ? (Float) nullValue : 0;
boolean isDouble = nullValue instanceof Double;
nullValueDouble = isDouble ? (Double) nullValue : 0;
nullValueLong = isNumber && !isFloat && !isDouble ? ((Number) nullValue).longValue() : 0;
return this;
}
/**
* Find the values for the given string property for objects matching the query.
*
* Note: null values are excluded from results.
*
* Note: results are not guaranteed to be in any particular order.
*
* See also: {@link #distinct()}, {@link #distinct(QueryBuilder.StringOrder)}
*
* @return Found strings
*/
public String[] findStrings() {
return query.callInReadTx(() -> {
boolean distinctNoCase = distinct && noCaseIfDistinct;
long cursorHandle = query.cursorHandle();
return nativeFindStrings(queryHandle, cursorHandle, propertyId, distinct, distinctNoCase,
enableNull, nullValueString);
});
}
/**
* Find the values for the given long property for objects matching the query.
*
* Note: null values are excluded from results.
*
* Note: results are not guaranteed to be in any particular order.
*
* See also: {@link #distinct()}
*
* @return Found longs
*/
public long[] findLongs() {
return query.callInReadTx(() ->
nativeFindLongs(queryHandle, query.cursorHandle(), propertyId, distinct, enableNull, nullValueLong)
);
}
/**
* Find the values for the given int property for objects matching the query.
*
* Note: null values are excluded from results.
*
* Note: results are not guaranteed to be in any particular order.
*
* See also: {@link #distinct()}
*/
public int[] findInts() {
return query.callInReadTx(() ->
nativeFindInts(queryHandle, query.cursorHandle(), propertyId, distinct, enableNull, (int) nullValueLong)
);
}
/**
* Find the values for the given int property for objects matching the query.
*
* Note: null values are excluded from results.
*
* Note: results are not guaranteed to be in any particular order.
*
* See also: {@link #distinct()}
*/
public short[] findShorts() {
return query.callInReadTx(() ->
nativeFindShorts(queryHandle, query.cursorHandle(), propertyId, distinct, enableNull, (short) nullValueLong)
);
}
/**
* Find the values for the given int property for objects matching the query.
*
* Note: null values are excluded from results.
*
* Note: results are not guaranteed to be in any particular order.
*
* See also: {@link #distinct()}
*/
public char[] findChars() {
return query.callInReadTx(() ->
nativeFindChars(queryHandle, query.cursorHandle(), propertyId, distinct, enableNull, (char) nullValueLong)
);
}
/**
* Find the values for the given byte property for objects matching the query.
*
* Note: null values are excluded from results.
*
* Note: results are not guaranteed to be in any particular order.
*/
public byte[] findBytes() {
return query.callInReadTx(() ->
nativeFindBytes(queryHandle, query.cursorHandle(), propertyId, distinct, enableNull, (byte) nullValueLong)
);
}
/**
* Find the values for the given int property for objects matching the query.
*
* Note: null values are excluded from results.
*
* Note: results are not guaranteed to be in any particular order.
*
* See also: {@link #distinct()}
*/
public float[] findFloats() {
return query.callInReadTx(() ->
nativeFindFloats(queryHandle, query.cursorHandle(), propertyId, distinct, enableNull, nullValueFloat)
);
}
/**
* Find the values for the given int property for objects matching the query.
*
* Note: null values are excluded from results.
*
* Note: results are not guaranteed to be in any particular order.
*
* See also: {@link #distinct()}
*/
public double[] findDoubles() {
return query.callInReadTx(() ->
nativeFindDoubles(queryHandle, query.cursorHandle(), propertyId, distinct, enableNull, nullValueDouble)
);
}
public String findString() {
return query.callInReadTx(() -> {
boolean distinctCase = distinct && !noCaseIfDistinct;
return nativeFindString(queryHandle, query.cursorHandle(), propertyId, unique, distinct,
distinctCase, enableNull, nullValueString);
});
}
private Object findNumber() {
return query.callInReadTx(() ->
nativeFindNumber(queryHandle, query.cursorHandle(), propertyId, unique, distinct,
enableNull, nullValueLong, nullValueFloat, nullValueDouble)
);
}
public Long findLong() {
return (Long) findNumber();
}
public Integer findInt() {
return (Integer) findNumber();
}
public Short findShort() {
return (Short) findNumber();
}
public Character findChar() {
return (Character) findNumber();
}
public Byte findByte() {
return (Byte) findNumber();
}
public Boolean findBoolean() {
return (Boolean) findNumber();
}
public Float findFloat() {
return (Float) findNumber();
}
public Double findDouble() {
return (Double) findNumber();
}
/**
* Sums up all values for the given property over all Objects matching the query.
*
* Note: this method is not recommended for properties of type long unless you know the contents of the DB not to
* overflow. Use {@link #sumDouble()} instead if you cannot guarantee the sum to be in the long value range.
*
* @return 0 in case no elements matched the query
* @throws io.objectbox.exception.NumericOverflowException if the sum exceeds the numbers {@link Long} can
* represent.
* This is different from Java arithmetic where it would "wrap around" (e.g. max. value + 1 = min. value).
*/
public long sum() {
return query.callInReadTx(
() -> nativeSum(queryHandle, query.cursorHandle(), propertyId)
);
}
/**
* Sums up all values for the given property over all Objects matching the query.
*
* Note: for integer types int and smaller, {@link #sum()} is usually preferred for sums.
*
* @return 0 in case no elements matched the query
*/
public double sumDouble() {
return query.callInReadTx(
() -> nativeSumDouble(queryHandle, query.cursorHandle(), propertyId)
);
}
/**
* Finds the maximum value for the given property over all Objects matching the query.
*
* @return Long.MIN_VALUE in case no elements matched the query
*/
public long max() {
return query.callInReadTx(
() -> nativeMax(queryHandle, query.cursorHandle(), propertyId)
);
}
/**
* Finds the maximum value for the given property over all Objects matching the query.
*
* @return NaN in case no elements matched the query
*/
public double maxDouble() {
return query.callInReadTx(
() -> nativeMaxDouble(queryHandle, query.cursorHandle(), propertyId)
);
}
/**
* Finds the minimum value for the given property over all Objects matching the query.
*
* @return Long.MAX_VALUE in case no elements matched the query
*/
public long min() {
return query.callInReadTx(
() -> nativeMin(queryHandle, query.cursorHandle(), propertyId)
);
}
/**
* Finds the minimum value for the given property over all objects matching the query.
*
* @return NaN in case no elements matched the query
*/
public double minDouble() {
return query.callInReadTx(
() -> nativeMinDouble(queryHandle, query.cursorHandle(), propertyId)
);
}
/**
* Calculates the average of all values for the given number property over all Objects matching the query.
*
* For integer properties you can also use {@link #avgLong()}.
*
* @return NaN in case no elements matched the query
*/
public double avg() {
return query.callInReadTx(
() -> nativeAvg(queryHandle, query.cursorHandle(), propertyId)
);
}
/**
* Calculates the average of all values for the given integer property over all Objects matching the query.
*
* For floating-point properties use {@link #avg()}.
*
* @return 0 in case no elements matched the query
*/
public long avgLong() {
return query.callInReadTx(
() -> nativeAvgLong(queryHandle, query.cursorHandle(), propertyId)
);
}
/**
* The count of non-null values.
*
* See also: {@link #distinct()}
*/
public long count() {
return query.callInReadTx(
() -> nativeCount(queryHandle, query.cursorHandle(), propertyId, distinct)
);
}
}