|
|
|
|
@@ -22,18 +22,22 @@ import java.util.List;
|
|
|
|
|
|
|
|
|
|
import org.bson.BsonNull;
|
|
|
|
|
import org.bson.Document;
|
|
|
|
|
|
|
|
|
|
import org.springframework.data.domain.Range;
|
|
|
|
|
import org.springframework.data.domain.Range.Bound;
|
|
|
|
|
import org.springframework.data.util.Streamable;
|
|
|
|
|
import org.springframework.lang.Nullable;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Encapsulation of individual {@link QueryCharacteristic query characteristics} used to define queries that can be
|
|
|
|
|
* executed when using queryable encryption.
|
|
|
|
|
*
|
|
|
|
|
* @author Christoph Strobl
|
|
|
|
|
* @since 4.5
|
|
|
|
|
*/
|
|
|
|
|
public class QueryCharacteristics implements Streamable<QueryCharacteristic> {
|
|
|
|
|
public class QueryCharacteristics implements Iterable<QueryCharacteristic> {
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* instance indicating none
|
|
|
|
|
*/
|
|
|
|
|
private static final QueryCharacteristics NONE = new QueryCharacteristics(Collections.emptyList());
|
|
|
|
|
|
|
|
|
|
private final List<QueryCharacteristic> characteristics;
|
|
|
|
|
@@ -42,18 +46,36 @@ public class QueryCharacteristics implements Streamable<QueryCharacteristic> {
|
|
|
|
|
this.characteristics = characteristics;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return marker instance indicating no characteristics have been defined.
|
|
|
|
|
*/
|
|
|
|
|
public static QueryCharacteristics none() {
|
|
|
|
|
return NONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create new {@link QueryCharacteristics} from given list of {@link QueryCharacteristic characteristics}.
|
|
|
|
|
*
|
|
|
|
|
* @param characteristics must not be {@literal null}.
|
|
|
|
|
* @return new instance of {@link QueryCharacteristics}.
|
|
|
|
|
*/
|
|
|
|
|
public static QueryCharacteristics of(List<QueryCharacteristic> characteristics) {
|
|
|
|
|
return new QueryCharacteristics(List.copyOf(characteristics));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create new {@link QueryCharacteristics} from given {@link QueryCharacteristic characteristics}.
|
|
|
|
|
*
|
|
|
|
|
* @param characteristics must not be {@literal null}.
|
|
|
|
|
* @return new instance of {@link QueryCharacteristics}.
|
|
|
|
|
*/
|
|
|
|
|
public static QueryCharacteristics of(QueryCharacteristic... characteristics) {
|
|
|
|
|
return new QueryCharacteristics(Arrays.asList(characteristics));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return the list of {@link QueryCharacteristic characteristics}.
|
|
|
|
|
*/
|
|
|
|
|
public List<QueryCharacteristic> getCharacteristics() {
|
|
|
|
|
return characteristics;
|
|
|
|
|
}
|
|
|
|
|
@@ -63,22 +85,50 @@ public class QueryCharacteristics implements Streamable<QueryCharacteristic> {
|
|
|
|
|
return this.characteristics.iterator();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create a new {@link RangeQuery range query characteristic} used to define range queries against an encrypted field.
|
|
|
|
|
*
|
|
|
|
|
* @param <T> targeted field type
|
|
|
|
|
* @return new instance of {@link RangeQuery}.
|
|
|
|
|
*/
|
|
|
|
|
public static <T> RangeQuery<T> range() {
|
|
|
|
|
return new RangeQuery<>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create a new {@link EqualityQuery equality query characteristic} used to define equality queries against an
|
|
|
|
|
* encrypted field.
|
|
|
|
|
*
|
|
|
|
|
* @param <T> targeted field type
|
|
|
|
|
* @return new instance of {@link EqualityQuery}.
|
|
|
|
|
*/
|
|
|
|
|
public static <T> EqualityQuery<T> equality() {
|
|
|
|
|
return new EqualityQuery<>(null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* {@link QueryCharacteristic} for equality comparison.
|
|
|
|
|
*
|
|
|
|
|
* @param <T>
|
|
|
|
|
* @since 4.5
|
|
|
|
|
*/
|
|
|
|
|
public static class EqualityQuery<T> implements QueryCharacteristic {
|
|
|
|
|
|
|
|
|
|
private final @Nullable Long contention;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create new instance of {@link EqualityQuery}.
|
|
|
|
|
*
|
|
|
|
|
* @param contention can be {@literal null}.
|
|
|
|
|
*/
|
|
|
|
|
public EqualityQuery(@Nullable Long contention) {
|
|
|
|
|
this.contention = contention;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param contention concurrent counter partition factor.
|
|
|
|
|
* @return new instance of {@link EqualityQuery}.
|
|
|
|
|
*/
|
|
|
|
|
public EqualityQuery<T> contention(long contention) {
|
|
|
|
|
return new EqualityQuery<>(contention);
|
|
|
|
|
}
|
|
|
|
|
@@ -94,64 +144,120 @@ public class QueryCharacteristics implements Streamable<QueryCharacteristic> {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* {@link QueryCharacteristic} for range comparison.
|
|
|
|
|
*
|
|
|
|
|
* @param <T>
|
|
|
|
|
* @since 4.5
|
|
|
|
|
*/
|
|
|
|
|
public static class RangeQuery<T> implements QueryCharacteristic {
|
|
|
|
|
|
|
|
|
|
private final @Nullable Range<T> valueRange;
|
|
|
|
|
private final @Nullable Integer trimFactor;
|
|
|
|
|
private final @Nullable Long sparsity;
|
|
|
|
|
private final @Nullable Long precision;
|
|
|
|
|
private final @Nullable Long contention;
|
|
|
|
|
|
|
|
|
|
private RangeQuery() {
|
|
|
|
|
this(Range.unbounded(), null, null, null);
|
|
|
|
|
this(Range.unbounded(), null, null, null, null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create new instance of {@link RangeQuery}.
|
|
|
|
|
*
|
|
|
|
|
* @param valueRange
|
|
|
|
|
* @param trimFactor
|
|
|
|
|
* @param sparsity
|
|
|
|
|
* @param contention
|
|
|
|
|
*/
|
|
|
|
|
public RangeQuery(@Nullable Range<T> valueRange, @Nullable Integer trimFactor, @Nullable Long sparsity,
|
|
|
|
|
@Nullable Long contention) {
|
|
|
|
|
@Nullable Long precision, @Nullable Long contention) {
|
|
|
|
|
this.valueRange = valueRange;
|
|
|
|
|
this.trimFactor = trimFactor;
|
|
|
|
|
this.sparsity = sparsity;
|
|
|
|
|
this.precision = precision;
|
|
|
|
|
this.contention = contention;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param lower the lower value range boundary for the queryable field.
|
|
|
|
|
* @return new instance of {@link RangeQuery}.
|
|
|
|
|
*/
|
|
|
|
|
public RangeQuery<T> min(T lower) {
|
|
|
|
|
|
|
|
|
|
Range<T> range = Range.of(Bound.inclusive(lower),
|
|
|
|
|
valueRange != null ? valueRange.getUpperBound() : Bound.unbounded());
|
|
|
|
|
return new RangeQuery<>(range, trimFactor, sparsity, precision, contention);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param upper the upper value range boundary for the queryable field.
|
|
|
|
|
* @return new instance of {@link RangeQuery}.
|
|
|
|
|
*/
|
|
|
|
|
public RangeQuery<T> max(T upper) {
|
|
|
|
|
|
|
|
|
|
Range<T> range = Range.of(valueRange != null ? valueRange.getLowerBound() : Bound.unbounded(),
|
|
|
|
|
Bound.inclusive(upper));
|
|
|
|
|
return new RangeQuery<>(range, trimFactor, sparsity, precision, contention);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param trimFactor value to control the throughput of concurrent inserts and updates.
|
|
|
|
|
* @return new instance of {@link RangeQuery}.
|
|
|
|
|
*/
|
|
|
|
|
public RangeQuery<T> trimFactor(int trimFactor) {
|
|
|
|
|
return new RangeQuery<>(valueRange, trimFactor, sparsity, precision, contention);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param sparsity value to control the value density within the index.
|
|
|
|
|
* @return new instance of {@link RangeQuery}.
|
|
|
|
|
*/
|
|
|
|
|
public RangeQuery<T> sparsity(long sparsity) {
|
|
|
|
|
return new RangeQuery<>(valueRange, trimFactor, sparsity, precision, contention);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param contention concurrent counter partition factor.
|
|
|
|
|
* @return new instance of {@link RangeQuery}.
|
|
|
|
|
*/
|
|
|
|
|
public RangeQuery<T> contention(long contention) {
|
|
|
|
|
return new RangeQuery<>(valueRange, trimFactor, sparsity, precision, contention);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param precision digits considered comparing floating point numbers.
|
|
|
|
|
* @return new instance of {@link RangeQuery}.
|
|
|
|
|
*/
|
|
|
|
|
public RangeQuery<T> precision(long precision) {
|
|
|
|
|
return new RangeQuery<>(valueRange, trimFactor, sparsity, precision, contention);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public String queryType() {
|
|
|
|
|
return "range";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public RangeQuery<T> min(T lower) {
|
|
|
|
|
|
|
|
|
|
Range<T> range = Range.of(Bound.inclusive(lower),
|
|
|
|
|
valueRange != null ? valueRange.getUpperBound() : Bound.unbounded());
|
|
|
|
|
return new RangeQuery<>(range, trimFactor, sparsity, contention);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public RangeQuery<T> max(T upper) {
|
|
|
|
|
|
|
|
|
|
Range<T> range = Range.of(valueRange != null ? valueRange.getLowerBound() : Bound.unbounded(),
|
|
|
|
|
Bound.inclusive(upper));
|
|
|
|
|
return new RangeQuery<>(range, trimFactor, sparsity, contention);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public RangeQuery<T> trimFactor(int trimFactor) {
|
|
|
|
|
return new RangeQuery<>(valueRange, trimFactor, sparsity, contention);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public RangeQuery<T> sparsity(long sparsity) {
|
|
|
|
|
return new RangeQuery<>(valueRange, trimFactor, sparsity, contention);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public RangeQuery<T> contention(long contention) {
|
|
|
|
|
return new RangeQuery<>(valueRange, trimFactor, sparsity, contention);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
|
public Document toDocument() {
|
|
|
|
|
|
|
|
|
|
return QueryCharacteristic.super.toDocument().append("contention", contention).append("trimFactor", trimFactor)
|
|
|
|
|
.append("sparsity", sparsity).append("min", valueRange.getLowerBound().getValue().orElse((T) BsonNull.VALUE))
|
|
|
|
|
.append("max", valueRange.getUpperBound().getValue().orElse((T) BsonNull.VALUE));
|
|
|
|
|
Document target = QueryCharacteristic.super.toDocument();
|
|
|
|
|
if (contention != null) {
|
|
|
|
|
target.append("contention", contention);
|
|
|
|
|
}
|
|
|
|
|
if (trimFactor != null) {
|
|
|
|
|
target.append("trimFactor", trimFactor);
|
|
|
|
|
}
|
|
|
|
|
if (valueRange != null) {
|
|
|
|
|
target.append("min", valueRange.getLowerBound().getValue().orElse((T) BsonNull.VALUE)).append("max",
|
|
|
|
|
valueRange.getUpperBound().getValue().orElse((T) BsonNull.VALUE));
|
|
|
|
|
}
|
|
|
|
|
if (sparsity != null) {
|
|
|
|
|
target.append("sparsity", sparsity);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return target;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|