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.dialect.impl; 017 018import com.mybatisflex.core.FlexGlobalConfig; 019import com.mybatisflex.core.dialect.IDialect; 020import com.mybatisflex.core.dialect.KeywordWrap; 021import com.mybatisflex.core.dialect.LimitOffsetProcesser; 022import com.mybatisflex.core.exception.FlexExceptions; 023import com.mybatisflex.core.query.*; 024import com.mybatisflex.core.row.Row; 025import com.mybatisflex.core.row.RowCPI; 026import com.mybatisflex.core.table.TableInfo; 027import com.mybatisflex.core.util.ArrayUtil; 028import com.mybatisflex.core.util.CollectionUtil; 029import com.mybatisflex.core.util.StringUtil; 030 031import java.util.List; 032import java.util.Map; 033import java.util.Set; 034import java.util.StringJoiner; 035 036/** 037 * 通用的方言设计,其他方言可以继承于当前 CommonsDialectImpl 038 * 创建或获取方言请参考 {@link com.mybatisflex.core.dialect.DialectFactory} 039 */ 040public class CommonsDialectImpl implements IDialect { 041 042 protected KeywordWrap keywordWrap = KeywordWrap.BACKQUOTE; 043 private LimitOffsetProcesser limitOffsetProcesser = LimitOffsetProcesser.MYSQL; 044 045 public CommonsDialectImpl() { 046 } 047 048 public CommonsDialectImpl(LimitOffsetProcesser limitOffsetProcesser) { 049 this.limitOffsetProcesser = limitOffsetProcesser; 050 } 051 052 public CommonsDialectImpl(KeywordWrap keywordWrap, LimitOffsetProcesser limitOffsetProcesser) { 053 this.keywordWrap = keywordWrap; 054 this.limitOffsetProcesser = limitOffsetProcesser; 055 } 056 057 @Override 058 public String wrap(String keyword) { 059 return keywordWrap.wrap(keyword); 060 } 061 062 @Override 063 public String forInsertRow(String tableName, Row row) { 064 StringBuilder fields = new StringBuilder(); 065 StringBuilder questions = new StringBuilder(); 066 067 Set<String> attrs = row.obtainModifyAttrs(); 068 int index = 0; 069 for (String attr : attrs) { 070 fields.append(wrap(attr)); 071 questions.append("?"); 072 if (index != attrs.size() - 1) { 073 fields.append(", "); 074 questions.append(", "); 075 } 076 index++; 077 } 078 079 String sql = "INSERT INTO " + wrap(tableName) + 080 "(" + fields + ") VALUES " + 081 "(" + questions + ")"; 082 return sql; 083 } 084 085 086 @Override 087 public String forInsertBatchWithFirstRowColumns(String tableName, List<Row> rows) { 088 StringBuilder fields = new StringBuilder(); 089 StringBuilder questions = new StringBuilder(); 090 091 Row firstRow = rows.get(0); 092 Set<String> attrs = firstRow.obtainModifyAttrs(); 093 int index = 0; 094 for (String column : attrs) { 095 fields.append(wrap(column)); 096 if (index != attrs.size() - 1) { 097 fields.append(", "); 098 } 099 index++; 100 } 101 102 for (int i = 0; i < rows.size(); i++) { 103 questions.append(buildQuestion(attrs.size(), true)); 104 if (i != rows.size() - 1) { 105 questions.append(","); 106 } 107 } 108 109 String sql = "INSERT INTO " + wrap(tableName) + 110 "(" + fields + ") VALUES " + questions; 111 return sql; 112 } 113 114 115 @Override 116 public String forDeleteById(String tableName, String[] primaryKeys) { 117 StringBuilder sql = new StringBuilder(); 118 sql.append("DELETE FROM "); 119 sql.append(wrap(tableName)); 120 sql.append(" WHERE "); 121 for (int i = 0; i < primaryKeys.length; i++) { 122 if (i > 0) { 123 sql.append(" AND "); 124 } 125 sql.append(wrap(primaryKeys[i])).append(" = ?"); 126 } 127 return sql.toString(); 128 } 129 130 131 @Override 132 public String forDeleteBatchByIds(String tableName, String[] primaryKeys, Object[] ids) { 133 StringBuilder sql = new StringBuilder(); 134 sql.append("DELETE FROM "); 135 sql.append(wrap(tableName)); 136 sql.append(" WHERE "); 137 138 //多主键的场景 139 if (primaryKeys.length > 1) { 140 for (int i = 0; i < ids.length / primaryKeys.length; i++) { 141 if (i > 0) { 142 sql.append(" OR "); 143 } 144 sql.append("("); 145 for (int j = 0; j < primaryKeys.length; j++) { 146 if (j > 0) { 147 sql.append(" AND "); 148 } 149 sql.append(wrap(primaryKeys[j])).append(" = ?"); 150 } 151 sql.append(")"); 152 } 153 } 154 // 单主键 155 else { 156 for (int i = 0; i < ids.length; i++) { 157 if (i > 0) { 158 sql.append(" OR "); 159 } 160 sql.append(wrap(primaryKeys[0])).append(" = ?"); 161 } 162 } 163 return sql.toString(); 164 } 165 166 @Override 167 public String forDeleteByQuery(QueryWrapper queryWrapper) { 168 return buildDeleteSql(queryWrapper); 169 } 170 171 @Override 172 public String forUpdateById(String tableName, Row row) { 173 StringBuilder sql = new StringBuilder(); 174 175 Set<String> modifyAttrs = row.obtainModifyAttrs(); 176 String[] primaryKeys = RowCPI.obtainsPrimaryKeyStrings(row); 177 178 sql.append("UPDATE ").append(wrap(tableName)).append(" SET "); 179 int index = 0; 180 for (Map.Entry<String, Object> e : row.entrySet()) { 181 String colName = e.getKey(); 182 if (modifyAttrs.contains(colName) && !ArrayUtil.contains(primaryKeys, colName)) { 183 if (index > 0) { 184 sql.append(", "); 185 } 186 sql.append(wrap(colName)).append(" = ? "); 187 index++; 188 } 189 } 190 sql.append(" WHERE "); 191 for (int i = 0; i < primaryKeys.length; i++) { 192 if (i > 0) { 193 sql.append(" AND "); 194 } 195 sql.append(wrap(primaryKeys[i])).append(" = ?"); 196 } 197 198 return sql.toString(); 199 } 200 201 @Override 202 public String forUpdateByQuery(QueryWrapper queryWrapper, Row row) { 203 StringBuilder sql = new StringBuilder(); 204 205 Set<String> modifyAttrs = row.obtainModifyAttrs(); 206 207 List<QueryTable> queryTables = CPI.getQueryTables(queryWrapper); 208 if (queryTables == null || queryTables.size() != 1) { 209 throw FlexExceptions.wrap("update sql must need 1 table."); 210 } 211 212 String tableName = queryTables.get(0).getName(); 213 sql.append("UPDATE ").append(wrap(tableName)).append(" SET "); 214 int index = 0; 215 for (String modifyAttr : modifyAttrs) { 216 if (index > 0) { 217 sql.append(", "); 218 } 219 sql.append(wrap(modifyAttr)).append(" = ? "); 220 index++; 221 } 222 223 String whereConditionSql = buildWhereConditionSql(queryWrapper); 224 if (StringUtil.isNotBlank(whereConditionSql)) { 225 sql.append(" WHERE ").append(whereConditionSql); 226 } 227 228 return sql.toString(); 229 } 230 231 @Override 232 public String forUpdateBatchById(String tableName, List<Row> rows) { 233 if (rows.size() == 1) { 234 return forUpdateById(tableName, rows.get(0)); 235 } 236 StringBuilder sql = new StringBuilder(); 237 for (Row row : rows) { 238 sql.append(forUpdateById(tableName, row)).append("; "); 239 } 240 return sql.toString(); 241 } 242 243 244 @Override 245 public String forSelectOneById(String tableName, String[] primaryKeys, Object[] primaryValues) { 246 StringBuilder sql = new StringBuilder("SELECT * FROM "); 247 sql.append(wrap(tableName)).append(" WHERE "); 248 for (int i = 0; i < primaryKeys.length; i++) { 249 if (i > 0) { 250 sql.append(" AND "); 251 } 252 sql.append(wrap(primaryKeys[i])).append(" = ?"); 253 } 254 return sql.toString(); 255 } 256 257 @Override 258 public String forSelectListByQuery(QueryWrapper queryWrapper) { 259 return buildSelectSql(queryWrapper); 260 } 261 262 263 @Override 264 public String forSelectCountByQuery(QueryWrapper queryWrapper) { 265 return buildSelectCountSql(queryWrapper); 266 } 267 268 269 ////////////build query sql/////// 270 @Override 271 public String buildSelectSql(QueryWrapper queryWrapper) { 272 List<QueryTable> queryTables = CPI.getQueryTables(queryWrapper); 273 List<QueryTable> joinTables = CPI.getJoinTables(queryWrapper); 274 List<QueryTable> allTables = CollectionUtil.merge(queryTables, joinTables); 275 276 List<QueryColumn> selectColumns = CPI.getSelectColumns(queryWrapper); 277 278 StringBuilder sqlBuilder = buildSelectColumnSql(allTables, selectColumns); 279 sqlBuilder.append(" FROM ").append(StringUtil.join(", ", queryTables, queryTable -> queryTable.toSql(this))); 280 281 buildJoinSql(sqlBuilder, queryWrapper, allTables); 282 buildWhereSql(sqlBuilder, queryWrapper, allTables, true); 283 buildGroupBySql(sqlBuilder, queryWrapper, allTables); 284 buildHavingSql(sqlBuilder, queryWrapper, allTables); 285 buildOrderBySql(sqlBuilder, queryWrapper, allTables); 286 287 List<UnionWrapper> unions = CPI.getUnions(queryWrapper); 288 if (CollectionUtil.isNotEmpty(unions)) { 289 sqlBuilder.insert(0, "(").append(")"); 290 for (UnionWrapper unionWrapper : unions) { 291 unionWrapper.buildSql(sqlBuilder, this); 292 } 293 } 294 295 Integer limitRows = CPI.getLimitRows(queryWrapper); 296 Integer limitOffset = CPI.getLimitOffset(queryWrapper); 297 if (limitRows != null || limitOffset != null) { 298 sqlBuilder = buildLimitOffsetSql(sqlBuilder, queryWrapper, limitRows, limitOffset); 299 } 300 301 return sqlBuilder.toString(); 302 } 303 304 private StringBuilder buildSelectColumnSql(List<QueryTable> queryTables, List<QueryColumn> selectColumns) { 305 StringBuilder sqlBuilder = new StringBuilder("SELECT "); 306 if (selectColumns == null || selectColumns.isEmpty()) { 307 sqlBuilder.append("*"); 308 } else { 309 int index = 0; 310 for (QueryColumn selectColumn : selectColumns) { 311 String selectColumnSql = CPI.toSelectSql(selectColumn, queryTables, this); 312 sqlBuilder.append(selectColumnSql); 313 if (index != selectColumns.size() - 1) { 314 sqlBuilder.append(", "); 315 } 316 index++; 317 } 318 } 319 return sqlBuilder; 320 } 321 322 323 @Override 324 public String buildSelectCountSql(QueryWrapper queryWrapper) { 325 List<QueryTable> queryTables = CPI.getQueryTables(queryWrapper); 326 List<QueryTable> joinTables = CPI.getJoinTables(queryWrapper); 327 List<QueryTable> allTables = CollectionUtil.merge(queryTables, joinTables); 328 329 //ignore selectColumns 330 StringBuilder sqlBuilder = new StringBuilder("SELECT COUNT(*) FROM "); 331 sqlBuilder.append(StringUtil.join(", ", queryTables, queryTable -> queryTable.toSql(this))); 332 333 334 buildJoinSql(sqlBuilder, queryWrapper, allTables); 335 buildWhereSql(sqlBuilder, queryWrapper, allTables, true); 336 buildGroupBySql(sqlBuilder, queryWrapper, allTables); 337 buildHavingSql(sqlBuilder, queryWrapper, allTables); 338 339 // ignore orderBy and limit 340 // buildOrderBySql(sqlBuilder, queryWrapper); 341 // buildLimitSql(sqlBuilder, queryWrapper); 342 343 return sqlBuilder.toString(); 344 } 345 346 @Override 347 public String buildDeleteSql(QueryWrapper queryWrapper) { 348 List<QueryTable> queryTables = CPI.getQueryTables(queryWrapper); 349 List<QueryTable> joinTables = CPI.getJoinTables(queryWrapper); 350 List<QueryTable> allTables = CollectionUtil.merge(queryTables, joinTables); 351 352 //ignore selectColumns 353 StringBuilder sqlBuilder = new StringBuilder("DELETE FROM "); 354 sqlBuilder.append(StringUtil.join(", ", queryTables, queryTable -> queryTable.toSql(this))); 355 356 buildJoinSql(sqlBuilder, queryWrapper, allTables); 357 buildWhereSql(sqlBuilder, queryWrapper, allTables, false); 358 buildGroupBySql(sqlBuilder, queryWrapper, allTables); 359 buildHavingSql(sqlBuilder, queryWrapper, allTables); 360 361 //ignore orderBy and limit 362 //buildOrderBySql(sqlBuilder, queryWrapper); 363 //buildLimitSql(sqlBuilder, queryWrapper); 364 365 return sqlBuilder.toString(); 366 } 367 368 @Override 369 public String buildWhereConditionSql(QueryWrapper queryWrapper) { 370 QueryCondition whereQueryCondition = CPI.getWhereQueryCondition(queryWrapper); 371 return whereQueryCondition != null ? whereQueryCondition.toSql(CPI.getQueryTables(queryWrapper), this) : ""; 372 } 373 374 @Override 375 public String forInsertEntity(TableInfo tableInfo, Object entity, boolean ignoreNulls) { 376 StringBuilder sql = new StringBuilder(); 377 sql.append("INSERT INTO ").append(wrap(tableInfo.getTableName())); 378 379 String[] insertColumns = tableInfo.obtainInsertColumns(entity, ignoreNulls); 380 Map<String, String> onInsertColumns = tableInfo.getOnInsertColumns(); 381 382 StringJoiner sqlFields = new StringJoiner(", "); 383 StringJoiner sqlValues = new StringJoiner(", "); 384 385 for (String insertColumn : insertColumns) { 386 sqlFields.add(wrap(insertColumn)); 387 if (onInsertColumns != null && onInsertColumns.containsKey(insertColumn)) { 388 sqlValues.add(onInsertColumns.get(insertColumn)); 389 } else { 390 sqlValues.add("?"); 391 } 392 } 393 394 return sql.append("(").append(sqlFields).append(")") 395 .append(" VALUES ") 396 .append("(").append(sqlValues).append(")").toString(); 397 } 398 399 @Override 400 public String forInsertEntityBatch(TableInfo tableInfo, List<Object> entities) { 401 StringBuilder sql = new StringBuilder(); 402 sql.append("INSERT INTO ").append(wrap(tableInfo.getTableName())); 403 String[] insertColumns = tableInfo.obtainInsertColumns(null, false); 404 String[] warpedInsertColumns = new String[insertColumns.length]; 405 for (int i = 0; i < insertColumns.length; i++) { 406 warpedInsertColumns[i] = wrap(insertColumns[i]); 407 } 408 sql.append("(").append(StringUtil.join(", ", warpedInsertColumns)).append(")"); 409 sql.append(" VALUES "); 410 411 Map<String, String> onInsertColumns = tableInfo.getOnInsertColumns(); 412 for (int i = 0; i < entities.size(); i++) { 413 StringJoiner stringJoiner = new StringJoiner(", ", "(", ")"); 414 for (String insertColumn : insertColumns) { 415 if (onInsertColumns != null && onInsertColumns.containsKey(insertColumn)) { 416 //直接读取 onInsert 配置的值,而不用 "?" 代替 417 stringJoiner.add(onInsertColumns.get(insertColumn)); 418 } else { 419 stringJoiner.add("?"); 420 } 421 } 422 sql.append(stringJoiner); 423 if (i != entities.size() - 1) { 424 sql.append(", "); 425 } 426 } 427 428 return sql.toString(); 429 } 430 431 @Override 432 public String forDeleteEntityById(TableInfo tableInfo) { 433 String logicDeleteColumn = tableInfo.getLogicDeleteColumn(); 434 Object[] tenantIdArgs = tableInfo.buildTenantIdArgs(); 435 //正常删除 436 if (StringUtil.isBlank(logicDeleteColumn)) { 437 String deleteByIdSql = forDeleteById(tableInfo.getTableName(), tableInfo.getPrimaryKeys()); 438 439 if (ArrayUtil.isNotEmpty(tenantIdArgs)) { 440 deleteByIdSql += " AND " + wrap(tableInfo.getTenantIdColumn()) + " IN " + buildQuestion(tenantIdArgs.length, true); 441 } 442 return deleteByIdSql; 443 } 444 445 //逻辑删除 446 StringBuilder sql = new StringBuilder(); 447 String[] primaryKeys = tableInfo.getPrimaryKeys(); 448 449 sql.append("UPDATE ").append(wrap(tableInfo.getTableName())); 450 sql.append(" SET ").append(wrap(logicDeleteColumn)).append(" = ").append(getLogicDeletedValue()); 451 sql.append(" WHERE "); 452 for (int i = 0; i < primaryKeys.length; i++) { 453 if (i > 0) { 454 sql.append(" AND "); 455 } 456 sql.append(wrap(primaryKeys[i])).append(" = ?"); 457 } 458 459 sql.append(" AND ").append(wrap(logicDeleteColumn)).append(" = ").append(getLogicNormalValue()); 460 461 //租户ID 462 if (ArrayUtil.isNotEmpty(tenantIdArgs)) { 463 sql.append(" AND ").append(wrap(tableInfo.getTenantIdColumn())).append(" IN ").append(buildQuestion(tenantIdArgs.length, true)); 464 } 465 466 return sql.toString(); 467 } 468 469 470 @Override 471 public String forDeleteEntityBatchByIds(TableInfo tableInfo, Object[] primaryValues) { 472 String logicDeleteColumn = tableInfo.getLogicDeleteColumn(); 473 Object[] tenantIdArgs = tableInfo.buildTenantIdArgs(); 474 475 //正常删除 476 if (StringUtil.isBlank(logicDeleteColumn)) { 477 String deleteSQL = forDeleteBatchByIds(tableInfo.getTableName(), tableInfo.getPrimaryKeys(), primaryValues); 478 479 //多租户 480 if (ArrayUtil.isNotEmpty(tenantIdArgs)) { 481 deleteSQL = deleteSQL.replace(" WHERE ", " WHERE (") + ")"; 482 deleteSQL += " AND " + wrap(tableInfo.getTenantIdColumn()) + " IN " + buildQuestion(tenantIdArgs.length, true); 483 } 484 return deleteSQL; 485 } 486 487 StringBuilder sql = new StringBuilder(); 488 sql.append("UPDATE "); 489 sql.append(wrap(tableInfo.getTableName())); 490 sql.append(" SET ").append(wrap(logicDeleteColumn)).append(" = ").append(getLogicDeletedValue()); 491 sql.append(" WHERE "); 492 sql.append("("); 493 494 String[] primaryKeys = tableInfo.getPrimaryKeys(); 495 496 //多主键的场景 497 if (primaryKeys.length > 1) { 498 for (int i = 0; i < primaryValues.length / primaryKeys.length; i++) { 499 if (i > 0) { 500 sql.append(" OR "); 501 } 502 sql.append("("); 503 for (int j = 0; j < primaryKeys.length; j++) { 504 if (j > 0) { 505 sql.append(" AND "); 506 } 507 sql.append(wrap(primaryKeys[j])).append(" = ?"); 508 } 509 sql.append(")"); 510 } 511 } 512 // 单主键 513 else { 514 for (int i = 0; i < primaryValues.length; i++) { 515 if (i > 0) { 516 sql.append(" OR "); 517 } 518 sql.append(wrap(primaryKeys[0])).append(" = ?"); 519 } 520 } 521 522 sql.append(") AND ").append(wrap(logicDeleteColumn)).append(" = ").append(getLogicNormalValue()); 523 524 if (ArrayUtil.isNotEmpty(tenantIdArgs)) { 525 sql.append(" AND ").append(wrap(tableInfo.getTenantIdColumn())).append(" IN ").append(buildQuestion(tenantIdArgs.length, true)); 526 } 527 528 return sql.toString(); 529 } 530 531 @Override 532 public String forDeleteEntityBatchByQuery(TableInfo tableInfo, QueryWrapper queryWrapper) { 533 534 String logicDeleteColumn = tableInfo.getLogicDeleteColumn(); 535 536 //正常删除 537 if (StringUtil.isBlank(logicDeleteColumn)) { 538 return forDeleteByQuery(queryWrapper); 539 } 540 541 542 //逻辑删除 543 List<QueryTable> queryTables = CPI.getQueryTables(queryWrapper); 544 List<QueryTable> joinTables = CPI.getJoinTables(queryWrapper); 545 List<QueryTable> allTables = CollectionUtil.merge(queryTables, joinTables); 546 547 //ignore selectColumns 548 StringBuilder sqlBuilder = new StringBuilder("UPDATE "); 549 sqlBuilder.append(wrap(tableInfo.getTableName())); 550 sqlBuilder.append(" SET ").append(wrap(logicDeleteColumn)).append(" = ").append(getLogicDeletedValue()); 551 552 553 buildJoinSql(sqlBuilder, queryWrapper, allTables); 554 buildWhereSql(sqlBuilder, queryWrapper, allTables, false); 555 buildGroupBySql(sqlBuilder, queryWrapper, allTables); 556 buildHavingSql(sqlBuilder, queryWrapper, allTables); 557 558 //ignore orderBy and limit 559 //buildOrderBySql(sqlBuilder, queryWrapper); 560 //buildLimitSql(sqlBuilder, queryWrapper); 561 562 return sqlBuilder.toString(); 563 } 564 565 566 @Override 567 public String forUpdateEntity(TableInfo tableInfo, Object entity, boolean ignoreNulls) { 568 StringBuilder sql = new StringBuilder(); 569 570 Set<String> modifyAttrs = tableInfo.obtainUpdateColumns(entity, ignoreNulls, false); 571 String[] primaryKeys = tableInfo.getPrimaryKeys(); 572 573 sql.append("UPDATE ").append(wrap(tableInfo.getTableName())).append(" SET "); 574 575 StringJoiner stringJoiner = new StringJoiner(", "); 576 577 for (String modifyAttr : modifyAttrs) { 578 stringJoiner.add(wrap(modifyAttr) + " = ?"); 579 } 580 581 Map<String, String> onUpdateColumns = tableInfo.getOnUpdateColumns(); 582 if (onUpdateColumns != null && !onUpdateColumns.isEmpty()) { 583 onUpdateColumns.forEach((column, value) -> stringJoiner.add(wrap(column) + " = " + value)); 584 } 585 586 //乐观锁字段 587 String versionColumn = tableInfo.getVersionColumn(); 588 if (StringUtil.isNotBlank(versionColumn)) { 589 stringJoiner.add(wrap(versionColumn) + " = " + wrap(versionColumn) + " + 1 "); 590 } 591 592 sql.append(stringJoiner); 593 594 sql.append(" WHERE "); 595 for (int i = 0; i < primaryKeys.length; i++) { 596 if (i > 0) { 597 sql.append(" AND "); 598 } 599 sql.append(wrap(primaryKeys[i])).append(" = ?"); 600 } 601 602 //逻辑删除条件,已删除的数据不能被修改 603 String logicDeleteColumn = tableInfo.getLogicDeleteColumn(); 604 if (StringUtil.isNotBlank(logicDeleteColumn)) { 605 sql.append(" AND ").append(wrap(logicDeleteColumn)).append(" = ").append(getLogicNormalValue()); 606 } 607 608 609 //租户ID字段 610 Object[] tenantIdArgs = tableInfo.buildTenantIdArgs(); 611 if (ArrayUtil.isNotEmpty(tenantIdArgs)) { 612 if (tenantIdArgs.length == 1) { 613 sql.append(" AND ").append(wrap(tableInfo.getTenantIdColumn())).append(" = ?"); 614 } else { 615 sql.append(" AND ").append(wrap(tableInfo.getTenantIdColumn())).append(" IN ").append(buildQuestion(tenantIdArgs.length, true)); 616 } 617 } 618 619 //乐观锁条件 620 if (StringUtil.isNotBlank(versionColumn)) { 621 Object versionValue = tableInfo.buildColumnSqlArg(entity, versionColumn); 622 if (versionValue == null) { 623 throw FlexExceptions.wrap("The version value of entity[%s] must not be null.", entity); 624 } 625 sql.append(" AND ").append(wrap(versionColumn)).append(" = ").append(versionValue); 626 } 627 628 629 return sql.toString(); 630 } 631 632 @Override 633 public String forUpdateEntityByQuery(TableInfo tableInfo, Object entity, boolean ignoreNulls, QueryWrapper queryWrapper) { 634 StringBuilder sql = new StringBuilder(); 635 636 Set<String> modifyAttrs = tableInfo.obtainUpdateColumns(entity, ignoreNulls, true); 637 638 sql.append("UPDATE ").append(wrap(tableInfo.getTableName())).append(" SET "); 639 640 StringJoiner stringJoiner = new StringJoiner(", "); 641 642 for (String modifyAttr : modifyAttrs) { 643 stringJoiner.add(wrap(modifyAttr) + " = ?"); 644 } 645 646 Map<String, String> onUpdateColumns = tableInfo.getOnUpdateColumns(); 647 if (onUpdateColumns != null && !onUpdateColumns.isEmpty()) { 648 onUpdateColumns.forEach((column, value) -> stringJoiner.add(wrap(column) + " = " + value)); 649 } 650 651 //乐观锁字段 652 String versionColumn = tableInfo.getVersionColumn(); 653 if (StringUtil.isNotBlank(versionColumn)) { 654 stringJoiner.add(wrap(versionColumn) + " = " + wrap(versionColumn) + " + 1 "); 655 } 656 657 sql.append(stringJoiner); 658 659 660 String whereConditionSql = buildWhereConditionSql(queryWrapper); 661 662 //不允许全量更新 663 if (StringUtil.isBlank(whereConditionSql)) { 664 throw new IllegalArgumentException("Not allowed UPDATE a table without where condition."); 665 } 666 667 sql.append(" WHERE ").append(whereConditionSql); 668 return sql.toString(); 669 } 670 671 @Override 672 public String forSelectOneEntityById(TableInfo tableInfo) { 673 StringBuilder sql = buildSelectColumnSql(null, tableInfo.getDefaultQueryColumn()); 674 sql.append(" FROM ").append(wrap(tableInfo.getTableName())); 675 sql.append(" WHERE "); 676 String[] pKeys = tableInfo.getPrimaryKeys(); 677 for (int i = 0; i < pKeys.length; i++) { 678 if (i > 0) { 679 sql.append(" AND "); 680 } 681 sql.append(wrap(pKeys[i])).append(" = ?"); 682 } 683 684 //逻辑删除的情况下,需要添加逻辑删除的条件 685 String logicDeleteColumn = tableInfo.getLogicDeleteColumn(); 686 if (StringUtil.isNotBlank(logicDeleteColumn)) { 687 sql.append(" AND ").append(wrap(logicDeleteColumn)).append(" = ").append(getLogicNormalValue()); 688 } 689 690 //多租户 691 Object[] tenantIdArgs = tableInfo.buildTenantIdArgs(); 692 if (ArrayUtil.isNotEmpty(tenantIdArgs)) { 693 sql.append(" AND ").append(wrap(tableInfo.getTenantIdColumn())).append(" IN ").append(buildQuestion(tenantIdArgs.length, true)); 694 } 695 696 return sql.toString(); 697 } 698 699 700 @Override 701 public String forSelectEntityListByIds(TableInfo tableInfo, Object[] primaryValues) { 702 StringBuilder sql = buildSelectColumnSql(null, tableInfo.getDefaultQueryColumn()); 703 sql.append(" FROM ").append(wrap(tableInfo.getTableName())); 704 sql.append(" WHERE "); 705 String[] primaryKeys = tableInfo.getPrimaryKeys(); 706 707 String logicDeleteColumn = tableInfo.getLogicDeleteColumn(); 708 Object[] tenantIdArgs = tableInfo.buildTenantIdArgs(); 709 if (StringUtil.isNotBlank(logicDeleteColumn) || ArrayUtil.isNotEmpty(tenantIdArgs)) { 710 sql.append("("); 711 } 712 713 //多主键的场景 714 if (primaryKeys.length > 1) { 715 for (int i = 0; i < primaryValues.length / primaryKeys.length; i++) { 716 if (i > 0) { 717 sql.append(" OR "); 718 } 719 sql.append("("); 720 for (int j = 0; j < primaryKeys.length; j++) { 721 if (j > 0) { 722 sql.append(" AND "); 723 } 724 sql.append(wrap(primaryKeys[j])).append(" = ?"); 725 } 726 sql.append(")"); 727 } 728 } 729 // 单主键 730 else { 731 for (int i = 0; i < primaryValues.length; i++) { 732 if (i > 0) { 733 sql.append(" OR "); 734 } 735 sql.append(wrap(primaryKeys[0])).append(" = ?"); 736 } 737 } 738 739 if (StringUtil.isNotBlank(logicDeleteColumn) || ArrayUtil.isNotEmpty(tenantIdArgs)) { 740 sql.append(")"); 741 } 742 743 744 if (StringUtil.isNotBlank(logicDeleteColumn)) { 745 sql.append(" AND ").append(wrap(logicDeleteColumn)).append(" = ").append(getLogicNormalValue()); 746 } 747 748 if (ArrayUtil.isNotEmpty(tenantIdArgs)) { 749 sql.append(" AND ").append(wrap(tableInfo.getTenantIdColumn())).append(" IN").append(buildQuestion(tenantIdArgs.length, true)); 750 } 751 752 return sql.toString(); 753 } 754 755 756 protected void buildJoinSql(StringBuilder sqlBuilder, QueryWrapper queryWrapper, List<QueryTable> queryTables) { 757 List<Join> joins = CPI.getJoins(queryWrapper); 758 if (joins != null && !joins.isEmpty()) { 759 for (Join join : joins) { 760 if (!join.checkEffective()) { 761 continue; 762 } 763 sqlBuilder.append(join.toSql(queryTables, this)); 764 } 765 } 766 } 767 768 769 protected void buildWhereSql(StringBuilder sqlBuilder, QueryWrapper queryWrapper, List<QueryTable> queryTables, boolean allowNoCondition) { 770 QueryCondition whereQueryCondition = CPI.getWhereQueryCondition(queryWrapper); 771 if (whereQueryCondition != null) { 772 String whereSql = whereQueryCondition.toSql(queryTables, this); 773 if (StringUtil.isNotBlank(whereSql)) { 774 sqlBuilder.append(" WHERE ").append(whereSql); 775 } else if (!allowNoCondition) { 776 throw new IllegalArgumentException("Not allowed DELETE a table without where condition."); 777 } 778 } 779 } 780 781 782 protected void buildGroupBySql(StringBuilder sqlBuilder, QueryWrapper queryWrapper, List<QueryTable> queryTables) { 783 List<QueryColumn> groupByColumns = CPI.getGroupByColumns(queryWrapper); 784 if (groupByColumns != null && !groupByColumns.isEmpty()) { 785 sqlBuilder.append(" GROUP BY "); 786 int index = 0; 787 for (QueryColumn groupByColumn : groupByColumns) { 788 String groupBy = CPI.toConditionSql(groupByColumn, queryTables, this); 789 sqlBuilder.append(groupBy); 790 if (index != groupByColumns.size() - 1) { 791 sqlBuilder.append(", "); 792 } 793 index++; 794 } 795 } 796 } 797 798 799 protected void buildHavingSql(StringBuilder sqlBuilder, QueryWrapper queryWrapper, List<QueryTable> queryTables) { 800 QueryCondition havingQueryCondition = CPI.getHavingQueryCondition(queryWrapper); 801 if (havingQueryCondition != null) { 802 String havingSql = havingQueryCondition.toSql(queryTables, this); 803 if (StringUtil.isNotBlank(havingSql)) { 804 sqlBuilder.append(" HAVING ").append(havingSql); 805 } 806 } 807 } 808 809 810 protected void buildOrderBySql(StringBuilder sqlBuilder, QueryWrapper queryWrapper, List<QueryTable> queryTables) { 811 List<QueryOrderBy> orderBys = CPI.getOrderBys(queryWrapper); 812 if (orderBys != null && !orderBys.isEmpty()) { 813 sqlBuilder.append(" ORDER BY "); 814 int index = 0; 815 for (QueryOrderBy orderBy : orderBys) { 816 sqlBuilder.append(orderBy.toSql(queryTables, this)); 817 if (index != orderBys.size() - 1) { 818 sqlBuilder.append(", "); 819 } 820 index++; 821 } 822 } 823 } 824 825 826 /** 827 * 构建 limit 和 offset 的参数 828 */ 829 protected StringBuilder buildLimitOffsetSql(StringBuilder sqlBuilder, QueryWrapper queryWrapper, Integer limitRows, Integer limitOffset) { 830 return limitOffsetProcesser.process(sqlBuilder, queryWrapper, limitRows, limitOffset); 831 } 832 833 834 protected String buildQuestion(int count, boolean withBrackets) { 835 StringBuilder sb = new StringBuilder(); 836 for (int i = 0; i < count; i++) { 837 sb.append("?"); 838 if (i != count - 1) { 839 sb.append(", "); 840 } 841 } 842 return withBrackets ? "(" + sb + ")" : sb.toString(); 843 } 844 845 846 protected Object getLogicNormalValue() { 847 Object normalValueOfLogicDelete = FlexGlobalConfig.getDefaultConfig().getNormalValueOfLogicDelete(); 848 if (normalValueOfLogicDelete instanceof Number) { 849 return normalValueOfLogicDelete; 850 } 851 return "\"" + normalValueOfLogicDelete.toString() + "\""; 852 } 853 854 855 protected Object getLogicDeletedValue() { 856 Object deletedValueOfLogicDelete = FlexGlobalConfig.getDefaultConfig().getDeletedValueOfLogicDelete(); 857 if (deletedValueOfLogicDelete instanceof Number) { 858 return deletedValueOfLogicDelete; 859 } 860 return "\"" + deletedValueOfLogicDelete.toString() + "\""; 861 } 862 863}