View Javadoc
1   /*
2    *    Copyright 2016-2025 the original author or authors.
3    *
4    *    Licensed under the Apache License, Version 2.0 (the "License");
5    *    you may not use this file except in compliance with the License.
6    *    You may obtain a copy of the License at
7    *
8    *       https://www.apache.org/licenses/LICENSE-2.0
9    *
10   *    Unless required by applicable law or agreed to in writing, software
11   *    distributed under the License is distributed on an "AS IS" BASIS,
12   *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *    See the License for the specific language governing permissions and
14   *    limitations under the License.
15   */
16  package org.mybatis.dynamic.sql.update;
17  
18  import java.util.ArrayList;
19  import java.util.Arrays;
20  import java.util.Collection;
21  import java.util.List;
22  import java.util.Objects;
23  import java.util.function.Consumer;
24  import java.util.function.Function;
25  import java.util.function.Supplier;
26  
27  import org.jspecify.annotations.Nullable;
28  import org.mybatis.dynamic.sql.BasicColumn;
29  import org.mybatis.dynamic.sql.SortSpecification;
30  import org.mybatis.dynamic.sql.SqlColumn;
31  import org.mybatis.dynamic.sql.SqlTable;
32  import org.mybatis.dynamic.sql.common.OrderByModel;
33  import org.mybatis.dynamic.sql.configuration.StatementConfiguration;
34  import org.mybatis.dynamic.sql.select.SelectModel;
35  import org.mybatis.dynamic.sql.util.AbstractColumnMapping;
36  import org.mybatis.dynamic.sql.util.Buildable;
37  import org.mybatis.dynamic.sql.util.ColumnToColumnMapping;
38  import org.mybatis.dynamic.sql.util.ConstantMapping;
39  import org.mybatis.dynamic.sql.util.NullMapping;
40  import org.mybatis.dynamic.sql.util.SelectMapping;
41  import org.mybatis.dynamic.sql.util.StringConstantMapping;
42  import org.mybatis.dynamic.sql.util.ValueMapping;
43  import org.mybatis.dynamic.sql.util.ValueOrNullMapping;
44  import org.mybatis.dynamic.sql.util.ValueWhenPresentMapping;
45  import org.mybatis.dynamic.sql.where.AbstractWhereFinisher;
46  import org.mybatis.dynamic.sql.where.AbstractWhereStarter;
47  import org.mybatis.dynamic.sql.where.EmbeddedWhereModel;
48  
49  public class UpdateDSL<R> implements AbstractWhereStarter<UpdateDSL<R>.UpdateWhereBuilder, UpdateDSL<R>>,
50          Buildable<R> {
51  
52      private final Function<UpdateModel, R> adapterFunction;
53      private final List<AbstractColumnMapping> columnMappings = new ArrayList<>();
54      private final SqlTable table;
55      private final @Nullable String tableAlias;
56      private @Nullable UpdateWhereBuilder whereBuilder;
57      private final StatementConfiguration statementConfiguration = new StatementConfiguration();
58      private @Nullable Long limit;
59      private @Nullable OrderByModel orderByModel;
60  
61      private UpdateDSL(SqlTable table, @Nullable String tableAlias, Function<UpdateModel, R> adapterFunction) {
62          this.table = Objects.requireNonNull(table);
63          this.tableAlias = tableAlias;
64          this.adapterFunction = Objects.requireNonNull(adapterFunction);
65      }
66  
67      public <T> SetClauseFinisher<T> set(SqlColumn<T> column) {
68          return new SetClauseFinisher<>(column);
69      }
70  
71      @Override
72      public UpdateWhereBuilder where() {
73          whereBuilder = Objects.requireNonNullElseGet(whereBuilder, UpdateWhereBuilder::new);
74          return whereBuilder;
75      }
76  
77      public UpdateDSL<R> limit(long limit) {
78          return limitWhenPresent(limit);
79      }
80  
81      public UpdateDSL<R> limitWhenPresent(@Nullable Long limit) {
82          this.limit = limit;
83          return this;
84      }
85  
86      public UpdateDSL<R> orderBy(SortSpecification... columns) {
87          return orderBy(Arrays.asList(columns));
88      }
89  
90      public UpdateDSL<R> orderBy(Collection<? extends SortSpecification> columns) {
91          orderByModel = OrderByModel.of(columns);
92          return this;
93      }
94  
95      /**
96       * WARNING! Calling this method could result in an update statement that updates
97       * all rows in a table.
98       *
99       * @return the update model
100      */
101     @Override
102     public R build() {
103         UpdateModel updateModel = UpdateModel.withTable(table)
104                 .withTableAlias(tableAlias)
105                 .withColumnMappings(columnMappings)
106                 .withLimit(limit)
107                 .withOrderByModel(orderByModel)
108                 .withWhereModel(whereBuilder == null ? null : whereBuilder.buildWhereModel())
109                 .withStatementConfiguration(statementConfiguration)
110                 .build();
111 
112         return adapterFunction.apply(updateModel);
113     }
114 
115     @Override
116     public UpdateDSL<R> configureStatement(Consumer<StatementConfiguration> consumer) {
117         consumer.accept(statementConfiguration);
118         return this;
119     }
120 
121     public static <R> UpdateDSL<R> update(Function<UpdateModel, R> adapterFunction, SqlTable table,
122                                           @Nullable String tableAlias) {
123         return new UpdateDSL<>(table, tableAlias, adapterFunction);
124     }
125 
126     public static UpdateDSL<UpdateModel> update(SqlTable table) {
127         return update(Function.identity(), table, null);
128     }
129 
130     public static UpdateDSL<UpdateModel> update(SqlTable table, String tableAlias) {
131         return update(Function.identity(), table, tableAlias);
132     }
133 
134     public class SetClauseFinisher<T> {
135 
136         private final SqlColumn<T> column;
137 
138         public SetClauseFinisher(SqlColumn<T> column) {
139             this.column = column;
140         }
141 
142         public UpdateDSL<R> equalToNull() {
143             columnMappings.add(NullMapping.of(column));
144             return UpdateDSL.this;
145         }
146 
147         public UpdateDSL<R> equalToConstant(String constant) {
148             columnMappings.add(ConstantMapping.of(column, constant));
149             return UpdateDSL.this;
150         }
151 
152         public UpdateDSL<R> equalToStringConstant(String constant) {
153             columnMappings.add(StringConstantMapping.of(column, constant));
154             return UpdateDSL.this;
155         }
156 
157         public UpdateDSL<R> equalTo(T value) {
158             return equalTo(() -> value);
159         }
160 
161         public UpdateDSL<R> equalTo(Supplier<T> valueSupplier) {
162             columnMappings.add(ValueMapping.of(column, valueSupplier));
163             return UpdateDSL.this;
164         }
165 
166         public UpdateDSL<R> equalTo(Buildable<SelectModel> buildable) {
167             columnMappings.add(SelectMapping.of(column, buildable));
168             return UpdateDSL.this;
169         }
170 
171         public UpdateDSL<R> equalTo(BasicColumn rightColumn) {
172             columnMappings.add(ColumnToColumnMapping.of(column, rightColumn));
173             return UpdateDSL.this;
174         }
175 
176         public UpdateDSL<R> equalToOrNull(@Nullable T value) {
177             return equalToOrNull(() -> value);
178         }
179 
180         public UpdateDSL<R> equalToOrNull(Supplier<@Nullable T> valueSupplier) {
181             columnMappings.add(ValueOrNullMapping.of(column, valueSupplier));
182             return UpdateDSL.this;
183         }
184 
185         public UpdateDSL<R> equalToWhenPresent(@Nullable T value) {
186             return equalToWhenPresent(() -> value);
187         }
188 
189         public UpdateDSL<R> equalToWhenPresent(Supplier<@Nullable T> valueSupplier) {
190             columnMappings.add(ValueWhenPresentMapping.of(column, valueSupplier));
191             return UpdateDSL.this;
192         }
193     }
194 
195     public class UpdateWhereBuilder extends AbstractWhereFinisher<UpdateWhereBuilder> implements Buildable<R> {
196 
197         private UpdateWhereBuilder() {
198             super(UpdateDSL.this);
199         }
200 
201         public UpdateDSL<R> limit(long limit) {
202             return limitWhenPresent(limit);
203         }
204 
205         public UpdateDSL<R> limitWhenPresent(@Nullable Long limit) {
206             return UpdateDSL.this.limitWhenPresent(limit);
207         }
208 
209         public UpdateDSL<R> orderBy(SortSpecification... columns) {
210             return orderBy(Arrays.asList(columns));
211         }
212 
213         public UpdateDSL<R> orderBy(Collection<? extends SortSpecification> columns) {
214             orderByModel = OrderByModel.of(columns);
215             return UpdateDSL.this;
216         }
217 
218         @Override
219         public R build() {
220             return UpdateDSL.this.build();
221         }
222 
223         @Override
224         protected UpdateWhereBuilder getThis() {
225             return this;
226         }
227 
228         protected EmbeddedWhereModel buildWhereModel() {
229             return buildModel();
230         }
231     }
232 }