Skip to content
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
7 changes: 4 additions & 3 deletions docs/src/main/asciidoc/spanner.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1170,13 +1170,14 @@ The SQL query for the method can be mapped to repository methods in one of two w
The names of the tags of the SQL correspond to the `@Param` annotated names of the method parameters.

Interleaved properties are loaded eagerly, unless they are annotated with `@Interleaved(lazy = true)`.
For a custom SQL query without a `Sort` or `Pageable` parameter, eager interleaved properties are loaded after the parent query so that the query's `ORDER BY`, `LIMIT`, and `OFFSET` clauses retain their Cloud Spanner semantics.
This may execute additional queries to load the interleaved properties.

Custom SQL query methods can accept a single `Sort` or `Pageable` parameter that is applied on top of the specified custom query.
It is the recommended way to control the sort order of the results, which is not guaranteed by the `ORDER BY` clause in the SQL query.
This is due to the fact that the user-provided query is used as a sub-query, and Cloud Spanner doesn't preserve order in subquery results.
When supplied, it is the recommended way to control the final sort order because it is applied to the outer query.

You might want to use `ORDER BY` with `LIMIT` to obtain the top records, according to a specified order.
However, to ensure the correct sort order of the final result set, sort options have to be passed in with a `Pageable`.
If a `Pageable` parameter is also used, include the desired sort options in the `Pageable`.

[source, java]
----
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ public static <A, T> List<A> executeQuery(
* eager-Interleaved lists with a single query. Please note, it doesn't make sense to pass it
* as {@code true} when the {@code sql} already contains a complete lists of all
* eager-Interleaved properties generated by the method {@link #getColumnsStringForSelect}.
* This option is ignored when no sorting or paging option requires wrapping the query.
* @param <T> the domain type.
* @return the final SQL string with paging and sorting applied.
* @see #getColumnsStringForSelect
Expand All @@ -182,13 +183,12 @@ public static <T> String applySortingPagingQueryOptions(
String sql,
SpannerMappingContext mappingContext,
boolean fetchInterleaved) {
// Cloud Spanner does not preserve the order of derived tables so we must not wrap the
// derived table
// in SELECT * FROM () if there is no overriding pageable param.
// Cloud Spanner does not preserve the order of derived tables, so do not wrap a custom query
// solely to fetch interleaved properties. SpannerTemplate resolves properties that are absent
// from the result after mapping, which preserves ORDER BY, LIMIT, and OFFSET in the custom SQL.
if ((options.getSort() == null || options.getSort().isUnsorted())
&& options.getLimit() == null
&& options.getOffset() == null
&& !fetchInterleaved) {
&& options.getOffset() == null) {
return sql;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,15 +156,9 @@ private <T> SqlSpannerQuery<T> createQuery(
void noPageableParamQueryTest(boolean useValueExpressionDelegate) throws NoSuchMethodException {
String sql =
"SELECT DISTINCT * FROM "
+ ":com.google.cloud.spring.data.spanner.repository.query.SqlSpannerQueryTests$Trade:";
// @formatter:off
String entityResolvedSql =
"SELECT *, ARRAY (SELECT AS STRUCT disabled, id, childId, value, ARRAY (SELECT AS STRUCT"
+ " canceled, documentId, id, childId, content FROM documents WHERE (documents.id ="
+ " children.id AND documents.childId = children.childId) AND (canceled = false)) AS"
+ " documents FROM children WHERE (children.id = trades.id) AND (disabled = false)) AS"
+ " children FROM (SELECT DISTINCT * FROM trades) trades";
// @formatter:on
+ ":com.google.cloud.spring.data.spanner.repository.query.SqlSpannerQueryTests$Trade:"
+ " ORDER BY id DESC LIMIT 3";
String entityResolvedSql = "SELECT DISTINCT * FROM trades ORDER BY id DESC LIMIT 3";

final Class toReturn = Trade.class;
when(queryMethod.isCollectionQuery()).thenReturn(false);
Expand Down