Skip to content

Support CASE Expressions in ORDER BY Phrases #830

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

Merged
merged 10 commits into from
Aug 6, 2024
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Significant changes:

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

## Release 1.5.2 - June 3, 2024

Expand Down
8 changes: 0 additions & 8 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -164,14 +164,6 @@
<version>1.5.6</version>
<scope>test</scope>
</dependency>
<!-- Hamcrest is only here to make Infinitest happy. Not really used in the project. -->
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest</artifactId>
<version>3.0</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ private <R> Collection<R> applyMapper(Function<? super T, ? extends R> mapper) {

private Collection<T> applyFilter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
return values.stream().filter(predicate).collect(Collectors.toList());
return values.stream().filter(predicate).toList();
}

protected <S extends AbstractListValueCondition<T>> S filterSupport(Predicate<? super T> predicate,
Expand Down
29 changes: 27 additions & 2 deletions src/main/java/org/mybatis/dynamic/sql/SortSpecification.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
*/
package org.mybatis.dynamic.sql;

import org.mybatis.dynamic.sql.exception.DynamicSqlException;
import org.mybatis.dynamic.sql.render.RenderingContext;
import org.mybatis.dynamic.sql.util.FragmentAndParameters;
import org.mybatis.dynamic.sql.util.Messages;

/**
* Defines attributes of columns that are necessary for rendering an order by expression.
*
Expand All @@ -34,13 +39,33 @@ public interface SortSpecification {
* NOT include the "DESC" word for descending sort specifications.
*
* @return the order by phrase
* @deprecated Please replace this method by overriding the more general "renderForOrderBy" method. Target for
* removal in release 2.1
*/
String orderByName();
@Deprecated(since = "2.0", forRemoval = true)
default String orderByName() {
throw new DynamicSqlException(Messages.getString("ERROR.44")); //$NON-NLS-1$
}

/**
* Return true if the sort order is descending.
*
* @return true if the SortSpecification should render as descending
* @deprecated Please replace this method by overriding the more general "renderForOrderBy" method. Target for
* removal in release 2.1
*/
boolean isDescending();
@Deprecated(since = "2.0", forRemoval = true)
default boolean isDescending() {
throw new DynamicSqlException(Messages.getString("ERROR.44")); //$NON-NLS-1$
}

// the default implementation ensures compatibility with prior releases. When the
// deprecated methods are removed, this function can become purely abstract.
default FragmentAndParameters renderForOrderBy(RenderingContext renderingContext) {
String phrase = orderByName();
if (isDescending()) {
phrase = phrase + " DESC"; //$NON-NLS-1$
}
return FragmentAndParameters.fromFragment(phrase);
}
}
23 changes: 9 additions & 14 deletions src/main/java/org/mybatis/dynamic/sql/SqlColumn.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public class SqlColumn<T> implements BindableColumn<T>, SortSpecification {
protected final String name;
protected final SqlTable table;
protected final JDBCType jdbcType;
protected final boolean isDescending;
protected final String descendingPhrase;
protected final String alias;
protected final String typeHandler;
protected final RenderingStrategy renderingStrategy;
Expand All @@ -42,7 +42,7 @@ private SqlColumn(Builder<T> builder) {
name = Objects.requireNonNull(builder.name);
table = Objects.requireNonNull(builder.table);
jdbcType = builder.jdbcType;
isDescending = builder.isDescending;
descendingPhrase = builder.descendingPhrase;
alias = builder.alias;
typeHandler = builder.typeHandler;
renderingStrategy = builder.renderingStrategy;
Expand Down Expand Up @@ -87,7 +87,7 @@ public Object convertParameterType(T value) {
@Override
public SortSpecification descending() {
Builder<T> b = copy();
return b.withDescending(true).build();
return b.withDescendingPhrase(" DESC").build(); //$NON-NLS-1$
}

@Override
Expand Down Expand Up @@ -126,13 +126,8 @@ public SqlColumn<T> asCamelCase() {
}

@Override
public boolean isDescending() {
return isDescending;
}

@Override
public String orderByName() {
return alias().orElse(name);
public FragmentAndParameters renderForOrderBy(RenderingContext renderingContext) {
return FragmentAndParameters.fromFragment(alias().orElse(name) + descendingPhrase);
}

@Override
Expand Down Expand Up @@ -188,7 +183,7 @@ private <S> Builder<S> copy() {
.withName(this.name)
.withTable(this.table)
.withJdbcType(this.jdbcType)
.withDescending(this.isDescending)
.withDescendingPhrase(this.descendingPhrase)
.withAlias(this.alias)
.withTypeHandler(this.typeHandler)
.withRenderingStrategy(this.renderingStrategy)
Expand All @@ -214,7 +209,7 @@ public static class Builder<T> {
protected String name;
protected SqlTable table;
protected JDBCType jdbcType;
protected boolean isDescending = false;
protected String descendingPhrase = ""; //$NON-NLS-1$
protected String alias;
protected String typeHandler;
protected RenderingStrategy renderingStrategy;
Expand All @@ -237,8 +232,8 @@ public Builder<T> withJdbcType(JDBCType jdbcType) {
return this;
}

public Builder<T> withDescending(boolean isDescending) {
this.isDescending = isDescending;
public Builder<T> withDescendingPhrase(String descendingPhrase) {
this.descendingPhrase = descendingPhrase;
return this;
}

Expand Down
24 changes: 12 additions & 12 deletions src/main/java/org/mybatis/dynamic/sql/common/OrderByRenderer.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,24 @@
*/
package org.mybatis.dynamic.sql.common;

import java.util.Objects;
import java.util.stream.Collectors;

import org.mybatis.dynamic.sql.SortSpecification;
import org.mybatis.dynamic.sql.render.RenderingContext;
import org.mybatis.dynamic.sql.util.FragmentAndParameters;
import org.mybatis.dynamic.sql.util.FragmentCollector;

public class OrderByRenderer {
public FragmentAndParameters render(OrderByModel orderByModel) {
String phrase = orderByModel.columns()
.map(this::calculateOrderByPhrase)
.collect(Collectors.joining(", ", "order by ", "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
return FragmentAndParameters.fromFragment(phrase);
private final RenderingContext renderingContext;

public OrderByRenderer(RenderingContext renderingContext) {
this.renderingContext = Objects.requireNonNull(renderingContext);
}

private String calculateOrderByPhrase(SortSpecification column) {
String phrase = column.orderByName();
if (column.isDescending()) {
phrase = phrase + " DESC"; //$NON-NLS-1$
}
return phrase;
public FragmentAndParameters render(OrderByModel orderByModel) {
return orderByModel.columns().map(c -> c.renderForOrderBy(renderingContext))
.collect(FragmentCollector.collect())
.toFragmentAndParameters(
Collectors.joining(", ", "order by ", "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ private Optional<FragmentAndParameters> calculateOrderByClause() {
}

private FragmentAndParameters renderOrderByClause(OrderByModel orderByModel) {
return new OrderByRenderer().render(orderByModel);
return new OrderByRenderer(renderingContext).render(orderByModel);
}

public static Builder withDeleteModel(DeleteModel deleteModel) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,11 @@ public BatchInsertModel<T> build() {
}

@SafeVarargs
public static <T> IntoGatherer<T> insert(T... records) {
return BatchInsertDSL.insert(Arrays.asList(records));
public static <T> BatchInsertDSL.IntoGatherer<T> insert(T... records) {
return insert(Arrays.asList(records));
}

public static <T> IntoGatherer<T> insert(Collection<T> records) {
public static <T> BatchInsertDSL.IntoGatherer<T> insert(Collection<T> records) {
return new IntoGatherer<>(records);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ public MultiRowInsertModel<T> build() {
}

@SafeVarargs
public static <T> IntoGatherer<T> insert(T... records) {
return MultiRowInsertDSL.insert(Arrays.asList(records));
public static <T> MultiRowInsertDSL.IntoGatherer<T> insert(T... records) {
return insert(Arrays.asList(records));
}

public static <T> IntoGatherer<T> insert(Collection<T> records) {
public static <T> MultiRowInsertDSL.IntoGatherer<T> insert(Collection<T> records) {
return new IntoGatherer<>(records);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

public class BatchInsert<T> {
private final String insertStatement;
Expand All @@ -38,7 +37,7 @@ private BatchInsert(Builder<T> builder) {
public List<InsertStatementProvider<T>> insertStatements() {
return records.stream()
.map(this::toInsertStatement)
.collect(Collectors.toList());
.toList();
}

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

public List<T> getRecords() {
return Collections.unmodifiableList(records);
return records;
}

public static <T> Builder<T> withRecords(List<T> records) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

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

return Optional.of(JoinModel.of(joinSpecificationBuilders.stream()
.map(JoinSpecification.Builder::build)
.collect(Collectors.toList())));
.toList()));
}

protected void addTableAlias(SqlTable table, String tableAlias) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,34 +19,31 @@

import org.mybatis.dynamic.sql.SortSpecification;
import org.mybatis.dynamic.sql.SqlColumn;
import org.mybatis.dynamic.sql.render.RenderingContext;
import org.mybatis.dynamic.sql.util.FragmentAndParameters;

public class ColumnSortSpecification implements SortSpecification {
private final String tableAlias;
private final SqlColumn<?> column;
private final boolean isDescending;
private final String descendingPhrase;

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

private ColumnSortSpecification(String tableAlias, SqlColumn<?> column, boolean isDescending) {
private ColumnSortSpecification(String tableAlias, SqlColumn<?> column, String descendingPhrase) {
this.tableAlias = Objects.requireNonNull(tableAlias);
this.column = Objects.requireNonNull(column);
this.isDescending = isDescending;
this.descendingPhrase = descendingPhrase;
}

@Override
public SortSpecification descending() {
return new ColumnSortSpecification(tableAlias, column, true);
return new ColumnSortSpecification(tableAlias, column, " DESC"); //$NON-NLS-1$
}

@Override
public String orderByName() {
return tableAlias + "." + column.name(); //$NON-NLS-1$
}

@Override
public boolean isDescending() {
return isDescending;
public FragmentAndParameters renderForOrderBy(RenderingContext renderingContext) {
return FragmentAndParameters.fromFragment(tableAlias + "." + column.name() + descendingPhrase); //$NON-NLS-1$
}
}
3 changes: 1 addition & 2 deletions src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.jetbrains.annotations.NotNull;
import org.mybatis.dynamic.sql.BasicColumn;
Expand Down Expand Up @@ -143,7 +142,7 @@ public R build() {
private List<QueryExpressionModel> buildModels() {
return queryExpressions.stream()
.map(QueryExpressionDSL::buildModel)
.collect(Collectors.toList());
.toList();
}

private Optional<PagingModel> buildPagingModel() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
import java.util.Objects;

import org.mybatis.dynamic.sql.SortSpecification;
import org.mybatis.dynamic.sql.render.RenderingContext;
import org.mybatis.dynamic.sql.util.FragmentAndParameters;

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

private final String name;
private final boolean isDescending;
private final String descendingPhrase;

private SimpleSortSpecification(String name) {
this(name, false);
this(name, ""); //$NON-NLS-1$
}

private SimpleSortSpecification(String name, boolean isDescending) {
private SimpleSortSpecification(String name, String descendingPhrase) {
this.name = Objects.requireNonNull(name);
this.isDescending = isDescending;
this.descendingPhrase = descendingPhrase;
}

@Override
public SortSpecification descending() {
return new SimpleSortSpecification(name, true);
return new SimpleSortSpecification(name, " DESC"); //$NON-NLS-1$
}

@Override
public String orderByName() {
return name;
}

@Override
public boolean isDescending() {
return isDescending;
public FragmentAndParameters renderForOrderBy(RenderingContext renderingContext) {
return FragmentAndParameters.fromFragment(name + descendingPhrase);
}

public static SimpleSortSpecification of(String name) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public SearchedCaseEnder else_(BasicColumn column) {
return new SearchedCaseEnder();
}

public BasicColumn end() {
public SearchedCaseModel end() {
return new SearchedCaseModel.Builder()
.withElseValue(elseValue)
.withWhenConditions(whenConditions)
Expand Down Expand Up @@ -100,7 +100,7 @@ protected WhenDSL getThis() {
}

public class SearchedCaseEnder {
public BasicColumn end() {
public SearchedCaseModel end() {
return SearchedCaseDSL.this.end();
}
}
Expand Down
Loading