Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix count query with different parameters than main query #1883

Open
wants to merge 3 commits into
base: 4.7.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,15 @@
String META_MEMBER_RAW_QUERY = "rawQuery";

/**
* Whether the user is a raw user specified query.
* Whether the user declared raw count query.
*/
String META_MEMBER_RAW_COUNT_QUERY = "rawCountQuery";

/**
* Used when there is a raw count query declared.
*/
String META_MEMBER_RAW_COUNT_PARAMETERS = "rawCountParameters";

/**
* Meta member for storing the parameter type defs.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ private void processMethodInfo(MethodMatchContext methodMatchContext, MethodMatc
// no need to annotation since already annotated, just replace the
// the computed parameter names
parameterBinding = queryResult.getParameterBindings();

encodeEntityParameters = methodInfo.isEncodeEntityParameters();
element.annotate(Query.class, (builder) -> builder.member(DataMethod.META_MEMBER_RAW_QUERY,
element.stringValue(Query.class)
.map(q -> addRawQueryParameterPlaceholders(queryEncoder, queryResult.getQuery(), queryResult.getQueryParts()))
Expand All @@ -324,10 +324,16 @@ private void processMethodInfo(MethodMatchContext methodMatchContext, MethodMatc
Query.class,
(builder) -> builder.member(DataMethod.META_MEMBER_RAW_COUNT_QUERY, addRawQueryParameterPlaceholders(queryEncoder, countQueryResult.getQuery(), countQueryResult.getQueryParts()))
);
// For count query, we might need to take parameters for that query
// since it can differ from the main query
final List<QueryParameterBinding> finalCountParameterBindings = countQueryResult.getParameterBindings();
if (CollectionUtils.isNotEmpty(finalCountParameterBindings)) {
final boolean finalEncodeEntityParameters = encodeEntityParameters;
element.annotate(DataMethod.class, builder -> bindParameters(supportsImplicitQueries, finalCountParameterBindings, finalEncodeEntityParameters,
builder, DataMethod.META_MEMBER_RAW_COUNT_PARAMETERS));
}
}
}

encodeEntityParameters = methodInfo.isEncodeEntityParameters();
} else {

encodeEntityParameters = methodInfo.isEncodeEntityParameters();
Expand Down Expand Up @@ -429,7 +435,7 @@ private void processMethodInfo(MethodMatchContext methodMatchContext, MethodMatc
.ifPresent(parameterElement -> annotationBuilder.member(DataMethod.META_MEMBER_ENTITY, parameterElement.getName()));

if (CollectionUtils.isNotEmpty(finalParameterBinding)) {
bindParameters(supportsImplicitQueries, finalParameterBinding, finalEncodeEntityParameters, annotationBuilder);
bindParameters(supportsImplicitQueries, finalParameterBinding, finalEncodeEntityParameters, annotationBuilder, DataMethod.META_MEMBER_PARAMETERS);
}

});
Expand All @@ -438,7 +444,8 @@ private void processMethodInfo(MethodMatchContext methodMatchContext, MethodMatc
private void bindParameters(boolean supportsImplicitQueries,
List<QueryParameterBinding> finalParameterBinding,
boolean finalEncodeEntityParameters,
AnnotationValueBuilder<DataMethod> annotationBuilder) {
AnnotationValueBuilder<DataMethod> annotationBuilder,
String parametersMemberName) {

List<AnnotationValue<?>> annotationValues = new ArrayList<>();
for (QueryParameterBinding p : finalParameterBinding) {
Expand Down Expand Up @@ -477,7 +484,7 @@ private void bindParameters(boolean supportsImplicitQueries,
annotationValues.add(builder.build());
}
AnnotationValue[] annotations = annotationValues.toArray(new AnnotationValue[0]);
annotationBuilder.member(DataMethod.META_MEMBER_PARAMETERS, annotations);
annotationBuilder.member(parametersMemberName, annotations);
}

private void bindAdditionalParameters(MatchContext matchContext,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import io.micronaut.core.annotation.Internal;
import io.micronaut.core.annotation.NonNull;
import io.micronaut.core.reflect.ReflectionUtils;
import io.micronaut.core.util.CollectionUtils;
import io.micronaut.core.util.StringUtils;
import io.micronaut.data.annotation.Query;
import io.micronaut.data.annotation.QueryHint;
Expand Down Expand Up @@ -158,7 +159,17 @@ public DefaultStoredQuery(
if (annotation == null) {
queryParameters = Collections.emptyList();
} else {
List<AnnotationValue<DataMethodQueryParameter>> params = annotation.getAnnotations(DataMethod.META_MEMBER_PARAMETERS, DataMethodQueryParameter.class);
List<AnnotationValue<DataMethodQueryParameter>> params = null;
if (isCount) {
// Count query might have different parameters from the main query, so we use them here if present
List<AnnotationValue<DataMethodQueryParameter>> countParams = annotation.getAnnotations(DataMethod.META_MEMBER_RAW_COUNT_PARAMETERS, DataMethodQueryParameter.class);
if (CollectionUtils.isNotEmpty(countParams)) {
params = countParams;
}
}
if (params == null) {
params = annotation.getAnnotations(DataMethod.META_MEMBER_PARAMETERS, DataMethodQueryParameter.class);
}
List<StoredQueryParameter> queryParameters = new ArrayList<>(params.size());
for (AnnotationValue<DataMethodQueryParameter> av : params) {
String[] propertyPath = av.stringValues(DataMethodQueryParameter.META_MEMBER_PROPERTY_PATH);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,4 +183,22 @@ abstract class AbstractPageSpec extends Specification {
cleanup:
bookRepository.deleteAll()
}

void "test pageable findBy and count using different params"() {
given:
def person1 = new Person(name: "John")
def person2 = new Person(name: "Jonas", enabled: false)
def person3 = new Person(name: "Joanna", enabled: false)
personRepository.saveAll(Arrays.asList(person1, person2, person3))
when: "People are searched by name and enabled"
def pageable = Pageable.from(0, 10)
Page<Person> page = personRepository.findByNameLikeAndEnabled("Jo%", true, pageable)

then: "The page returns correct results and count"
page.offset == 0
page.pageNumber == 0
page.totalSize == 3
page.content
page.content.size() == 1
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ public interface PersonRepository extends CrudRepository<Person, Long>, Pageable

Page<Person> findByNameLike(String name, Pageable pageable);

@Query(value = "select * from person person_ where person_.name like :name AND enabled = :enabled",
countQuery = "select count(*) from person person_ where person_.name like :name")
Page<Person> findByNameLikeAndEnabled(String name, boolean enabled, Pageable pageable);

List<Person> listTop10(Sort sort);

Slice<Person> find(Pageable pageable);
Expand Down