Skip to content

Commit 95a2c12

Browse files
committed
Implement ValueWhenPresent mapping in update
1 parent f20bead commit 95a2c12

13 files changed

+302
-48
lines changed

src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2016-2019 the original author or authors.
2+
* Copyright 2016-2020 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.
@@ -38,6 +38,7 @@
3838
import org.mybatis.dynamic.sql.util.SelectMapping;
3939
import org.mybatis.dynamic.sql.util.StringConstantMapping;
4040
import org.mybatis.dynamic.sql.util.ValueMapping;
41+
import org.mybatis.dynamic.sql.util.ValueWhenPresentMapping;
4142
import org.mybatis.dynamic.sql.util.mybatis3.MyBatis3Utils;
4243
import org.mybatis.dynamic.sql.where.AbstractWhereDSL;
4344
import org.mybatis.dynamic.sql.where.WhereApplier;
@@ -159,9 +160,7 @@ public UpdateDSL<R> equalToWhenPresent(T value) {
159160
}
160161

161162
public UpdateDSL<R> equalToWhenPresent(Supplier<T> valueSupplier) {
162-
if (valueSupplier.get() != null) {
163-
columnMappings.add(ValueMapping.of(column, valueSupplier));
164-
}
163+
columnMappings.add(ValueWhenPresentMapping.of(column, valueSupplier));
165164
return UpdateDSL.this;
166165
}
167166
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/**
2+
* Copyright 2016-2020 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+
* http://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.render;
17+
18+
import java.util.ArrayList;
19+
import java.util.HashMap;
20+
import java.util.List;
21+
import java.util.Map;
22+
import java.util.Optional;
23+
import java.util.stream.Collector;
24+
import java.util.stream.Stream;
25+
26+
import org.mybatis.dynamic.sql.util.FragmentAndParameters;
27+
28+
public class OptionalFragmentCollector {
29+
List<Optional<FragmentAndParameters>> fragments = new ArrayList<>();
30+
31+
OptionalFragmentCollector() {
32+
super();
33+
}
34+
35+
public void add(Optional<FragmentAndParameters> fragmentAndParameters) {
36+
fragments.add(fragmentAndParameters);
37+
}
38+
39+
public OptionalFragmentCollector merge(OptionalFragmentCollector other) {
40+
fragments.addAll(other.fragments);
41+
return this;
42+
}
43+
44+
public Stream<String> fragments() {
45+
return fragments.stream()
46+
.filter(Optional::isPresent)
47+
.map(Optional::get)
48+
.map(FragmentAndParameters::fragment);
49+
}
50+
51+
public Map<String, Object> parameters() {
52+
return fragments.stream()
53+
.filter(Optional::isPresent)
54+
.map(Optional::get)
55+
.map(FragmentAndParameters::parameters)
56+
.collect(HashMap::new, HashMap::putAll, HashMap::putAll);
57+
}
58+
59+
public static Collector<Optional<FragmentAndParameters>, OptionalFragmentCollector, OptionalFragmentCollector> collect() {
60+
return Collector.of(OptionalFragmentCollector::new,
61+
OptionalFragmentCollector::add,
62+
OptionalFragmentCollector::merge);
63+
}
64+
}

src/main/java/org/mybatis/dynamic/sql/update/render/SetPhraseVisitor.java

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

1818
import java.util.Objects;
19+
import java.util.Optional;
1920
import java.util.concurrent.atomic.AtomicInteger;
2021
import java.util.function.Function;
2122

@@ -32,8 +33,9 @@
3233
import org.mybatis.dynamic.sql.util.StringConstantMapping;
3334
import org.mybatis.dynamic.sql.util.UpdateMappingVisitor;
3435
import org.mybatis.dynamic.sql.util.ValueMapping;
36+
import org.mybatis.dynamic.sql.util.ValueWhenPresentMapping;
3537

36-
public class SetPhraseVisitor extends UpdateMappingVisitor<FragmentAndParameters> {
38+
public class SetPhraseVisitor extends UpdateMappingVisitor<Optional<FragmentAndParameters>> {
3739

3840
private AtomicInteger sequence;
3941
private RenderingStrategy renderingStrategy;
@@ -44,31 +46,31 @@ public SetPhraseVisitor(AtomicInteger sequence, RenderingStrategy renderingStrat
4446
}
4547

4648
@Override
47-
public FragmentAndParameters visit(NullMapping mapping) {
49+
public Optional<FragmentAndParameters> visit(NullMapping mapping) {
4850
return FragmentAndParameters.withFragment(mapping.mapColumn(SqlColumn::name) + " = null") //$NON-NLS-1$
49-
.build();
51+
.buildOptional();
5052
}
5153

5254
@Override
53-
public FragmentAndParameters visit(ConstantMapping mapping) {
55+
public Optional<FragmentAndParameters> visit(ConstantMapping mapping) {
5456
String fragment = mapping.mapColumn(SqlColumn::name) + " = " + mapping.constant(); //$NON-NLS-1$
5557
return FragmentAndParameters.withFragment(fragment)
56-
.build();
58+
.buildOptional();
5759
}
5860

5961
@Override
60-
public FragmentAndParameters visit(StringConstantMapping mapping) {
62+
public Optional<FragmentAndParameters> visit(StringConstantMapping mapping) {
6163
String fragment = mapping.mapColumn(SqlColumn::name)
6264
+ " = '" //$NON-NLS-1$
6365
+ mapping.constant()
6466
+ "'"; //$NON-NLS-1$
6567

6668
return FragmentAndParameters.withFragment(fragment)
67-
.build();
69+
.buildOptional();
6870
}
6971

7072
@Override
71-
public <T> FragmentAndParameters visit(ValueMapping<T> mapping) {
73+
public <T> Optional<FragmentAndParameters> visit(ValueMapping<T> mapping) {
7274
String mapKey = RenderingStrategy.formatParameterMapKey(sequence);
7375

7476
String jdbcPlaceholder = mapping.mapColumn(toJdbcPlaceholder(mapKey));
@@ -78,11 +80,28 @@ public <T> FragmentAndParameters visit(ValueMapping<T> mapping) {
7880

7981
return FragmentAndParameters.withFragment(setPhrase)
8082
.withParameter(mapKey, mapping.value())
81-
.build();
83+
.buildOptional();
8284
}
8385

8486
@Override
85-
public FragmentAndParameters visit(SelectMapping mapping) {
87+
public <R> Optional<FragmentAndParameters> visit(ValueWhenPresentMapping<R> mapping) {
88+
return mapping.value().flatMap(v -> {
89+
String mapKey = RenderingStrategy.formatParameterMapKey(sequence);
90+
91+
String jdbcPlaceholder = mapping.mapColumn(toJdbcPlaceholder(mapKey));
92+
String setPhrase = mapping.mapColumn(SqlColumn::name)
93+
+ " = " //$NON-NLS-1$
94+
+ jdbcPlaceholder;
95+
96+
return FragmentAndParameters.withFragment(setPhrase)
97+
.withParameter(mapKey, v)
98+
.buildOptional();
99+
100+
});
101+
}
102+
103+
@Override
104+
public Optional<FragmentAndParameters> visit(SelectMapping mapping) {
86105
SelectStatementProvider selectStatement = SelectRenderer.withSelectModel(mapping.selectModel())
87106
.withRenderingStrategy(renderingStrategy)
88107
.withSequence(sequence)
@@ -96,17 +115,17 @@ public FragmentAndParameters visit(SelectMapping mapping) {
96115

97116
return FragmentAndParameters.withFragment(fragment)
98117
.withParameters(selectStatement.getParameters())
99-
.build();
118+
.buildOptional();
100119
}
101120

102121
@Override
103-
public FragmentAndParameters visit(ColumnToColumnMapping mapping) {
122+
public Optional<FragmentAndParameters> visit(ColumnToColumnMapping mapping) {
104123
String setPhrase = mapping.mapColumn(SqlColumn::name)
105124
+ " = " //$NON-NLS-1$
106125
+ mapping.rightColumn().renderWithTableAlias(TableAliasCalculator.empty());
107126

108127
return FragmentAndParameters.withFragment(setPhrase)
109-
.build();
128+
.buildOptional();
110129
}
111130

112131
private Function<SqlColumn<?>, String> toJdbcPlaceholder(String parameterName) {

src/main/java/org/mybatis/dynamic/sql/update/render/UpdateRenderer.java

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import org.mybatis.dynamic.sql.update.UpdateModel;
2929
import org.mybatis.dynamic.sql.util.AbstractColumnMapping;
3030
import org.mybatis.dynamic.sql.util.FragmentAndParameters;
31-
import org.mybatis.dynamic.sql.util.FragmentCollector;
3231
import org.mybatis.dynamic.sql.where.WhereModel;
3332
import org.mybatis.dynamic.sql.where.render.WhereClauseProvider;
3433
import org.mybatis.dynamic.sql.where.render.WhereRenderer;
@@ -44,47 +43,47 @@ private UpdateRenderer(Builder builder) {
4443
}
4544

4645
public UpdateStatementProvider render() {
47-
FragmentCollector fc = calculateColumnMappings();
46+
OptionalFragmentCollector fc = calculateColumnMappings();
4847

4948
return updateModel.whereModel()
5049
.flatMap(this::renderWhereClause)
5150
.map(wc -> renderWithWhereClause(fc, wc))
5251
.orElseGet(() -> renderWithoutWhereClause(fc));
5352
}
5453

55-
private FragmentCollector calculateColumnMappings() {
54+
private OptionalFragmentCollector calculateColumnMappings() {
5655
SetPhraseVisitor visitor = new SetPhraseVisitor(sequence, renderingStrategy);
5756

5857
return updateModel.mapColumnMappings(toFragmentAndParameters(visitor))
59-
.collect(FragmentCollector.collect());
58+
.collect(OptionalFragmentCollector.collect());
6059
}
6160

62-
private UpdateStatementProvider renderWithWhereClause(FragmentCollector columnMappings,
61+
private UpdateStatementProvider renderWithWhereClause(OptionalFragmentCollector columnMappings,
6362
WhereClauseProvider whereClause) {
6463
return DefaultUpdateStatementProvider.withUpdateStatement(calculateUpdateStatement(columnMappings, whereClause))
6564
.withParameters(columnMappings.parameters())
6665
.withParameters(whereClause.getParameters())
6766
.build();
6867
}
6968

70-
private String calculateUpdateStatement(FragmentCollector fc, WhereClauseProvider whereClause) {
69+
private String calculateUpdateStatement(OptionalFragmentCollector fc, WhereClauseProvider whereClause) {
7170
return calculateUpdateStatement(fc)
7271
+ spaceBefore(whereClause.getWhereClause());
7372
}
7473

75-
private String calculateUpdateStatement(FragmentCollector fc) {
74+
private String calculateUpdateStatement(OptionalFragmentCollector fc) {
7675
return "update" //$NON-NLS-1$
7776
+ spaceBefore(updateModel.table().tableNameAtRuntime())
7877
+ spaceBefore(calculateSetPhrase(fc));
7978
}
8079

81-
private UpdateStatementProvider renderWithoutWhereClause(FragmentCollector columnMappings) {
80+
private UpdateStatementProvider renderWithoutWhereClause(OptionalFragmentCollector columnMappings) {
8281
return DefaultUpdateStatementProvider.withUpdateStatement(calculateUpdateStatement(columnMappings))
8382
.withParameters(columnMappings.parameters())
8483
.build();
8584
}
8685

87-
private String calculateSetPhrase(FragmentCollector collector) {
86+
private String calculateSetPhrase(OptionalFragmentCollector collector) {
8887
return collector.fragments()
8988
.collect(Collectors.joining(", ", "set ", "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
9089
}
@@ -98,11 +97,11 @@ private Optional<WhereClauseProvider> renderWhereClause(WhereModel whereModel) {
9897
.render();
9998
}
10099

101-
private Function<AbstractColumnMapping, FragmentAndParameters> toFragmentAndParameters(SetPhraseVisitor visitor) {
100+
private Function<AbstractColumnMapping, Optional<FragmentAndParameters>> toFragmentAndParameters(SetPhraseVisitor visitor) {
102101
return updateMapping -> toFragmentAndParameters(visitor, updateMapping);
103102
}
104103

105-
private FragmentAndParameters toFragmentAndParameters(SetPhraseVisitor visitor,
104+
private Optional<FragmentAndParameters> toFragmentAndParameters(SetPhraseVisitor visitor,
106105
AbstractColumnMapping updateMapping) {
107106
return updateMapping.accept(visitor);
108107
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ public interface ColumnMappingVisitor<T> {
3838

3939
<R> T visit(ValueMapping<R> mapping);
4040

41+
<R> T visit(ValueWhenPresentMapping<R> mapping);
42+
4143
T visit(SelectMapping mapping);
4244

4345
T visit(PropertyMapping mapping);

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2016-2019 the original author or authors.
2+
* Copyright 2016-2020 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.
@@ -23,8 +23,7 @@
2323
import java.util.stream.Stream;
2424

2525
public class FragmentCollector {
26-
List<String> fragments = new ArrayList<>();
27-
Map<String, Object> parameters = new HashMap<>();
26+
List<FragmentAndParameters> fragments = new ArrayList<>();
2827

2928
FragmentCollector() {
3029
super();
@@ -35,22 +34,23 @@ private FragmentCollector(FragmentAndParameters initialFragment) {
3534
}
3635

3736
public void add(FragmentAndParameters fragmentAndParameters) {
38-
fragments.add(fragmentAndParameters.fragment());
39-
parameters.putAll(fragmentAndParameters.parameters());
37+
fragments.add(fragmentAndParameters);
4038
}
4139

4240
public FragmentCollector merge(FragmentCollector other) {
4341
fragments.addAll(other.fragments);
44-
parameters.putAll(other.parameters);
4542
return this;
4643
}
4744

4845
public Stream<String> fragments() {
49-
return fragments.stream();
46+
return fragments.stream()
47+
.map(FragmentAndParameters::fragment);
5048
}
5149

5250
public Map<String, Object> parameters() {
53-
return parameters;
51+
return fragments.stream()
52+
.map(FragmentAndParameters::parameters)
53+
.collect(HashMap::new, HashMap::putAll, HashMap::putAll);
5454
}
5555

5656
public boolean hasMultipleFragments() {

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,10 @@ public final T visit(PropertyMapping mapping) {
3030
public final T visit(ColumnToColumnMapping columnMapping) {
3131
throw new UnsupportedOperationException();
3232
}
33+
34+
@Override
35+
public <R> T visit(ValueWhenPresentMapping<R> mapping) {
36+
// TODO - remove this method
37+
return null;
38+
}
3339
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,10 @@ public final T visit(SelectMapping mapping) {
3030
public final T visit(ColumnToColumnMapping columnMapping) {
3131
throw new UnsupportedOperationException();
3232
}
33+
34+
@Override
35+
public <R> T visit(ValueWhenPresentMapping<R> mapping) {
36+
// TODO - remove this method
37+
return null;
38+
}
3339
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,9 @@ public final T visit(SelectMapping mapping) {
3030
public final T visit(ColumnToColumnMapping columnMapping) {
3131
throw new UnsupportedOperationException();
3232
}
33+
34+
@Override
35+
public final <R> T visit(ValueWhenPresentMapping<R> mapping) {
36+
throw new UnsupportedOperationException();
37+
}
3338
}

0 commit comments

Comments
 (0)