1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.mybatis.generator.api;
17
18 import java.util.ArrayList;
19 import java.util.Iterator;
20 import java.util.List;
21 import java.util.Objects;
22 import java.util.Optional;
23 import java.util.function.Function;
24 import java.util.stream.Stream;
25
26 import org.jspecify.annotations.Nullable;
27 import org.mybatis.generator.internal.PluginAggregator;
28 import org.mybatis.generator.internal.rules.ConditionalModelRules;
29 import org.mybatis.generator.internal.rules.FlatModelRules;
30 import org.mybatis.generator.internal.rules.HierarchicalModelRules;
31 import org.mybatis.generator.internal.rules.Rules;
32
33
34
35
36
37
38
39
40 public class IntrospectedTable extends CodeGenerationAttributes {
41 protected final List<IntrospectedColumn> primaryKeyColumns = new ArrayList<>();
42 protected final List<IntrospectedColumn> baseColumns = new ArrayList<>();
43 protected final List<IntrospectedColumn> blobColumns = new ArrayList<>();
44
45
46
47
48 protected @Nullable String remarks;
49
50
51
52
53
54
55 protected @Nullable String tableType;
56
57 protected IntrospectedTable(Builder builder) {
58 super(builder);
59 Objects.requireNonNull(builder.pluginAggregator);
60 builder.pluginAggregator.initialized(this);
61 }
62
63 public Optional<IntrospectedColumn> getColumn(String columnName) {
64 return Stream.of(primaryKeyColumns.stream(), baseColumns.stream(), blobColumns.stream())
65 .flatMap(Function.identity())
66 .filter(ic -> columnMatches(ic, columnName))
67 .findFirst();
68 }
69
70 private boolean columnMatches(IntrospectedColumn introspectedColumn, String columnName) {
71 if (introspectedColumn.isColumnNameDelimited()) {
72 return introspectedColumn.getActualColumnName().equals(columnName);
73 } else {
74 return introspectedColumn.getActualColumnName().equalsIgnoreCase(columnName);
75 }
76 }
77
78
79
80
81
82
83
84 public boolean hasJDBCDateColumns() {
85 return Stream.of(primaryKeyColumns.stream(), baseColumns.stream())
86 .flatMap(Function.identity())
87 .anyMatch(IntrospectedColumn::isJDBCDateColumn);
88 }
89
90
91
92
93
94
95
96 public boolean hasJDBCTimeColumns() {
97 return Stream.of(primaryKeyColumns.stream(), baseColumns.stream())
98 .flatMap(Function.identity())
99 .anyMatch(IntrospectedColumn::isJDBCTimeColumn);
100 }
101
102
103
104
105
106
107
108
109 public List<IntrospectedColumn> getPrimaryKeyColumns() {
110 return primaryKeyColumns;
111 }
112
113 public boolean hasPrimaryKeyColumns() {
114 return !primaryKeyColumns.isEmpty();
115 }
116
117 public List<IntrospectedColumn> getBaseColumns() {
118 return baseColumns;
119 }
120
121
122
123
124
125
126
127 public List<IntrospectedColumn> getAllColumns() {
128 return Stream.of(primaryKeyColumns.stream(), baseColumns.stream(), blobColumns.stream())
129 .flatMap(Function.identity())
130 .toList();
131 }
132
133
134
135
136
137
138 public List<IntrospectedColumn> getNonBLOBColumns() {
139 return Stream.of(primaryKeyColumns.stream(), baseColumns.stream())
140 .flatMap(Function.identity())
141 .toList();
142 }
143
144 public int getColumnCount() {
145 return primaryKeyColumns.size() + baseColumns.size() + blobColumns.size();
146 }
147
148 public int getNonBLOBColumnCount() {
149 return primaryKeyColumns.size() + baseColumns.size();
150 }
151
152 public List<IntrospectedColumn> getNonPrimaryKeyColumns() {
153 return Stream.of(baseColumns.stream(), blobColumns.stream())
154 .flatMap(Function.identity())
155 .toList();
156 }
157
158 public List<IntrospectedColumn> getBLOBColumns() {
159 return blobColumns;
160 }
161
162 public boolean hasBLOBColumns() {
163 return !blobColumns.isEmpty();
164 }
165
166 public boolean hasBaseColumns() {
167 return !baseColumns.isEmpty();
168 }
169
170 public boolean hasAnyColumns() {
171 return hasPrimaryKeyColumns() || hasBaseColumns() || hasBLOBColumns();
172 }
173
174 public void addColumn(IntrospectedColumn introspectedColumn) {
175 if (introspectedColumn.isBLOBColumn()) {
176 blobColumns.add(introspectedColumn);
177 } else {
178 baseColumns.add(introspectedColumn);
179 }
180
181 introspectedColumn.setIntrospectedTable(this);
182 }
183
184 public void addPrimaryKeyColumn(String columnName) {
185 boolean found = false;
186
187 Iterator<IntrospectedColumn> iter = baseColumns.iterator();
188 while (iter.hasNext()) {
189 IntrospectedColumn introspectedColumn = iter.next();
190 if (introspectedColumn.getActualColumnName().equals(columnName)) {
191 primaryKeyColumns.add(introspectedColumn);
192 iter.remove();
193 found = true;
194 break;
195 }
196 }
197
198
199 if (!found) {
200 iter = blobColumns.iterator();
201 while (iter.hasNext()) {
202 IntrospectedColumn introspectedColumn = iter.next();
203 if (introspectedColumn.getActualColumnName().equals(columnName)) {
204 primaryKeyColumns.add(introspectedColumn);
205 iter.remove();
206 break;
207 }
208 }
209 }
210 }
211
212 public Optional<String> getRemarks() {
213 return Optional.ofNullable(remarks);
214 }
215
216 public void setRemarks(String remarks) {
217 this.remarks = remarks;
218 }
219
220 public String getTableType() {
221 return Objects.requireNonNull(tableType);
222 }
223
224 public void setTableType(String tableType) {
225 this.tableType = tableType;
226 }
227
228 @Override
229 protected Rules calculateRules() {
230 if (knownRuntime.isDynamicSqlBased() || knownRuntime == KnownRuntime.MYBATIS3_SIMPLE) {
231 return new FlatModelRules(this);
232 }
233
234 return switch (getModelType()) {
235 case HIERARCHICAL -> new HierarchicalModelRules(this);
236 case FLAT, RECORD -> new FlatModelRules(this);
237 case CONDITIONAL -> new ConditionalModelRules(this);
238 };
239 }
240
241 public static class Builder extends AbstractBuilder<Builder> {
242 private @Nullable PluginAggregator pluginAggregator;
243
244 public Builder withPluginAggregator(PluginAggregator pluginAggregator) {
245 this.pluginAggregator = pluginAggregator;
246 return this;
247 }
248
249 public IntrospectedTable build() {
250 return new IntrospectedTable(this);
251 }
252
253 @Override
254 protected Builder getThis() {
255 return this;
256 }
257 }
258 }