1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.mybatis.generator.config;
17
18 import static org.mybatis.generator.internal.util.StringUtility.composeFullyQualifiedTableName;
19 import static org.mybatis.generator.internal.util.StringUtility.isTrue;
20 import static org.mybatis.generator.internal.util.StringUtility.stringHasValue;
21
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Objects;
28 import java.util.Optional;
29 import java.util.Properties;
30
31 import org.jspecify.annotations.Nullable;
32 import org.mybatis.generator.api.KnownRuntime;
33 import org.mybatis.generator.internal.util.messages.Messages;
34
35 public class TableConfiguration extends PropertyHolder {
36 private final boolean insertStatementEnabled;
37 private final boolean selectByPrimaryKeyStatementEnabled;
38 private final boolean selectByExampleStatementEnabled;
39 private final boolean updateByPrimaryKeyStatementEnabled;
40 private final boolean deleteByPrimaryKeyStatementEnabled;
41 private final boolean deleteByExampleStatementEnabled;
42 private final boolean countByExampleStatementEnabled;
43 private final boolean updateByExampleStatementEnabled;
44 private final List<ColumnOverride> columnOverrides;
45
46
47 private final Map<IgnoredColumn, Boolean> ignoredColumns;
48 private final @Nullable GeneratedKey generatedKey;
49 private final @Nullable String catalog;
50 private final @Nullable String schema;
51 private final String tableName;
52 private final @Nullable String domainObjectName;
53 private final @Nullable String alias;
54 private final @Nullable ModelType modelType;
55 private final boolean wildcardEscapingEnabled;
56 private final boolean delimitIdentifiers;
57 private final @Nullable DomainObjectRenamingRule domainObjectRenamingRule;
58 private final @Nullable ColumnRenamingRule columnRenamingRule;
59 private final boolean isAllColumnDelimitingEnabled;
60 private final @Nullable String mapperName;
61 private final @Nullable String sqlProviderName;
62 private final List<IgnoredColumnPattern> ignoredColumnPatterns;
63 private final String fullyQualifiedName;
64
65 protected TableConfiguration(Builder builder) {
66 super(builder);
67
68 catalog = builder.catalog;
69 schema = builder.schema;
70 tableName = Objects.requireNonNull(builder.tableName);
71 domainObjectName = builder.domainObjectName;
72 alias = builder.alias;
73 modelType = builder.modelType;
74 insertStatementEnabled = builder.insertStatementEnabled;
75 selectByPrimaryKeyStatementEnabled = builder.selectByPrimaryKeyStatementEnabled;
76 selectByExampleStatementEnabled = builder.selectByExampleStatementEnabled;
77 updateByPrimaryKeyStatementEnabled = builder.updateByPrimaryKeyStatementEnabled;
78 deleteByPrimaryKeyStatementEnabled = builder.deleteByPrimaryKeyStatementEnabled;
79 deleteByExampleStatementEnabled = builder.deleteByExampleStatementEnabled;
80 countByExampleStatementEnabled = builder.countByExampleStatementEnabled;
81 updateByExampleStatementEnabled = builder.updateByExampleStatementEnabled;
82 wildcardEscapingEnabled = builder.wildcardEscapingEnabled;
83 delimitIdentifiers = builder.delimitIdentifiers;
84 isAllColumnDelimitingEnabled = builder.isAllColumnDelimitingEnabled;
85 mapperName = builder.mapperName;
86 sqlProviderName = builder.sqlProviderName;
87 columnOverrides = Collections.unmodifiableList(builder.columnOverrides);
88 ignoredColumns = builder.ignoredColumns;
89 generatedKey = builder.generatedKey;
90 domainObjectRenamingRule = builder.domainObjectRenamingRule;
91 columnRenamingRule = builder.columnRenamingRule;
92 ignoredColumnPatterns = Collections.unmodifiableList(builder.ignoredColumnPatterns);
93 fullyQualifiedName = composeFullyQualifiedTableName(catalog, schema, tableName, '.');
94 }
95
96 public boolean isDeleteByPrimaryKeyStatementEnabled() {
97 return deleteByPrimaryKeyStatementEnabled;
98 }
99
100 public boolean isInsertStatementEnabled() {
101 return insertStatementEnabled;
102 }
103
104 public boolean isSelectByPrimaryKeyStatementEnabled() {
105 return selectByPrimaryKeyStatementEnabled;
106 }
107
108 public boolean isUpdateByPrimaryKeyStatementEnabled() {
109 return updateByPrimaryKeyStatementEnabled;
110 }
111
112 public boolean isColumnIgnored(String columnName) {
113 for (Map.Entry<IgnoredColumn, Boolean> entry : ignoredColumns.entrySet()) {
114 if (entry.getKey().matches(columnName)) {
115 entry.setValue(Boolean.TRUE);
116 return true;
117 }
118 }
119
120 for (IgnoredColumnPattern ignoredColumnPattern : ignoredColumnPatterns) {
121 if (ignoredColumnPattern.matches(columnName)) {
122 return true;
123 }
124 }
125
126 return false;
127 }
128
129 @Override
130 public boolean equals(Object obj) {
131 if (this == obj) {
132 return true;
133 }
134
135 if (!(obj instanceof TableConfiguration other)) {
136 return false;
137 }
138
139 return Objects.equals(this.catalog, other.catalog)
140 && Objects.equals(this.schema, other.schema)
141 && Objects.equals(this.tableName, other.tableName);
142 }
143
144 @Override
145 public int hashCode() {
146 return Objects.hash(catalog, schema, tableName);
147 }
148
149 public boolean isSelectByExampleStatementEnabled() {
150 return selectByExampleStatementEnabled;
151 }
152
153
154
155
156
157
158
159
160 public Optional<ColumnOverride> getColumnOverride(String columnName) {
161 for (ColumnOverride co : columnOverrides) {
162 if (co.isColumnNameDelimited()) {
163 if (columnName.equals(co.getColumnName())) {
164 return Optional.of(co);
165 }
166 } else {
167 if (columnName.equalsIgnoreCase(co.getColumnName())) {
168 return Optional.of(co);
169 }
170 }
171 }
172
173 return Optional.empty();
174 }
175
176 public Optional<GeneratedKey> getGeneratedKey() {
177 return Optional.ofNullable(generatedKey);
178 }
179
180 public boolean isDeleteByExampleStatementEnabled() {
181 return deleteByExampleStatementEnabled;
182 }
183
184 public boolean areAnyStatementsEnabled() {
185 return selectByExampleStatementEnabled
186 || selectByPrimaryKeyStatementEnabled || insertStatementEnabled
187 || updateByPrimaryKeyStatementEnabled
188 || deleteByExampleStatementEnabled
189 || deleteByPrimaryKeyStatementEnabled
190 || countByExampleStatementEnabled
191 || updateByExampleStatementEnabled;
192 }
193
194 public @Nullable String getAlias() {
195 return alias;
196 }
197
198 public @Nullable String getCatalog() {
199 return catalog;
200 }
201
202 public @Nullable String getDomainObjectName() {
203 return domainObjectName;
204 }
205
206 public @Nullable String getSchema() {
207 return schema;
208 }
209
210 public String getTableName() {
211 return tableName;
212 }
213
214 public String getFullyQualifiedName() {
215 return fullyQualifiedName;
216 }
217
218 public List<ColumnOverride> getColumnOverrides() {
219 return columnOverrides;
220 }
221
222
223
224
225
226
227
228
229
230 public List<String> getIgnoredColumnsInError() {
231 List<String> answer = new ArrayList<>();
232
233 for (Map.Entry<IgnoredColumn, Boolean> entry : ignoredColumns.entrySet()) {
234 if (Boolean.FALSE.equals(entry.getValue())) {
235 answer.add(entry.getKey().getColumnName());
236 }
237 }
238
239 return answer;
240 }
241
242 public Optional<ModelType> getModelType() {
243 return Optional.ofNullable(modelType);
244 }
245
246 public boolean isWildcardEscapingEnabled() {
247 return wildcardEscapingEnabled;
248 }
249
250 @Override
251 public String toString() {
252 return fullyQualifiedName;
253 }
254
255 public boolean isDelimitIdentifiers() {
256 return delimitIdentifiers;
257 }
258
259 public boolean isCountByExampleStatementEnabled() {
260 return countByExampleStatementEnabled;
261 }
262
263 public boolean isUpdateByExampleStatementEnabled() {
264 return updateByExampleStatementEnabled;
265 }
266
267 public void validate(List<String> errors, int listPosition, Context context, KnownRuntime knownRuntime) {
268 if (!stringHasValue(tableName)) {
269 errors.add(Messages.getString(
270 "ValidationError.6", Integer.toString(listPosition)));
271 }
272
273 if (generatedKey != null) {
274
275 ModelType mt = getModelType().orElseGet(context::getDefaultModelType);
276 if (mt == ModelType.RECORD) {
277 errors.add(Messages.getString("ValidationError.30", fullyQualifiedName, context.getId(),
278 "record"));
279 }
280
281
282 if (isImmutable(context) && knownRuntime != KnownRuntime.MYBATIS3_KOTLIN) {
283 errors.add(Messages.getString("ValidationError.30", fullyQualifiedName, context.getId(),
284 "immutable"));
285 }
286
287 generatedKey.validate(errors, fullyQualifiedName, context.getId());
288 }
289
290 if (domainObjectRenamingRule != null) {
291 domainObjectRenamingRule.validate(errors, fullyQualifiedName);
292 }
293
294 if (columnRenamingRule != null) {
295 columnRenamingRule.validate(errors, fullyQualifiedName);
296 }
297
298 for (ColumnOverride columnOverride : columnOverrides) {
299 columnOverride.validate(errors, fullyQualifiedName);
300 }
301
302 for (IgnoredColumn ignoredColumn : ignoredColumns.keySet()) {
303 ignoredColumn.validate(errors, fullyQualifiedName);
304 }
305
306 for (IgnoredColumnPattern ignoredColumnPattern : ignoredColumnPatterns) {
307 ignoredColumnPattern.validate(errors, fullyQualifiedName);
308 }
309 }
310
311 public boolean isImmutable(Context context) {
312 Properties properties;
313
314 if (getProperties().containsKey(PropertyRegistry.ANY_IMMUTABLE)) {
315 properties = getProperties();
316 } else {
317 properties = context.getModelGeneratorConfiguration().getProperties();
318 }
319
320 return isTrue(properties.getProperty(PropertyRegistry.ANY_IMMUTABLE));
321 }
322
323 public boolean generateKotlinV1Model(Context context) {
324 Properties properties;
325
326 if (getProperties().containsKey(PropertyRegistry.GENERATE_KOTLIN_V1_MODEL)) {
327 properties = getProperties();
328 } else {
329 properties = context.getModelGeneratorConfiguration().getProperties();
330 }
331
332 return isTrue(properties.getProperty(PropertyRegistry.GENERATE_KOTLIN_V1_MODEL));
333 }
334
335 public @Nullable DomainObjectRenamingRule getDomainObjectRenamingRule() {
336 return domainObjectRenamingRule;
337 }
338
339 public Optional<ColumnRenamingRule> getColumnRenamingRule() {
340 return Optional.ofNullable(columnRenamingRule);
341 }
342
343 public boolean isAllColumnDelimitingEnabled() {
344 return isAllColumnDelimitingEnabled;
345 }
346
347 public @Nullable String getMapperName() {
348 return mapperName;
349 }
350
351 public @Nullable String getSqlProviderName() {
352 return sqlProviderName;
353 }
354
355 public @Nullable String getDynamicSqlSupportClassName() {
356 return getProperty(PropertyRegistry.TABLE_DYNAMIC_SQL_SUPPORT_CLASS_NAME);
357 }
358
359 public @Nullable String getDynamicSqlTableObjectName() {
360 return getProperty(PropertyRegistry.TABLE_DYNAMIC_SQL_TABLE_OBJECT_NAME);
361 }
362
363 public static class Builder extends AbstractBuilder<Builder> {
364 private @Nullable ModelType modelType;
365 private @Nullable String catalog;
366 private @Nullable String schema;
367 private @Nullable String tableName;
368 private @Nullable String domainObjectName;
369 private @Nullable String alias;
370 private boolean insertStatementEnabled = true;
371 private boolean selectByPrimaryKeyStatementEnabled = true;
372 private boolean selectByExampleStatementEnabled = true;
373 private boolean updateByPrimaryKeyStatementEnabled = true;
374 private boolean deleteByPrimaryKeyStatementEnabled = true;
375 private boolean deleteByExampleStatementEnabled = true;
376 private boolean countByExampleStatementEnabled = true;
377 private boolean updateByExampleStatementEnabled = true;
378 private boolean wildcardEscapingEnabled;
379 private boolean delimitIdentifiers;
380 private boolean isAllColumnDelimitingEnabled;
381 private @Nullable String mapperName;
382 private @Nullable String sqlProviderName;
383 private @Nullable GeneratedKey generatedKey;
384 private @Nullable DomainObjectRenamingRule domainObjectRenamingRule;
385 private @Nullable ColumnRenamingRule columnRenamingRule;
386 private final List<IgnoredColumnPattern> ignoredColumnPatterns = new ArrayList<>();
387 private final List<ColumnOverride> columnOverrides = new ArrayList<>();
388 private final Map<IgnoredColumn, Boolean> ignoredColumns = new HashMap<>();
389
390 public TableConfiguration build() {
391 return new TableConfiguration(this);
392 }
393
394 @Override
395 protected Builder getThis() {
396 return this;
397 }
398
399 public Builder withModelType(@Nullable String tableModelType) {
400 this.modelType = tableModelType == null ? null : ModelType.getModelType(tableModelType);
401 return getThis();
402 }
403
404 public Builder withCatalog(@Nullable String catalog) {
405 this.catalog = catalog;
406 return this;
407 }
408
409 public Builder withSchema(@Nullable String schema) {
410 this.schema = schema;
411 return this;
412 }
413
414 public Builder withTableName(@Nullable String tableName) {
415 this.tableName = tableName;
416 return this;
417 }
418
419 public Builder withDomainObjectName(@Nullable String domainObjectName) {
420 this.domainObjectName = domainObjectName;
421 return this;
422 }
423
424 public Builder withAlias(@Nullable String alias) {
425 this.alias = alias;
426 return this;
427 }
428
429 @SuppressWarnings("UnusedReturnValue")
430 public Builder withInsertStatementEnabled(boolean insertStatementEnabled) {
431 this.insertStatementEnabled = insertStatementEnabled;
432 return this;
433 }
434
435 @SuppressWarnings("UnusedReturnValue")
436 public Builder withSelectByPrimaryKeyStatementEnabled(boolean selectByPrimaryKeyStatementEnabled) {
437 this.selectByPrimaryKeyStatementEnabled = selectByPrimaryKeyStatementEnabled;
438 return this;
439 }
440
441 @SuppressWarnings("UnusedReturnValue")
442 public Builder withSelectByExampleStatementEnabled(boolean selectByExampleStatementEnabled) {
443 this.selectByExampleStatementEnabled = selectByExampleStatementEnabled;
444 return this;
445 }
446
447 @SuppressWarnings("UnusedReturnValue")
448 public Builder withUpdateByPrimaryKeyStatementEnabled(boolean updateByPrimaryKeyStatementEnabled) {
449 this.updateByPrimaryKeyStatementEnabled = updateByPrimaryKeyStatementEnabled;
450 return this;
451 }
452
453 @SuppressWarnings("UnusedReturnValue")
454 public Builder withDeleteByPrimaryKeyStatementEnabled(boolean deleteByPrimaryKeyStatementEnabled) {
455 this.deleteByPrimaryKeyStatementEnabled = deleteByPrimaryKeyStatementEnabled;
456 return this;
457 }
458
459 @SuppressWarnings("UnusedReturnValue")
460 public Builder withDeleteByExampleStatementEnabled(boolean deleteByExampleStatementEnabled) {
461 this.deleteByExampleStatementEnabled = deleteByExampleStatementEnabled;
462 return this;
463 }
464
465 @SuppressWarnings("UnusedReturnValue")
466 public Builder withCountByExampleStatementEnabled(boolean countByExampleStatementEnabled) {
467 this.countByExampleStatementEnabled = countByExampleStatementEnabled;
468 return this;
469 }
470
471 @SuppressWarnings("UnusedReturnValue")
472 public Builder withUpdateByExampleStatementEnabled(boolean updateByExampleStatementEnabled) {
473 this.updateByExampleStatementEnabled = updateByExampleStatementEnabled;
474 return this;
475 }
476
477 @SuppressWarnings("UnusedReturnValue")
478 public Builder withWildcardEscapingEnabled(boolean wildcardEscapingEnabled) {
479 this.wildcardEscapingEnabled = wildcardEscapingEnabled;
480 return this;
481 }
482
483 @SuppressWarnings("UnusedReturnValue")
484 public Builder withDelimitIdentifiers(boolean delimitIdentifiers) {
485 this.delimitIdentifiers = delimitIdentifiers;
486 return this;
487 }
488
489 @SuppressWarnings("UnusedReturnValue")
490 public Builder withAllColumnDelimitingEnabled(boolean isAllColumnDelimitingEnabled) {
491 this.isAllColumnDelimitingEnabled = isAllColumnDelimitingEnabled;
492 return this;
493 }
494
495 public Builder withMapperName(@Nullable String mapperName) {
496 this.mapperName = mapperName;
497 return this;
498 }
499
500 public Builder withSqlProviderName(@Nullable String sqlProviderName) {
501 this.sqlProviderName = sqlProviderName;
502 return this;
503 }
504
505 @SuppressWarnings("UnusedReturnValue")
506 public Builder withGeneratedKey(@Nullable GeneratedKey generatedKey) {
507 this.generatedKey = generatedKey;
508 return this;
509 }
510
511 @SuppressWarnings("UnusedReturnValue")
512 public Builder withDomainObjectRenamingRule(@Nullable DomainObjectRenamingRule domainObjectRenamingRule) {
513 this.domainObjectRenamingRule = domainObjectRenamingRule;
514 return this;
515 }
516
517 @SuppressWarnings("UnusedReturnValue")
518 public Builder withColumnRenamingRule(@Nullable ColumnRenamingRule columnRenamingRule) {
519 this.columnRenamingRule = columnRenamingRule;
520 return this;
521 }
522
523 @SuppressWarnings("UnusedReturnValue")
524 public Builder withIgnoredColumnPattern(IgnoredColumnPattern ignoredColumnPattern) {
525 this.ignoredColumnPatterns.add(ignoredColumnPattern);
526 return this;
527 }
528
529 @SuppressWarnings("UnusedReturnValue")
530 public Builder withIgnoredColumn(IgnoredColumn ignoredColumn) {
531 this.ignoredColumns.put(ignoredColumn, Boolean.FALSE);
532 return this;
533 }
534
535 @SuppressWarnings("UnusedReturnValue")
536 public Builder withColumnOverride(ColumnOverride columnOverride) {
537 this.columnOverrides.add(columnOverride);
538 return this;
539 }
540 }
541 }