View Javadoc
1   /*
2    *    Copyright 2016-2025 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.common;
17  
18  import java.util.ArrayList;
19  import java.util.Arrays;
20  import java.util.List;
21  
22  import org.jspecify.annotations.Nullable;
23  import org.mybatis.dynamic.sql.AndOrCriteriaGroup;
24  import org.mybatis.dynamic.sql.BindableColumn;
25  import org.mybatis.dynamic.sql.ColumnAndConditionCriterion;
26  import org.mybatis.dynamic.sql.CriteriaGroup;
27  import org.mybatis.dynamic.sql.ExistsCriterion;
28  import org.mybatis.dynamic.sql.ExistsPredicate;
29  import org.mybatis.dynamic.sql.RenderableCondition;
30  import org.mybatis.dynamic.sql.SqlCriterion;
31  import org.mybatis.dynamic.sql.util.Validator;
32  
33  public abstract class AbstractBooleanExpressionDSL<T extends AbstractBooleanExpressionDSL<T>> {
34      private @Nullable SqlCriterion initialCriterion;
35      protected final List<AndOrCriteriaGroup> subCriteria = new ArrayList<>();
36  
37      public <S> T and(BindableColumn<S> column, RenderableCondition<S> condition,
38                       AndOrCriteriaGroup... subCriteria) {
39          return and(column, condition, Arrays.asList(subCriteria));
40      }
41  
42      public <S> T and(BindableColumn<S> column, RenderableCondition<S> condition,
43                       List<AndOrCriteriaGroup> subCriteria) {
44          addSubCriteria("and", buildCriterion(column, condition), subCriteria); //$NON-NLS-1$
45          return getThis();
46      }
47  
48      public T and(ExistsPredicate existsPredicate, AndOrCriteriaGroup... subCriteria) {
49          return and(existsPredicate, Arrays.asList(subCriteria));
50      }
51  
52      public T and(ExistsPredicate existsPredicate, List<AndOrCriteriaGroup> subCriteria) {
53          addSubCriteria("and", buildCriterion(existsPredicate), subCriteria); //$NON-NLS-1$
54          return getThis();
55      }
56  
57      public T and(SqlCriterion initialCriterion, AndOrCriteriaGroup... subCriteria) {
58          return and(initialCriterion, Arrays.asList(subCriteria));
59      }
60  
61      public T and(SqlCriterion initialCriterion, List<AndOrCriteriaGroup> subCriteria) {
62          addSubCriteria("and", buildCriterion(initialCriterion), subCriteria); //$NON-NLS-1$
63          return getThis();
64      }
65  
66      public T and(List<AndOrCriteriaGroup> criteria) {
67          addSubCriteria("and", criteria); //$NON-NLS-1$
68          return getThis();
69      }
70  
71      public <S> T or(BindableColumn<S> column, RenderableCondition<S> condition,
72                      AndOrCriteriaGroup... subCriteria) {
73          return or(column, condition, Arrays.asList(subCriteria));
74      }
75  
76      public <S> T or(BindableColumn<S> column, RenderableCondition<S> condition,
77                      List<AndOrCriteriaGroup> subCriteria) {
78          addSubCriteria("or", buildCriterion(column, condition), subCriteria); //$NON-NLS-1$
79          return getThis();
80      }
81  
82      public T or(ExistsPredicate existsPredicate, AndOrCriteriaGroup... subCriteria) {
83          return or(existsPredicate, Arrays.asList(subCriteria));
84      }
85  
86      public T or(ExistsPredicate existsPredicate, List<AndOrCriteriaGroup> subCriteria) {
87          addSubCriteria("or", buildCriterion(existsPredicate), subCriteria); //$NON-NLS-1$
88          return getThis();
89      }
90  
91      public T or(SqlCriterion initialCriterion, AndOrCriteriaGroup... subCriteria) {
92          return or(initialCriterion, Arrays.asList(subCriteria));
93      }
94  
95      public T or(SqlCriterion initialCriterion, List<AndOrCriteriaGroup> subCriteria) {
96          addSubCriteria("or", buildCriterion(initialCriterion), subCriteria); //$NON-NLS-1$
97          return getThis();
98      }
99  
100     public T or(List<AndOrCriteriaGroup> criteria) {
101         addSubCriteria("or", criteria); //$NON-NLS-1$
102         return getThis();
103     }
104 
105     private <R> SqlCriterion buildCriterion(BindableColumn<R> column, RenderableCondition<R> condition) {
106         return ColumnAndConditionCriterion.withColumn(column).withCondition(condition).build();
107     }
108 
109     private SqlCriterion buildCriterion(ExistsPredicate existsPredicate) {
110         return new ExistsCriterion.Builder().withExistsPredicate(existsPredicate).build();
111     }
112 
113     private SqlCriterion buildCriterion(SqlCriterion initialCriterion) {
114         return new CriteriaGroup.Builder().withInitialCriterion(initialCriterion).build();
115     }
116 
117     private void addSubCriteria(String connector, SqlCriterion initialCriterion,
118                                 List<AndOrCriteriaGroup> subCriteria) {
119         this.subCriteria.add(new AndOrCriteriaGroup.Builder()
120                 .withInitialCriterion(initialCriterion)
121                 .withConnector(connector)
122                 .withSubCriteria(subCriteria)
123                 .build());
124     }
125 
126     private void addSubCriteria(String connector, List<AndOrCriteriaGroup> criteria) {
127         this.subCriteria.add(new AndOrCriteriaGroup.Builder()
128                 .withConnector(connector)
129                 .withSubCriteria(criteria)
130                 .build());
131     }
132 
133     protected void setInitialCriterion(@Nullable SqlCriterion initialCriterion) {
134         this.initialCriterion = initialCriterion;
135     }
136 
137     protected void setInitialCriterion(@Nullable SqlCriterion initialCriterion, StatementType statementType) {
138         Validator.assertTrue(this.initialCriterion == null, statementType.messageNumber());
139         setInitialCriterion(initialCriterion);
140     }
141 
142     protected @Nullable SqlCriterion getInitialCriterion() {
143         return initialCriterion;
144     }
145 
146     protected abstract T getThis();
147 
148     public enum StatementType {
149         WHERE("ERROR.32"), //$NON-NLS-1$
150         HAVING("ERROR.31"); //$NON-NLS-1$
151 
152         private final String messageNumber;
153 
154         public String messageNumber() {
155             return messageNumber;
156         }
157 
158         StatementType(String messageNumber) {
159             this.messageNumber = messageNumber;
160         }
161     }
162 }