
org.jnosql.diana.couchbase.document.QueryConverter Maven / Gradle / Ivy
/*
* Copyright (c) 2017 Otávio Santana and others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php.
*
* You may elect to redistribute this code under either of these licenses.
*
* Contributors:
*
* Otavio Santana
*/
package org.jnosql.diana.couchbase.document;
import com.couchbase.client.java.document.json.JsonObject;
import com.couchbase.client.java.query.Delete;
import com.couchbase.client.java.query.Statement;
import com.couchbase.client.java.query.dsl.Expression;
import com.couchbase.client.java.query.dsl.path.MutateLimitPath;
import org.jnosql.diana.api.Condition;
import org.jnosql.diana.api.Sort;
import org.jnosql.diana.api.TypeReference;
import org.jnosql.diana.api.document.Document;
import org.jnosql.diana.api.document.DocumentCondition;
import org.jnosql.diana.api.document.DocumentDeleteQuery;
import org.jnosql.diana.api.document.DocumentQuery;
import org.jnosql.diana.driver.ValueUtil;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import static com.couchbase.client.java.query.dsl.Expression.x;
import static java.util.Objects.nonNull;
import static org.jnosql.diana.api.Condition.EQUALS;
import static org.jnosql.diana.api.Condition.IN;
import static org.jnosql.diana.couchbase.document.EntityConverter.ID_FIELD;
import static org.jnosql.diana.couchbase.document.EntityConverter.KEY_FIELD;
import static org.jnosql.diana.couchbase.document.StatementFactory.create;
final class QueryConverter {
private static final Set NOT_APPENDABLE = EnumSet.of(IN, Condition.AND, Condition.OR);
private static final char PARAM_PREFIX = '$';
private static final String[] ALL_SELECT = {"*"};
private static final Function SORT_MAP = s -> {
if (Sort.SortType.ASC.equals(s.getType())) {
return com.couchbase.client.java.query.dsl.Sort.asc(s.getName());
} else {
return com.couchbase.client.java.query.dsl.Sort.desc(s.getName());
}
};
private QueryConverter() {
}
static QueryConverterResult select(DocumentQuery query, String bucket) {
JsonObject params = JsonObject.create();
List keys = new ArrayList<>();
String[] documents = query.getDocuments().stream().toArray(String[]::new);
if (documents.length == 0) {
documents = ALL_SELECT;
}
Statement statement = null;
int skip = (int) query.getSkip();
int limit = (int) query.getLimit();
com.couchbase.client.java.query.dsl.Sort[] sorts = query.getSorts().stream().map(SORT_MAP).
toArray(com.couchbase.client.java.query.dsl.Sort[]::new);
if (query.getCondition().isPresent()) {
Expression condition = getCondition(query.getCondition().get(), params, keys, query.getDocumentCollection());
if (nonNull(condition)) {
statement = create(bucket, documents, skip, limit, sorts, condition);
} else {
statement = null;
}
} else {
statement = create(bucket, documents, skip, limit, sorts);
}
return new QueryConverterResult(params, statement, keys);
}
static QueryConverterResult delete(DocumentDeleteQuery query, String bucket) {
JsonObject params = JsonObject.create();
List ids = new ArrayList<>();
Expression condition = getCondition(query.getCondition()
.orElseThrow(() -> new IllegalArgumentException("Condigtion is required")), params, ids,
query.getDocumentCollection());
MutateLimitPath statement = null;
if (nonNull(condition)) {
statement = Delete.deleteFrom(bucket).where(condition);
}
return new QueryConverterResult(params, statement, ids);
}
private static Expression getCondition(DocumentCondition condition, JsonObject params
, List keys, String documentCollection) {
Document document = condition.getDocument();
if (!NOT_APPENDABLE.contains(condition.getCondition()) && isKeyField(document)) {
if (IN.equals(condition.getCondition())) {
inKeys(keys, documentCollection, document);
} else if (EQUALS.equals(condition.getCondition())) {
eqKeys(keys, documentCollection, document);
}
return null;
}
if (!NOT_APPENDABLE.contains(condition.getCondition())) {
if(Condition.BETWEEN.equals(condition.getCondition()) || Condition.IN.equals(condition.getCondition())) {
params.put(document.getName(), ValueUtil.convertToList(document.getValue()));
} else {
params.put(document.getName(), ValueUtil.convert(document.getValue()));
}
}
switch (condition.getCondition()) {
case EQUALS:
return x(document.getName()).eq(x(PARAM_PREFIX + document.getName()));
case LESSER_THAN:
return x(document.getName()).lt(x(PARAM_PREFIX + document.getName()));
case LESSER_EQUALS_THAN:
return x(document.getName()).lte(x(PARAM_PREFIX + document.getName()));
case GREATER_THAN:
return x(document.getName()).gt(x(PARAM_PREFIX + document.getName()));
case GREATER_EQUALS_THAN:
return x(document.getName()).gte(x(PARAM_PREFIX + document.getName()));
case LIKE:
return x(document.getName()).like(x(PARAM_PREFIX + document.getName()));
case IN:
return x(document.getName()).in(x(PARAM_PREFIX + document.getName()));
case BETWEEN:
return x(document.getName()).between(x(PARAM_PREFIX + document.getName()));
case AND:
return document.get(new TypeReference>() {
})
.stream()
.map(d -> getCondition(d, params, keys, documentCollection))
.filter(Objects::nonNull)
.reduce(Expression::and)
.orElseThrow(() -> new IllegalStateException("An and condition cannot be empty"));
case OR:
return document.get(new TypeReference>() {
})
.stream()
.map(d -> getCondition(d, params, keys, documentCollection))
.reduce(Expression::or)
.orElseThrow(() -> new IllegalStateException("An or condition cannot be empty"));
case NOT:
DocumentCondition dc = document.get(DocumentCondition.class);
return getCondition(dc, params, keys, documentCollection).not();
default:
throw new IllegalStateException("This condition is not supported at coubhbase: " + condition.getCondition());
}
}
private static void eqKeys(List keys, String documentCollection, Document document) {
if(document.getName().equals(KEY_FIELD)){
keys.add(document.get(String.class));
} else {
keys.add(EntityConverter.getPrefix(documentCollection, document.get(String.class)));
}
}
private static void inKeys(List keys, String documentCollection, Document document) {
if(document.getName().equals(KEY_FIELD)){
keys.addAll(document.get(new TypeReference>() {
}));
} else {
List ids = document.get(new TypeReference>() {});
ids.stream().map(id -> EntityConverter.getPrefix(documentCollection, id))
.forEach(keys::add);
}
}
private static boolean isKeyField(Document document) {
return ID_FIELD.equals(document.getName()) || KEY_FIELD.equals(document.getName());
}
static class QueryConverterResult {
private final JsonObject params;
private final Statement statement;
private final List keys;
QueryConverterResult(JsonObject params, Statement statement, List keys) {
this.params = params;
this.statement = statement;
this.keys = keys;
}
JsonObject getParams() {
return params;
}
Statement getStatement() {
return statement;
}
List getKeys() {
return keys;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy