Search in sources :

Example 11 with Path

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());
}
Also used : Path(org.immutables.criteria.expression.Path) Query(org.immutables.criteria.expression.Query) BsonDocumentReader(org.bson.BsonDocumentReader) LocalDate(java.time.LocalDate) TypeHolder(org.immutables.criteria.typemodel.TypeHolder) LocalDateHolderCriteria(org.immutables.criteria.typemodel.LocalDateHolderCriteria) BsonDocument(org.bson.BsonDocument) BsonDateTime(org.bson.BsonDateTime) BsonString(org.bson.BsonString) BsonArray(org.bson.BsonArray) ProjectedTuple(org.immutables.criteria.backend.ProjectedTuple) Test(org.junit.jupiter.api.Test)

Example 12 with Path

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");
}
Also used : Path(org.immutables.criteria.expression.Path) BsonInt32(org.bson.BsonInt32) Query(org.immutables.criteria.expression.Query) BsonDocument(org.bson.BsonDocument) BsonDocumentReader(org.bson.BsonDocumentReader) ProjectedTuple(org.immutables.criteria.backend.ProjectedTuple) Person(org.immutables.criteria.personmodel.Person) Test(org.junit.jupiter.api.Test)

Example 13 with Path

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;
}
Also used : Path(org.immutables.criteria.expression.Path) Document(org.bson.Document) Iterables(com.google.common.collect.Iterables) ReplaceOneModel(com.mongodb.client.model.ReplaceOneModel) Path(org.immutables.criteria.expression.Path) PathNaming(org.immutables.criteria.backend.PathNaming) Projections(com.mongodb.client.model.Projections) StandardOperations(org.immutables.criteria.backend.StandardOperations) ReplaceOptions(com.mongodb.client.model.ReplaceOptions) BsonDocumentWriter(org.bson.BsonDocumentWriter) DefaultResult(org.immutables.criteria.backend.DefaultResult) MongoCollection(com.mongodb.reactivestreams.client.MongoCollection) CodecRegistry(org.bson.codecs.configuration.CodecRegistry) ExpressionNaming(org.immutables.criteria.backend.ExpressionNaming) Backend(org.immutables.criteria.backend.Backend) Function(java.util.function.Function) FlowableTransformer(io.reactivex.FlowableTransformer) BsonDocument(org.bson.BsonDocument) BsonValue(org.bson.BsonValue) Query(org.immutables.criteria.expression.Query) Level(java.util.logging.Level) FullDocument(com.mongodb.client.model.changestream.FullDocument) Bson(org.bson.conversions.Bson) ChangeStreamPublisher(com.mongodb.reactivestreams.client.ChangeStreamPublisher) Flowable(io.reactivex.Flowable) EncoderContext(org.bson.codecs.EncoderContext) WatchEvent(org.immutables.criteria.backend.WatchEvent) ProjectedTuple(org.immutables.criteria.backend.ProjectedTuple) Collation(org.immutables.criteria.expression.Collation) ExpressionConverter(org.immutables.criteria.expression.ExpressionConverter) MongoException(com.mongodb.MongoException) Publisher(org.reactivestreams.Publisher) CodecRegistries(org.bson.codecs.configuration.CodecRegistries) Logger(java.util.logging.Logger) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) KeyExtractor(org.immutables.criteria.backend.KeyExtractor) Visitors(org.immutables.criteria.expression.Visitors) List(java.util.List) Sorts(com.mongodb.client.model.Sorts) BulkWriteResult(com.mongodb.bulk.BulkWriteResult) UniqueCachedNaming(org.immutables.criteria.backend.UniqueCachedNaming) FindPublisher(com.mongodb.reactivestreams.client.FindPublisher) Codec(org.bson.codecs.Codec) WriteResult(org.immutables.criteria.backend.WriteResult) Optional(java.util.Optional) BackendException(org.immutables.criteria.backend.BackendException) ExpressionNaming(org.immutables.criteria.backend.ExpressionNaming) Query(org.immutables.criteria.expression.Query) Collation(org.immutables.criteria.expression.Collation) Bson(org.bson.conversions.Bson) BsonDocument(org.bson.BsonDocument) CodecRegistry(org.bson.codecs.configuration.CodecRegistry)

Example 14 with Path

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);
}
Also used : Path(org.immutables.criteria.expression.Path) Call(org.immutables.criteria.expression.Call) Expression(org.immutables.criteria.expression.Expression)

Example 15 with Path

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));
}
Also used : Operator(org.immutables.criteria.expression.Operator) Path(org.immutables.criteria.expression.Path) Pattern(java.util.regex.Pattern) Expression(org.immutables.criteria.expression.Expression)

Aggregations

Path (org.immutables.criteria.expression.Path)15 Expression (org.immutables.criteria.expression.Expression)8 BsonDocument (org.bson.BsonDocument)5 ProjectedTuple (org.immutables.criteria.backend.ProjectedTuple)5 Query (org.immutables.criteria.expression.Query)5 Iterables (com.google.common.collect.Iterables)3 Objects (java.util.Objects)3 Optional (java.util.Optional)3 BsonString (org.bson.BsonString)3 Test (org.junit.jupiter.api.Test)3 ObjectNode (com.fasterxml.jackson.databind.node.ObjectNode)2 MongoException (com.mongodb.MongoException)2 BulkWriteResult (com.mongodb.bulk.BulkWriteResult)2 Projections (com.mongodb.client.model.Projections)2 ReplaceOneModel (com.mongodb.client.model.ReplaceOneModel)2 ReplaceOptions (com.mongodb.client.model.ReplaceOptions)2 Sorts (com.mongodb.client.model.Sorts)2 FullDocument (com.mongodb.client.model.changestream.FullDocument)2 ChangeStreamPublisher (com.mongodb.reactivestreams.client.ChangeStreamPublisher)2 FindPublisher (com.mongodb.reactivestreams.client.FindPublisher)2