001/* 002 * Copyright (c) 2022-2025, 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.query.CPI; 022import com.mybatisflex.core.query.QueryWrapper; 023import com.mybatisflex.core.row.Row; 024import com.mybatisflex.core.row.RowCPI; 025import com.mybatisflex.core.row.RowMapper; 026import com.mybatisflex.core.table.TableInfo; 027import com.mybatisflex.core.table.TableInfoFactory; 028import com.mybatisflex.core.util.ArrayUtil; 029import com.mybatisflex.core.util.ClassUtil; 030 031import java.util.Collection; 032import java.util.LinkedHashSet; 033import java.util.List; 034import java.util.Map; 035import java.util.Set; 036 037@SuppressWarnings({"rawtypes", "DuplicatedCode"}) 038public class RowSqlProvider { 039 040 public static final String METHOD_RAW_SQL = "providerRawSql"; 041 042 /** 043 * 不让实例化,使用静态方法的模式,效率更高,非静态方法每次都会实例化当前类 044 * 参考源码: {{@link org.apache.ibatis.builder.annotation.ProviderSqlSource#getBoundSql(Object)} 045 */ 046 private RowSqlProvider() { 047 } 048 049 /** 050 * 执行原生 sql 的方法 051 * 052 * @param params 方法参数 053 * @return SQL 语句 054 * @see RowMapper#insertBySql(String, Object...) 055 * @see RowMapper#deleteBySql(String, Object...) 056 * @see RowMapper#updateBySql(String, Object...) 057 */ 058 public static String providerRawSql(Map params) { 059 ProviderUtil.flatten(params); 060 return ProviderUtil.getSqlString(params); 061 } 062 063 /** 064 * insert 的 SQL 构建。 065 * 066 * @param params 方法参数 067 * @return SQL 语句 068 * @see RowMapper#insert(String, String, Row) 069 */ 070 public static String insert(Map params) { 071 String tableName = ProviderUtil.getTableName(params); 072 String schema = ProviderUtil.getSchemaName(params); 073 Row row = ProviderUtil.getRow(params); 074 075 // 先生成 SQL,再设置参数 076 String sql = DialectFactory.getDialect().forInsertRow(schema, tableName, row); 077 ProviderUtil.setSqlArgs(params, row.obtainInsertValues()); 078 return sql; 079 } 080 081 /** 082 * insertBatch 的 SQL 构建。 083 * 084 * @param params 方法参数 085 * @return SQL 语句 086 * @see RowMapper#insertBatchWithFirstRowColumns(String, String, List) 087 */ 088 public static String insertBatchWithFirstRowColumns(Map params) { 089 List<Row> rows = ProviderUtil.getRows(params); 090 091 FlexAssert.notEmpty(rows, "rows"); 092 093 String tableName = ProviderUtil.getTableName(params); 094 String schema = ProviderUtil.getSchemaName(params); 095 096 // 让所有 row 的列顺序和值的数量与第条数据保持一致 097 // 这个必须 new 一个 LinkedHashSet,因为 keepModifyAttrs 会清除 row 所有的 modifyAttrs 098 Set<String> modifyAttrs = new LinkedHashSet<>(RowCPI.getInsertAttrs(rows.get(0))); 099 100 // sql: INSERT INTO `tb_table`(`name`, `sex`) VALUES (?, ?),(?, ?),(?, ?) 101 String sql = DialectFactory.getDialect().forInsertBatchWithFirstRowColumns(schema, tableName, rows); 102 103 Object[] values = new Object[]{}; 104 for (Row row : rows) { 105 values = ArrayUtil.concat(values, row.obtainInsertValues(modifyAttrs)); 106 } 107 ProviderUtil.setSqlArgs(params, values); 108 109 return sql; 110 } 111 112 /** 113 * deleteById 的 SQL 构建。 114 * 115 * @param params 方法参数 116 * @return SQL 语句 117 * @see RowMapper#deleteById(String, String, String, Object) 118 */ 119 public static String deleteById(Map params) { 120 Object[] primaryValues = ProviderUtil.getPrimaryValues(params); 121 122 FlexAssert.notEmpty(primaryValues, "primaryValues"); 123 124 String schema = ProviderUtil.getSchemaName(params); 125 String tableName = ProviderUtil.getTableName(params); 126 String[] primaryKeys = ProviderUtil.getPrimaryKeys(params); 127 128 String sql = DialectFactory.getDialect().forDeleteById(schema, tableName, primaryKeys); 129 ProviderUtil.setSqlArgs(params, primaryValues); 130 return sql; 131 } 132 133 /** 134 * deleteBatchByIds 的 SQL 构建。 135 * 136 * @param params 方法参数 137 * @return SQL 语句 138 * @see RowMapper#deleteBatchByIds(String, String, String, Collection) 139 */ 140 public static String deleteBatchByIds(Map params) { 141 String schema = ProviderUtil.getSchemaName(params); 142 String tableName = ProviderUtil.getTableName(params); 143 String[] primaryKeys = ProviderUtil.getPrimaryKeys(params); 144 Object[] primaryValues = ProviderUtil.getPrimaryValues(params); 145 146 String sql = DialectFactory.getDialect().forDeleteBatchByIds(schema, tableName, primaryKeys, primaryValues); 147 ProviderUtil.setSqlArgs(params, primaryValues); 148 return sql; 149 } 150 151 /** 152 * deleteByQuery 的 SQL 构建。 153 * 154 * @param params 方法参数 155 * @return SQL 语句 156 * @see RowMapper#deleteByQuery(String, String, QueryWrapper) 157 */ 158 public static String deleteByQuery(Map params) { 159 String schema = ProviderUtil.getSchemaName(params); 160 String tableName = ProviderUtil.getTableName(params); 161 QueryWrapper queryWrapper = ProviderUtil.getQueryWrapper(params); 162 CPI.setFromIfNecessary(queryWrapper, schema, tableName); 163 164 // 优先构建 sql,再构建参数 165 String sql = DialectFactory.getDialect().forDeleteByQuery(queryWrapper); 166 Object[] valueArray = CPI.getValueArray(queryWrapper); 167 ProviderUtil.setSqlArgs(params, valueArray); 168 169 return sql; 170 } 171 172 /** 173 * updateById 的 SQL 构建。 174 * 175 * @param params 方法参数 176 * @return SQL 语句 177 * @see RowMapper#updateById(String, String, Row) 178 */ 179 public static String updateById(Map params) { 180 String schema = ProviderUtil.getSchemaName(params); 181 String tableName = ProviderUtil.getTableName(params); 182 Row row = ProviderUtil.getRow(params); 183 String sql = DialectFactory.getDialect().forUpdateById(schema, tableName, row); 184 ProviderUtil.setSqlArgs(params, RowCPI.obtainUpdateValues(row)); 185 return sql; 186 } 187 188 /** 189 * updateByQuery 的 SQL 构建。 190 * 191 * @param params 方法参数 192 * @return SQL 语句 193 * @see RowMapper#updateByQuery(String, String, Row, QueryWrapper) 194 */ 195 public static String updateByQuery(Map params) { 196 String schema = ProviderUtil.getSchemaName(params); 197 String tableName = ProviderUtil.getTableName(params); 198 Row data = ProviderUtil.getRow(params); 199 200 QueryWrapper queryWrapper = ProviderUtil.getQueryWrapper(params); 201 CPI.setFromIfNecessary(queryWrapper, schema, tableName); 202 203 // 优先构建 sql,再构建参数 204 String sql = DialectFactory.getDialect().forUpdateByQuery(queryWrapper, data); 205 206 Object[] modifyValues = RowCPI.obtainModifyValues(data); 207 Object[] valueArray = CPI.getValueArray(queryWrapper); 208 209 ProviderUtil.setSqlArgs(params, ArrayUtil.concat(modifyValues, valueArray)); 210 211 return sql; 212 } 213 214 /** 215 * updateBatchById 的 SQL 构建。 216 * mysql 等链接配置需要开启 allowMultiQueries=true 217 * 218 * @param params 方法参数 219 * @return SQL 语句 220 * @see RowMapper#updateBatchById(String, String, List) 221 */ 222 public static String updateBatchById(Map params) { 223 List<Row> rows = ProviderUtil.getRows(params); 224 225 FlexAssert.notEmpty(rows, "rows"); 226 227 String schema = ProviderUtil.getSchemaName(params); 228 String tableName = ProviderUtil.getTableName(params); 229 230 String sql = DialectFactory.getDialect().forUpdateBatchById(schema, tableName, rows); 231 232 Object[] values = FlexConsts.EMPTY_ARRAY; 233 for (Row row : rows) { 234 values = ArrayUtil.concat(values, RowCPI.obtainUpdateValues(row)); 235 } 236 ProviderUtil.setSqlArgs(params, values); 237 return sql; 238 } 239 240 /** 241 * updateEntity 的 SQL 构建。 242 * 243 * @param params 方法参数 244 * @return SQL 语句 245 * @see RowMapper#updateEntity(Object entities) 246 */ 247 public static String updateEntity(Map params) { 248 Object entity = ProviderUtil.getEntity(params); 249 250 FlexAssert.notNull(entity, "entity can not be null for execute update"); 251 252 // 该 Mapper 是通用 Mapper 无法通过 ProviderContext 获取,直接使用 TableInfoFactory 253 254 TableInfo tableInfo = TableInfoFactory.ofEntityClass(ClassUtil.getUsefulClass(entity.getClass())); 255 // 执行 onUpdate 监听器 256 tableInfo.invokeOnUpdateListener(entity); 257 258 String sql = DialectFactory.getDialect().forUpdateEntity(tableInfo, entity, false); 259 260 Object[] updateValues = tableInfo.buildUpdateSqlArgs(entity, false, false); 261 Object[] primaryValues = tableInfo.buildPkSqlArgs(entity); 262 Object[] tenantIdArgs = tableInfo.buildTenantIdArgs(); 263 264 FlexAssert.assertAreNotNull(primaryValues, "The value of primary key must not be null for execute update an entity, entity[%s]", entity); 265 266 ProviderUtil.setSqlArgs(params, ArrayUtil.concat(updateValues, primaryValues, tenantIdArgs)); 267 return sql; 268 } 269 270 271 /** 272 * selectOneById 的 SQL 构建。 273 * 274 * @param params 方法参数 275 * @return SQL 语句 276 * @see RowMapper#selectOneById(String, String, String, Object) 277 */ 278 public static String selectOneById(Map params) { 279 String schema = ProviderUtil.getSchemaName(params); 280 String tableName = ProviderUtil.getTableName(params); 281 String[] primaryKeys = ProviderUtil.getPrimaryKeys(params); 282 Object[] primaryValues = ProviderUtil.getPrimaryValues(params); 283 284 String sql = DialectFactory.getDialect().forSelectOneById(schema, tableName, primaryKeys, primaryValues); 285 ProviderUtil.setSqlArgs(params, primaryValues); 286 287 return sql; 288 } 289 290 /** 291 * selectListByQuery 的 SQL 构建。 292 * 293 * @param params 方法参数 294 * @return SQL 语句 295 * @see RowMapper#selectListByQuery(String, String, QueryWrapper) 296 */ 297 public static String selectListByQuery(Map params) { 298 String schema = ProviderUtil.getSchemaName(params); 299 String tableName = ProviderUtil.getTableName(params); 300 301 QueryWrapper queryWrapper = ProviderUtil.getQueryWrapper(params); 302 CPI.setFromIfNecessary(queryWrapper, schema, tableName); 303 304 // 优先构建 sql,再构建参数 305 String sql = DialectFactory.getDialect().forSelectByQuery(queryWrapper); 306 307 Object[] valueArray = CPI.getValueArray(queryWrapper); 308 ProviderUtil.setSqlArgs(params, valueArray); 309 310 return sql; 311 } 312 313}