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