Skip to content

Improve string query parsing flow. #3321

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

Closed
wants to merge 2 commits into from
Closed
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
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa-parent</artifactId>
<version>3.2.3-SNAPSHOT</version>
<version>3.2.x-3310-SNAPSHOT</version>
<packaging>pom</packaging>

<name>Spring Data JPA Parent</name>
Expand Down
4 changes: 2 additions & 2 deletions spring-data-envers/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-envers</artifactId>
<version>3.2.3-SNAPSHOT</version>
<version>3.2.x-3310-SNAPSHOT</version>

<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa-parent</artifactId>
<version>3.2.3-SNAPSHOT</version>
<version>3.2.x-3310-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion spring-data-jpa-distribution/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa-parent</artifactId>
<version>3.2.3-SNAPSHOT</version>
<version>3.2.x-3310-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
4 changes: 2 additions & 2 deletions spring-data-jpa/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>3.2.3-SNAPSHOT</version>
<version>3.2.x-3310-SNAPSHOT</version>

<name>Spring Data JPA</name>
<description>Spring Data module for JPA repositories.</description>
Expand All @@ -15,7 +15,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa-parent</artifactId>
<version>3.2.3-SNAPSHOT</version>
<version>3.2.x-3310-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;

import java.util.Objects;

import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.QueryRewriter;
Expand All @@ -28,6 +30,7 @@
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ConcurrentLruCache;

/**
* Base class for {@link String} based JPA queries.
Expand All @@ -40,6 +43,7 @@
* @author Mark Paluch
* @author Diego Krupitza
* @author Greg Turnquist
* @author Christoph Strobl
*/
abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery {

Expand All @@ -49,6 +53,7 @@ abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery {
private final SpelExpressionParser parser;
private final QueryParameterSetter.QueryMetadataCache metadataCache = new QueryParameterSetter.QueryMetadataCache();
private final QueryRewriter queryRewriter;
private ConcurrentLruCache<CachableQuery, String> queryCache = new ConcurrentLruCache<>(16, this::applySorting);

/**
* Creates a new {@link AbstractStringBasedJpaQuery} from the given {@link JpaQueryMethod}, {@link EntityManager} and
Expand Down Expand Up @@ -92,12 +97,12 @@ public AbstractStringBasedJpaQuery(JpaQueryMethod method, EntityManager em, Stri
@Override
public Query doCreateQuery(JpaParametersParameterAccessor accessor) {

String sortedQueryString = QueryEnhancerFactory.forQuery(query) //
.applySorting(accessor.getSort(), query.getAlias());
Sort sort = accessor.getSort();
String sortedQueryString = applySortingIfNecessary(query, sort);

ResultProcessor processor = getQueryMethod().getResultProcessor().withDynamicProjection(accessor);

Query query = createJpaQuery(sortedQueryString, accessor.getSort(), accessor.getPageable(),
processor.getReturnedType());
Query query = createJpaQuery(sortedQueryString, sort, accessor.getPageable(), processor.getReturnedType());

QueryParameterSetter.QueryMetadata metadata = metadataCache.getMetadata(sortedQueryString, query);

Expand All @@ -106,6 +111,10 @@ public Query doCreateQuery(JpaParametersParameterAccessor accessor) {
return parameterBinder.get().bindAndPrepare(query, metadata, accessor);
}

protected String applySorting(DeclaredQuery query, Sort sort) {
return queryCache.get(new CachableQuery(query, sort));
}

@Override
protected ParameterBinder createBinder() {

Expand Down Expand Up @@ -179,4 +188,77 @@ protected String potentiallyRewriteQuery(String originalQuery, Sort sort, @Nulla
? queryRewriter.rewrite(originalQuery, pageable) //
: queryRewriter.rewrite(originalQuery, sort);
}

String applySorting(CachableQuery cachableQuery) {

return QueryEnhancerFactory.forQuery(cachableQuery.getDeclaredQuery()).applySorting(cachableQuery.getSort(),
cachableQuery.getAlias());
}

private String applySortingIfNecessary(DeclaredQuery query, Sort sort) {

if (sort.isUnsorted()) {
return query.getQueryString();
}
return applySorting(query, sort);
}

/**
* Value object with optimized {@link Object#equals(Object)} to cache a query based on its query string and
* {@link Sort sorting}.
*
* @since 3.2.3
* @author Christoph Strobl
*/
static class CachableQuery {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The caching key is already quite complex. I'd suggest to keep only the isUnsorted code path and refine the way we render queries with a sort. That is, render everything before and after ORDER BY in a first pass (e.g. held in a QueryEnhancer instance). Then, render Sort with rather simple string concatenation.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The above is deliberately targeting the 3.2.x line without applying major changes.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created #3326 to follow up on splitting the transformation (targeting main development line)


private DeclaredQuery declaredQuery;
private final String queryString;
private final Sort sort;

CachableQuery(DeclaredQuery query, Sort sort) {

this.declaredQuery = query;
this.queryString = query.getQueryString();
this.sort = sort;
}

DeclaredQuery getDeclaredQuery() {
return declaredQuery;
}

Sort getSort() {
return sort;
}

String getAlias() {
return declaredQuery.getAlias();
}

@Override
public boolean equals(Object o) {

if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}

CachableQuery that = (CachableQuery) o;

if (!Objects.equals(queryString, that.queryString)) {
return false;
}
return Objects.equals(sort, that.sort);
}

@Override
public int hashCode() {

int result = queryString != null ? queryString.hashCode() : 0;
result = 31 * result + (sort != null ? sort.hashCode() : 0);
return result;
}
}
}
Loading