Skip to content

Commit e59d1a1

Browse files
committed
Initial implementation of for and wait
This add forUpdate(), forShare(), etc. to the select DSL
1 parent a645046 commit e59d1a1

File tree

8 files changed

+452
-11
lines changed

8 files changed

+452
-11
lines changed

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.mybatis.dynamic.sql.select.QueryExpressionDSL.FromGatherer;
3333
import org.mybatis.dynamic.sql.util.Buildable;
3434
import org.mybatis.dynamic.sql.util.ConfigurableStatement;
35+
import org.mybatis.dynamic.sql.util.Validator;
3536

3637
/**
3738
* Implements a SQL DSL for building select statements.
@@ -50,6 +51,8 @@ public class SelectDSL<R> implements Buildable<R>, ConfigurableStatement<SelectD
5051
private @Nullable Long offset;
5152
private @Nullable Long fetchFirstRows;
5253
final StatementConfiguration statementConfiguration = new StatementConfiguration();
54+
private @Nullable String forClause;
55+
private @Nullable String waitClause;
5356

5457
private SelectDSL(Function<SelectModel, R> adapterFunction) {
5558
this.adapterFunction = Objects.requireNonNull(adapterFunction);
@@ -122,6 +125,42 @@ public FetchFirstFinisher<R> fetchFirstWhenPresent(@Nullable Long fetchFirstRows
122125
return () -> this;
123126
}
124127

128+
public SelectDSL<R> forUpdate() {
129+
Validator.assertNull(forClause, "ERROR.48"); //$NON-NLS-1$
130+
forClause = "for update"; //$NON-NLS-1$
131+
return this;
132+
}
133+
134+
public SelectDSL<R> forNoKeyUpdate() {
135+
Validator.assertNull(forClause, "ERROR.48"); //$NON-NLS-1$
136+
forClause = "for no key update"; //$NON-NLS-1$
137+
return this;
138+
}
139+
140+
public SelectDSL<R> forShare() {
141+
Validator.assertNull(forClause, "ERROR.48"); //$NON-NLS-1$
142+
forClause = "for share"; //$NON-NLS-1$
143+
return this;
144+
}
145+
146+
public SelectDSL<R> forKeyShare() {
147+
Validator.assertNull(forClause, "ERROR.48"); //$NON-NLS-1$
148+
forClause = "for key share"; //$NON-NLS-1$
149+
return this;
150+
}
151+
152+
public SelectDSL<R> skipLocked() {
153+
Validator.assertNull(waitClause, "ERROR.49"); //$NON-NLS-1$
154+
waitClause = "skip locked"; //$NON-NLS-1$
155+
return this;
156+
}
157+
158+
public SelectDSL<R> nowait() {
159+
Validator.assertNull(waitClause, "ERROR.49"); //$NON-NLS-1$
160+
waitClause = "nowait"; //$NON-NLS-1$
161+
return this;
162+
}
163+
125164
@Override
126165
public SelectDSL<R> configureStatement(Consumer<StatementConfiguration> consumer) {
127166
consumer.accept(statementConfiguration);
@@ -134,6 +173,8 @@ public R build() {
134173
.withOrderByModel(orderByModel)
135174
.withPagingModel(buildPagingModel().orElse(null))
136175
.withStatementConfiguration(statementConfiguration)
176+
.withForClause(forClause)
177+
.withWaitClause(waitClause)
137178
.build();
138179
return adapterFunction.apply(selectModel);
139180
}

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,26 +18,40 @@
1818
import java.util.ArrayList;
1919
import java.util.List;
2020
import java.util.Objects;
21+
import java.util.Optional;
2122
import java.util.stream.Stream;
2223

24+
import org.jspecify.annotations.Nullable;
2325
import org.mybatis.dynamic.sql.render.RenderingStrategy;
2426
import org.mybatis.dynamic.sql.select.render.SelectRenderer;
2527
import org.mybatis.dynamic.sql.select.render.SelectStatementProvider;
2628
import org.mybatis.dynamic.sql.util.Validator;
2729

2830
public class SelectModel extends AbstractSelectModel {
2931
private final List<QueryExpressionModel> queryExpressions;
32+
private @Nullable final String forClause;
33+
private @Nullable final String waitClause;
3034

3135
private SelectModel(Builder builder) {
3236
super(builder);
3337
queryExpressions = Objects.requireNonNull(builder.queryExpressions);
3438
Validator.assertNotEmpty(queryExpressions, "ERROR.14"); //$NON-NLS-1$
39+
forClause = builder.forClause;
40+
waitClause = builder.waitClause;
3541
}
3642

3743
public Stream<QueryExpressionModel> queryExpressions() {
3844
return queryExpressions.stream();
3945
}
4046

47+
public Optional<String> forClause() {
48+
return Optional.ofNullable(forClause);
49+
}
50+
51+
public Optional<String> waitClause() {
52+
return Optional.ofNullable(waitClause);
53+
}
54+
4155
public SelectStatementProvider render(RenderingStrategy renderingStrategy) {
4256
return SelectRenderer.withSelectModel(this)
4357
.withRenderingStrategy(renderingStrategy)
@@ -51,6 +65,8 @@ public static Builder withQueryExpressions(List<QueryExpressionModel> queryExpre
5165

5266
public static class Builder extends AbstractBuilder<Builder> {
5367
private final List<QueryExpressionModel> queryExpressions = new ArrayList<>();
68+
private @Nullable String forClause;
69+
private @Nullable String waitClause;
5470

5571
public Builder withQueryExpression(QueryExpressionModel queryExpression) {
5672
this.queryExpressions.add(queryExpression);
@@ -62,6 +78,16 @@ public Builder withQueryExpressions(List<QueryExpressionModel> queryExpressions)
6278
return this;
6379
}
6480

81+
public Builder withForClause(@Nullable String forClause) {
82+
this.forClause = forClause;
83+
return this;
84+
}
85+
86+
public Builder withWaitClause(@Nullable String waitClause) {
87+
this.waitClause = waitClause;
88+
return this;
89+
}
90+
6591
@Override
6692
protected Builder getThis() {
6793
return this;

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

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
package org.mybatis.dynamic.sql.select.render;
1717

1818
import java.util.Objects;
19-
import java.util.Optional;
2019
import java.util.stream.Collectors;
2120

2221
import org.jspecify.annotations.Nullable;
@@ -48,8 +47,21 @@ public FragmentAndParameters render() {
4847
.map(this::renderQueryExpression)
4948
.collect(FragmentCollector.collect());
5049

51-
renderOrderBy().ifPresent(fragmentCollector::add);
52-
renderPagingModel().ifPresent(fragmentCollector::add);
50+
selectModel.orderByModel()
51+
.map(this::renderOrderBy)
52+
.ifPresent(fragmentCollector::add);
53+
54+
selectModel.pagingModel()
55+
.map(this::renderPagingModel)
56+
.ifPresent(fragmentCollector::add);
57+
58+
selectModel.forClause()
59+
.map(FragmentAndParameters::fromFragment)
60+
.ifPresent(fragmentCollector::add);
61+
62+
selectModel.waitClause()
63+
.map(FragmentAndParameters::fromFragment)
64+
.ifPresent(fragmentCollector::add);
5365

5466
return fragmentCollector.toFragmentAndParameters(Collectors.joining(" ", prefix, suffix)); //$NON-NLS-1$
5567
}
@@ -61,18 +73,10 @@ private FragmentAndParameters renderQueryExpression(QueryExpressionModel queryEx
6173
.render();
6274
}
6375

64-
private Optional<FragmentAndParameters> renderOrderBy() {
65-
return selectModel.orderByModel().map(this::renderOrderBy);
66-
}
67-
6876
private FragmentAndParameters renderOrderBy(OrderByModel orderByModel) {
6977
return new OrderByRenderer(renderingContext).render(orderByModel);
7078
}
7179

72-
private Optional<FragmentAndParameters> renderPagingModel() {
73-
return selectModel.pagingModel().map(this::renderPagingModel);
74-
}
75-
7680
private FragmentAndParameters renderPagingModel(PagingModel pagingModel) {
7781
return new PagingModelRenderer.Builder()
7882
.withPagingModel(pagingModel)

src/main/java/org/mybatis/dynamic/sql/util/Validator.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import java.util.Collection;
1919

20+
import org.jspecify.annotations.Nullable;
2021
import org.mybatis.dynamic.sql.exception.InvalidSqlException;
2122

2223
public class Validator {
@@ -49,4 +50,10 @@ public static void assertTrue(boolean condition, String messageNumber) {
4950
public static void assertTrue(boolean condition, String messageNumber, String p1) {
5051
assertFalse(!condition, messageNumber, p1);
5152
}
53+
54+
public static void assertNull(@Nullable Object object, String messageNumber) {
55+
if (object != null) {
56+
throw new InvalidSqlException(Messages.getString(messageNumber));
57+
}
58+
}
5259
}

src/main/resources/org/mybatis/dynamic/sql/util/messages.properties

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,7 @@ ERROR.44={0} conditions must contain at least one value
6464
ERROR.45=You cannot call "on" in a Kotlin join expression more than once
6565
ERROR.46=At least one join criterion must render
6666
ERROR.47=A Kotlin case statement must specify a "then" clause for every "when" clause
67+
ERROR.48=You cannot call more than one of "forUpdate", "forNoKeyUpdate", "forShare", or "forKeyShare" in a select \
68+
statement
69+
ERROR.49=You cannot call more than one of "skipLocked", or "nowait" in a select statement
6770
INTERNAL.ERROR=Internal Error {0}

0 commit comments

Comments
 (0)