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