use of org.immutables.criteria.expression.Path in project immutables by immutables.
the class TupleCodecProviderTest method localDate.
@Test
void localDate() {
LocalDateHolderCriteria criteria = LocalDateHolderCriteria.localDateHolder;
Query query = Query.of(TypeHolder.LocalDateHolder.class).addProjections(Matchers.toExpression(criteria.value), Matchers.toExpression(criteria.nullable), Matchers.toExpression(criteria.optional));
Path idPath = Visitors.toPath(KeyExtractor.defaultFactory().create(TypeHolder.LocalDateHolder.class).metadata().keys().get(0));
TupleCodecProvider provider = new TupleCodecProvider(query, new MongoPathNaming(idPath, PathNaming.defaultNaming()).toExpression());
Codec<ProjectedTuple> codec = provider.get(ProjectedTuple.class, registry);
LocalDate now = LocalDate.now();
final long millisEpoch = now.atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli();
BsonDocument doc = new BsonDocument().append("id", new BsonString("id1")).append("value", new BsonDateTime(millisEpoch)).append("nullable", BsonNull.VALUE).append("optional", BsonNull.VALUE).append("array", new BsonArray()).append("list", new BsonArray());
ProjectedTuple tuple = codec.decode(new BsonDocumentReader(doc), DecoderContext.builder().build());
check(tuple.get(Matchers.toExpression(criteria.value))).is(now);
check(tuple.get(Matchers.toExpression(criteria.nullable))).isNull();
check(tuple.get(Matchers.toExpression(criteria.optional))).is(Optional.empty());
}
use of org.immutables.criteria.expression.Path in project immutables by immutables.
the class TupleCodecProviderTest method age.
@Test
public void age() {
Query query = Query.of(Person.class).addProjections(Matchers.toExpression(PersonCriteria.person.age));
Path idPath = Visitors.toPath(KeyExtractor.defaultFactory().create(Person.class).metadata().keys().get(0));
TupleCodecProvider provider = new TupleCodecProvider(query, new MongoPathNaming(idPath, PathNaming.defaultNaming()).toExpression());
Codec<ProjectedTuple> codec = provider.get(ProjectedTuple.class, registry);
ProjectedTuple tuple = codec.decode(new BsonDocumentReader(new BsonDocument("age", new BsonInt32(10))), DecoderContext.builder().build());
check(tuple.values()).hasSize(1);
check(tuple.values().get(0)).asString().is("10");
}
use of org.immutables.criteria.expression.Path in project immutables by immutables.
the class MongoSession method query.
private Publisher<?> query(StandardOperations.Select select) {
final Query query = select.query();
final boolean hasProjections = query.hasProjections();
boolean useAggregationPipeline = query.hasAggregations() || query.distinct() || query.count() && query.limit().isPresent();
ExpressionNaming expressionNaming = useAggregationPipeline ? ExpressionNaming.from(UniqueCachedNaming.of(query.projections())) : expression -> pathNaming.name((Path) expression);
MongoCollection<?> collection = this.collection;
if (hasProjections) {
// add special TupleCodecProvider for projections
CodecRegistry newRegistry = CodecRegistries.fromRegistries(this.collection.getCodecRegistry(), CodecRegistries.fromProviders(new TupleCodecProvider(query, expressionNaming)));
collection = this.collection.withDocumentClass(ProjectedTuple.class).withCodecRegistry(newRegistry);
}
if (useAggregationPipeline) {
// aggregations
AggregationQuery agg = new AggregationQuery(query, pathNaming);
if (query.count()) {
// also for empty result-set mongo does not return single(0) but empty publisher
return Flowable.fromPublisher(collection.aggregate(agg.toPipeline(), BsonDocument.class)).map(d -> d.get("count").asNumber().longValue()).defaultIfEmpty(// return Single.just(0) for empty publisher
0L);
}
return collection.aggregate(agg.toPipeline(), ProjectedTuple.class);
}
Bson filter = toBsonFilter(query);
if (query.count()) {
// simple form of count all (without distinct, aggregations etc.) : count(*)
return Flowable.fromPublisher(collection.countDocuments(filter));
}
final FindPublisher<?> find = collection.find(filter);
if (!query.collations().isEmpty()) {
// add sorting
final Function<Collation, Bson> toSortFn = col -> {
final String path = col.path().toStringPath();
return col.direction().isAscending() ? Sorts.ascending(path) : Sorts.descending(path);
};
final List<Bson> sorts = query.collations().stream().map(toSortFn).collect(Collectors.toList());
find.sort(Sorts.orderBy(sorts));
}
query.limit().ifPresent(limit -> find.limit((int) limit));
query.offset().ifPresent(offset -> find.skip((int) offset));
if (hasProjections) {
List<String> fields = query.projections().stream().map(p -> pathNaming.name((Path) p)).collect(Collectors.toList());
find.projection(Projections.include(fields));
return find;
}
// post-process result with projections
return find;
}
use of org.immutables.criteria.expression.Path in project immutables by immutables.
the class AggregationQuery method extractPath.
private static Path extractPath(Expression expression) {
if (expression instanceof Path) {
return (Path) expression;
}
if (expression instanceof Call) {
Call call = (Call) expression;
if (call.operator().arity() != Operator.Arity.UNARY) {
throw new IllegalArgumentException("Expected unary operator but got " + call);
}
Expression arg = call.arguments().get(0);
Preconditions.checkArgument(arg instanceof Path, "expected path got %s", arg);
return (Path) arg;
}
throw new IllegalArgumentException("Can't extract path from " + expression);
}
use of org.immutables.criteria.expression.Path in project immutables by immutables.
the class ElasticsearchQueryVisitor method binaryCall.
private QueryBuilders.QueryBuilder binaryCall(Call call) {
final List<Expression> arguments = call.arguments();
Preconditions.checkArgument(arguments.size() == 2, "Size should be 2 for %s but was %s", call.operator(), arguments.size());
final Operator op = call.operator();
final Path path = Visitors.toPath(arguments.get(0));
final String field = pathNaming.name(path);
final Object value = Visitors.toConstant(arguments.get(1)).value();
if (op == Operators.EQUAL || op == Operators.NOT_EQUAL) {
QueryBuilders.QueryBuilder builder;
if (idPredicate.test(path)) {
// use more efficient ids query for keys
builder = QueryBuilders.idsQuery(Collections.singleton(value));
} else {
builder = QueryBuilders.termQuery(field, value);
}
if (op == Operators.NOT_EQUAL) {
QueryBuilders.BoolQueryBuilder bool = QueryBuilders.boolQuery().mustNot(builder);
if ("".equals(value)) {
// string is not empty (should also exists)
bool = bool.should(QueryBuilders.existsQuery(field));
}
builder = bool;
}
return builder;
}
if (op == Operators.IN || op == Operators.NOT_IN) {
final Collection<Object> values = ImmutableSet.copyOf(Visitors.toConstant(arguments.get(1)).values());
QueryBuilders.QueryBuilder builder;
if (idPredicate.test(path)) {
// more efficient query by ID
builder = QueryBuilders.idsQuery(values);
} else {
builder = QueryBuilders.termsQuery(field, values);
}
if (op == Operators.NOT_IN) {
builder = QueryBuilders.boolQuery().mustNot(builder);
}
return builder;
}
if (ComparableOperators.isComparable(op)) {
final QueryBuilders.RangeQueryBuilder builder = QueryBuilders.rangeQuery(field);
if (op == ComparableOperators.GREATER_THAN) {
builder.gt(value);
} else if (op == ComparableOperators.GREATER_THAN_OR_EQUAL) {
builder.gte(value);
} else if (op == ComparableOperators.LESS_THAN) {
builder.lt(value);
} else if (op == ComparableOperators.LESS_THAN_OR_EQUAL) {
builder.lte(value);
} else {
throw new UnsupportedOperationException("Unknown comparison " + call);
}
return builder;
}
if (op == StringOperators.STARTS_WITH) {
return QueryBuilders.prefixQuery(field, value.toString());
}
if (op == StringOperators.MATCHES) {
Preconditions.checkArgument(value instanceof Pattern, "%s is not regex pattern", value);
// In elastic / lucene, patterns match the entire string.
return QueryBuilders.regexpQuery(field, ((Pattern) value).pattern());
}
if (op == StringOperators.ENDS_WITH || op == StringOperators.CONTAINS) {
return QueryBuilders.wildcardQuery(field, "*" + value.toString() + (op == StringOperators.CONTAINS ? "*" : ""));
}
throw new UnsupportedOperationException(String.format("Call %s not supported", call));
}
Aggregations