001/* 002 * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package com.mybatisflex.core.query; 017 018 019import com.mybatisflex.core.constant.SqlConnector; 020import com.mybatisflex.core.constant.SqlConsts; 021import com.mybatisflex.core.constant.SqlOperator; 022import com.mybatisflex.core.dialect.IDialect; 023import com.mybatisflex.core.exception.FlexExceptions; 024import com.mybatisflex.core.util.ClassUtil; 025import com.mybatisflex.core.util.ObjectUtil; 026import com.mybatisflex.core.util.StringUtil; 027 028import java.lang.reflect.Array; 029import java.util.List; 030import java.util.function.BooleanSupplier; 031 032public class QueryCondition implements CloneSupport<QueryCondition> { 033 034 035 protected QueryColumn column; 036 protected String logic; 037 protected Object value; 038 protected boolean effective = true; 039 040 //当前条件的上一个条件 041 protected QueryCondition prev; 042 043 //当前条件的下一个条件 044 protected QueryCondition next; 045 046 //两个条件直接的连接符 047 protected SqlConnector connector; 048 049 050 public static QueryCondition createEmpty() { 051 return new QueryCondition().when(false); 052 } 053 054 055 public static QueryCondition create(String schema, String table, String column, String logic, Object value) { 056 QueryCondition condition = new QueryCondition(); 057 condition.setColumn(new QueryColumn(schema, table, column)); 058 condition.setLogic(logic); 059 condition.setValue(value); 060 return condition; 061 } 062 063 public static QueryCondition create(QueryColumn queryColumn, Object value) { 064 return create(queryColumn, SqlConsts.EQUALS, value); 065 } 066 067 public static QueryCondition create(QueryColumn queryColumn, String logic, Object value) { 068 QueryCondition condition = new QueryCondition(); 069 condition.setColumn(queryColumn); 070 condition.setLogic(logic); 071 condition.setValue(value); 072 return condition; 073 } 074 075 public static QueryCondition create(QueryColumn queryColumn, SqlOperator logic, Object value) { 076 QueryCondition condition = new QueryCondition(); 077 condition.setColumn(queryColumn); 078 condition.setLogic(logic.getValue()); 079 condition.setValue(value); 080 return condition; 081 } 082 083 public QueryColumn getColumn() { 084 return column; 085 } 086 087 public void setColumn(QueryColumn column) { 088 this.column = column; 089 } 090 091 public Object getValue() { 092 return checkEffective() ? value : null; 093 } 094 095 public void setValue(Object value) { 096 this.value = value; 097 } 098 099 public String getLogic() { 100 return logic; 101 } 102 103 public void setLogic(String logic) { 104 this.logic = logic; 105 } 106 107 /** 108 * 动态条件构造。 109 * 110 * @param effective 是否启用该条件 111 * @return {@link QueryCondition} 112 */ 113 public QueryCondition when(boolean effective) { 114 this.effective = effective; 115 return this; 116 } 117 118 119 /** 120 * 动态条件构造。 121 * 122 * @param fn 是否启用该条件 123 * @return {@link QueryCondition} 124 */ 125 public QueryCondition when(BooleanSupplier fn) { 126 this.effective = fn.getAsBoolean(); 127 return this; 128 } 129 130 public boolean checkEffective() { 131 return effective; 132 } 133 134 135 public QueryCondition and(String sql) { 136 return and(new RawFragment(sql)); 137 } 138 139 public QueryCondition and(String sql, Object... params) { 140 return and(new RawFragment(sql, params)); 141 } 142 143 public QueryCondition and(QueryCondition nextCondition) { 144 return new Brackets(this).and(nextCondition); 145 } 146 147 public QueryCondition or(String sql) { 148 return or(new RawFragment(sql)); 149 } 150 151 public QueryCondition or(String sql, Object... params) { 152 return or(new RawFragment(sql, params)); 153 } 154 155 public QueryCondition or(QueryCondition nextCondition) { 156 return new Brackets(this).or(nextCondition); 157 } 158 159 protected void connect(QueryCondition nextCondition, SqlConnector connector) { 160 if (this.next != null) { 161 this.next.connect(nextCondition, connector); 162 } else { 163 this.next = nextCondition; 164 this.connector = connector; 165 nextCondition.prev = this; 166 } 167 } 168 169 public String toSql(List<QueryTable> queryTables, IDialect dialect) { 170 StringBuilder sql = new StringBuilder(); 171 //检测是否生效 172 if (checkEffective()) { 173 QueryCondition prevEffectiveCondition = getPrevEffectiveCondition(); 174 if (prevEffectiveCondition != null) { 175 sql.append(prevEffectiveCondition.connector); 176 } 177 //列 178 sql.append(getColumn().toConditionSql(queryTables, dialect)); 179 180 //逻辑符号 181 sql.append(logic); 182 183 //值(或者问号) 184 if (value instanceof QueryColumn) { 185 sql.append(((QueryColumn) value).toConditionSql(queryTables, dialect)); 186 } 187 //子查询 188 else if (value instanceof QueryWrapper) { 189 sql.append(SqlConsts.BRACKET_LEFT) 190 .append(dialect.buildSelectSql((QueryWrapper) value)) 191 .append(SqlConsts.BRACKET_RIGHT); 192 } 193 //原生sql 194 else if (value instanceof RawFragment) { 195 sql.append(((RawFragment) value).getContent()); 196 } 197 //正常查询,构建问号 198 else { 199 appendQuestionMark(sql); 200 } 201 } 202 203 if (this.next != null) { 204 return sql + next.toSql(queryTables, dialect); 205 } 206 207 return sql.toString(); 208 } 209 210 211 protected QueryCondition getPrevEffectiveCondition() { 212 if (prev == null) { 213 return null; 214 } 215 return prev.checkEffective() ? prev : prev.getPrevEffectiveCondition(); 216 } 217 218 protected QueryCondition getNextEffectiveCondition() { 219 if (next == null) { 220 return null; 221 } 222 return next.checkEffective() ? next : next.getNextEffectiveCondition(); 223 } 224 225 226 protected void appendQuestionMark(StringBuilder sqlBuilder) { 227 //noinspection StatementWithEmptyBody 228 if (SqlConsts.IS_NULL.equals(logic) 229 || SqlConsts.IS_NOT_NULL.equals(logic) 230 || value instanceof QueryColumn 231 || value instanceof QueryWrapper 232 || value instanceof RawFragment) { 233 //do nothing 234 } 235 236 //between, not between 237 else if (SqlConsts.BETWEEN.equals(logic) || SqlConsts.NOT_BETWEEN.equals(logic)) { 238 sqlBuilder.append(SqlConsts.AND_PLACEHOLDER); 239 } 240 //in, not in 241 else if (SqlConsts.IN.equals(logic) || SqlConsts.NOT_IN.equals(logic)) { 242 int paramsCount = calculateValueArrayCount(); 243 sqlBuilder.append(SqlConsts.BRACKET_LEFT); 244 for (int i = 0; i < paramsCount; i++) { 245 sqlBuilder.append(SqlConsts.PLACEHOLDER); 246 if (i != paramsCount - 1) { 247 sqlBuilder.append(SqlConsts.DELIMITER); 248 } 249 } 250 sqlBuilder.append(SqlConsts.BRACKET_RIGHT); 251 } else { 252 sqlBuilder.append(SqlConsts.PLACEHOLDER); 253 } 254 } 255 256 257 private int calculateValueArrayCount() { 258 Object[] values = (Object[]) value; 259 int paramsCount = 0; 260 for (Object object : values) { 261 if (object != null && ClassUtil.isArray(object.getClass())) { 262 paramsCount += Array.getLength(object); 263 } else { 264 paramsCount++; 265 } 266 } 267 return paramsCount; 268 } 269 270 271 boolean containsTable(String... tables) { 272 if (column == null || !checkEffective()) { 273 return nextContainsTable(tables); 274 } 275 for (String table : tables) { 276 String tableName = StringUtil.getTableNameWithAlisa(table)[0]; 277 if (column.table != null && tableName.equals(column.table.name)) { 278 return true; 279 } 280 } 281 return nextContainsTable(tables); 282 } 283 284 boolean nextContainsTable(String... tables) { 285 if (next == null) { 286 return false; 287 } 288 return next.containsTable(tables); 289 } 290 291 @Override 292 public String toString() { 293 return "QueryCondition{" + 294 "column=" + column + 295 ", logic='" + logic + '\'' + 296 ", value=" + value + 297 ", effective=" + effective + 298 '}'; 299 } 300 301 @Override 302 public QueryCondition clone() { 303 try { 304 QueryCondition clone = (QueryCondition) super.clone(); 305 // deep clone ... 306 clone.column = ObjectUtil.clone(this.column); 307 clone.value = ObjectUtil.cloneObject(this.value); 308 clone.prev = clone.next = null; 309 if (this.next != null) { 310 clone.next = this.next.clone(); 311 clone.next.prev = clone; 312 } 313 return clone; 314 } catch (CloneNotSupportedException e) { 315 throw FlexExceptions.wrap(e); 316 } 317 } 318 319}