DATACOUCH-156 - Make generated N1QL queries filter on the type field.
The generated N1QL queries currently don't filter on the type at all. Add a criteria to the WHERE clause that checks the field holding type information is matching the entity fully qualified class name. Add a placeholder for inline N1QL queries that can be replaced by the same type information criteria.
This commit is contained in:
@@ -51,4 +51,9 @@ public interface CouchbaseConverter
|
||||
* @see #convertForWriteIfNeeded(Object)
|
||||
*/
|
||||
Class<?> getWriteClassFor(Class<?> clazz);
|
||||
|
||||
/**
|
||||
* @return the name of the field that will hold type information.
|
||||
*/
|
||||
String getTypeKey();
|
||||
}
|
||||
|
||||
@@ -130,9 +130,7 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter
|
||||
return mappingContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name of the field that will hold type information.
|
||||
*/
|
||||
@Override
|
||||
public String getTypeKey() {
|
||||
return typeMapper.getTypeKey();
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.data.couchbase.repository.query;
|
||||
|
||||
import static com.couchbase.client.java.query.dsl.Expression.i;
|
||||
import static com.couchbase.client.java.query.dsl.Expression.s;
|
||||
import static com.couchbase.client.java.query.dsl.Expression.x;
|
||||
|
||||
@@ -93,12 +94,14 @@ public class N1qlQueryCreator extends AbstractQueryCreator<LimitPath, Expression
|
||||
|
||||
private final WherePath selectFrom;
|
||||
private final CouchbaseConverter converter;
|
||||
private final CouchbaseQueryMethod queryMethod;
|
||||
|
||||
public N1qlQueryCreator(PartTree tree, ParameterAccessor parameters, WherePath selectFrom,
|
||||
CouchbaseConverter converter) {
|
||||
CouchbaseConverter converter, CouchbaseQueryMethod queryMethod) {
|
||||
super(tree, parameters);
|
||||
this.selectFrom = selectFrom;
|
||||
this.converter = converter;
|
||||
this.queryMethod = queryMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -122,6 +125,16 @@ public class N1qlQueryCreator extends AbstractQueryCreator<LimitPath, Expression
|
||||
|
||||
@Override
|
||||
protected LimitPath complete(Expression criteria, Sort sort) {
|
||||
//add part that filters on type key
|
||||
String typeKey = converter.getTypeKey();
|
||||
String typeValue = queryMethod.getEntityInformation().getJavaType().getName();
|
||||
Expression typeSelector = i(typeKey).eq(s(typeValue));
|
||||
if (criteria == null) {
|
||||
criteria = typeSelector;
|
||||
} else {
|
||||
criteria = criteria.and(typeSelector);
|
||||
}
|
||||
|
||||
OrderByPath selectFromWhere = selectFrom.where(criteria);
|
||||
|
||||
if (sort != null) {
|
||||
|
||||
@@ -61,7 +61,8 @@ public class PartTreeN1qlBasedQuery extends AbstractN1qlBasedQuery {
|
||||
}
|
||||
WherePath selectFrom = select.from(bucket);
|
||||
|
||||
N1qlQueryCreator queryCreator = new N1qlQueryCreator(partTree, accessor, selectFrom, getCouchbaseOperations().getConverter());
|
||||
N1qlQueryCreator queryCreator = new N1qlQueryCreator(partTree, accessor, selectFrom,
|
||||
getCouchbaseOperations().getConverter(), getQueryMethod());
|
||||
LimitPath selectFromWhereOrderBy = queryCreator.createQuery();
|
||||
|
||||
if (partTree.isLimiting()) {
|
||||
|
||||
@@ -52,18 +52,29 @@ public class StringN1qlBasedQuery extends AbstractN1qlBasedQuery {
|
||||
*/
|
||||
public static final String PLACEHOLDER_ENTITY = "$ENTITY$";
|
||||
|
||||
/**
|
||||
* Use this placeholder in a {@link org.springframework.data.couchbase.core.view.Query @Query} annotation's inline
|
||||
* statement WHERE clause. This will be replaced by the expression allowing to only select documents matching the
|
||||
* entity's class.
|
||||
*/
|
||||
public static final String PLACEHOLDER_FILTER_TYPE = "$FILTER_TYPE$";
|
||||
|
||||
private final Statement statement;
|
||||
|
||||
public StringN1qlBasedQuery(String statement, CouchbaseQueryMethod queryMethod, CouchbaseOperations couchbaseOperations) {
|
||||
super(queryMethod, couchbaseOperations);
|
||||
this.statement = prepare(statement, couchbaseOperations.getCouchbaseBucket().name());
|
||||
String typeField = getCouchbaseOperations().getConverter().getTypeKey();
|
||||
Class<?> typeValue = getQueryMethod().getEntityInformation().getJavaType();
|
||||
this.statement = prepare(statement, couchbaseOperations.getCouchbaseBucket().name(), typeField, typeValue);
|
||||
}
|
||||
|
||||
protected static Statement prepare(String statement, String bucketName) {
|
||||
protected static Statement prepare(String statement, String bucketName, String typeField, Class<?> typeValue) {
|
||||
String b = "`" + bucketName + "`";
|
||||
String entity = "META(" + b + ").id AS " + CouchbaseOperations.SELECT_ID +
|
||||
", META(" + b + ").cas AS " + CouchbaseOperations.SELECT_CAS;
|
||||
String selectEntity = "SELECT " + entity + ", " + b + ".* FROM " + b;
|
||||
String typeSelection = "`" + typeField + "` = \"" + typeValue.getName() + "\"";
|
||||
|
||||
String result = statement;
|
||||
if (statement.contains(PLACEHOLDER_SELECT_FROM)) {
|
||||
result = result.replaceFirst("\\$SELECT_ENTITY\\$", selectEntity);
|
||||
@@ -75,6 +86,11 @@ public class StringN1qlBasedQuery extends AbstractN1qlBasedQuery {
|
||||
result = result.replaceFirst("\\$ENTITY\\$", entity);
|
||||
}
|
||||
}
|
||||
|
||||
if (statement.contains(PLACEHOLDER_FILTER_TYPE)) {
|
||||
result = result.replaceFirst("\\$FILTER_TYPE\\$", typeSelection);
|
||||
}
|
||||
|
||||
return Query.simple(result).statement();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user