Null precedence is now supported if the underlying database supports it.
Original pull request #1156 Closes #821
This commit is contained in:
committed by
Jens Schauder
parent
73a6b3390e
commit
60a59b61c1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2021 the original author or authors.
|
||||
* Copyright 2017-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -51,6 +51,7 @@ import java.util.stream.Collectors;
|
||||
* @author Milan Milanov
|
||||
* @author Myeonghyeon Lee
|
||||
* @author Mikhail Polivakha
|
||||
* @author Chirag Tailor
|
||||
*/
|
||||
class SqlGenerator {
|
||||
|
||||
@@ -714,7 +715,7 @@ class SqlGenerator {
|
||||
|
||||
SqlIdentifier columnName = this.entity.getRequiredPersistentProperty(order.getProperty()).getColumnName();
|
||||
Column column = Column.create(columnName, this.getTable());
|
||||
return OrderByField.from(column, order.getDirection());
|
||||
return OrderByField.from(column, order.getDirection()).withNullHandling(order.getNullHandling());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -257,6 +257,21 @@ class JdbcAggregateTemplateIntegrationTests {
|
||||
.containsExactly("Star");
|
||||
}
|
||||
|
||||
@Test // GH-821
|
||||
@EnabledOnFeature({SUPPORTS_QUOTED_IDS, SUPPORTS_NULL_HANDLING})
|
||||
void saveAndLoadManyEntitiesWithReferencedEntitySortedWithNullHandling() {
|
||||
|
||||
template.save(createLegoSet(null));
|
||||
template.save(createLegoSet("Star"));
|
||||
template.save(createLegoSet("Frozen"));
|
||||
|
||||
Iterable<LegoSet> reloadedLegoSets = template.findAll(LegoSet.class, Sort.by(new Sort.Order(Sort.Direction.ASC, "name", Sort.NullHandling.NULLS_LAST)));
|
||||
|
||||
assertThat(reloadedLegoSets) //
|
||||
.extracting("name") //
|
||||
.containsExactly("Frozen", "Star", null);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-112
|
||||
@EnabledOnFeature(SUPPORTS_QUOTED_IDS)
|
||||
void saveAndLoadManyEntitiesByIdWithReferencedEntity() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2021 the original author or authors.
|
||||
* Copyright 2017-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,7 +25,6 @@ import java.util.Set;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.ReadOnlyProperty;
|
||||
import org.springframework.data.annotation.Version;
|
||||
@@ -64,6 +63,7 @@ import org.springframework.data.relational.core.sql.Table;
|
||||
* @author Milan Milanov
|
||||
* @author Myeonghyeon Lee
|
||||
* @author Mikhail Polivakha
|
||||
* @author Chirag Tailor
|
||||
*/
|
||||
class SqlGeneratorUnitTests {
|
||||
|
||||
@@ -245,6 +245,26 @@ class SqlGeneratorUnitTests {
|
||||
"x_other ASC");
|
||||
}
|
||||
|
||||
@Test // GH-821
|
||||
void findAllSortedWithNullHandling_resolvesNullHandlingWhenDialectSupportsIt() {
|
||||
|
||||
SqlGenerator sqlGenerator = createSqlGenerator(DummyEntity.class, PostgresDialect.INSTANCE);
|
||||
|
||||
String sql = sqlGenerator.getFindAll(Sort.by(new Sort.Order(Sort.Direction.ASC, "name", Sort.NullHandling.NULLS_LAST)));
|
||||
|
||||
assertThat(sql).contains("ORDER BY \"dummy_entity\".\"x_name\" ASC NULLS LAST");
|
||||
}
|
||||
|
||||
@Test // GH-821
|
||||
void findAllSortedWithNullHandling_ignoresNullHandlingWhenDialectDoesNotSupportIt() {
|
||||
|
||||
SqlGenerator sqlGenerator = createSqlGenerator(DummyEntity.class, SqlServerDialect.INSTANCE);
|
||||
|
||||
String sql = sqlGenerator.getFindAll(Sort.by(new Sort.Order(Sort.Direction.ASC, "name", Sort.NullHandling.NULLS_LAST)));
|
||||
|
||||
assertThat(sql).endsWith("ORDER BY dummy_entity.x_name ASC");
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-101
|
||||
void findAllPagedByUnpaged() {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020-2021 the original author or authors.
|
||||
* Copyright 2020-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -29,6 +29,7 @@ import org.springframework.jdbc.core.JdbcOperations;
|
||||
* presence or absence of features in tests.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Chirag Tailor
|
||||
*/
|
||||
public class TestDatabaseFeatures {
|
||||
|
||||
@@ -83,6 +84,10 @@ public class TestDatabaseFeatures {
|
||||
assumeThat(database).isNotIn(Database.H2, Database.Hsql);
|
||||
}
|
||||
|
||||
private void supportsNullHandling() {
|
||||
assumeThat(database).isNotIn(Database.MySql, Database.MariaDb, Database.SqlServer);
|
||||
}
|
||||
|
||||
public void databaseIs(Database database) {
|
||||
assumeThat(this.database).isEqualTo(database);
|
||||
}
|
||||
@@ -115,6 +120,7 @@ public class TestDatabaseFeatures {
|
||||
SUPPORTS_ARRAYS(TestDatabaseFeatures::supportsArrays), //
|
||||
SUPPORTS_GENERATED_IDS_IN_REFERENCED_ENTITIES(TestDatabaseFeatures::supportsGeneratedIdsInReferencedEntities), //
|
||||
SUPPORTS_NANOSECOND_PRECISION(TestDatabaseFeatures::supportsNanosecondPrecision), //
|
||||
SUPPORTS_NULL_HANDLING(TestDatabaseFeatures::supportsNullHandling),
|
||||
IS_POSTGRES(f -> f.databaseIs(Database.PostgreSql)), //
|
||||
IS_HSQL(f -> f.databaseIs(Database.Hsql));
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2021 the original author or authors.
|
||||
* Copyright 2019-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,6 +18,7 @@ package org.springframework.data.relational.core.dialect;
|
||||
import java.util.OptionalLong;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.relational.core.sql.LockMode;
|
||||
import org.springframework.data.relational.core.sql.LockOptions;
|
||||
import org.springframework.data.relational.core.sql.Select;
|
||||
@@ -28,6 +29,7 @@ import org.springframework.data.relational.core.sql.render.SelectRenderContext;
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Myeonghyeon Lee
|
||||
* @author Chirag Tailor
|
||||
* @since 1.1
|
||||
*/
|
||||
public abstract class AbstractDialect implements Dialect {
|
||||
@@ -38,7 +40,7 @@ public abstract class AbstractDialect implements Dialect {
|
||||
Function<Select, ? extends CharSequence> afterFromTable = getAfterFromTable();
|
||||
Function<Select, ? extends CharSequence> afterOrderBy = getAfterOrderBy();
|
||||
|
||||
return new DialectSelectRenderContext(afterFromTable, afterOrderBy);
|
||||
return new DialectSelectRenderContext(afterFromTable, afterOrderBy, orderByNullHandling());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,12 +103,14 @@ public abstract class AbstractDialect implements Dialect {
|
||||
|
||||
private final Function<Select, ? extends CharSequence> afterFromTable;
|
||||
private final Function<Select, ? extends CharSequence> afterOrderBy;
|
||||
private final OrderByNullHandling orderByNullHandling;
|
||||
|
||||
DialectSelectRenderContext(Function<Select, ? extends CharSequence> afterFromTable,
|
||||
Function<Select, ? extends CharSequence> afterOrderBy) {
|
||||
Function<Select, ? extends CharSequence> afterOrderBy, OrderByNullHandling orderByNullHandling) {
|
||||
|
||||
this.afterFromTable = afterFromTable;
|
||||
this.afterOrderBy = afterOrderBy;
|
||||
this.orderByNullHandling = orderByNullHandling;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -118,6 +122,11 @@ public abstract class AbstractDialect implements Dialect {
|
||||
public Function<Select, ? extends CharSequence> afterOrderBy(boolean hasOrderBy) {
|
||||
return afterOrderBy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String evaluateOrderByNullHandling(Sort.NullHandling nullHandling) {
|
||||
return orderByNullHandling.evaluate(nullHandling);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2021 the original author or authors.
|
||||
* Copyright 2019-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -33,6 +33,7 @@ import org.springframework.data.relational.core.sql.render.SelectRenderContext;
|
||||
* @author Myeonghyeon Lee
|
||||
* @author Christoph Strobl
|
||||
* @author Mikhail Polivakha
|
||||
* @author Chirag Tailor
|
||||
* @since 1.1
|
||||
*/
|
||||
public interface Dialect {
|
||||
@@ -120,4 +121,13 @@ public interface Dialect {
|
||||
default InsertRenderContext getInsertRenderContext() {
|
||||
return InsertRenderContexts.DEFAULT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link OrderByNullHandling} used by this dialect.
|
||||
*
|
||||
* @return the {@link OrderByNullHandling} used by this dialect.
|
||||
*/
|
||||
default OrderByNullHandling orderByNullHandling() {
|
||||
return OrderByNullHandling.SQL_STANDARD;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,4 +133,9 @@ public class MySqlDialect extends AbstractDialect {
|
||||
public Collection<Object> getConverters() {
|
||||
return Collections.singletonList(TimestampAtUtcToOffsetDateTimeConverter.INSTANCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrderByNullHandling orderByNullHandling() {
|
||||
return OrderByNullHandling.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.relational.core.dialect;
|
||||
|
||||
import org.springframework.data.domain.Sort;
|
||||
|
||||
/**
|
||||
* Represents how the {@link Sort.NullHandling} option of an {@code ORDER BY} sort expression is to be evaluated.
|
||||
*
|
||||
* @author Chirag Tailor
|
||||
*/
|
||||
public interface OrderByNullHandling {
|
||||
/**
|
||||
* An {@link OrderByNullHandling} that can be used for databases conforming to the SQL standard which uses
|
||||
* {@code NULLS FIRST} and {@code NULLS LAST} in {@code ORDER BY} sort expressions to make null values appear before
|
||||
* or after non-null values in the result set.
|
||||
*/
|
||||
OrderByNullHandling SQL_STANDARD = new SqlStandardOrderByNullHandling();
|
||||
|
||||
/**
|
||||
* An {@link OrderByNullHandling} that can be used for databases that do not support the SQL standard usage of
|
||||
* {@code NULLS FIRST} and {@code NULLS LAST} in {@code ORDER BY} sort expressions to control where null values appear
|
||||
* respective to non-null values in the result set.
|
||||
*/
|
||||
OrderByNullHandling NONE = nullHandling -> "";
|
||||
|
||||
/**
|
||||
* Converts a {@link Sort.NullHandling} option to the appropriate SQL text to be included an {@code ORDER BY} sort
|
||||
* expression.
|
||||
*/
|
||||
String evaluate(Sort.NullHandling nullHandling);
|
||||
|
||||
/**
|
||||
* An {@link OrderByNullHandling} implementation for databases conforming to the SQL standard which uses
|
||||
* {@code NULLS FIRST} and {@code NULLS LAST} in {@code ORDER BY} sort expressions to make null values appear before
|
||||
* or after non-null values in the result set.
|
||||
*
|
||||
* @author Chirag Tailor
|
||||
*/
|
||||
class SqlStandardOrderByNullHandling implements OrderByNullHandling {
|
||||
|
||||
private static final String NULLS_FIRST = "NULLS FIRST";
|
||||
private static final String NULLS_LAST = "NULLS LAST";
|
||||
private static final String UNSPECIFIED = "";
|
||||
|
||||
@Override
|
||||
public String evaluate(Sort.NullHandling nullHandling) {
|
||||
|
||||
switch (nullHandling) {
|
||||
case NULLS_FIRST: return NULLS_FIRST;
|
||||
case NULLS_LAST: return NULLS_LAST;
|
||||
case NATIVE: return UNSPECIFIED;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Sort.NullHandling " + nullHandling + " not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -116,4 +116,9 @@ public class SqlServerDialect extends AbstractDialect {
|
||||
public InsertRenderContext getInsertRenderContext() {
|
||||
return InsertRenderContexts.MS_SQL_SERVER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrderByNullHandling orderByNullHandling() {
|
||||
return OrderByNullHandling.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2021 the original author or authors.
|
||||
* Copyright 2019-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,6 +24,7 @@ import org.springframework.data.relational.core.sql.Visitable;
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Jens Schauder
|
||||
* @author Chirag Tailor
|
||||
* @since 1.1
|
||||
*/
|
||||
class OrderByClauseVisitor extends TypedSubtreeVisitor<OrderByField> implements PartRenderer {
|
||||
@@ -51,11 +52,15 @@ class OrderByClauseVisitor extends TypedSubtreeVisitor<OrderByField> implements
|
||||
@Override
|
||||
Delegation leaveMatched(OrderByField segment) {
|
||||
|
||||
OrderByField field = segment;
|
||||
|
||||
if (field.getDirection() != null) {
|
||||
if (segment.getDirection() != null) {
|
||||
builder.append(" ") //
|
||||
.append(field.getDirection());
|
||||
.append(segment.getDirection());
|
||||
}
|
||||
|
||||
String nullHandling = context.getSelectRenderContext().evaluateOrderByNullHandling(segment.getNullHandling());
|
||||
if (!nullHandling.isEmpty()) {
|
||||
builder.append(" ") //
|
||||
.append(nullHandling);
|
||||
}
|
||||
|
||||
return Delegation.leave();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2021 the original author or authors.
|
||||
* Copyright 2019-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,17 +18,20 @@ package org.springframework.data.relational.core.sql.render;
|
||||
import java.util.OptionalLong;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.relational.core.dialect.OrderByNullHandling;
|
||||
import org.springframework.data.relational.core.sql.LockMode;
|
||||
import org.springframework.data.relational.core.sql.Select;
|
||||
|
||||
/**
|
||||
* Render context specifically for {@code SELECT} statements. This interface declares rendering hooks that are called
|
||||
* before/after a specific {@code SELECT} clause part. The rendering content is appended directly after/before an
|
||||
* before/after/during a specific {@code SELECT} clause part. The rendering content is appended directly after/before an
|
||||
* element without further whitespace processing. Hooks are responsible for adding required surrounding whitespaces.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Myeonghyeon Lee
|
||||
* @author Jens Schauder
|
||||
* @author Chirag Tailor
|
||||
* @since 1.1
|
||||
*/
|
||||
public interface SelectRenderContext {
|
||||
@@ -86,4 +89,14 @@ public interface SelectRenderContext {
|
||||
return lockPrefix;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Customization hook: Rendition of the null handling option for an {@code ORDER BY} sort expression.
|
||||
*
|
||||
* @param nullHandling the {@link Sort.NullHandling} for the {@code ORDER BY} sort expression. Must not be {@literal null}.
|
||||
* @return render {@link String} SQL text to be included in an {@code ORDER BY} sort expression.
|
||||
*/
|
||||
default String evaluateOrderByNullHandling(Sort.NullHandling nullHandling) {
|
||||
return OrderByNullHandling.NONE.evaluate(nullHandling);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2021 the original author or authors.
|
||||
* Copyright 2019-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,7 +20,10 @@ import static org.assertj.core.api.Assertions.*;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.relational.core.sql.Column;
|
||||
import org.springframework.data.relational.core.sql.LockMode;
|
||||
import org.springframework.data.relational.core.sql.OrderByField;
|
||||
import org.springframework.data.relational.core.sql.Select;
|
||||
import org.springframework.data.relational.core.sql.StatementBuilder;
|
||||
import org.springframework.data.relational.core.sql.Table;
|
||||
@@ -33,6 +36,7 @@ import org.springframework.data.relational.core.sql.render.SqlRenderer;
|
||||
* @author Mark Paluch
|
||||
* @author Jens Schauder
|
||||
* @author Myeonghyeon Lee
|
||||
* @author Chirag Tailor
|
||||
*/
|
||||
public class PostgresDialectRenderingUnitTests {
|
||||
|
||||
@@ -147,4 +151,62 @@ public class PostgresDialectRenderingUnitTests {
|
||||
|
||||
assertThat(sql).isEqualTo("SELECT foo.* FROM foo LIMIT 10 FOR SHARE OF foo");
|
||||
}
|
||||
|
||||
@Test // GH-821
|
||||
void shouldRenderSelectOrderByWithNoOptions() {
|
||||
|
||||
Table table = Table.create("foo");
|
||||
Select select = StatementBuilder.select(table.asterisk())
|
||||
.from(table)
|
||||
.orderBy(OrderByField.from(Column.create("bar", table)))
|
||||
.build();
|
||||
|
||||
String sql = SqlRenderer.create(factory.createRenderContext()).render(select);
|
||||
|
||||
assertThat(sql).isEqualTo("SELECT foo.* FROM foo ORDER BY foo.bar");
|
||||
}
|
||||
|
||||
@Test // GH-821
|
||||
void shouldRenderSelectOrderByWithDirection() {
|
||||
|
||||
Table table = Table.create("foo");
|
||||
Select select = StatementBuilder.select(table.asterisk())
|
||||
.from(table)
|
||||
.orderBy(OrderByField.from(Column.create("bar", table), Sort.Direction.ASC))
|
||||
.build();
|
||||
|
||||
String sql = SqlRenderer.create(factory.createRenderContext()).render(select);
|
||||
|
||||
assertThat(sql).isEqualTo("SELECT foo.* FROM foo ORDER BY foo.bar ASC");
|
||||
}
|
||||
|
||||
@Test // GH-821
|
||||
void shouldRenderSelectOrderByWithNullHandling() {
|
||||
|
||||
Table table = Table.create("foo");
|
||||
Select select = StatementBuilder.select(table.asterisk())
|
||||
.from(table)
|
||||
.orderBy(OrderByField.from(Column.create("bar", table))
|
||||
.withNullHandling(Sort.NullHandling.NULLS_FIRST))
|
||||
.build();
|
||||
|
||||
String sql = SqlRenderer.create(factory.createRenderContext()).render(select);
|
||||
|
||||
assertThat(sql).isEqualTo("SELECT foo.* FROM foo ORDER BY foo.bar NULLS FIRST");
|
||||
}
|
||||
|
||||
@Test // GH-821
|
||||
void shouldRenderSelectOrderByWithDirectionAndNullHandling() {
|
||||
|
||||
Table table = Table.create("foo");
|
||||
Select select = StatementBuilder.select(table.asterisk())
|
||||
.from(table)
|
||||
.orderBy(OrderByField.from(Column.create("bar", table), Sort.Direction.DESC)
|
||||
.withNullHandling(Sort.NullHandling.NULLS_FIRST))
|
||||
.build();
|
||||
|
||||
String sql = SqlRenderer.create(factory.createRenderContext()).render(select);
|
||||
|
||||
assertThat(sql).isEqualTo("SELECT foo.* FROM foo ORDER BY foo.bar DESC NULLS FIRST");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2021 the original author or authors.
|
||||
* Copyright 2019-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,7 +20,10 @@ import static org.assertj.core.api.Assertions.*;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.relational.core.sql.Column;
|
||||
import org.springframework.data.relational.core.sql.LockMode;
|
||||
import org.springframework.data.relational.core.sql.OrderByField;
|
||||
import org.springframework.data.relational.core.sql.Select;
|
||||
import org.springframework.data.relational.core.sql.StatementBuilder;
|
||||
import org.springframework.data.relational.core.sql.Table;
|
||||
@@ -33,6 +36,7 @@ import org.springframework.data.relational.core.sql.render.SqlRenderer;
|
||||
* @author Mark Paluch
|
||||
* @author Jens Schauder
|
||||
* @author Myeonghyeon Lee
|
||||
* @author Chirag Tailor
|
||||
*/
|
||||
public class SqlServerDialectRenderingUnitTests {
|
||||
|
||||
@@ -192,4 +196,19 @@ public class SqlServerDialectRenderingUnitTests {
|
||||
|
||||
assertThat(sql).isEqualTo("SELECT foo.* FROM foo WITH (HOLDLOCK, ROWLOCK) ORDER BY foo.column_1 OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY");
|
||||
}
|
||||
|
||||
@Test // GH-821
|
||||
void shouldRenderSelectOrderByIgnoringNullHandling() {
|
||||
|
||||
Table table = Table.create("foo");
|
||||
Select select = StatementBuilder.select(table.asterisk())
|
||||
.from(table)
|
||||
.orderBy(OrderByField.from(Column.create("bar", table))
|
||||
.withNullHandling(Sort.NullHandling.NULLS_FIRST))
|
||||
.build();
|
||||
|
||||
String sql = SqlRenderer.create(factory.createRenderContext()).render(select);
|
||||
|
||||
assertThat(sql).isEqualTo("SELECT foo.* FROM foo ORDER BY foo.bar");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user