Skip to content

Commit 9348bc0

Browse files
committed
Support SimpleFunction as order by expression
To allow ordering results on for example the highest updated date, when joining with multiple tables; ORDER BY GREATEST(table1.created_at, table2.created_at) ASC
1 parent 76ea47a commit 9348bc0

File tree

2 files changed

+43
-0
lines changed

2 files changed

+43
-0
lines changed

spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/render/OrderByClauseVisitor.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,27 @@
1717

1818
import org.springframework.data.relational.core.sql.Column;
1919
import org.springframework.data.relational.core.sql.OrderByField;
20+
import org.springframework.data.relational.core.sql.SimpleFunction;
2021
import org.springframework.data.relational.core.sql.Visitable;
22+
import org.springframework.lang.Nullable;
2123

2224
/**
2325
* {@link PartRenderer} for {@link OrderByField}s.
2426
*
2527
* @author Mark Paluch
2628
* @author Jens Schauder
2729
* @author Chirag Tailor
30+
* @author Koen Punt
2831
* @since 1.1
2932
*/
3033
class OrderByClauseVisitor extends TypedSubtreeVisitor<OrderByField> implements PartRenderer {
3134

3235
private final RenderContext context;
3336

3437
private final StringBuilder builder = new StringBuilder();
38+
39+
@Nullable private PartRenderer delegate;
40+
3541
private boolean first = true;
3642

3743
OrderByClauseVisitor(RenderContext context) {
@@ -68,8 +74,22 @@ Delegation leaveMatched(OrderByField segment) {
6874
return Delegation.leave();
6975
}
7076

77+
@Override
78+
Delegation enterNested(Visitable segment) {
79+
if (segment instanceof SimpleFunction) {
80+
delegate = new SimpleFunctionVisitor(context);
81+
return Delegation.delegateTo((SimpleFunctionVisitor)delegate);
82+
}
83+
84+
return super.enterNested(segment);
85+
}
86+
7187
@Override
7288
Delegation leaveNested(Visitable segment) {
89+
if (delegate instanceof SimpleFunctionVisitor) {
90+
builder.append(delegate.getRenderedPart());
91+
delegate = null;
92+
}
7393

7494
if (segment instanceof Column) {
7595
builder.append(NameRenderer.fullyQualifiedReference(context, (Column) segment));

spring-data-relational/src/test/java/org/springframework/data/relational/core/sql/render/OrderByClauseVisitorUnitTests.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,18 @@
2222
import org.springframework.data.relational.core.sql.OrderByField;
2323
import org.springframework.data.relational.core.sql.SQL;
2424
import org.springframework.data.relational.core.sql.Select;
25+
import org.springframework.data.relational.core.sql.SimpleFunction;
2526
import org.springframework.data.relational.core.sql.Table;
2627

28+
import java.util.Arrays;
29+
import java.util.List;
30+
2731
/**
2832
* Unit tests for {@link OrderByClauseVisitor}.
2933
*
3034
* @author Mark Paluch
3135
* @author Jens Schauder
36+
* @author Koen Punt
3237
*/
3338
class OrderByClauseVisitorUnitTests {
3439

@@ -88,4 +93,22 @@ void shouldRenderOrderByFullyQualifiedNameWithTableAlias() {
8893
assertThat(visitor.getRenderedPart().toString()).isEqualTo("emp.name ASC");
8994
}
9095

96+
@Test // GH-1348
97+
void shouldRenderOrderBySimpleFunction() {
98+
99+
Table employee = SQL.table("employee").as("emp");
100+
Column column = employee.column("name");
101+
List<Expression> columns = Arrays.asList(employee.column("id"), column);
102+
103+
SimpleFunction simpleFunction = SimpleFunction.create("GREATEST", columns);
104+
105+
Select select = Select.builder().select(column).from(employee)
106+
.orderBy(OrderByField.from(simpleFunction).asc(), OrderByField.from(column).asc()).build();
107+
108+
OrderByClauseVisitor visitor = new OrderByClauseVisitor(new SimpleRenderContext(NamingStrategies.asIs()));
109+
select.visit(visitor);
110+
111+
assertThat(visitor.getRenderedPart().toString()).isEqualTo("GREATEST(emp.id, emp.name) ASC, emp.name ASC");
112+
}
113+
91114
}

0 commit comments

Comments
 (0)