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.provider; 017 018import com.mybatisflex.core.FlexConsts; 019import com.mybatisflex.core.dialect.DialectFactory; 020import com.mybatisflex.core.exception.FlexAssert; 021import com.mybatisflex.core.exception.FlexExceptions; 022import com.mybatisflex.core.query.CPI; 023import com.mybatisflex.core.query.QueryTable; 024import com.mybatisflex.core.query.QueryWrapper; 025import com.mybatisflex.core.table.TableInfo; 026import com.mybatisflex.core.table.TableInfoFactory; 027import com.mybatisflex.core.util.ArrayUtil; 028import com.mybatisflex.core.util.CollectionUtil; 029import com.mybatisflex.core.util.StringUtil; 030import org.apache.ibatis.builder.annotation.ProviderContext; 031 032import java.io.Serializable; 033import java.util.*; 034 035@SuppressWarnings({"rawtypes", "DuplicatedCode"}) 036public class EntitySqlProvider { 037 038 /** 039 * 不让实例化,使用静态方法的模式,效率更高,非静态方法每次都会实例化当前类 040 * 参考源码: {{@link org.apache.ibatis.builder.annotation.ProviderSqlSource#getBoundSql(Object)} 041 */ 042 private EntitySqlProvider() { 043 } 044 045 /** 046 * insert 的 SQL 构建。 047 * 048 * @param params 方法参数 049 * @param context 上下文对象 050 * @return SQL 语句 051 * @see com.mybatisflex.core.BaseMapper#insert(Object) 052 */ 053 public static String insert(Map params, ProviderContext context) { 054 Object entity = ProviderUtil.getEntity(params); 055 056 FlexAssert.notNull(entity, "entity can not be null."); 057 058 boolean ignoreNulls = ProviderUtil.isIgnoreNulls(params); 059 060 TableInfo tableInfo = ProviderUtil.getTableInfo(context); 061 062 //设置乐观锁版本字段的初始化数据 063 tableInfo.initVersionValueIfNecessary(entity); 064 065 //设置租户ID 066 tableInfo.initTenantIdIfNecessary(entity); 067 068 //设置逻辑删除字段的出初始化数据 069 tableInfo.initLogicDeleteValueIfNecessary(entity); 070 071 //执行 onInsert 监听器 072 tableInfo.invokeOnInsertListener(entity); 073 074 Object[] values = tableInfo.buildInsertSqlArgs(entity, ignoreNulls); 075 ProviderUtil.setSqlArgs(params, values); 076 077 return DialectFactory.getDialect().forInsertEntity(tableInfo, entity, ignoreNulls); 078 } 079 080 081 /** 082 * insertWithPk 的 SQL 构建。 083 * 084 * @param params 方法参数 085 * @param context 上下文对象 086 * @return SQL 语句 087 * @see com.mybatisflex.core.BaseMapper#insertWithPk(Object, boolean) 088 */ 089 public static String insertWithPk(Map params, ProviderContext context) { 090 Object entity = ProviderUtil.getEntity(params); 091 092 FlexAssert.notNull(entity, "entity can not be null."); 093 094 boolean ignoreNulls = ProviderUtil.isIgnoreNulls(params); 095 096 TableInfo tableInfo = ProviderUtil.getTableInfo(context); 097 098 //设置乐观锁版本字段的初始化数据 099 tableInfo.initVersionValueIfNecessary(entity); 100 101 //设置租户ID 102 tableInfo.initTenantIdIfNecessary(entity); 103 104 //设置逻辑删除字段的出初始化数据 105 tableInfo.initLogicDeleteValueIfNecessary(entity); 106 107 //执行 onInsert 监听器 108 tableInfo.invokeOnInsertListener(entity); 109 110 Object[] values = tableInfo.buildInsertSqlArgsWithPk(entity, ignoreNulls); 111 ProviderUtil.setSqlArgs(params, values); 112 113 return DialectFactory.getDialect().forInsertEntityWithPk(tableInfo, entity, ignoreNulls); 114 } 115 116 117 /** 118 * insertBatch 的 SQL 构建。 119 * 120 * @param params 方法参数 121 * @param context 上下文对象 122 * @return SQL 语句 123 * @see com.mybatisflex.core.BaseMapper#insertBatch(List) 124 * @see com.mybatisflex.core.FlexConsts#METHOD_INSERT_BATCH 125 */ 126 public static String insertBatch(Map params, ProviderContext context) { 127 List<Object> entities = ProviderUtil.getEntities(params); 128 129 FlexAssert.notEmpty(entities, "entities can not be null or empty."); 130 131 TableInfo tableInfo = ProviderUtil.getTableInfo(context); 132 for (Object entity : entities) { 133 tableInfo.initVersionValueIfNecessary(entity); 134 tableInfo.initTenantIdIfNecessary(entity); 135 tableInfo.initLogicDeleteValueIfNecessary(entity); 136 137 //执行 onInsert 监听器 138 tableInfo.invokeOnInsertListener(entity); 139 } 140 141 142 Object[] allValues = FlexConsts.EMPTY_ARRAY; 143 for (Object entity : entities) { 144 allValues = ArrayUtil.concat(allValues, tableInfo.buildInsertSqlArgs(entity, false)); 145 } 146 147 ProviderUtil.setSqlArgs(params, allValues); 148 149 return DialectFactory.getDialect().forInsertEntityBatch(tableInfo, entities); 150 } 151 152 153 /** 154 * deleteById 的 SQL 构建。 155 * 156 * @param params 方法参数 157 * @param context 上下文对象 158 * @return SQL 语句 159 * @see com.mybatisflex.core.BaseMapper#deleteById(Serializable) 160 */ 161 public static String deleteById(Map params, ProviderContext context) { 162 Object[] primaryValues = ProviderUtil.getPrimaryValues(params); 163 164 FlexAssert.notEmpty(primaryValues, "primaryValues can not be null or empty."); 165 166 TableInfo tableInfo = ProviderUtil.getTableInfo(context); 167 168 Object[] allValues = ArrayUtil.concat(primaryValues, tableInfo.buildTenantIdArgs()); 169 ProviderUtil.setSqlArgs(params, allValues); 170 171 return DialectFactory.getDialect().forDeleteEntityById(tableInfo); 172 } 173 174 175 /** 176 * deleteBatchByIds 的 SQL 构建。 177 * 178 * @param params 方法参数 179 * @param context 上下文对象 180 * @return SQL 语句 181 * @see com.mybatisflex.core.BaseMapper#deleteBatchByIds(Collection) 182 */ 183 public static String deleteBatchByIds(Map params, ProviderContext context) { 184 Object[] primaryValues = ProviderUtil.getPrimaryValues(params); 185 186 FlexAssert.notEmpty(primaryValues, "primaryValues can not be null or empty."); 187 188 TableInfo tableInfo = ProviderUtil.getTableInfo(context); 189 190 Object[] tenantIdArgs = tableInfo.buildTenantIdArgs(); 191 ProviderUtil.setSqlArgs(params, ArrayUtil.concat(primaryValues, tenantIdArgs)); 192 193 return DialectFactory.getDialect().forDeleteEntityBatchByIds(tableInfo, primaryValues); 194 } 195 196 197 /** 198 * deleteByQuery 的 SQL 构建。 199 * 200 * @param params 方法参数 201 * @param context 上下文对象 202 * @return SQL 语句 203 * @see com.mybatisflex.core.BaseMapper#deleteByQuery(QueryWrapper) 204 */ 205 public static String deleteByQuery(Map params, ProviderContext context) { 206 QueryWrapper queryWrapper = ProviderUtil.getQueryWrapper(params); 207 208 TableInfo tableInfo = ProviderUtil.getTableInfo(context); 209 CPI.setFromIfNecessary(queryWrapper, tableInfo.getSchema(), tableInfo.getTableName()); 210 211 tableInfo.appendConditions(null, queryWrapper); 212 213 String sql = DialectFactory.getDialect().forDeleteEntityBatchByQuery(tableInfo, queryWrapper); 214 ProviderUtil.setSqlArgs(params, CPI.getValueArray(queryWrapper)); 215 return sql; 216 } 217 218 219 /** 220 * update 的 SQL 构建。 221 * 222 * @param params 方法参数 223 * @param context 上下文对象 224 * @return SQL 语句 225 * @see com.mybatisflex.core.BaseMapper#update(Object, boolean) 226 */ 227 public static String update(Map params, ProviderContext context) { 228 Object entity = ProviderUtil.getEntity(params); 229 230 FlexAssert.notNull(entity, "entity can not be null"); 231 232 boolean ignoreNulls = ProviderUtil.isIgnoreNulls(params); 233 234 TableInfo tableInfo = ProviderUtil.getTableInfo(context); 235 236 //执行 onUpdate 监听器 237 tableInfo.invokeOnUpdateListener(entity); 238 239 Object[] updateValues = tableInfo.buildUpdateSqlArgs(entity, ignoreNulls, false); 240 Object[] primaryValues = tableInfo.buildPkSqlArgs(entity); 241 Object[] tenantIdArgs = tableInfo.buildTenantIdArgs(); 242 243 FlexExceptions.assertAreNotNull(primaryValues, "The value of primary key must not be null, entity[%s]", entity); 244 245 ProviderUtil.setSqlArgs(params, ArrayUtil.concat(updateValues, primaryValues, tenantIdArgs)); 246 247 return DialectFactory.getDialect().forUpdateEntity(tableInfo, entity, ignoreNulls); 248 } 249 250 251 /** 252 * updateByQuery 的 SQL 构建。 253 * 254 * @param params 方法参数 255 * @param context 上下文对象 256 * @return SQL 语句 257 * @see com.mybatisflex.core.BaseMapper#updateByQuery(Object, boolean, QueryWrapper) 258 */ 259 public static String updateByQuery(Map params, ProviderContext context) { 260 Object entity = ProviderUtil.getEntity(params); 261 262 FlexAssert.notNull(entity, "entity can not be null"); 263 264 boolean ignoreNulls = ProviderUtil.isIgnoreNulls(params); 265 QueryWrapper queryWrapper = ProviderUtil.getQueryWrapper(params); 266 267 TableInfo tableInfo = ProviderUtil.getTableInfo(context); 268 269 //执行 onUpdate 监听器 270 tableInfo.invokeOnUpdateListener(entity); 271 272 //处理逻辑删除 和 多租户等 273 tableInfo.appendConditions(entity, queryWrapper); 274 275 //优先构建 sql,再构建参数 276 String sql = DialectFactory.getDialect().forUpdateEntityByQuery(tableInfo, entity, ignoreNulls, queryWrapper); 277 278 Object[] values = tableInfo.buildUpdateSqlArgs(entity, ignoreNulls, true); 279 Object[] queryParams = CPI.getValueArray(queryWrapper); 280 ProviderUtil.setSqlArgs(params, ArrayUtil.concat(values, queryParams)); 281 282 return sql; 283 } 284 285 /** 286 * updateNumberByQuery 的 SQL 构建。 287 * 288 * @param params 方法参数 289 * @param context 上下文对象 290 * @return SQL 语句 291 * @see com.mybatisflex.core.BaseMapper#updateNumberAddByQuery(String, Number, QueryWrapper) 292 */ 293 public static String updateNumberAddByQuery(Map params, ProviderContext context) { 294 QueryWrapper queryWrapper = ProviderUtil.getQueryWrapper(params); 295 296 String fieldName = ProviderUtil.getFieldName(params); 297 Number value = (Number) ProviderUtil.getValue(params); 298 299 TableInfo tableInfo = ProviderUtil.getTableInfo(context); 300 301 //处理逻辑删除 和 多租户等 302 tableInfo.appendConditions(null, queryWrapper); 303 304 //优先构建 sql,再构建参数 305 String sql = DialectFactory.getDialect().forUpdateNumberAddByQuery(tableInfo.getSchema() 306 , tableInfo.getTableName(), fieldName, value, queryWrapper); 307 308 Object[] queryParams = CPI.getValueArray(queryWrapper); 309 ProviderUtil.setSqlArgs(params, queryParams); 310 311 return sql; 312 } 313 314 315 /** 316 * selectOneById 的 SQL 构建。 317 * 318 * @param params 方法参数 319 * @param context 上下文对象 320 * @return SQL 语句 321 * @see com.mybatisflex.core.BaseMapper#selectOneById(Serializable) 322 */ 323 public static String selectOneById(Map params, ProviderContext context) { 324 Object[] primaryValues = ProviderUtil.getPrimaryValues(params); 325 326 FlexAssert.notEmpty(primaryValues, "primaryValues can not be null or empty."); 327 328 TableInfo tableInfo = ProviderUtil.getTableInfo(context); 329 330 Object[] allValues = ArrayUtil.concat(primaryValues, tableInfo.buildTenantIdArgs()); 331 332 ProviderUtil.setSqlArgs(params, allValues); 333 334 return DialectFactory.getDialect().forSelectOneEntityById(tableInfo); 335 } 336 337 338 /** 339 * selectListByIds 的 SQL 构建。 340 * 341 * @param params 方法参数 342 * @param context 上下文对象 343 * @return SQL 语句 344 * @see com.mybatisflex.core.BaseMapper#selectListByIds(Collection) 345 */ 346 public static String selectListByIds(Map params, ProviderContext context) { 347 Object[] primaryValues = ProviderUtil.getPrimaryValues(params); 348 349 FlexAssert.notEmpty(primaryValues, "primaryValues can not be null or empty."); 350 351 TableInfo tableInfo = ProviderUtil.getTableInfo(context); 352 353 Object[] allValues = ArrayUtil.concat(primaryValues, tableInfo.buildTenantIdArgs()); 354 ProviderUtil.setSqlArgs(params, allValues); 355 356 return DialectFactory.getDialect().forSelectEntityListByIds(tableInfo, primaryValues); 357 } 358 359 360 /** 361 * selectListByQuery 的 SQL 构建。 362 * 363 * @param params 方法参数 364 * @param context 上下文对象 365 * @return SQL 语句 366 * @see com.mybatisflex.core.BaseMapper#selectListByQuery(QueryWrapper) 367 */ 368 public static String selectListByQuery(Map params, ProviderContext context) { 369 QueryWrapper queryWrapper = ProviderUtil.getQueryWrapper(params); 370 371 appendTableConditions(context, queryWrapper, true); 372 373 //优先构建 sql,再构建参数 374 String sql = DialectFactory.getDialect().forSelectByQuery(queryWrapper); 375 376 Object[] values = CPI.getValueArray(queryWrapper); 377 ProviderUtil.setSqlArgs(params, values); 378 379 return sql; 380 } 381 382 383 /** 384 * selectCountByQuery 的 SQL 构建。 385 * 386 * @param params 方法参数 387 * @param context 上下文对象 388 * @return SQL 语句 389 * @see com.mybatisflex.core.BaseMapper#selectObjectByQuery(QueryWrapper) 390 */ 391 public static String selectObjectByQuery(Map params, ProviderContext context) { 392 QueryWrapper queryWrapper = ProviderUtil.getQueryWrapper(params); 393 394 appendTableConditions(context, queryWrapper, false); 395 396 //优先构建 sql,再构建参数 397 String sql = DialectFactory.getDialect().forSelectByQuery(queryWrapper); 398 399 Object[] values = CPI.getValueArray(queryWrapper); 400 ProviderUtil.setSqlArgs(params, values); 401 402 return sql; 403 } 404 405 406 private static void appendTableConditions(ProviderContext context, QueryWrapper queryWrapper, boolean setSelectColumns) { 407 List<TableInfo> tableInfos = getTableInfos(context, queryWrapper); 408 if (CollectionUtil.isNotEmpty(tableInfos)) { 409 for (TableInfo tableInfo : tableInfos) { 410 tableInfo.appendConditions(null, queryWrapper); 411 if (setSelectColumns) { 412 CPI.setSelectColumnsIfNecessary(queryWrapper, tableInfo.getDefaultQueryColumn()); 413 } 414 CPI.setFromIfNecessary(queryWrapper, tableInfo.getSchema(), tableInfo.getTableName()); 415 } 416 } else { 417 List<QueryWrapper> childQueryWrappers = CPI.getChildSelect(queryWrapper); 418 if (CollectionUtil.isNotEmpty(childQueryWrappers)) { 419 for (QueryWrapper childQueryWrapper : childQueryWrappers) { 420 appendTableConditions(context, childQueryWrapper, setSelectColumns); 421 } 422 } 423 } 424 } 425 426 427 private static List<TableInfo> getTableInfos(ProviderContext context, QueryWrapper queryWrapper) { 428 List<TableInfo> tableInfos; 429 List<QueryTable> queryTables = CPI.getQueryTables(queryWrapper); 430 if (CollectionUtil.isNotEmpty(queryTables)) { 431 tableInfos = new ArrayList<>(); 432 for (QueryTable queryTable : queryTables) { 433 String tableNameWithSchema = queryTable.getNameWithSchema(); 434 if (StringUtil.isNotBlank(tableNameWithSchema)) { 435 TableInfo tableInfo = TableInfoFactory.ofTableName(tableNameWithSchema); 436 if (tableInfo != null) { 437 tableInfos.add(tableInfo); 438 } 439 } 440 } 441 } else { 442 tableInfos = Collections.singletonList(ProviderUtil.getTableInfo(context)); 443 } 444 return tableInfos; 445 } 446 447 448}