Skip to content

Commit e2d75aa

Browse files
authored
Merge pull request #830 from jeffgbutler/case-in-order-by
Support CASE Expressions in ORDER BY Phrases
2 parents 028da50 + dca5d3d commit e2d75aa

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+750
-115
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Significant changes:
88

99
- The library now requires Java 17
1010
- Deprecated code from prior releases is removed
11+
- Allow CASE expressions in ORDER BY Clauses
1112

1213
## Release 1.5.2 - June 3, 2024
1314

pom.xml

-8
Original file line numberDiff line numberDiff line change
@@ -164,14 +164,6 @@
164164
<version>1.5.6</version>
165165
<scope>test</scope>
166166
</dependency>
167-
<!-- Hamcrest is only here to make Infinitest happy. Not really used in the project. -->
168-
<dependency>
169-
<groupId>org.hamcrest</groupId>
170-
<artifactId>hamcrest</artifactId>
171-
<version>3.0</version>
172-
<scope>test</scope>
173-
</dependency>
174-
175167
<dependency>
176168
<groupId>org.testcontainers</groupId>
177169
<artifactId>postgresql</artifactId>

src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ private <R> Collection<R> applyMapper(Function<? super T, ? extends R> mapper) {
5151

5252
private Collection<T> applyFilter(Predicate<? super T> predicate) {
5353
Objects.requireNonNull(predicate);
54-
return values.stream().filter(predicate).collect(Collectors.toList());
54+
return values.stream().filter(predicate).toList();
5555
}
5656

5757
protected <S extends AbstractListValueCondition<T>> S filterSupport(Predicate<? super T> predicate,

src/main/java/org/mybatis/dynamic/sql/SortSpecification.java

+27-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515
*/
1616
package org.mybatis.dynamic.sql;
1717

18+
import org.mybatis.dynamic.sql.exception.DynamicSqlException;
19+
import org.mybatis.dynamic.sql.render.RenderingContext;
20+
import org.mybatis.dynamic.sql.util.FragmentAndParameters;
21+
import org.mybatis.dynamic.sql.util.Messages;
22+
1823
/**
1924
* Defines attributes of columns that are necessary for rendering an order by expression.
2025
*
@@ -34,13 +39,33 @@ public interface SortSpecification {
3439
* NOT include the "DESC" word for descending sort specifications.
3540
*
3641
* @return the order by phrase
42+
* @deprecated Please replace this method by overriding the more general "renderForOrderBy" method. Target for
43+
* removal in release 2.1
3744
*/
38-
String orderByName();
45+
@Deprecated(since = "2.0", forRemoval = true)
46+
default String orderByName() {
47+
throw new DynamicSqlException(Messages.getString("ERROR.44")); //$NON-NLS-1$
48+
}
3949

4050
/**
4151
* Return true if the sort order is descending.
4252
*
4353
* @return true if the SortSpecification should render as descending
54+
* @deprecated Please replace this method by overriding the more general "renderForOrderBy" method. Target for
55+
* removal in release 2.1
4456
*/
45-
boolean isDescending();
57+
@Deprecated(since = "2.0", forRemoval = true)
58+
default boolean isDescending() {
59+
throw new DynamicSqlException(Messages.getString("ERROR.44")); //$NON-NLS-1$
60+
}
61+
62+
// the default implementation ensures compatibility with prior releases. When the
63+
// deprecated methods are removed, this function can become purely abstract.
64+
default FragmentAndParameters renderForOrderBy(RenderingContext renderingContext) {
65+
String phrase = orderByName();
66+
if (isDescending()) {
67+
phrase = phrase + " DESC"; //$NON-NLS-1$
68+
}
69+
return FragmentAndParameters.fromFragment(phrase);
70+
}
4671
}

src/main/java/org/mybatis/dynamic/sql/SqlColumn.java

+9-14
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public class SqlColumn<T> implements BindableColumn<T>, SortSpecification {
3030
protected final String name;
3131
protected final SqlTable table;
3232
protected final JDBCType jdbcType;
33-
protected final boolean isDescending;
33+
protected final String descendingPhrase;
3434
protected final String alias;
3535
protected final String typeHandler;
3636
protected final RenderingStrategy renderingStrategy;
@@ -42,7 +42,7 @@ private SqlColumn(Builder<T> builder) {
4242
name = Objects.requireNonNull(builder.name);
4343
table = Objects.requireNonNull(builder.table);
4444
jdbcType = builder.jdbcType;
45-
isDescending = builder.isDescending;
45+
descendingPhrase = builder.descendingPhrase;
4646
alias = builder.alias;
4747
typeHandler = builder.typeHandler;
4848
renderingStrategy = builder.renderingStrategy;
@@ -87,7 +87,7 @@ public Object convertParameterType(T value) {
8787
@Override
8888
public SortSpecification descending() {
8989
Builder<T> b = copy();
90-
return b.withDescending(true).build();
90+
return b.withDescendingPhrase(" DESC").build(); //$NON-NLS-1$
9191
}
9292

9393
@Override
@@ -126,13 +126,8 @@ public SqlColumn<T> asCamelCase() {
126126
}
127127

128128
@Override
129-
public boolean isDescending() {
130-
return isDescending;
131-
}
132-
133-
@Override
134-
public String orderByName() {
135-
return alias().orElse(name);
129+
public FragmentAndParameters renderForOrderBy(RenderingContext renderingContext) {
130+
return FragmentAndParameters.fromFragment(alias().orElse(name) + descendingPhrase);
136131
}
137132

138133
@Override
@@ -188,7 +183,7 @@ private <S> Builder<S> copy() {
188183
.withName(this.name)
189184
.withTable(this.table)
190185
.withJdbcType(this.jdbcType)
191-
.withDescending(this.isDescending)
186+
.withDescendingPhrase(this.descendingPhrase)
192187
.withAlias(this.alias)
193188
.withTypeHandler(this.typeHandler)
194189
.withRenderingStrategy(this.renderingStrategy)
@@ -214,7 +209,7 @@ public static class Builder<T> {
214209
protected String name;
215210
protected SqlTable table;
216211
protected JDBCType jdbcType;
217-
protected boolean isDescending = false;
212+
protected String descendingPhrase = ""; //$NON-NLS-1$
218213
protected String alias;
219214
protected String typeHandler;
220215
protected RenderingStrategy renderingStrategy;
@@ -237,8 +232,8 @@ public Builder<T> withJdbcType(JDBCType jdbcType) {
237232
return this;
238233
}
239234

240-
public Builder<T> withDescending(boolean isDescending) {
241-
this.isDescending = isDescending;
235+
public Builder<T> withDescendingPhrase(String descendingPhrase) {
236+
this.descendingPhrase = descendingPhrase;
242237
return this;
243238
}
244239

src/main/java/org/mybatis/dynamic/sql/common/OrderByRenderer.java

+12-12
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,24 @@
1515
*/
1616
package org.mybatis.dynamic.sql.common;
1717

18+
import java.util.Objects;
1819
import java.util.stream.Collectors;
1920

20-
import org.mybatis.dynamic.sql.SortSpecification;
21+
import org.mybatis.dynamic.sql.render.RenderingContext;
2122
import org.mybatis.dynamic.sql.util.FragmentAndParameters;
23+
import org.mybatis.dynamic.sql.util.FragmentCollector;
2224

2325
public class OrderByRenderer {
24-
public FragmentAndParameters render(OrderByModel orderByModel) {
25-
String phrase = orderByModel.columns()
26-
.map(this::calculateOrderByPhrase)
27-
.collect(Collectors.joining(", ", "order by ", "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
28-
return FragmentAndParameters.fromFragment(phrase);
26+
private final RenderingContext renderingContext;
27+
28+
public OrderByRenderer(RenderingContext renderingContext) {
29+
this.renderingContext = Objects.requireNonNull(renderingContext);
2930
}
3031

31-
private String calculateOrderByPhrase(SortSpecification column) {
32-
String phrase = column.orderByName();
33-
if (column.isDescending()) {
34-
phrase = phrase + " DESC"; //$NON-NLS-1$
35-
}
36-
return phrase;
32+
public FragmentAndParameters render(OrderByModel orderByModel) {
33+
return orderByModel.columns().map(c -> c.renderForOrderBy(renderingContext))
34+
.collect(FragmentCollector.collect())
35+
.toFragmentAndParameters(
36+
Collectors.joining(", ", "order by ", "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
3737
}
3838
}

src/main/java/org/mybatis/dynamic/sql/delete/render/DeleteRenderer.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ private Optional<FragmentAndParameters> calculateOrderByClause() {
9696
}
9797

9898
private FragmentAndParameters renderOrderByClause(OrderByModel orderByModel) {
99-
return new OrderByRenderer().render(orderByModel);
99+
return new OrderByRenderer(renderingContext).render(orderByModel);
100100
}
101101

102102
public static Builder withDeleteModel(DeleteModel deleteModel) {

src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertDSL.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,11 @@ public BatchInsertModel<T> build() {
5858
}
5959

6060
@SafeVarargs
61-
public static <T> IntoGatherer<T> insert(T... records) {
62-
return BatchInsertDSL.insert(Arrays.asList(records));
61+
public static <T> BatchInsertDSL.IntoGatherer<T> insert(T... records) {
62+
return insert(Arrays.asList(records));
6363
}
6464

65-
public static <T> IntoGatherer<T> insert(Collection<T> records) {
65+
public static <T> BatchInsertDSL.IntoGatherer<T> insert(Collection<T> records) {
6666
return new IntoGatherer<>(records);
6767
}
6868

src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertDSL.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,11 @@ public MultiRowInsertModel<T> build() {
5757
}
5858

5959
@SafeVarargs
60-
public static <T> IntoGatherer<T> insert(T... records) {
61-
return MultiRowInsertDSL.insert(Arrays.asList(records));
60+
public static <T> MultiRowInsertDSL.IntoGatherer<T> insert(T... records) {
61+
return insert(Arrays.asList(records));
6262
}
6363

64-
public static <T> IntoGatherer<T> insert(Collection<T> records) {
64+
public static <T> MultiRowInsertDSL.IntoGatherer<T> insert(Collection<T> records) {
6565
return new IntoGatherer<>(records);
6666
}
6767

src/main/java/org/mybatis/dynamic/sql/insert/render/BatchInsert.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import java.util.Collections;
2020
import java.util.List;
2121
import java.util.Objects;
22-
import java.util.stream.Collectors;
2322

2423
public class BatchInsert<T> {
2524
private final String insertStatement;
@@ -38,7 +37,7 @@ private BatchInsert(Builder<T> builder) {
3837
public List<InsertStatementProvider<T>> insertStatements() {
3938
return records.stream()
4039
.map(this::toInsertStatement)
41-
.collect(Collectors.toList());
40+
.toList();
4241
}
4342

4443
private InsertStatementProvider<T> toInsertStatement(T row) {
@@ -57,7 +56,7 @@ public String getInsertStatementSQL() {
5756
}
5857

5958
public List<T> getRecords() {
60-
return Collections.unmodifiableList(records);
59+
return records;
6160
}
6261

6362
public static <T> Builder<T> withRecords(List<T> records) {

src/main/java/org/mybatis/dynamic/sql/select/AbstractQueryExpressionDSL.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import java.util.Map;
2424
import java.util.Objects;
2525
import java.util.Optional;
26-
import java.util.stream.Collectors;
2726

2827
import org.mybatis.dynamic.sql.SqlTable;
2928
import org.mybatis.dynamic.sql.TableExpression;
@@ -196,7 +195,7 @@ protected Optional<JoinModel> buildJoinModel() {
196195

197196
return Optional.of(JoinModel.of(joinSpecificationBuilders.stream()
198197
.map(JoinSpecification.Builder::build)
199-
.collect(Collectors.toList())));
198+
.toList()));
200199
}
201200

202201
protected void addTableAlias(SqlTable table, String tableAlias) {

src/main/java/org/mybatis/dynamic/sql/select/ColumnSortSpecification.java

+9-12
Original file line numberDiff line numberDiff line change
@@ -19,34 +19,31 @@
1919

2020
import org.mybatis.dynamic.sql.SortSpecification;
2121
import org.mybatis.dynamic.sql.SqlColumn;
22+
import org.mybatis.dynamic.sql.render.RenderingContext;
23+
import org.mybatis.dynamic.sql.util.FragmentAndParameters;
2224

2325
public class ColumnSortSpecification implements SortSpecification {
2426
private final String tableAlias;
2527
private final SqlColumn<?> column;
26-
private final boolean isDescending;
28+
private final String descendingPhrase;
2729

2830
public ColumnSortSpecification(String tableAlias, SqlColumn<?> column) {
29-
this(tableAlias, column, false);
31+
this(tableAlias, column, ""); //$NON-NLS-1$
3032
}
3133

32-
private ColumnSortSpecification(String tableAlias, SqlColumn<?> column, boolean isDescending) {
34+
private ColumnSortSpecification(String tableAlias, SqlColumn<?> column, String descendingPhrase) {
3335
this.tableAlias = Objects.requireNonNull(tableAlias);
3436
this.column = Objects.requireNonNull(column);
35-
this.isDescending = isDescending;
37+
this.descendingPhrase = descendingPhrase;
3638
}
3739

3840
@Override
3941
public SortSpecification descending() {
40-
return new ColumnSortSpecification(tableAlias, column, true);
42+
return new ColumnSortSpecification(tableAlias, column, " DESC"); //$NON-NLS-1$
4143
}
4244

4345
@Override
44-
public String orderByName() {
45-
return tableAlias + "." + column.name(); //$NON-NLS-1$
46-
}
47-
48-
@Override
49-
public boolean isDescending() {
50-
return isDescending;
46+
public FragmentAndParameters renderForOrderBy(RenderingContext renderingContext) {
47+
return FragmentAndParameters.fromFragment(tableAlias + "." + column.name() + descendingPhrase); //$NON-NLS-1$
5148
}
5249
}

src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import java.util.Optional;
2424
import java.util.function.Consumer;
2525
import java.util.function.Function;
26-
import java.util.stream.Collectors;
2726

2827
import org.jetbrains.annotations.NotNull;
2928
import org.mybatis.dynamic.sql.BasicColumn;
@@ -143,7 +142,7 @@ public R build() {
143142
private List<QueryExpressionModel> buildModels() {
144143
return queryExpressions.stream()
145144
.map(QueryExpressionDSL::buildModel)
146-
.collect(Collectors.toList());
145+
.toList();
147146
}
148147

149148
private Optional<PagingModel> buildPagingModel() {

src/main/java/org/mybatis/dynamic/sql/select/SimpleSortSpecification.java

+9-12
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
import java.util.Objects;
1919

2020
import org.mybatis.dynamic.sql.SortSpecification;
21+
import org.mybatis.dynamic.sql.render.RenderingContext;
22+
import org.mybatis.dynamic.sql.util.FragmentAndParameters;
2123

2224
/**
2325
* This class is used for an order by phrase where there is no suitable column name
@@ -28,30 +30,25 @@
2830
public class SimpleSortSpecification implements SortSpecification {
2931

3032
private final String name;
31-
private final boolean isDescending;
33+
private final String descendingPhrase;
3234

3335
private SimpleSortSpecification(String name) {
34-
this(name, false);
36+
this(name, ""); //$NON-NLS-1$
3537
}
3638

37-
private SimpleSortSpecification(String name, boolean isDescending) {
39+
private SimpleSortSpecification(String name, String descendingPhrase) {
3840
this.name = Objects.requireNonNull(name);
39-
this.isDescending = isDescending;
41+
this.descendingPhrase = descendingPhrase;
4042
}
4143

4244
@Override
4345
public SortSpecification descending() {
44-
return new SimpleSortSpecification(name, true);
46+
return new SimpleSortSpecification(name, " DESC"); //$NON-NLS-1$
4547
}
4648

4749
@Override
48-
public String orderByName() {
49-
return name;
50-
}
51-
52-
@Override
53-
public boolean isDescending() {
54-
return isDescending;
50+
public FragmentAndParameters renderForOrderBy(RenderingContext renderingContext) {
51+
return FragmentAndParameters.fromFragment(name + descendingPhrase);
5552
}
5653

5754
public static SimpleSortSpecification of(String name) {

src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SearchedCaseDSL.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public SearchedCaseEnder else_(BasicColumn column) {
7171
return new SearchedCaseEnder();
7272
}
7373

74-
public BasicColumn end() {
74+
public SearchedCaseModel end() {
7575
return new SearchedCaseModel.Builder()
7676
.withElseValue(elseValue)
7777
.withWhenConditions(whenConditions)
@@ -100,7 +100,7 @@ protected WhenDSL getThis() {
100100
}
101101

102102
public class SearchedCaseEnder {
103-
public BasicColumn end() {
103+
public SearchedCaseModel end() {
104104
return SearchedCaseDSL.this.end();
105105
}
106106
}

0 commit comments

Comments
 (0)