Fixes JIRA issue SGF-277 - OQL Join in Repository Interface.

This commit is contained in:
John Blum
2014-04-28 14:21:45 -07:00
parent edca5232a4
commit 8fd0b0bf6d
14 changed files with 470 additions and 39 deletions

View File

@@ -60,10 +60,10 @@ public class PartTreeGemfireRepositoryQuery extends GemfireRepositoryQuery {
*/
@Override
public Object execute(Object[] parameters) {
ParametersParameterAccessor parameterAccessor = new ParametersParameterAccessor(method.getParameters(), parameters);
QueryString query = new GemfireQueryCreator(tree, method.getPersistentEntity()).createQuery(parameterAccessor
.getSort());
QueryString query = new GemfireQueryCreator(tree, method.getPersistentEntity())
.createQuery(parameterAccessor.getSort());
RepositoryQuery repositoryQuery = new StringBasedGemfireRepositoryQuery(query.toString(), method, template);

View File

@@ -21,23 +21,23 @@ import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.gemstone.gemfire.cache.Region;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import com.gemstone.gemfire.cache.Region;
/**
* Value object to work with OQL query strings.
*
* @author Oliver Gierke
* @author David Turanski
* @author John Blum
*/
class QueryString {
//private static final String REGION_PATTERN = "(?<=\\/)\\w+";
private static final String REGION_PATTERN = "\\/(\\/?\\w)+";
private static final String IN_PARAMETER_PATTERN = "(?<=IN (SET|LIST) \\$)\\d";
private static final String IN_PATTERN = "(?<=IN (SET|LIST) )\\$\\d";
private static final String IN_PARAMETER_PATTERN = "(?<=IN (SET|LIST) \\$)\\d";
private static final String REGION_PATTERN = "\\/(\\/?\\w)+";
private final String query;
@@ -47,8 +47,7 @@ class QueryString {
* @param source
*/
public QueryString(String source) {
Assert.hasText(source);
Assert.hasText(source, "The OQL statement (Query) to execute must be specified!");
this.query = source;
}
@@ -57,7 +56,8 @@ class QueryString {
*
* @param domainClass must not be {@literal null}.
*/
public QueryString(Class<?> domainClass) {
@SuppressWarnings("unused")
public QueryString(Class<?> domainClass) {
this(domainClass, false);
}
@@ -68,8 +68,7 @@ class QueryString {
* @param isCountQuery indicates if this is a count query
*/
public QueryString(Class<?> domainClass, boolean isCountQuery) {
this(String
.format(isCountQuery ? "SELECT count(*) FROM /%s" : "SELECT * FROM /%s", domainClass.getSimpleName()));
this(String.format(isCountQuery ? "SELECT count(*) FROM /%s" : "SELECT * FROM /%s", domainClass.getSimpleName()));
}
/**
@@ -79,6 +78,7 @@ class QueryString {
* @param region must not be {@literal null}.
* @return
*/
@SuppressWarnings("unused")
public QueryString forRegion(Class<?> domainClass, Region<?, ?> region) {
return new QueryString(query.replaceAll(REGION_PATTERN, region.getFullPath()));
}
@@ -90,23 +90,21 @@ class QueryString {
* @param values the values to bind, returns the {@link QueryString} as is if {@literal null} is given.
* @return
*/
public QueryString bindIn(Collection<?> values) {
public QueryString bindIn(Collection<?> values) {
if (values != null) {
String valueString = StringUtils.collectionToDelimitedString(values, ", ", "'", "'");
return new QueryString(query.replaceFirst(IN_PATTERN, String.format("(%s)", valueString)));
}
if (values == null) {
return this;
}
return this;
}
String valueString = StringUtils.collectionToDelimitedString(values, ", ", "'", "'");
return new QueryString(query.replaceFirst(IN_PATTERN, String.format("(%s)", valueString)));
}
/**
/**
* Returns the parameter indexes used in this query.
*
* @return the parameter indexes used in this query or an empty {@link Iterable} if none are used.
*/
public Iterable<Integer> getInParameterIndexes() {
Pattern pattern = Pattern.compile(IN_PARAMETER_PATTERN);
Matcher matcher = pattern.matcher(query);
List<Integer> result = new ArrayList<Integer>();
@@ -126,4 +124,5 @@ class QueryString {
public String toString() {
return query;
}
}

View File

@@ -38,11 +38,13 @@ import com.gemstone.gemfire.cache.query.internal.ResultsBag;
*/
public class StringBasedGemfireRepositoryQuery extends GemfireRepositoryQuery {
private static final String INVALID_EXECUTION = "Paging and modifying queries are not supported!";
private static final String INVALID_QUERY = "Paging and modifying queries are not supported!";
private boolean userDefinedQuery = false;
private final QueryString query;
private final GemfireQueryMethod method;
private final GemfireTemplate template;
private final QueryString query;
/*
* (non-Javadoc)
@@ -69,34 +71,50 @@ public class StringBasedGemfireRepositoryQuery extends GemfireRepositoryQuery {
* Creates a new {@link StringBasedGemfireRepositoryQuery} using the given query {@link String},
* {@link GemfireQueryMethod} and {@link GemfireTemplate}.
*
* @param query will fall back to the query annotated to the given {@link GemfireQueryMethod} if {@literal null} is
* given.
* @param query will fall back to the query annotated to the given {@link GemfireQueryMethod} if {@literal null}.
* @param method must not be {@literal null}.
* @param template must not be {@literal null}.
*/
public StringBasedGemfireRepositoryQuery(String query, GemfireQueryMethod method, GemfireTemplate template) {
super(method);
Assert.notNull(template);
this.userDefinedQuery |= !StringUtils.hasText(query);
this.query = new QueryString(StringUtils.hasText(query) ? query : method.getAnnotatedQuery());
this.method = method;
this.template = template;
if (method.isPageQuery() || method.isModifyingQuery()) {
throw new IllegalStateException(INVALID_EXECUTION);
throw new IllegalStateException(INVALID_QUERY);
}
}
/*
/*
* (non-Javadoc)
*/
public StringBasedGemfireRepositoryQuery asUserDefinedQuery() {
this.userDefinedQuery = true;
return this;
}
/*
* (non-Javadoc)
*/
public boolean isUserDefinedQuery() {
return userDefinedQuery;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.query.RepositoryQuery#execute(java.lang.Object[])
*/
@Override
public Object execute(Object[] parameters) {
ParametersParameterAccessor accessor = new ParametersParameterAccessor(method.getParameters(), parameters);
QueryString query = this.query.forRegion(method.getEntityInformation().getJavaType(), template.getRegion());
QueryString query = (isUserDefinedQuery() ? this.query :
this.query.forRegion(method.getEntityInformation().getJavaType(), template.getRegion()));
for (Integer index : query.getInParameterIndexes()) {
query = query.bindIn(toCollection(accessor.getBindableValue(index - 1)));

View File

@@ -147,18 +147,18 @@ public class GemfireRepositoryFactory extends RepositoryFactorySupport {
return new QueryLookupStrategy() {
@Override
public RepositoryQuery resolveQuery(Method method, RepositoryMetadata metadata, NamedQueries namedQueries) {
GemfireQueryMethod queryMethod = new GemfireQueryMethod(method, metadata, context);
GemfireTemplate template = getTemplate(metadata);
if (queryMethod.hasAnnotatedQuery()) {
return new StringBasedGemfireRepositoryQuery(queryMethod, template);
return new StringBasedGemfireRepositoryQuery(queryMethod, template).asUserDefinedQuery();
}
String namedQueryName = queryMethod.getNamedQueryName();
if (namedQueries.hasQuery(namedQueryName)) {
return new StringBasedGemfireRepositoryQuery(namedQueries.getQuery(namedQueryName), queryMethod,
template);
template).asUserDefinedQuery();
}
return new PartTreeGemfireRepositoryQuery(queryMethod, template);