Skip to content

Commit d97c153

Browse files
authored
Merge pull request #612 from jeffgbutler/map-to-row
Add Map to Row Function for Insert Statements
2 parents 2aa431a + 77b0765 commit d97c153

33 files changed

+1046
-85
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ The pull request for this change is ([#591](https://github.com/mybatis/mybatis-d
112112
5. Add `SqlBuilder.concat` and the equivalent in Kotlin. This is a concatenate function that works on more databases.
113113
([#573](https://github.com/mybatis/mybatis-dynamic-sql/pull/573))
114114
6. Several classes and methods in the Kotlin DSL are deprecated in response to the new "having" support
115+
7. Added support for inserting a list of simple classes like Integers, Strings, etc. This is via a new "map to row"
116+
function on the insert, batch insert, and multirow insert statements. ([#612](https://github.com/mybatis/mybatis-dynamic-sql/pull/612))
115117

116118
## Release 1.4.1 - October 7, 2022
117119

src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertDSL.java

+6
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.mybatis.dynamic.sql.util.ConstantMapping;
3030
import org.mybatis.dynamic.sql.util.NullMapping;
3131
import org.mybatis.dynamic.sql.util.PropertyMapping;
32+
import org.mybatis.dynamic.sql.util.RowMapping;
3233
import org.mybatis.dynamic.sql.util.StringConstantMapping;
3334

3435
public class BatchInsertDSL<T> implements Buildable<BatchInsertModel<T>> {
@@ -103,6 +104,11 @@ public BatchInsertDSL<T> toStringConstant(String constant) {
103104
columnMappings.add(StringConstantMapping.of(column, constant));
104105
return BatchInsertDSL.this;
105106
}
107+
108+
public BatchInsertDSL<T> toRow() {
109+
columnMappings.add(RowMapping.of(column));
110+
return BatchInsertDSL.this;
111+
}
106112
}
107113

108114
public abstract static class AbstractBuilder<T, B extends AbstractBuilder<T, B>> {

src/main/java/org/mybatis/dynamic/sql/insert/InsertDSL.java

+6
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.mybatis.dynamic.sql.util.NullMapping;
3131
import org.mybatis.dynamic.sql.util.PropertyMapping;
3232
import org.mybatis.dynamic.sql.util.PropertyWhenPresentMapping;
33+
import org.mybatis.dynamic.sql.util.RowMapping;
3334
import org.mybatis.dynamic.sql.util.StringConstantMapping;
3435

3536
public class InsertDSL<T> implements Buildable<InsertModel<T>> {
@@ -104,6 +105,11 @@ public InsertDSL<T> toStringConstant(String constant) {
104105
columnMappings.add(StringConstantMapping.of(column, constant));
105106
return InsertDSL.this;
106107
}
108+
109+
public InsertDSL<T> toRow() {
110+
columnMappings.add(RowMapping.of(column));
111+
return InsertDSL.this;
112+
}
107113
}
108114

109115
public static class Builder<T> {

src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertDSL.java

+6
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.mybatis.dynamic.sql.util.ConstantMapping;
2929
import org.mybatis.dynamic.sql.util.NullMapping;
3030
import org.mybatis.dynamic.sql.util.PropertyMapping;
31+
import org.mybatis.dynamic.sql.util.RowMapping;
3132
import org.mybatis.dynamic.sql.util.StringConstantMapping;
3233

3334
public class MultiRowInsertDSL<T> implements Buildable<MultiRowInsertModel<T>> {
@@ -102,6 +103,11 @@ public MultiRowInsertDSL<T> toStringConstant(String constant) {
102103
columnMappings.add(StringConstantMapping.of(column, constant));
103104
return MultiRowInsertDSL.this;
104105
}
106+
107+
public MultiRowInsertDSL<T> toRow() {
108+
columnMappings.add(RowMapping.of(column));
109+
return MultiRowInsertDSL.this;
110+
}
105111
}
106112

107113
public static class Builder<T> extends BatchInsertDSL.AbstractBuilder<T, Builder<T>> {

src/main/java/org/mybatis/dynamic/sql/insert/render/AbstractMultiRowValuePhraseVisitor.java

-69
This file was deleted.

src/main/java/org/mybatis/dynamic/sql/insert/render/BatchInsertRenderer.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ private BatchInsertRenderer(Builder<T> builder) {
3131
}
3232

3333
public BatchInsert<T> render() {
34-
BatchValuePhraseVisitor visitor = new BatchValuePhraseVisitor(renderingStrategy, "row"); //$NON-NLS-1$)
34+
MultiRowValuePhraseVisitor visitor = new MultiRowValuePhraseVisitor(renderingStrategy, "row"); //$NON-NLS-1$)
3535
FieldAndValueCollector collector = model.mapColumnMappings(m -> m.accept(visitor))
3636
.collect(FieldAndValueCollector.collect());
3737

src/main/java/org/mybatis/dynamic/sql/insert/render/MultiRowValuePhraseVisitor.java

+57-3
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,65 @@
1515
*/
1616
package org.mybatis.dynamic.sql.insert.render;
1717

18+
import org.mybatis.dynamic.sql.SqlColumn;
1819
import org.mybatis.dynamic.sql.render.RenderingStrategy;
20+
import org.mybatis.dynamic.sql.util.ConstantMapping;
21+
import org.mybatis.dynamic.sql.util.MultiRowInsertMappingVisitor;
22+
import org.mybatis.dynamic.sql.util.NullMapping;
23+
import org.mybatis.dynamic.sql.util.PropertyMapping;
24+
import org.mybatis.dynamic.sql.util.RowMapping;
25+
import org.mybatis.dynamic.sql.util.StringConstantMapping;
1926

20-
public class MultiRowValuePhraseVisitor extends AbstractMultiRowValuePhraseVisitor {
27+
public class MultiRowValuePhraseVisitor extends MultiRowInsertMappingVisitor<FieldAndValueAndParameters> {
28+
protected final RenderingStrategy renderingStrategy;
29+
protected final String prefix;
2130

22-
public MultiRowValuePhraseVisitor(RenderingStrategy renderingStrategy, String prefix) {
23-
super(renderingStrategy, prefix);
31+
protected MultiRowValuePhraseVisitor(RenderingStrategy renderingStrategy, String prefix) {
32+
this.renderingStrategy = renderingStrategy;
33+
this.prefix = prefix;
34+
}
35+
36+
@Override
37+
public FieldAndValueAndParameters visit(NullMapping mapping) {
38+
return FieldAndValueAndParameters.withFieldName(mapping.columnName())
39+
.withValuePhrase("null") //$NON-NLS-1$
40+
.build();
41+
}
42+
43+
@Override
44+
public FieldAndValueAndParameters visit(ConstantMapping mapping) {
45+
return FieldAndValueAndParameters.withFieldName(mapping.columnName())
46+
.withValuePhrase(mapping.constant())
47+
.build();
48+
}
49+
50+
@Override
51+
public FieldAndValueAndParameters visit(StringConstantMapping mapping) {
52+
return FieldAndValueAndParameters.withFieldName(mapping.columnName())
53+
.withValuePhrase("'" + mapping.constant() + "'") //$NON-NLS-1$ //$NON-NLS-2$
54+
.build();
55+
}
56+
57+
@Override
58+
public FieldAndValueAndParameters visit(PropertyMapping mapping) {
59+
return FieldAndValueAndParameters.withFieldName(mapping.columnName())
60+
.withValuePhrase(mapping.mapColumn(c -> calculateJdbcPlaceholder(c, mapping.property())))
61+
.build();
62+
}
63+
64+
@Override
65+
public FieldAndValueAndParameters visit(RowMapping mapping) {
66+
return FieldAndValueAndParameters.withFieldName(mapping.columnName())
67+
.withValuePhrase(mapping.mapColumn(this::calculateJdbcPlaceholder))
68+
.build();
69+
}
70+
71+
private String calculateJdbcPlaceholder(SqlColumn<?> column) {
72+
return column.renderingStrategy().orElse(renderingStrategy).getRecordBasedInsertBinding(column, prefix);
73+
}
74+
75+
private String calculateJdbcPlaceholder(SqlColumn<?> column, String parameterName) {
76+
return column.renderingStrategy().orElse(renderingStrategy)
77+
.getRecordBasedInsertBinding(column, prefix, parameterName);
2478
}
2579
}

src/main/java/org/mybatis/dynamic/sql/insert/render/ValuePhraseVisitor.java

+13
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.mybatis.dynamic.sql.util.NullMapping;
2525
import org.mybatis.dynamic.sql.util.PropertyMapping;
2626
import org.mybatis.dynamic.sql.util.PropertyWhenPresentMapping;
27+
import org.mybatis.dynamic.sql.util.RowMapping;
2728
import org.mybatis.dynamic.sql.util.StringConstantMapping;
2829

2930
public class ValuePhraseVisitor extends InsertMappingVisitor<Optional<FieldAndValueAndParameters>> {
@@ -71,6 +72,18 @@ public Optional<FieldAndValueAndParameters> visit(PropertyWhenPresentMapping map
7172
}
7273
}
7374

75+
@Override
76+
public Optional<FieldAndValueAndParameters> visit(RowMapping mapping) {
77+
return FieldAndValueAndParameters.withFieldName(mapping.columnName())
78+
.withValuePhrase(mapping.mapColumn(this::calculateJdbcPlaceholder))
79+
.buildOptional();
80+
}
81+
82+
private String calculateJdbcPlaceholder(SqlColumn<?> column) {
83+
return column.renderingStrategy().orElse(renderingStrategy)
84+
.getRecordBasedInsertBinding(column, "row"); //$NON-NLS-1$
85+
}
86+
7487
private String calculateJdbcPlaceholder(SqlColumn<?> column, String parameterName) {
7588
return column.renderingStrategy().orElse(renderingStrategy)
7689
.getRecordBasedInsertBinding(column, "row", parameterName); //$NON-NLS-1$

src/main/java/org/mybatis/dynamic/sql/render/MyBatis3RenderingStrategy.java

+10
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,16 @@ public String getFormattedJdbcPlaceholder(BindableColumn<?> column, String prefi
3939
+ "}"; //$NON-NLS-1$
4040
}
4141

42+
@Override
43+
public String getRecordBasedInsertBinding(BindableColumn<?> column, String parameterName) {
44+
return "#{" //$NON-NLS-1$
45+
+ parameterName
46+
+ renderJdbcType(column)
47+
+ renderJavaType(column)
48+
+ renderTypeHandler(column)
49+
+ "}"; //$NON-NLS-1$
50+
}
51+
4252
private String renderTypeHandler(BindableColumn<?> column) {
4353
return column.typeHandler()
4454
.map(th -> ",typeHandler=" + th) //$NON-NLS-1$

src/main/java/org/mybatis/dynamic/sql/render/RenderingStrategy.java

+20-3
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,29 @@ public String formatParameterMapKey(AtomicInteger sequence) {
9292
*
9393
* @param column column definition used for generating type details in a MyBatis binding. Ignored for Spring.
9494
* @param prefix parameter prefix used for locating the parameters in a SQL provider object. Typically, will be
95-
* {@link RenderingStrategy#DEFAULT_PARAMETER_PREFIX}. This is ignored for Spring.
96-
* @param parameterName name of the parameter. Typically generated by calling
97-
* {@link RenderingStrategy#formatParameterMapKey(AtomicInteger)}
95+
* either "row" or "records[x]" to match the properties of the generated statement object class.
96+
* @param parameterName name of the parameter. Typically, this is a property in the row class associated with the
97+
* insert statement.
9898
* @return the generated binding
9999
*/
100100
public String getRecordBasedInsertBinding(BindableColumn<?> column, String prefix, String parameterName) {
101101
return getFormattedJdbcPlaceholder(column, prefix, parameterName);
102102
}
103+
104+
/**
105+
* This method generates a binding for a parameter to a placeholder in a record based insert statement.
106+
*
107+
* <p>This binding is specifically for use with insert, batch insert, and multirow insert statements and the
108+
* MapToRow mapping. These statements bind parameters to the row class directly.
109+
*
110+
* <p>For MyBatis, a binding looks like this: "#{parameterName,jdbcType=xxx,typeHandler=xxx,javaType=xxx}"
111+
*
112+
* <p>For Spring, a binding looks like this: ":parameterName"
113+
*
114+
* @param column column definition used for generating type details in a MyBatis binding. Ignored for Spring.
115+
* @param parameterName name of the parameter. Typically, will be
116+
* either "row" or "records[x]" to match the properties of the generated statement object class.
117+
* @return the generated binding
118+
*/
119+
public abstract String getRecordBasedInsertBinding(BindableColumn<?> column, String parameterName);
103120
}

src/main/java/org/mybatis/dynamic/sql/render/SpringNamedParameterRenderingStrategy.java

+5
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,9 @@ public String getFormattedJdbcPlaceholder(String prefix, String parameterName) {
3333
public String getRecordBasedInsertBinding(BindableColumn<?> column, String prefix, String parameterName) {
3434
return ":" + prefix + "." + parameterName; //$NON-NLS-1$ //$NON-NLS-2$
3535
}
36+
37+
@Override
38+
public String getRecordBasedInsertBinding(BindableColumn<?> column, String parameterName) {
39+
return ":" + parameterName; //$NON-NLS-1$
40+
}
3641
}

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,7 @@ public interface ColumnMappingVisitor<R> {
4949

5050
R visit(PropertyWhenPresentMapping mapping);
5151

52-
R visit(ColumnToColumnMapping columnMapping);
52+
R visit(ColumnToColumnMapping mapping);
53+
54+
R visit(RowMapping mapping);
5355
}

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

+5
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,9 @@ public final R visit(PropertyWhenPresentMapping mapping) {
3535
public final R visit(ColumnToColumnMapping columnMapping) {
3636
throw new UnsupportedOperationException(Messages.getInternalErrorString(InternalError.INTERNAL_ERROR_4));
3737
}
38+
39+
@Override
40+
public final R visit(RowMapping mapping) {
41+
throw new UnsupportedOperationException(Messages.getInternalErrorString(InternalError.INTERNAL_ERROR_14));
42+
}
3843
}

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ public enum InternalError {
3131
INTERNAL_ERROR_10(10),
3232
INTERNAL_ERROR_11(11),
3333
INTERNAL_ERROR_12(12),
34-
INTERNAL_ERROR_13(13);
34+
INTERNAL_ERROR_13(13),
35+
INTERNAL_ERROR_14(14),
36+
INTERNAL_ERROR_15(15);
3537

3638
private final int number;
3739

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright 2016-2023 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.util;
17+
18+
import org.mybatis.dynamic.sql.SqlColumn;
19+
20+
public class RowMapping extends AbstractColumnMapping {
21+
private RowMapping(SqlColumn<?> column) {
22+
super(column);
23+
}
24+
25+
public static RowMapping of(SqlColumn<?> column) {
26+
return new RowMapping(column);
27+
}
28+
29+
@Override
30+
public <R> R accept(ColumnMappingVisitor<R> visitor) {
31+
return visitor.visit(this);
32+
}
33+
}

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

+5
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,9 @@ public final R visit(PropertyMapping mapping) {
2525
public final R visit(PropertyWhenPresentMapping mapping) {
2626
throw new UnsupportedOperationException(Messages.getInternalErrorString(InternalError.INTERNAL_ERROR_11));
2727
}
28+
29+
@Override
30+
public final R visit(RowMapping mapping) {
31+
throw new UnsupportedOperationException(Messages.getInternalErrorString(InternalError.INTERNAL_ERROR_15));
32+
}
2833
}

0 commit comments

Comments
 (0)