Skip to content

Commit ea9bd6e

Browse files
committed
Initial implementation of limit and offset
1 parent 97e7837 commit ea9bd6e

File tree

9 files changed

+603
-13
lines changed

9 files changed

+603
-13
lines changed

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

+12-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2016-2018 the original author or authors.
2+
* Copyright 2016-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -33,7 +33,7 @@ public class SqlColumn<T> implements BindableColumn<T>, SortSpecification {
3333
private SqlColumn(Builder builder) {
3434
name = Objects.requireNonNull(builder.name);
3535
jdbcType = builder.jdbcType;
36-
table = Objects.requireNonNull(builder.table);
36+
table = builder.table;
3737
typeHandler = builder.typeHandler;
3838
}
3939

@@ -89,9 +89,14 @@ public String aliasOrName() {
8989
return alias().orElse(name);
9090
}
9191

92+
public Optional<SqlTable> table() {
93+
return Optional.ofNullable(table);
94+
}
95+
9296
@Override
9397
public String renderWithTableAlias(TableAliasCalculator tableAliasCalculator) {
94-
return tableAliasCalculator.aliasForColumn(table)
98+
return table()
99+
.flatMap(tableAliasCalculator::aliasForColumn)
95100
.map(this::applyTableAlias)
96101
.orElseGet(this::name);
97102
}
@@ -106,6 +111,10 @@ private String applyTableAlias(String tableAlias) {
106111
return tableAlias + "." + name(); //$NON-NLS-1$
107112
}
108113

114+
public static <T> SqlColumn<T> of(String name) {
115+
return SqlColumn.withName(name).build();
116+
}
117+
109118
public static <T> SqlColumn<T> of(String name, SqlTable table) {
110119
return SqlColumn.withName(name)
111120
.withTable(table)

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

+43-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2016-2018 the original author or authors.
2+
* Copyright 2016-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -144,6 +144,16 @@ protected QueryExpressionModel buildModel() {
144144
.build();
145145
}
146146

147+
public SelectDSL<R>.LimitFinisher limit(long limit) {
148+
selectDSL.addQueryExpression(buildModel());
149+
return selectDSL.limit(limit);
150+
}
151+
152+
public SelectDSL<R>.OffsetFinisher offset(long offset) {
153+
selectDSL.addQueryExpression(buildModel());
154+
return selectDSL.offset(offset);
155+
}
156+
147157
public static class FromGatherer<R> {
148158
private FromGathererBuilder<R> builder;
149159
private Map<SqlTable, String> tableAliasMap = new HashMap<>();
@@ -234,6 +244,18 @@ public GroupByFinisher groupBy(BasicColumn...columns) {
234244
return new GroupByFinisher();
235245
}
236246

247+
public SelectDSL<R>.LimitFinisher limit(long limit) {
248+
whereModel = buildWhereModel();
249+
selectDSL.addQueryExpression(buildModel());
250+
return selectDSL.limit(limit);
251+
}
252+
253+
public SelectDSL<R>.OffsetFinisher offset(long offset) {
254+
whereModel = buildWhereModel();
255+
selectDSL.addQueryExpression(buildModel());
256+
return selectDSL.offset(offset);
257+
}
258+
237259
@Override
238260
public R build() {
239261
whereModel = buildWhereModel();
@@ -384,6 +406,18 @@ public SelectDSL<R> orderBy(SortSpecification...columns) {
384406
selectDSL.setOrderByModel(OrderByModel.of(columns));
385407
return selectDSL;
386408
}
409+
410+
public SelectDSL<R>.LimitFinisher limit(long limit) {
411+
joinModel = buildJoinModel();
412+
selectDSL.addQueryExpression(buildModel());
413+
return selectDSL.limit(limit);
414+
}
415+
416+
public SelectDSL<R>.OffsetFinisher offset(long offset) {
417+
joinModel = buildJoinModel();
418+
selectDSL.addQueryExpression(buildModel());
419+
return selectDSL.offset(offset);
420+
}
387421
}
388422

389423
public class GroupByFinisher implements Buildable<R> {
@@ -396,6 +430,14 @@ public SelectDSL<R> orderBy(SortSpecification...columns) {
396430
public R build() {
397431
return selectDSL.build();
398432
}
433+
434+
public SelectDSL<R>.LimitFinisher limit(long limit) {
435+
return selectDSL.limit(limit);
436+
}
437+
438+
public SelectDSL<R>.OffsetFinisher offset(long offset) {
439+
return selectDSL.offset(offset);
440+
}
399441
}
400442

401443
public class UnionBuilder {

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

+36-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2016-2018 the original author or authors.
2+
* Copyright 2016-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@
2424
import org.mybatis.dynamic.sql.select.QueryExpressionDSL.FromGatherer;
2525
import org.mybatis.dynamic.sql.select.QueryExpressionDSL.FromGathererBuilder;
2626
import org.mybatis.dynamic.sql.select.render.SelectStatementProvider;
27+
import org.mybatis.dynamic.sql.util.Buildable;
2728

2829
/**
2930
* Implements a standard SQL dialect for building model classes.
@@ -32,11 +33,13 @@
3233
*
3334
* @param <R> the type of model produced by this builder
3435
*/
35-
public class SelectDSL<R> {
36+
public class SelectDSL<R> implements Buildable<R> {
3637

3738
private Function<SelectModel, R> adapterFunction;
3839
private List<QueryExpressionModel> queryExpressions = new ArrayList<>();
3940
private OrderByModel orderByModel;
41+
private Long limit;
42+
private Long offset;
4043

4144
private SelectDSL(Function<SelectModel, R> adapterFunction) {
4245
this.adapterFunction = Objects.requireNonNull(adapterFunction);
@@ -96,10 +99,41 @@ void setOrderByModel(OrderByModel orderByModel) {
9699
this.orderByModel = orderByModel;
97100
}
98101

102+
public LimitFinisher limit(long limit) {
103+
this.limit = limit;
104+
return new LimitFinisher();
105+
}
106+
107+
public OffsetFinisher offset(long offset) {
108+
this.offset = offset;
109+
return new OffsetFinisher();
110+
}
111+
112+
@Override
99113
public R build() {
100114
SelectModel selectModel = SelectModel.withQueryExpressions(queryExpressions)
101115
.withOrderByModel(orderByModel)
116+
.withLimit(limit)
117+
.withOffset(offset)
102118
.build();
103119
return adapterFunction.apply(selectModel);
104120
}
121+
122+
public class LimitFinisher implements Buildable<R> {
123+
public OffsetFinisher offset(int offset) {
124+
return SelectDSL.this.offset(offset);
125+
}
126+
127+
@Override
128+
public R build() {
129+
return SelectDSL.this.build();
130+
}
131+
}
132+
133+
public class OffsetFinisher implements Buildable<R> {
134+
@Override
135+
public R build() {
136+
return SelectDSL.this.build();
137+
}
138+
}
105139
}

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

+25-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2016-2018 the original author or authors.
2+
* Copyright 2016-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -29,10 +29,14 @@
2929
public class SelectModel {
3030
private List<QueryExpressionModel> queryExpressions;
3131
private OrderByModel orderByModel;
32+
private Long limit;
33+
private Long offset;
3234

3335
private SelectModel(Builder builder) {
3436
queryExpressions = Objects.requireNonNull(builder.queryExpressions);
3537
orderByModel = builder.orderByModel;
38+
limit = builder.limit;
39+
offset = builder.offset;
3640
}
3741

3842
public <R> Stream<R> mapQueryExpressions(Function<QueryExpressionModel, R> mapper) {
@@ -43,6 +47,14 @@ public Optional<OrderByModel> orderByModel() {
4347
return Optional.ofNullable(orderByModel);
4448
}
4549

50+
public Optional<Long> limit() {
51+
return Optional.ofNullable(limit);
52+
}
53+
54+
public Optional<Long> offset() {
55+
return Optional.ofNullable(offset);
56+
}
57+
4658
public SelectStatementProvider render(RenderingStrategy renderingStrategy) {
4759
return SelectRenderer.withSelectModel(this)
4860
.withRenderingStrategy(renderingStrategy)
@@ -57,6 +69,8 @@ public static Builder withQueryExpressions(List<QueryExpressionModel> queryExpre
5769
public static class Builder {
5870
private List<QueryExpressionModel> queryExpressions = new ArrayList<>();
5971
private OrderByModel orderByModel;
72+
private Long limit;
73+
private Long offset;
6074

6175
public Builder withQueryExpressions(List<QueryExpressionModel> queryExpressions) {
6276
this.queryExpressions.addAll(queryExpressions);
@@ -68,6 +82,16 @@ public Builder withOrderByModel(OrderByModel orderByModel) {
6882
return this;
6983
}
7084

85+
public Builder withLimit(Long limit) {
86+
this.limit = limit;
87+
return this;
88+
}
89+
90+
public Builder withOffset(Long offset) {
91+
this.offset = offset;
92+
return this;
93+
}
94+
7195
public SelectModel build() {
7296
return new SelectModel(this);
7397
}

src/main/java/org/mybatis/dynamic/sql/select/render/DefaultSelectStatementProvider.java

+18-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2016-2018 the original author or authors.
2+
* Copyright 2016-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -27,11 +27,15 @@ public class DefaultSelectStatementProvider implements SelectStatementProvider {
2727
private String queryExpression;
2828
private Map<String, Object> parameters;
2929
private Optional<String> orderByClause;
30+
private Optional<String> limitClause;
31+
private Optional<String> offsetClause;
3032

3133
private DefaultSelectStatementProvider(Builder builder) {
3234
queryExpression = Objects.requireNonNull(builder.queryExpression);
3335
orderByClause = Objects.requireNonNull(builder.orderByClause);
3436
parameters = Collections.unmodifiableMap(Objects.requireNonNull(builder.parameters));
37+
limitClause = Objects.requireNonNull(builder.limitClause);
38+
offsetClause = Objects.requireNonNull(builder.offsetClause);
3539
}
3640

3741
@Override
@@ -41,7 +45,7 @@ public Map<String, Object> getParameters() {
4145

4246
@Override
4347
public String getSelectStatement() {
44-
return queryExpression + spaceBefore(orderByClause);
48+
return queryExpression + spaceBefore(orderByClause) + spaceBefore(limitClause) + spaceBefore(offsetClause);
4549
}
4650

4751
public static Builder withQueryExpression(String queryExpression) {
@@ -52,6 +56,8 @@ public static class Builder {
5256
private String queryExpression;
5357
private Optional<String> orderByClause = Optional.empty();
5458
private Map<String, Object> parameters = new HashMap<>();
59+
private Optional<String> limitClause = Optional.empty();
60+
private Optional<String> offsetClause = Optional.empty();
5561

5662
public Builder withQueryExpression(String queryExpression) {
5763
this.queryExpression = queryExpression;
@@ -68,6 +74,16 @@ public Builder withParameters(Map<String, Object> parameters) {
6874
return this;
6975
}
7076

77+
public Builder withLimitClause(Optional<String> limitClause) {
78+
this.limitClause = limitClause;
79+
return this;
80+
}
81+
82+
public Builder withOffsetClause(Optional<String> offsetClause) {
83+
this.offsetClause = offsetClause;
84+
return this;
85+
}
86+
7187
public DefaultSelectStatementProvider build() {
7288
return new DefaultSelectStatementProvider(this);
7389
}

src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java

+27-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2016-2018 the original author or authors.
2+
* Copyright 2016-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -15,18 +15,23 @@
1515
*/
1616
package org.mybatis.dynamic.sql.select.render;
1717

18+
import java.util.Map;
1819
import java.util.Objects;
1920
import java.util.Optional;
2021
import java.util.concurrent.atomic.AtomicInteger;
2122

23+
import org.mybatis.dynamic.sql.BindableColumn;
2224
import org.mybatis.dynamic.sql.SortSpecification;
25+
import org.mybatis.dynamic.sql.SqlColumn;
2326
import org.mybatis.dynamic.sql.render.RenderingStrategy;
2427
import org.mybatis.dynamic.sql.select.OrderByModel;
2528
import org.mybatis.dynamic.sql.select.QueryExpressionModel;
2629
import org.mybatis.dynamic.sql.select.SelectModel;
2730
import org.mybatis.dynamic.sql.util.CustomCollectors;
2831

2932
public class SelectRenderer {
33+
private static final String LIMIT_PARAMETER = "_limit"; //$NON-NLS-1$
34+
private static final String OFFSET_PARAMETER = "_offset"; //$NON-NLS-1$
3035
private SelectModel selectModel;
3136
private RenderingStrategy renderingStrategy;
3237
private AtomicInteger sequence;
@@ -42,9 +47,15 @@ public SelectStatementProvider render() {
4247
.mapQueryExpressions(this::renderQueryExpression)
4348
.collect(QueryExpressionCollector.collect());
4449

50+
Map<String, Object> parameters = collector.parameters();
51+
Optional<String> limitClause = selectModel.limit().map(l -> renderLimit(parameters, l));
52+
Optional<String> offsetClause = selectModel.offset().map(o -> renderOffset(parameters, o));
53+
4554
return DefaultSelectStatementProvider.withQueryExpression(collector.queryExpression())
46-
.withParameters(collector.parameters())
55+
.withParameters(parameters)
4756
.withOrderByClause(selectModel.orderByModel().map(this::renderOrderBy))
57+
.withLimitClause(limitClause)
58+
.withOffsetClause(offsetClause)
4859
.build();
4960
}
5061

@@ -69,6 +80,20 @@ private String orderByPhrase(SortSpecification column) {
6980
return phrase;
7081
}
7182

83+
private String renderLimit(Map<String, Object> parameters, Long limit) {
84+
BindableColumn<Integer> bc = SqlColumn.of(LIMIT_PARAMETER);
85+
String placeholder = renderingStrategy.getFormattedJdbcPlaceholder(bc, "parameters", LIMIT_PARAMETER); //$NON-NLS-1$
86+
parameters.put(LIMIT_PARAMETER, limit);
87+
return "limit " + placeholder; //$NON-NLS-1$
88+
}
89+
90+
private String renderOffset(Map<String, Object> parameters, Long offset) {
91+
BindableColumn<Integer> bc = SqlColumn.of(OFFSET_PARAMETER);
92+
String placeholder = renderingStrategy.getFormattedJdbcPlaceholder(bc, "parameters", OFFSET_PARAMETER); //$NON-NLS-1$
93+
parameters.put(OFFSET_PARAMETER, offset);
94+
return "offset " + placeholder; //$NON-NLS-1$
95+
}
96+
7297
public static Builder withSelectModel(SelectModel selectModel) {
7398
return new Builder().withSelectModel(selectModel);
7499
}

0 commit comments

Comments
 (0)