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 311 for (QueryColumn selectColumn : selectColumns) { 312 String selectColumnSql = CPI.toSelectSql(selectColumn, queryTables, this); 313 sqlBuilder.append(selectColumnSql); 314 if (index != selectColumns.size() - 1) { 315 sqlBuilder.append(", "); 316 } 317 index++; 318 } 319 } 320 return sqlBuilder; 321 } 322 323 324 @Override 325 public String buildSelectCountSql(QueryWrapper queryWrapper) { 326 List<QueryTable> queryTables = CPI.getQueryTables(queryWrapper); 327 List<QueryTable> joinTables = CPI.getJoinTables(queryWrapper); 328 List<QueryTable> allTables = CollectionUtil.merge(queryTables, joinTables); 329 330 //ignore selectColumns 331 StringBuilder sqlBuilder = new StringBuilder("SELECT COUNT(*) FROM "); 332 sqlBuilder.append(StringUtil.join(", ", queryTables, queryTable -> queryTable.toSql(this))); 333 334 335 buildJoinSql(sqlBuilder, queryWrapper, allTables); 336 buildWhereSql(sqlBuilder, queryWrapper, allTables, true); 337 buildGroupBySql(sqlBuilder, queryWrapper, allTables); 338 buildHavingSql(sqlBuilder, queryWrapper, allTables); 339 340 // ignore orderBy and limit 341 // buildOrderBySql(sqlBuilder, queryWrapper); 342 // buildLimitSql(sqlBuilder, queryWrapper); 343 344 return sqlBuilder.toString(); 345 } 346 347 @Override 348 public String buildDeleteSql(QueryWrapper queryWrapper) { 349 List<QueryTable> queryTables = CPI.getQueryTables(queryWrapper); 350 List<QueryTable> joinTables = CPI.getJoinTables(queryWrapper); 351 List<QueryTable> allTables = CollectionUtil.merge(queryTables, joinTables); 352 353 //ignore selectColumns 354 StringBuilder sqlBuilder = new StringBuilder("DELETE FROM "); 355 sqlBuilder.append(StringUtil.join(", ", queryTables, queryTable -> queryTable.toSql(this))); 356 357 buildJoinSql(sqlBuilder, queryWrapper, allTables); 358 buildWhereSql(sqlBuilder, queryWrapper, allTables, false); 359 buildGroupBySql(sqlBuilder, queryWrapper, allTables); 360 buildHavingSql(sqlBuilder, queryWrapper, allTables); 361 362 //ignore orderBy and limit 363 //buildOrderBySql(sqlBuilder, queryWrapper); 364 //buildLimitSql(sqlBuilder, queryWrapper); 365 366 return sqlBuilder.toString(); 367 } 368 369 @Override 370 public String buildWhereConditionSql(QueryWrapper queryWrapper) { 371 QueryCondition whereQueryCondition = CPI.getWhereQueryCondition(queryWrapper); 372 return whereQueryCondition != null ? whereQueryCondition.toSql(CPI.getQueryTables(queryWrapper), this) : ""; 373 } 374 375 @Override 376 public String forInsertEntity(TableInfo tableInfo, Object entity, boolean ignoreNulls) { 377 StringBuilder sql = new StringBuilder(); 378 sql.append("INSERT INTO ").append(wrap(tableInfo.getTableName())); 379 380 String[] insertColumns = tableInfo.obtainInsertColumns(entity, ignoreNulls); 381 Map<String, String> onInsertColumns = tableInfo.getOnInsertColumns(); 382 383 StringJoiner sqlFields = new StringJoiner(", "); 384 StringJoiner sqlValues = new StringJoiner(", "); 385 386 for (String insertColumn : insertColumns) { 387 sqlFields.add(wrap(insertColumn)); 388 if (onInsertColumns != null && onInsertColumns.containsKey(insertColumn)) { 389 sqlValues.add(onInsertColumns.get(insertColumn)); 390 } else { 391 sqlValues.add("?"); 392 } 393 } 394 395 return sql.append("(").append(sqlFields).append(")") 396 .append(" VALUES ") 397 .append("(").append(sqlValues).append(")").toString(); 398 } 399 400 @Override 401 public String forInsertEntityBatch(TableInfo tableInfo, List<Object> entities) { 402 StringBuilder sql = new StringBuilder(); 403 sql.append("INSERT INTO ").append(wrap(tableInfo.getTableName())); 404 String[] insertColumns = tableInfo.obtainInsertColumns(null, false); 405 String[] warpedInsertColumns = new String[insertColumns.length]; 406 for (int i = 0; i < insertColumns.length; i++) { 407 warpedInsertColumns[i] = wrap(insertColumns[i]); 408 } 409 sql.append("(").append(StringUtil.join(", ", warpedInsertColumns)).append(")"); 410 sql.append(" VALUES "); 411 412 Map<String, String> onInsertColumns = tableInfo.getOnInsertColumns(); 413 for (int i = 0; i < entities.size(); i++) { 414 StringJoiner stringJoiner = new StringJoiner(", ", "(", ")"); 415 for (String insertColumn : insertColumns) { 416 if (onInsertColumns != null && onInsertColumns.containsKey(insertColumn)) { 417 //直接读取 onInsert 配置的值,而不用 "?" 代替 418 stringJoiner.add(onInsertColumns.get(insertColumn)); 419 } else { 420 stringJoiner.add("?"); 421 } 422 } 423 sql.append(stringJoiner); 424 if (i != entities.size() - 1) { 425 sql.append(", "); 426 } 427 } 428 429 return sql.toString(); 430 } 431 432 @Override 433 public String forDeleteEntityById(TableInfo tableInfo) { 434 String logicDeleteColumn = tableInfo.getLogicDeleteColumn(); 435 Object[] tenantIdArgs = tableInfo.buildTenantIdArgs(); 436 //正常删除 437 if (StringUtil.isBlank(logicDeleteColumn)) { 438 String deleteByIdSql = forDeleteById(tableInfo.getTableName(), tableInfo.getPrimaryKeys()); 439 440 if (ArrayUtil.isNotEmpty(tenantIdArgs)) { 441 deleteByIdSql += " AND " + wrap(tableInfo.getTenantIdColumn()) + " IN " + buildQuestion(tenantIdArgs.length, true); 442 } 443 return deleteByIdSql; 444 } 445 446 //逻辑删除 447 StringBuilder sql = new StringBuilder(); 448 String[] primaryKeys = tableInfo.getPrimaryKeys(); 449 450 sql.append("UPDATE ").append(wrap(tableInfo.getTableName())); 451 sql.append(" SET ").append(wrap(logicDeleteColumn)).append(" = ").append(getLogicDeletedValue()); 452 sql.append(" WHERE "); 453 for (int i = 0; i < primaryKeys.length; i++) { 454 if (i > 0) { 455 sql.append(" AND "); 456 } 457 sql.append(wrap(primaryKeys[i])).append(" = ?"); 458 } 459 460 sql.append(" AND ").append(wrap(logicDeleteColumn)).append(" = ").append(getLogicNormalValue()); 461 462 //租户ID 463 if (ArrayUtil.isNotEmpty(tenantIdArgs)) { 464 sql.append(" AND ").append(wrap(tableInfo.getTenantIdColumn())).append(" IN ").append(buildQuestion(tenantIdArgs.length, true)); 465 } 466 467 return sql.toString(); 468 } 469 470 471 @Override 472 public String forDeleteEntityBatchByIds(TableInfo tableInfo, Object[] primaryValues) { 473 String logicDeleteColumn = tableInfo.getLogicDeleteColumn(); 474 Object[] tenantIdArgs = tableInfo.buildTenantIdArgs(); 475 476 //正常删除 477 if (StringUtil.isBlank(logicDeleteColumn)) { 478 String deleteSQL = forDeleteBatchByIds(tableInfo.getTableName(), tableInfo.getPrimaryKeys(), primaryValues); 479 480 //多租户 481 if (ArrayUtil.isNotEmpty(tenantIdArgs)) { 482 deleteSQL = deleteSQL.replace(" WHERE ", " WHERE (") + ")"; 483 deleteSQL += " AND " + wrap(tableInfo.getTenantIdColumn()) + " IN " + buildQuestion(tenantIdArgs.length, true); 484 } 485 return deleteSQL; 486 } 487 488 StringBuilder sql = new StringBuilder(); 489 sql.append("UPDATE "); 490 sql.append(wrap(tableInfo.getTableName())); 491 sql.append(" SET ").append(wrap(logicDeleteColumn)).append(" = ").append(getLogicDeletedValue()); 492 sql.append(" WHERE "); 493 sql.append("("); 494 495 String[] primaryKeys = tableInfo.getPrimaryKeys(); 496 497 //多主键的场景 498 if (primaryKeys.length > 1) { 499 for (int i = 0; i < primaryValues.length / primaryKeys.length; i++) { 500 if (i > 0) { 501 sql.append(" OR "); 502 } 503 sql.append("("); 504 for (int j = 0; j < primaryKeys.length; j++) { 505 if (j > 0) { 506 sql.append(" AND "); 507 } 508 sql.append(wrap(primaryKeys[j])).append(" = ?"); 509 } 510 sql.append(")"); 511 } 512 } 513 // 单主键 514 else { 515 for (int i = 0; i < primaryValues.length; i++) { 516 if (i > 0) { 517 sql.append(" OR "); 518 } 519 sql.append(wrap(primaryKeys[0])).append(" = ?"); 520 } 521 } 522 523 sql.append(") AND ").append(wrap(logicDeleteColumn)).append(" = ").append(getLogicNormalValue()); 524 525 if (ArrayUtil.isNotEmpty(tenantIdArgs)) { 526 sql.append(" AND ").append(wrap(tableInfo.getTenantIdColumn())).append(" IN ").append(buildQuestion(tenantIdArgs.length, true)); 527 } 528 529 return sql.toString(); 530 } 531 532 @Override 533 public String forDeleteEntityBatchByQuery(TableInfo tableInfo, QueryWrapper queryWrapper) { 534 535 String logicDeleteColumn = tableInfo.getLogicDeleteColumn(); 536 537 //正常删除 538 if (StringUtil.isBlank(logicDeleteColumn)) { 539 return forDeleteByQuery(queryWrapper); 540 } 541 542 543 //逻辑删除 544 List<QueryTable> queryTables = CPI.getQueryTables(queryWrapper); 545 List<QueryTable> joinTables = CPI.getJoinTables(queryWrapper); 546 List<QueryTable> allTables = CollectionUtil.merge(queryTables, joinTables); 547 548 //ignore selectColumns 549 StringBuilder sqlBuilder = new StringBuilder("UPDATE "); 550 sqlBuilder.append(wrap(tableInfo.getTableName())); 551 sqlBuilder.append(" SET ").append(wrap(logicDeleteColumn)).append(" = ").append(getLogicDeletedValue()); 552 553 554 buildJoinSql(sqlBuilder, queryWrapper, allTables); 555 buildWhereSql(sqlBuilder, queryWrapper, allTables, false); 556 buildGroupBySql(sqlBuilder, queryWrapper, allTables); 557 buildHavingSql(sqlBuilder, queryWrapper, allTables); 558 559 //ignore orderBy and limit 560 //buildOrderBySql(sqlBuilder, queryWrapper); 561 //buildLimitSql(sqlBuilder, queryWrapper); 562 563 return sqlBuilder.toString(); 564 } 565 566 567 @Override 568 public String forUpdateEntity(TableInfo tableInfo, Object entity, boolean ignoreNulls) { 569 StringBuilder sql = new StringBuilder(); 570 571 Set<String> modifyAttrs = tableInfo.obtainUpdateColumns(entity, ignoreNulls, false); 572 String[] primaryKeys = tableInfo.getPrimaryKeys(); 573 574 sql.append("UPDATE ").append(wrap(tableInfo.getTableName())).append(" SET "); 575 576 StringJoiner stringJoiner = new StringJoiner(", "); 577 578 for (String modifyAttr : modifyAttrs) { 579 stringJoiner.add(wrap(modifyAttr) + " = ?"); 580 } 581 582 Map<String, String> onUpdateColumns = tableInfo.getOnUpdateColumns(); 583 if (onUpdateColumns != null && !onUpdateColumns.isEmpty()) { 584 onUpdateColumns.forEach((column, value) -> stringJoiner.add(wrap(column) + " = " + value)); 585 } 586 587 //乐观锁字段 588 String versionColumn = tableInfo.getVersionColumn(); 589 if (StringUtil.isNotBlank(versionColumn)) { 590 stringJoiner.add(wrap(versionColumn) + " = " + wrap(versionColumn) + " + 1 "); 591 } 592 593 sql.append(stringJoiner); 594 595 sql.append(" WHERE "); 596 for (int i = 0; i < primaryKeys.length; i++) { 597 if (i > 0) { 598 sql.append(" AND "); 599 } 600 sql.append(wrap(primaryKeys[i])).append(" = ?"); 601 } 602 603 //逻辑删除条件,已删除的数据不能被修改 604 String logicDeleteColumn = tableInfo.getLogicDeleteColumn(); 605 if (StringUtil.isNotBlank(logicDeleteColumn)) { 606 sql.append(" AND ").append(wrap(logicDeleteColumn)).append(" = ").append(getLogicNormalValue()); 607 } 608 609 610 //租户ID字段 611 Object[] tenantIdArgs = tableInfo.buildTenantIdArgs(); 612 if (ArrayUtil.isNotEmpty(tenantIdArgs)) { 613 if (tenantIdArgs.length == 1) { 614 sql.append(" AND ").append(wrap(tableInfo.getTenantIdColumn())).append(" = ?"); 615 } else { 616 sql.append(" AND ").append(wrap(tableInfo.getTenantIdColumn())).append(" IN ").append(buildQuestion(tenantIdArgs.length, true)); 617 } 618 } 619 620 //乐观锁条件 621 if (StringUtil.isNotBlank(versionColumn)) { 622 Object versionValue = tableInfo.buildColumnSqlArg(entity, versionColumn); 623 if (versionValue == null) { 624 throw FlexExceptions.wrap("The version value of entity[%s] must not be null.", entity); 625 } 626 sql.append(" AND ").append(wrap(versionColumn)).append(" = ").append(versionValue); 627 } 628 629 630 return sql.toString(); 631 } 632 633 @Override 634 public String forUpdateEntityByQuery(TableInfo tableInfo, Object entity, boolean ignoreNulls, QueryWrapper queryWrapper) { 635 StringBuilder sql = new StringBuilder(); 636 637 Set<String> modifyAttrs = tableInfo.obtainUpdateColumns(entity, ignoreNulls, true); 638 639 sql.append("UPDATE ").append(wrap(tableInfo.getTableName())).append(" SET "); 640 641 StringJoiner stringJoiner = new StringJoiner(", "); 642 643 for (String modifyAttr : modifyAttrs) { 644 stringJoiner.add(wrap(modifyAttr) + " = ?"); 645 } 646 647 Map<String, String> onUpdateColumns = tableInfo.getOnUpdateColumns(); 648 if (onUpdateColumns != null && !onUpdateColumns.isEmpty()) { 649 onUpdateColumns.forEach((column, value) -> stringJoiner.add(wrap(column) + " = " + value)); 650 } 651 652 //乐观锁字段 653 String versionColumn = tableInfo.getVersionColumn(); 654 if (StringUtil.isNotBlank(versionColumn)) { 655 stringJoiner.add(wrap(versionColumn) + " = " + wrap(versionColumn) + " + 1 "); 656 } 657 658 sql.append(stringJoiner); 659 660 661 String whereConditionSql = buildWhereConditionSql(queryWrapper); 662 663 //不允许全量更新 664 if (StringUtil.isBlank(whereConditionSql)) { 665 throw new IllegalArgumentException("Not allowed UPDATE a table without where condition."); 666 } 667 668 sql.append(" WHERE ").append(whereConditionSql); 669 return sql.toString(); 670 } 671 672 @Override 673 public String forSelectOneEntityById(TableInfo tableInfo) { 674 StringBuilder sql = buildSelectColumnSql(null, tableInfo.getDefaultQueryColumn()); 675 sql.append(" FROM ").append(wrap(tableInfo.getTableName())); 676 sql.append(" WHERE "); 677 String[] pKeys = tableInfo.getPrimaryKeys(); 678 for (int i = 0; i < pKeys.length; i++) { 679 if (i > 0) { 680 sql.append(" AND "); 681 } 682 sql.append(wrap(pKeys[i])).append(" = ?"); 683 } 684 685 //逻辑删除的情况下,需要添加逻辑删除的条件 686 String logicDeleteColumn = tableInfo.getLogicDeleteColumn(); 687 if (StringUtil.isNotBlank(logicDeleteColumn)) { 688 sql.append(" AND ").append(wrap(logicDeleteColumn)).append(" = ").append(getLogicNormalValue()); 689 } 690 691 //多租户 692 Object[] tenantIdArgs = tableInfo.buildTenantIdArgs(); 693 if (ArrayUtil.isNotEmpty(tenantIdArgs)) { 694 sql.append(" AND ").append(wrap(tableInfo.getTenantIdColumn())).append(" IN ").append(buildQuestion(tenantIdArgs.length, true)); 695 } 696 697 return sql.toString(); 698 } 699 700 701 @Override 702 public String forSelectEntityListByIds(TableInfo tableInfo, Object[] primaryValues) { 703 StringBuilder sql = buildSelectColumnSql(null, tableInfo.getDefaultQueryColumn()); 704 sql.append(" FROM ").append(wrap(tableInfo.getTableName())); 705 sql.append(" WHERE "); 706 String[] primaryKeys = tableInfo.getPrimaryKeys(); 707 708 String logicDeleteColumn = tableInfo.getLogicDeleteColumn(); 709 Object[] tenantIdArgs = tableInfo.buildTenantIdArgs(); 710 if (StringUtil.isNotBlank(logicDeleteColumn) || ArrayUtil.isNotEmpty(tenantIdArgs)) { 711 sql.append("("); 712 } 713 714 //多主键的场景 715 if (primaryKeys.length > 1) { 716 for (int i = 0; i < primaryValues.length / primaryKeys.length; i++) { 717 if (i > 0) { 718 sql.append(" OR "); 719 } 720 sql.append("("); 721 for (int j = 0; j < primaryKeys.length; j++) { 722 if (j > 0) { 723 sql.append(" AND "); 724 } 725 sql.append(wrap(primaryKeys[j])).append(" = ?"); 726 } 727 sql.append(")"); 728 } 729 } 730 // 单主键 731 else { 732 for (int i = 0; i < primaryValues.length; i++) { 733 if (i > 0) { 734 sql.append(" OR "); 735 } 736 sql.append(wrap(primaryKeys[0])).append(" = ?"); 737 } 738 } 739 740 if (StringUtil.isNotBlank(logicDeleteColumn) || ArrayUtil.isNotEmpty(tenantIdArgs)) { 741 sql.append(")"); 742 } 743 744 745 if (StringUtil.isNotBlank(logicDeleteColumn)) { 746 sql.append(" AND ").append(wrap(logicDeleteColumn)).append(" = ").append(getLogicNormalValue()); 747 } 748 749 if (ArrayUtil.isNotEmpty(tenantIdArgs)) { 750 sql.append(" AND ").append(wrap(tableInfo.getTenantIdColumn())).append(" IN").append(buildQuestion(tenantIdArgs.length, true)); 751 } 752 753 return sql.toString(); 754 } 755 756 757 protected void buildJoinSql(StringBuilder sqlBuilder, QueryWrapper queryWrapper, List<QueryTable> queryTables) { 758 List<Join> joins = CPI.getJoins(queryWrapper); 759 if (joins != null && !joins.isEmpty()) { 760 for (Join join : joins) { 761 if (!join.checkEffective()) { 762 continue; 763 } 764 sqlBuilder.append(join.toSql(queryTables, this)); 765 } 766 } 767 } 768 769 770 protected void buildWhereSql(StringBuilder sqlBuilder, QueryWrapper queryWrapper, List<QueryTable> queryTables, boolean allowNoCondition) { 771 QueryCondition whereQueryCondition = CPI.getWhereQueryCondition(queryWrapper); 772 if (whereQueryCondition != null) { 773 String whereSql = whereQueryCondition.toSql(queryTables, this); 774 if (StringUtil.isNotBlank(whereSql)) { 775 sqlBuilder.append(" WHERE ").append(whereSql); 776 } else if (!allowNoCondition) { 777 throw new IllegalArgumentException("Not allowed DELETE a table without where condition."); 778 } 779 } 780 } 781 782 783 protected void buildGroupBySql(StringBuilder sqlBuilder, QueryWrapper queryWrapper, List<QueryTable> queryTables) { 784 List<QueryColumn> groupByColumns = CPI.getGroupByColumns(queryWrapper); 785 if (groupByColumns != null && !groupByColumns.isEmpty()) { 786 sqlBuilder.append(" GROUP BY "); 787 int index = 0; 788 for (QueryColumn groupByColumn : groupByColumns) { 789 String groupBy = CPI.toConditionSql(groupByColumn, queryTables, this); 790 sqlBuilder.append(groupBy); 791 if (index != groupByColumns.size() - 1) { 792 sqlBuilder.append(", "); 793 } 794 index++; 795 } 796 } 797 } 798 799 800 protected void buildHavingSql(StringBuilder sqlBuilder, QueryWrapper queryWrapper, List<QueryTable> queryTables) { 801 QueryCondition havingQueryCondition = CPI.getHavingQueryCondition(queryWrapper); 802 if (havingQueryCondition != null) { 803 String havingSql = havingQueryCondition.toSql(queryTables, this); 804 if (StringUtil.isNotBlank(havingSql)) { 805 sqlBuilder.append(" HAVING ").append(havingSql); 806 } 807 } 808 } 809 810 811 protected void buildOrderBySql(StringBuilder sqlBuilder, QueryWrapper queryWrapper, List<QueryTable> queryTables) { 812 List<QueryOrderBy> orderBys = CPI.getOrderBys(queryWrapper); 813 if (orderBys != null && !orderBys.isEmpty()) { 814 sqlBuilder.append(" ORDER BY "); 815 int index = 0; 816 for (QueryOrderBy orderBy : orderBys) { 817 sqlBuilder.append(orderBy.toSql(queryTables, this)); 818 if (index != orderBys.size() - 1) { 819 sqlBuilder.append(", "); 820 } 821 index++; 822 } 823 } 824 } 825 826 827 /** 828 * 构建 limit 和 offset 的参数 829 */ 830 protected StringBuilder buildLimitOffsetSql(StringBuilder sqlBuilder, QueryWrapper queryWrapper, Integer limitRows, Integer limitOffset) { 831 return limitOffsetProcesser.process(sqlBuilder, queryWrapper, limitRows, limitOffset); 832 } 833 834 835 protected String buildQuestion(int count, boolean withBrackets) { 836 StringBuilder sb = new StringBuilder(); 837 for (int i = 0; i < count; i++) { 838 sb.append("?"); 839 if (i != count - 1) { 840 sb.append(", "); 841 } 842 } 843 return withBrackets ? "(" + sb + ")" : sb.toString(); 844 } 845 846 847 protected Object getLogicNormalValue() { 848 Object normalValueOfLogicDelete = FlexGlobalConfig.getDefaultConfig().getNormalValueOfLogicDelete(); 849 if (normalValueOfLogicDelete instanceof Number) { 850 return normalValueOfLogicDelete; 851 } 852 return "\"" + normalValueOfLogicDelete.toString() + "\""; 853 } 854 855 856 protected Object getLogicDeletedValue() { 857 Object deletedValueOfLogicDelete = FlexGlobalConfig.getDefaultConfig().getDeletedValueOfLogicDelete(); 858 if (deletedValueOfLogicDelete instanceof Number) { 859 return deletedValueOfLogicDelete; 860 } 861 return "\"" + deletedValueOfLogicDelete.toString() + "\""; 862 } 863 864}