Merge pull request #1835 from querydsl/i1834

Improve limit/offset handling
This commit is contained in:
Timo Westkämper 2016-04-01 18:06:31 +03:00
commit c1377f699e
4 changed files with 85 additions and 6 deletions

View File

@ -91,6 +91,9 @@ public class SQLServer2005Templates extends SQLServerTemplates {
for (OrderSpecifier<?> os : metadata.getOrderBy()) {
rn.orderBy(os);
}
if (metadata.getOrderBy().isEmpty()) {
rn.orderBy(Expressions.currentTimestamp().asc());
}
FactoryExpression<?> pr = Projections.appending(metadata.getProjection(), rn.as("rn"));
metadata.setProjection(FactoryExpressionUtils.wrap(pr));
metadata.clearOrderBy();

View File

@ -13,12 +13,15 @@
*/
package com.querydsl.sql;
import java.util.Map;
import java.util.Set;
import com.querydsl.core.QueryFlag;
import com.querydsl.core.QueryFlag.Position;
import com.querydsl.core.QueryMetadata;
import com.querydsl.core.QueryModifiers;
import com.querydsl.core.types.Expression;
import com.querydsl.core.types.Path;
import com.querydsl.core.types.dsl.Expressions;
/**
@ -67,20 +70,54 @@ public class SQLServer2012Templates extends SQLServerTemplates {
public void serialize(QueryMetadata metadata, boolean forCountRow, SQLSerializer context) {
if (!forCountRow && metadata.getModifiers().isRestricting() && metadata.getOrderBy().isEmpty()
&& !metadata.getJoins().isEmpty()) {
metadata = metadata.clone();
QueryModifiers mod = metadata.getModifiers();
// use top if order by is empty
if (mod.getOffset() == null) {
// select top ...
metadata = metadata.clone();
metadata.addFlag(new QueryFlag(QueryFlag.Position.AFTER_SELECT,
Expressions.template(Integer.class, topTemplate, mod.getLimit())));
context.serializeForQuery(metadata, forCountRow);
} else {
throw new IllegalStateException("offset not supported without order by");
// order by first column
metadata.addOrderBy(Expressions.ONE.asc());
}
} else {
context.serializeForQuery(metadata, forCountRow);
}
context.serializeForQuery(metadata, forCountRow);
if (!metadata.getFlags().isEmpty()) {
context.serialize(Position.END, metadata.getFlags());
}
}
@Override
public void serializeDelete(QueryMetadata metadata, RelationalPath<?> entity, SQLSerializer context) {
// limit
QueryModifiers mod = metadata.getModifiers();
if (mod.isRestricting()) {
metadata = metadata.clone();
metadata.addFlag(new QueryFlag(QueryFlag.Position.AFTER_SELECT,
Expressions.template(Integer.class, topTemplate, mod.getLimit())));
}
context.serializeForDelete(metadata, entity);
if (!metadata.getFlags().isEmpty()) {
context.serialize(Position.END, metadata.getFlags());
}
}
@Override
public void serializeUpdate(QueryMetadata metadata, RelationalPath<?> entity,
Map<Path<?>, Expression<?>> updates, SQLSerializer context) {
// limit
QueryModifiers mod = metadata.getModifiers();
if (mod.isRestricting()) {
metadata = metadata.clone();
metadata.addFlag(new QueryFlag(QueryFlag.Position.AFTER_SELECT,
Expressions.template(Integer.class, topTemplate, mod.getLimit())));
}
context.serializeForUpdate(metadata, entity, updates);
if (!metadata.getFlags().isEmpty()) {
context.serialize(Position.END, metadata.getFlags());

View File

@ -67,12 +67,22 @@ public class SQLServer2005TemplatesTest extends AbstractSQLTemplatesTest {
@Test
public void modifiers() {
query.from(survey1).limit(5).offset(3);
query.orderBy(survey1.id.asc());
query.getMetadata().setProjection(survey1.id);
assertEquals("select * from (" +
" select survey1.ID, row_number() over () as rn from SURVEY survey1) a " +
" select survey1.ID, row_number() over (order by survey1.ID asc) as rn from SURVEY survey1) a " +
"where rn > ? and rn <= ? order by rn", query.toString());
}
@Test
public void modifiers_noOrder() {
query.from(survey1).limit(5).offset(3);
query.getMetadata().setProjection(survey1.id);
assertEquals("select * from (" +
" select survey1.ID, row_number() over (order by current_timestamp asc) as rn from SURVEY survey1) a " +
"where rn > ? and rn <= ? order by rn", query.toString());
}
@Test
public void nextVal() {
Operation<String> nextval = ExpressionUtils.operation(String.class, SQLOps.NEXTVAL, ConstantImpl.create("myseq"));

View File

@ -24,6 +24,8 @@ import com.querydsl.core.types.Operation;
import com.querydsl.core.types.Path;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.core.types.dsl.NumberExpression;
import com.querydsl.sql.dml.SQLDeleteClause;
import com.querydsl.sql.dml.SQLUpdateClause;
public class SQLServer2012TemplatesTest extends AbstractSQLTemplatesTest {
@ -67,6 +69,33 @@ public class SQLServer2012TemplatesTest extends AbstractSQLTemplatesTest {
assertEquals("select top 5 survey1.ID from SURVEY survey1", query.toString());
}
@Test
public void limitOffset() {
query.from(survey1).limit(5).offset(5);
query.getMetadata().setProjection(survey1.id);
assertEquals("select survey1.ID from SURVEY survey1 " +
"order by 1 asc " +
"offset ? rows fetch next ? rows only", query.toString());
}
@Test
public void delete_limit() {
SQLDeleteClause clause = new SQLDeleteClause(null, createTemplates(), survey1);
clause.where(survey1.name.eq("Bob"));
clause.limit(5);
assertEquals("delete top 5 from SURVEY\n" +
"where SURVEY.NAME = ?", clause.toString());
}
@Test
public void update_limit() {
SQLUpdateClause clause = new SQLUpdateClause(null, createTemplates(), survey1);
clause.set(survey1.name, "Bob");
clause.limit(5);
assertEquals("update top 5 SURVEY\n" +
"set NAME = ?", clause.toString());
}
@Test
public void modifiers() {
query.from(survey1).limit(5).offset(3).orderBy(survey1.id.asc());