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