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:
Simon Baslé
2015-07-31 18:24:40 +02:00
parent 60196095a6
commit f57a03ad21
11 changed files with 144 additions and 17 deletions

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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) {

View File

@@ -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()) {

View File

@@ -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();
}