org.immutables.criteria.elasticsearch.ElasticsearchQueryVisitor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of criteria-elasticsearch Show documentation
Show all versions of criteria-elasticsearch Show documentation
Criteria support for ElasticSearch
/*
* Copyright 2019 Immutables Authors and Contributors
*
* 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 org.immutables.criteria.elasticsearch;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import org.immutables.criteria.backend.PathNaming;
import org.immutables.criteria.expression.AbstractExpressionVisitor;
import org.immutables.criteria.expression.Call;
import org.immutables.criteria.expression.ComparableOperators;
import org.immutables.criteria.expression.Expression;
import org.immutables.criteria.expression.Operator;
import org.immutables.criteria.expression.Operators;
import org.immutables.criteria.expression.OptionalOperators;
import org.immutables.criteria.expression.Path;
import org.immutables.criteria.expression.StringOperators;
import org.immutables.criteria.expression.Visitors;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.regex.Pattern;
/**
* Evaluating expression into Elastic Query DSL
*/
class ElasticsearchQueryVisitor extends AbstractExpressionVisitor {
private final PathNaming pathNaming;
private final Predicate idPredicate;
ElasticsearchQueryVisitor(PathNaming pathNaming, Predicate idPredicate) {
super(e -> { throw new UnsupportedOperationException(); });
this.pathNaming = Objects.requireNonNull(pathNaming, "pathNaming");
this.idPredicate = Objects.requireNonNull(idPredicate, "idPredicate");
}
@Override
public QueryBuilders.QueryBuilder visit(Call call) {
final Operator op = call.operator();
final List args = call.arguments();
if (op == OptionalOperators.IS_PRESENT || op == OptionalOperators.IS_ABSENT) {
final String field = pathNaming.name(Visitors.toPath(args.get(0)));
QueryBuilders.QueryBuilder builder = QueryBuilders.existsQuery(field);
if (op == OptionalOperators.IS_ABSENT) {
builder = QueryBuilders.boolQuery().mustNot(builder);
}
return builder;
}
if (op == Operators.AND || op == Operators.OR) {
Preconditions.checkArgument(!args.isEmpty(), "Size should be >=1 for %s but was %s", op, args.size());
final QueryBuilders.BoolQueryBuilder builder = args.stream()
.map(a -> a.accept(this))
.reduce(QueryBuilders.boolQuery(), (a, b) -> op == Operators.AND ? a.must(b) : a.should(b), (a, b) -> b);
return builder;
}
if (op == Operators.NOT) {
Preconditions.checkArgument(args.size() == 1, "Size should be 1 for %s but was %s", op, args.size());
final QueryBuilders.QueryBuilder builder = args.get(0).accept(this);
return QueryBuilders.boolQuery().mustNot(builder);
}
if (op.arity() == Operator.Arity.BINARY) {
return binaryCall(call);
}
throw new UnsupportedOperationException("Don't know how to handle " + call);
}
private QueryBuilders.QueryBuilder binaryCall(Call call) {
final List 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