|
|
|
@ -22,18 +22,22 @@ import java.util.List; |
|
|
|
|
|
|
|
|
|
|
|
import org.bson.BsonNull; |
|
|
|
import org.bson.BsonNull; |
|
|
|
import org.bson.Document; |
|
|
|
import org.bson.Document; |
|
|
|
|
|
|
|
|
|
|
|
import org.springframework.data.domain.Range; |
|
|
|
import org.springframework.data.domain.Range; |
|
|
|
import org.springframework.data.domain.Range.Bound; |
|
|
|
import org.springframework.data.domain.Range.Bound; |
|
|
|
import org.springframework.data.util.Streamable; |
|
|
|
|
|
|
|
import org.springframework.lang.Nullable; |
|
|
|
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 |
|
|
|
* @author Christoph Strobl |
|
|
|
* @since 4.5 |
|
|
|
* @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 static final QueryCharacteristics NONE = new QueryCharacteristics(Collections.emptyList()); |
|
|
|
|
|
|
|
|
|
|
|
private final List<QueryCharacteristic> characteristics; |
|
|
|
private final List<QueryCharacteristic> characteristics; |
|
|
|
@ -42,18 +46,36 @@ public class QueryCharacteristics implements Streamable<QueryCharacteristic> { |
|
|
|
this.characteristics = characteristics; |
|
|
|
this.characteristics = characteristics; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* @return marker instance indicating no characteristics have been defined. |
|
|
|
|
|
|
|
*/ |
|
|
|
public static QueryCharacteristics none() { |
|
|
|
public static QueryCharacteristics none() { |
|
|
|
return 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) { |
|
|
|
public static QueryCharacteristics of(List<QueryCharacteristic> characteristics) { |
|
|
|
return new QueryCharacteristics(List.copyOf(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) { |
|
|
|
public static QueryCharacteristics of(QueryCharacteristic... characteristics) { |
|
|
|
return new QueryCharacteristics(Arrays.asList(characteristics)); |
|
|
|
return new QueryCharacteristics(Arrays.asList(characteristics)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* @return the list of {@link QueryCharacteristic characteristics}. |
|
|
|
|
|
|
|
*/ |
|
|
|
public List<QueryCharacteristic> getCharacteristics() { |
|
|
|
public List<QueryCharacteristic> getCharacteristics() { |
|
|
|
return characteristics; |
|
|
|
return characteristics; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -63,22 +85,50 @@ public class QueryCharacteristics implements Streamable<QueryCharacteristic> { |
|
|
|
return this.characteristics.iterator(); |
|
|
|
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() { |
|
|
|
public static <T> RangeQuery<T> range() { |
|
|
|
return new RangeQuery<>(); |
|
|
|
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() { |
|
|
|
public static <T> EqualityQuery<T> equality() { |
|
|
|
return new EqualityQuery<>(null); |
|
|
|
return new EqualityQuery<>(null); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* {@link QueryCharacteristic} for equality comparison. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param <T> |
|
|
|
|
|
|
|
* @since 4.5 |
|
|
|
|
|
|
|
*/ |
|
|
|
public static class EqualityQuery<T> implements QueryCharacteristic { |
|
|
|
public static class EqualityQuery<T> implements QueryCharacteristic { |
|
|
|
|
|
|
|
|
|
|
|
private final @Nullable Long contention; |
|
|
|
private final @Nullable Long contention; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Create new instance of {@link EqualityQuery}. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param contention can be {@literal null}. |
|
|
|
|
|
|
|
*/ |
|
|
|
public EqualityQuery(@Nullable Long contention) { |
|
|
|
public EqualityQuery(@Nullable Long contention) { |
|
|
|
this.contention = contention; |
|
|
|
this.contention = contention; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* @param contention concurrent counter partition factor. |
|
|
|
|
|
|
|
* @return new instance of {@link EqualityQuery}. |
|
|
|
|
|
|
|
*/ |
|
|
|
public EqualityQuery<T> contention(long contention) { |
|
|
|
public EqualityQuery<T> contention(long contention) { |
|
|
|
return new EqualityQuery<>(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 { |
|
|
|
public static class RangeQuery<T> implements QueryCharacteristic { |
|
|
|
|
|
|
|
|
|
|
|
private final @Nullable Range<T> valueRange; |
|
|
|
private final @Nullable Range<T> valueRange; |
|
|
|
private final @Nullable Integer trimFactor; |
|
|
|
private final @Nullable Integer trimFactor; |
|
|
|
private final @Nullable Long sparsity; |
|
|
|
private final @Nullable Long sparsity; |
|
|
|
|
|
|
|
private final @Nullable Long precision; |
|
|
|
private final @Nullable Long contention; |
|
|
|
private final @Nullable Long contention; |
|
|
|
|
|
|
|
|
|
|
|
private RangeQuery() { |
|
|
|
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, |
|
|
|
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.valueRange = valueRange; |
|
|
|
this.trimFactor = trimFactor; |
|
|
|
this.trimFactor = trimFactor; |
|
|
|
this.sparsity = sparsity; |
|
|
|
this.sparsity = sparsity; |
|
|
|
|
|
|
|
this.precision = precision; |
|
|
|
this.contention = contention; |
|
|
|
this.contention = contention; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
/** |
|
|
|
public String queryType() { |
|
|
|
* @param lower the lower value range boundary for the queryable field. |
|
|
|
return "range"; |
|
|
|
* @return new instance of {@link RangeQuery}. |
|
|
|
} |
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
public RangeQuery<T> min(T lower) { |
|
|
|
public RangeQuery<T> min(T lower) { |
|
|
|
|
|
|
|
|
|
|
|
Range<T> range = Range.of(Bound.inclusive(lower), |
|
|
|
Range<T> range = Range.of(Bound.inclusive(lower), |
|
|
|
valueRange != null ? valueRange.getUpperBound() : Bound.unbounded()); |
|
|
|
valueRange != null ? valueRange.getUpperBound() : Bound.unbounded()); |
|
|
|
return new RangeQuery<>(range, trimFactor, sparsity, contention); |
|
|
|
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) { |
|
|
|
public RangeQuery<T> max(T upper) { |
|
|
|
|
|
|
|
|
|
|
|
Range<T> range = Range.of(valueRange != null ? valueRange.getLowerBound() : Bound.unbounded(), |
|
|
|
Range<T> range = Range.of(valueRange != null ? valueRange.getLowerBound() : Bound.unbounded(), |
|
|
|
Bound.inclusive(upper)); |
|
|
|
Bound.inclusive(upper)); |
|
|
|
return new RangeQuery<>(range, trimFactor, sparsity, contention); |
|
|
|
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) { |
|
|
|
public RangeQuery<T> trimFactor(int trimFactor) { |
|
|
|
return new RangeQuery<>(valueRange, trimFactor, sparsity, contention); |
|
|
|
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) { |
|
|
|
public RangeQuery<T> sparsity(long sparsity) { |
|
|
|
return new RangeQuery<>(valueRange, trimFactor, sparsity, contention); |
|
|
|
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) { |
|
|
|
public RangeQuery<T> contention(long contention) { |
|
|
|
return new RangeQuery<>(valueRange, trimFactor, sparsity, 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"; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
@SuppressWarnings("unchecked") |
|
|
|
@SuppressWarnings("unchecked") |
|
|
|
public Document toDocument() { |
|
|
|
public Document toDocument() { |
|
|
|
|
|
|
|
|
|
|
|
return QueryCharacteristic.super.toDocument().append("contention", contention).append("trimFactor", trimFactor) |
|
|
|
Document target = QueryCharacteristic.super.toDocument(); |
|
|
|
.append("sparsity", sparsity).append("min", valueRange.getLowerBound().getValue().orElse((T) BsonNull.VALUE)) |
|
|
|
if (contention != null) { |
|
|
|
.append("max", valueRange.getUpperBound().getValue().orElse((T) BsonNull.VALUE)); |
|
|
|
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; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|