1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.mybatis.generator.runtime.kotlin.elements;
17
18 import static org.mybatis.generator.api.dom.OutputUtilities.kotlinIndent;
19 import static org.mybatis.generator.internal.util.StringUtility.escapeStringForKotlin;
20 import static org.mybatis.generator.internal.util.StringUtility.stringHasValue;
21
22 import java.util.HashSet;
23 import java.util.Iterator;
24 import java.util.List;
25 import java.util.Set;
26
27 import org.mybatis.generator.api.IntrospectedColumn;
28 import org.mybatis.generator.api.IntrospectedTable;
29 import org.mybatis.generator.api.dom.kotlin.FullyQualifiedKotlinType;
30 import org.mybatis.generator.api.dom.kotlin.JavaToKotlinTypeConverter;
31 import org.mybatis.generator.api.dom.kotlin.KotlinArg;
32 import org.mybatis.generator.codegen.mybatis3.ListUtilities;
33 import org.mybatis.generator.config.GeneratedKey;
34 import org.mybatis.generator.runtime.kotlin.KotlinDynamicSqlSupportClassGenerator;
35
36 public class KotlinFragmentGenerator {
37
38 private final IntrospectedTable introspectedTable;
39 private final String resultMapId;
40 private final String supportObjectImport;
41 private final String tableFieldName;
42
43 private KotlinFragmentGenerator(Builder builder) {
44 introspectedTable = builder.introspectedTable;
45 resultMapId = builder.resultMapId;
46 supportObjectImport = builder.supportObjectImport;
47 tableFieldName = builder.tableFieldName;
48 }
49
50 public KotlinFunctionParts getPrimaryKeyWhereClauseAndParameters(boolean forUpdate) {
51 KotlinFunctionParts.Builder builder = new KotlinFunctionParts.Builder();
52
53 int columnCount = introspectedTable.getPrimaryKeyColumns().size();
54 boolean first = true;
55 for (IntrospectedColumn column : introspectedTable.getPrimaryKeyColumns()) {
56 String argName;
57 if (forUpdate) {
58 argName = "row." + column.getJavaProperty() + "!!";
59 } else {
60 argName = column.getJavaProperty() + "_";
61 FullyQualifiedKotlinType kt = JavaToKotlinTypeConverter.convert(column.getFullyQualifiedJavaType());
62 builder.withImports(kt.getImportList());
63 builder.withArgument(KotlinArg.newArg(argName)
64 .withDataType(kt.getShortNameWithTypeArguments())
65 .build());
66 }
67
68 AbstractKotlinFunctionGenerator.FieldNameAndImport fieldNameAndImport =
69 AbstractKotlinFunctionGenerator.calculateFieldNameAndImport(tableFieldName,
70 supportObjectImport, column);
71
72 builder.withImport(fieldNameAndImport.importString());
73 if(columnCount == 1) {
74 builder.withCodeLine(singleColumnWhere(fieldNameAndImport.fieldName(), argName));
75 first = false;
76 } else if (first) {
77 builder.withCodeLine(" where {");
78 builder.withCodeLine(multiColumnWhere(fieldNameAndImport.fieldName(), argName));
79 first = false;
80 } else {
81 builder.withCodeLine(multiColumnAnd(fieldNameAndImport.fieldName(), argName));
82 }
83 }
84 if (columnCount > 1) {
85 builder.withCodeLine(" }");
86 }
87
88 return builder.build();
89 }
90
91 private String singleColumnWhere(String columName, String property) {
92 return " where { " + composeIsEqualTo(columName, property) + " }";
93 }
94
95 private String multiColumnWhere(String columName, String property) {
96 return " " + composeIsEqualTo(columName, property);
97 }
98
99 private String multiColumnAnd(String columName, String property) {
100 return " and { " + composeIsEqualTo(columName, property) + " }";
101 }
102
103 private String composeIsEqualTo(String columName, String property) {
104 return columName + " isEqualTo " + property;
105 }
106
107 public KotlinFunctionParts getAnnotatedResults() {
108 KotlinFunctionParts.Builder builder = new KotlinFunctionParts.Builder();
109
110 builder.withImport("org.apache.ibatis.type.JdbcType");
111 builder.withImport("org.apache.ibatis.annotations.Result");
112 builder.withImport("org.apache.ibatis.annotations.Results");
113
114 builder.withAnnotation("@Results(id=\"" + resultMapId + "\", value = [");
115
116 StringBuilder sb = new StringBuilder();
117
118 Set<String> imports = new HashSet<>();
119 Iterator<IntrospectedColumn> iterPk = introspectedTable.getPrimaryKeyColumns().iterator();
120 Iterator<IntrospectedColumn> iterNonPk = introspectedTable.getNonPrimaryKeyColumns().iterator();
121 while (iterPk.hasNext()) {
122 IntrospectedColumn introspectedColumn = iterPk.next();
123 sb.setLength(0);
124 kotlinIndent(sb, 1);
125 sb.append(getResultAnnotation(imports, introspectedColumn, true));
126
127 if (iterPk.hasNext() || iterNonPk.hasNext()) {
128 sb.append(',');
129 }
130
131 builder.withAnnotation(sb.toString());
132 }
133
134 while (iterNonPk.hasNext()) {
135 IntrospectedColumn introspectedColumn = iterNonPk.next();
136 sb.setLength(0);
137 kotlinIndent(sb, 1);
138 sb.append(getResultAnnotation(imports, introspectedColumn, false));
139
140 if (iterNonPk.hasNext()) {
141 sb.append(',');
142 }
143
144 builder.withAnnotation(sb.toString());
145 }
146
147 builder.withAnnotation("])")
148 .withImports(imports);
149
150 return builder.build();
151 }
152
153 private String getResultAnnotation(Set<String> imports, IntrospectedColumn introspectedColumn,
154 boolean idColumn) {
155 StringBuilder sb = new StringBuilder();
156 sb.append("Result(column=\"");
157 sb.append(escapeStringForKotlin(introspectedColumn.getActualColumnName()));
158 sb.append("\", property=\"");
159 sb.append(introspectedColumn.getJavaProperty());
160 sb.append('\"');
161
162 if (stringHasValue(introspectedColumn.getTypeHandler())) {
163 FullyQualifiedKotlinType fqjt =
164 new FullyQualifiedKotlinType(introspectedColumn.getTypeHandler());
165 imports.add(introspectedColumn.getTypeHandler());
166 sb.append(", typeHandler=");
167 sb.append(fqjt.getShortNameWithoutTypeArguments());
168 sb.append("::class");
169 }
170
171 sb.append(", jdbcType=JdbcType.");
172 sb.append(introspectedColumn.getJdbcTypeName());
173 if (idColumn) {
174 sb.append(", id=true");
175 }
176 sb.append(')');
177
178 return sb.toString();
179 }
180
181 public KotlinFunctionParts getGeneratedKeyAnnotation(GeneratedKey gk) {
182 KotlinFunctionParts.Builder builder = new KotlinFunctionParts.Builder();
183
184 StringBuilder sb = new StringBuilder();
185 introspectedTable.getColumn(gk.getColumn()).ifPresent(introspectedColumn -> {
186 if (gk.isJdbcStandard()) {
187 builder.withImport("org.apache.ibatis.annotations.Options");
188 sb.append("@Options(useGeneratedKeys=true,keyProperty=\"row.");
189 sb.append(introspectedColumn.getJavaProperty());
190 sb.append("\")");
191 builder.withAnnotation(sb.toString());
192 } else {
193 builder.withImport("org.apache.ibatis.annotations.SelectKey");
194 FullyQualifiedKotlinType kt =
195 JavaToKotlinTypeConverter.convert(introspectedColumn.getFullyQualifiedJavaType());
196
197 sb.append("@SelectKey(statement=[\"");
198 sb.append(gk.getRuntimeSqlStatement());
199 sb.append("\"], keyProperty=\"row.");
200 sb.append(introspectedColumn.getJavaProperty());
201 sb.append("\", before=");
202 sb.append(gk.isIdentity() ? "false" : "true");
203 sb.append(", resultType=");
204 sb.append(kt.getShortNameWithoutTypeArguments());
205 sb.append("::class)");
206 builder.withAnnotation(sb.toString());
207 }
208 });
209
210 return builder.build();
211 }
212
213 public KotlinFunctionParts getSetEqualLines(List<IntrospectedColumn> columnList) {
214
215 KotlinFunctionParts.Builder builder = new KotlinFunctionParts.Builder();
216
217 List<IntrospectedColumn> columns = ListUtilities.removeIdentityAndGeneratedAlwaysColumns(columnList);
218 for (IntrospectedColumn column : columns) {
219 AbstractKotlinFunctionGenerator.FieldNameAndImport fieldNameAndImport =
220 AbstractKotlinFunctionGenerator.calculateFieldNameAndImport(tableFieldName,
221 supportObjectImport, column);
222 builder.withImport(fieldNameAndImport.importString());
223
224 builder.withCodeLine(" set(" + fieldNameAndImport.fieldName()
225 + ") equalToOrNull row::" + column.getJavaProperty());
226 }
227
228 return builder.build();
229 }
230
231 public KotlinFunctionParts getSetEqualWhenPresentLines(List<IntrospectedColumn> columnList) {
232
233 KotlinFunctionParts.Builder builder = new KotlinFunctionParts.Builder();
234
235 List<IntrospectedColumn> columns = ListUtilities.removeIdentityAndGeneratedAlwaysColumns(columnList);
236 for (IntrospectedColumn column : columns) {
237 AbstractKotlinFunctionGenerator.FieldNameAndImport fieldNameAndImport =
238 AbstractKotlinFunctionGenerator.calculateFieldNameAndImport(tableFieldName,
239 supportObjectImport, column);
240 builder.withImport(fieldNameAndImport.importString());
241
242 builder.withCodeLine(" set(" + fieldNameAndImport.fieldName()
243 + ") equalToWhenPresent row::" + column.getJavaProperty());
244 }
245
246 return builder.build();
247 }
248
249 public static class Builder {
250 private IntrospectedTable introspectedTable;
251 private String resultMapId;
252 private String supportObjectImport;
253 private String tableFieldName;
254
255 public Builder withIntrospectedTable(IntrospectedTable introspectedTable) {
256 this.introspectedTable = introspectedTable;
257 return this;
258 }
259
260 public Builder withResultMapId(String resultMapId) {
261 this.resultMapId = resultMapId;
262 return this;
263 }
264
265 public Builder withDynamicSqlSupportClassGenerator(KotlinDynamicSqlSupportClassGenerator generator) {
266 supportObjectImport = generator.getSupportObjectImport();
267 return this;
268 }
269
270 public Builder withTableFieldName(String tableFieldName) {
271 this.tableFieldName = tableFieldName;
272 return this;
273 }
274
275 public KotlinFragmentGenerator build() {
276 return new KotlinFragmentGenerator(this);
277 }
278 }
279 }