View Javadoc
1   /*
2    *    Copyright 2006-2026 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.generator.internal.rules;
17  
18  import org.mybatis.generator.api.IntrospectedTable;
19  import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
20  import org.mybatis.generator.config.GeneratedKey;
21  import org.mybatis.generator.config.PropertyRegistry;
22  import org.mybatis.generator.config.TableConfiguration;
23  import org.mybatis.generator.internal.util.StringUtility;
24  import org.mybatis.generator.runtime.mybatis3.ListUtilities;
25  
26  /**
27   * This class centralizes all the rules related to code generation - including
28   * the methods and objects to create, and certain attributes related to those
29   * objects.
30   *
31   * @author Jeff Butler
32   */
33  public abstract class BaseRules implements Rules {
34      protected final TableConfiguration tableConfiguration;
35      protected final IntrospectedTable introspectedTable;
36      protected final boolean isModelOnly;
37  
38      protected BaseRules(IntrospectedTable introspectedTable) {
39          this.introspectedTable = introspectedTable;
40          this.tableConfiguration = introspectedTable.getTableConfiguration();
41          String modelOnly = tableConfiguration.getProperty(PropertyRegistry.TABLE_MODEL_ONLY);
42          isModelOnly = StringUtility.isTrue(modelOnly);
43      }
44  
45      /**
46       * Implements the rule for generating the insert SQL Map element and mapper
47       * method. If the insert statement is allowed, then generate the element and
48       * method.
49       *
50       * @return true if the element and method should be generated
51       */
52      @Override
53      public boolean generateInsert() {
54          if (isModelOnly) {
55              return false;
56          }
57  
58          return tableConfiguration.isInsertStatementEnabled();
59      }
60  
61      /**
62       * Implements the rule for generating the insert selective SQL Map element
63       * and mapper method. If the insert statement is allowed, then generate the
64       * element and method.
65       *
66       * @return true if the element and method should be generated
67       */
68      @Override
69      public boolean generateInsertSelective() {
70          return generateInsert();
71      }
72  
73      /**
74       * Calculates the class that contains all fields. This class is used as the
75       * insert statement parameter, as well as the returned value from the select
76       * by primary key method. The actual class depends on how the domain model
77       * is generated.
78       *
79       * @return the type of the class that holds all fields
80       */
81      @Override
82      public FullyQualifiedJavaType calculateAllFieldsClass() {
83  
84          String answer;
85  
86          if (generateRecordWithBLOBsClass()) {
87              answer = introspectedTable.getRecordWithBLOBsType();
88          } else if (generateBaseRecordClass()) {
89              answer = introspectedTable.getBaseRecordType();
90          } else {
91              answer = introspectedTable.getPrimaryKeyType();
92          }
93  
94          return new FullyQualifiedJavaType(answer);
95      }
96  
97      /**
98       * Implements the rule for generating the update by primary key without
99       * BLOBs SQL Map element and mapper method. If the table has a primary key as
100      * well as other non-BLOB fields, and the updateByPrimaryKey statement is
101      * allowed, then generate the element and method.
102      *
103      * @return true if the element and method should be generated
104      */
105     @Override
106     public boolean generateUpdateByPrimaryKeyWithoutBLOBs() {
107         if (isModelOnly) {
108             return false;
109         }
110 
111         if (ListUtilities.filterColumnsForUpdate(introspectedTable.getBaseColumns()).isEmpty()) {
112             return false;
113         }
114 
115         return tableConfiguration.isUpdateByPrimaryKeyStatementEnabled()
116                 && introspectedTable.hasPrimaryKeyColumns()
117                 && introspectedTable.hasBaseColumns();
118     }
119 
120     /**
121      * Implements the rule for generating the update by primary key with BLOBs
122      * SQL Map element and mapper method. If the table has a primary key as well as
123      * other BLOB fields, and the updateByPrimaryKey statement is allowed, then
124      * generate the element and method.
125      *
126      * @return true if the element and method should be generated
127      */
128     @Override
129     public boolean generateUpdateByPrimaryKeyWithBLOBs() {
130         if (isModelOnly) {
131             return false;
132         }
133 
134         if (ListUtilities.filterColumnsForUpdate(introspectedTable.getNonPrimaryKeyColumns()).isEmpty()) {
135             return false;
136         }
137 
138         return tableConfiguration.isUpdateByPrimaryKeyStatementEnabled()
139                 && introspectedTable.hasPrimaryKeyColumns()
140                 && introspectedTable.hasBLOBColumns();
141     }
142 
143     /**
144      * Implements the rule for generating the update by primary key selective
145      * SQL Map element and mapper method. If the table has a primary key as well as
146      * other fields, and the updateByPrimaryKey statement is allowed, then
147      * generate the element and method.
148      *
149      * @return true if the element and method should be generated
150      */
151     @Override
152     public boolean generateUpdateByPrimaryKeySelective() {
153         if (isModelOnly) {
154             return false;
155         }
156 
157         if (ListUtilities.filterColumnsForUpdate(introspectedTable.getNonPrimaryKeyColumns()).isEmpty()) {
158             return false;
159         }
160 
161         return tableConfiguration.isUpdateByPrimaryKeyStatementEnabled()
162                 && introspectedTable.hasPrimaryKeyColumns()
163                 && (introspectedTable.hasBLOBColumns() || introspectedTable
164                         .hasBaseColumns());
165     }
166 
167     /**
168      * Implements the rule for generating the delete by primary key SQL Map
169      * element and mapper method. If the table has a primary key, and the
170      * deleteByPrimaryKey statement is allowed, then generate the element and
171      * method.
172      *
173      * @return true if the element and method should be generated
174      */
175     @Override
176     public boolean generateDeleteByPrimaryKey() {
177         if (isModelOnly) {
178             return false;
179         }
180 
181         return tableConfiguration.isDeleteByPrimaryKeyStatementEnabled()
182                 && introspectedTable.hasPrimaryKeyColumns();
183     }
184 
185     /**
186      * Implements the rule for generating the delete by example SQL Map element
187      * and mapper method. If the deleteByExample statement is allowed, then
188      * generate the element and method.
189      *
190      * @return true if the element and method should be generated
191      */
192     @Override
193     public boolean generateDeleteByExample() {
194         if (isModelOnly) {
195             return false;
196         }
197 
198         return tableConfiguration.isDeleteByExampleStatementEnabled();
199     }
200 
201     /**
202      * Implements the rule for generating the result map without BLOBs. If
203      * either select method is allowed, then generate the result map.
204      *
205      * @return true if the result map should be generated
206      */
207     @Override
208     public boolean generateBaseResultMap() {
209         if (isModelOnly) {
210             return true;
211         }
212 
213         return tableConfiguration.isSelectByExampleStatementEnabled()
214                 || tableConfiguration.isSelectByPrimaryKeyStatementEnabled();
215     }
216 
217     /**
218      * Implements the rule for generating the result map with BLOBs. If the
219      * table has BLOB columns, and either select method is allowed, then
220      * generate the result map.
221      *
222      * @return true if the result map should be generated
223      */
224     @Override
225     public boolean generateResultMapWithBLOBs() {
226         boolean rc;
227 
228         if (introspectedTable.hasBLOBColumns()) {
229             if (isModelOnly) {
230                 rc = true;
231             } else {
232                 rc = tableConfiguration.isSelectByExampleStatementEnabled()
233                         || tableConfiguration.isSelectByPrimaryKeyStatementEnabled();
234             }
235         } else {
236             rc = false;
237         }
238 
239         return rc;
240     }
241 
242     /**
243      * Implements the rule for generating the SQL example where clause element.
244      *
245      * <p>In MyBatis3, generate the element if the selectByExample,
246      * deleteByExample, or countByExample statements are allowed.
247      *
248      * @return true if the SQL where clause element should be generated
249      */
250     @Override
251     public boolean generateSQLExampleWhereClause() {
252         if (isModelOnly) {
253             return false;
254         }
255 
256         return tableConfiguration.isSelectByExampleStatementEnabled()
257                 || tableConfiguration.isDeleteByExampleStatementEnabled()
258                 || tableConfiguration.isCountByExampleStatementEnabled();
259     }
260 
261     /**
262      * Implements the rule for generating the SQL example where clause element
263      * specifically for use in the update by example methods.
264      *
265      * <p>In MyBatis3, generate the element if the updateByExample statements are
266      * allowed.
267      *
268      * @return true if the SQL where clause element should be generated
269      */
270     @Override
271     public boolean generateMyBatis3UpdateByExampleWhereClause() {
272         if (isModelOnly) {
273             return false;
274         }
275 
276         return introspectedTable.getKnownRuntime().isLegacyMyBatis3Based()
277                 && tableConfiguration.isUpdateByExampleStatementEnabled();
278     }
279 
280     /**
281      * Implements the rule for generating the select by primary key SQL Map
282      * element and mapper method. If the table has a primary key as well as other
283      * fields, and the selectByPrimaryKey statement is allowed, then generate
284      * the element and method.
285      *
286      * @return true if the element and method should be generated
287      */
288     @Override
289     public boolean generateSelectByPrimaryKey() {
290         if (isModelOnly) {
291             return false;
292         }
293 
294         return tableConfiguration.isSelectByPrimaryKeyStatementEnabled()
295                 && introspectedTable.hasPrimaryKeyColumns()
296                 && (introspectedTable.hasBaseColumns() || introspectedTable
297                         .hasBLOBColumns());
298     }
299 
300     /**
301      * Implements the rule for generating the select by example without BLOBs
302      * SQL Map element and mapper method. If the selectByExample statement is
303      * allowed, then generate the element and method.
304      *
305      * @return true if the element and method should be generated
306      */
307     @Override
308     public boolean generateSelectByExampleWithoutBLOBs() {
309         if (isModelOnly) {
310             return false;
311         }
312 
313         return tableConfiguration.isSelectByExampleStatementEnabled();
314     }
315 
316     /**
317      * Implements the rule for generating the select by example with BLOBs SQL
318      * Map element and mapper method. If the table has BLOB fields and the
319      * selectByExample statement is allowed, then generate the element and
320      * method.
321      *
322      * @return true if the element and method should be generated
323      */
324     @Override
325     public boolean generateSelectByExampleWithBLOBs() {
326         if (isModelOnly) {
327             return false;
328         }
329 
330         return tableConfiguration.isSelectByExampleStatementEnabled()
331                 && introspectedTable.hasBLOBColumns();
332     }
333 
334     /**
335      * Implements the rule for generating an example class. The class should be
336      * generated if the selectByExample or deleteByExample or countByExample
337      * methods are allowed.
338      *
339      * @return true if the example class should be generated
340      */
341     @Override
342     public boolean generateExampleClass() {
343         if (introspectedTable.getContext().getSqlMapGeneratorConfiguration().isEmpty()
344                 && introspectedTable.getContext().getClientGeneratorConfiguration().isEmpty()) {
345             // this is a model only context - don't generate the example class
346             return false;
347         }
348 
349         if (isModelOnly) {
350             return false;
351         }
352 
353         return tableConfiguration.isSelectByExampleStatementEnabled()
354                 || tableConfiguration.isDeleteByExampleStatementEnabled()
355                 || tableConfiguration.isCountByExampleStatementEnabled()
356                 || tableConfiguration.isUpdateByExampleStatementEnabled();
357     }
358 
359     @Override
360     public boolean generateCountByExample() {
361         if (isModelOnly) {
362             return false;
363         }
364 
365         return tableConfiguration.isCountByExampleStatementEnabled();
366     }
367 
368     @Override
369     public boolean generateUpdateByExampleSelective() {
370         if (isModelOnly) {
371             return false;
372         }
373 
374         return tableConfiguration.isUpdateByExampleStatementEnabled();
375     }
376 
377     @Override
378     public boolean generateUpdateByExampleWithoutBLOBs() {
379         if (isModelOnly) {
380             return false;
381         }
382 
383         return tableConfiguration.isUpdateByExampleStatementEnabled()
384                 && (introspectedTable.hasPrimaryKeyColumns() || introspectedTable
385                         .hasBaseColumns());
386     }
387 
388     @Override
389     public boolean generateUpdateByExampleWithBLOBs() {
390         if (isModelOnly) {
391             return false;
392         }
393 
394         return tableConfiguration.isUpdateByExampleStatementEnabled()
395                 && introspectedTable.hasBLOBColumns();
396     }
397 
398     @Override
399     public IntrospectedTable getIntrospectedTable() {
400         return introspectedTable;
401     }
402 
403     @Override
404     public boolean generateBaseColumnList() {
405         if (isModelOnly) {
406             return false;
407         }
408 
409         return generateSelectByPrimaryKey()
410                 || generateSelectByExampleWithoutBLOBs();
411     }
412 
413     @Override
414     public boolean generateBlobColumnList() {
415         if (isModelOnly) {
416             return false;
417         }
418 
419         return introspectedTable.hasBLOBColumns()
420                 && (tableConfiguration.isSelectByExampleStatementEnabled() || tableConfiguration
421                         .isSelectByPrimaryKeyStatementEnabled());
422     }
423 
424     @Override
425     public boolean generateClient() {
426         return !isModelOnly;
427     }
428 
429     @Override
430     public boolean generateDeleteByPrimaryKeyForDSQL() {
431         return introspectedTable.hasPrimaryKeyColumns();
432     }
433 
434     @Override
435     public boolean generateMultipleRowInsertForDSQL() {
436         // multi row inserts work if we don't expect generated keys, or of the generated keys are
437         // JDBC standard.
438         return introspectedTable.getGeneratedKey().map(GeneratedKey::isJdbcStandard)
439                 .orElse(true);
440     }
441 
442     @Override
443     public boolean generateSelectByPrimaryKeyForDSQL() {
444         return introspectedTable.hasPrimaryKeyColumns()
445                 && (introspectedTable.hasBaseColumns() || introspectedTable
446                         .hasBLOBColumns());
447     }
448 
449     @Override
450     public boolean generateUpdateByPrimaryKeyForDSQL() {
451         if (ListUtilities.filterColumnsForUpdate(introspectedTable.getNonPrimaryKeyColumns()).isEmpty()) {
452             return false;
453         }
454 
455         return introspectedTable.hasPrimaryKeyColumns()
456                 && (introspectedTable.hasBLOBColumns() || introspectedTable
457                         .hasBaseColumns());
458     }
459 }