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.dialect.DialectFactory;
019import com.mybatisflex.core.exception.FlexExceptions;
020import com.mybatisflex.core.query.CPI;
021import com.mybatisflex.core.query.QueryWrapper;
022import com.mybatisflex.core.row.Row;
023import com.mybatisflex.core.row.RowCPI;
024import com.mybatisflex.core.row.RowMapper;
025import com.mybatisflex.core.util.ArrayUtil;
026import com.mybatisflex.core.util.CollectionUtil;
027
028import java.util.*;
029
030public class RowSqlProvider {
031
032
033    public static final String METHOD_RAW_SQL = "providerRawSql";
034
035    /**
036     * 不让实例化,使用静态方法的模式,效率更高,非静态方法每次都会实例化当前类
037     * 参考源码: {{@link org.apache.ibatis.builder.annotation.ProviderSqlSource#getBoundSql(Object)}
038     */
039    private RowSqlProvider() {
040    }
041
042    /**
043     * 执行原生 sql 的方法
044     *
045     * @param params
046     * @return sql
047     * @see RowMapper#insertBySql(String, Object...)
048     * @see RowMapper#deleteBySql(String, Object...)
049     * @see RowMapper#updateBySql(String, Object...)
050     */
051    public static String providerRawSql(Map params) {
052        return ProviderUtil.getSqlString(params);
053    }
054
055    /**
056     * insert 的 sql 构建
057     *
058     * @param params
059     * @return sql
060     * @see RowMapper#insert(String, Row)
061     */
062    public static String insert(Map params) {
063        String tableName = ProviderUtil.getTableName(params);
064        Row row = ProviderUtil.getRow(params);
065        ProviderUtil.setSqlArgs(params, RowCPI.obtainModifyValues(row));
066        return DialectFactory.getDialect().forInsertRow(tableName, row);
067    }
068
069    /**
070     * insertBatch 的 sql 构建
071     *
072     * @param params
073     * @return sql
074     * @see RowMapper#insertBatchWithFirstRowColumns(String, List)
075     */
076    public static String insertBatchWithFirstRowColumns(Map params) {
077        String tableName = ProviderUtil.getTableName(params);
078        List<Row> rows = ProviderUtil.getRows(params);
079        if (rows == null || rows.isEmpty()) {
080            throw FlexExceptions.wrap("rows can not be null or empty.");
081        }
082
083        //让所有 row 的列顺序和值的数量与第条数据保持一致
084        //这个必须 new 一个 LinkedHashSet,因为 keepModifyAttrs 会清除 row 所有的 modifyAttrs
085        Set<String> modifyAttrs = new LinkedHashSet<>(rows.get(0).obtainModifyAttrs());
086        rows.forEach(row -> RowCPI.keepModifyAttrs(row, modifyAttrs));
087
088
089        Object[] values = new Object[]{};
090        for (Row row : rows) {
091            values = ArrayUtil.concat(values, RowCPI.obtainModifyValues(row));
092        }
093        ProviderUtil.setSqlArgs(params, values);
094
095        //sql: INSERT INTO `tb_table`(`name`, `sex`) VALUES (?, ?),(?, ?),(?, ?)
096        return DialectFactory.getDialect().forInsertBatchWithFirstRowColumns(tableName, rows);
097    }
098
099    /**
100     * deleteById 的 sql 构建
101     *
102     * @param params
103     * @return sql
104     * @see RowMapper#deleteById(String, String, Object)
105     */
106    public static String deleteById(Map params) {
107        String tableName = ProviderUtil.getTableName(params);
108        String[] primaryKeys = ProviderUtil.getPrimaryKeys(params);
109        Object[] primaryValues = ProviderUtil.getPrimaryValues(params);
110
111        if (primaryValues.length == 0) {
112            throw FlexExceptions.wrap("primaryValue can not be null");
113        } else {
114            ProviderUtil.setSqlArgs(params, primaryValues);
115        }
116
117        return DialectFactory.getDialect().forDeleteById(tableName, primaryKeys);
118    }
119
120    /**
121     * deleteBatchByIds 的 sql 构建
122     *
123     * @param params
124     * @return sql
125     * @see RowMapper#deleteBatchByIds(String, String, Collection)
126     */
127    public static String deleteBatchByIds(Map params) {
128        String tableName = ProviderUtil.getTableName(params);
129        String[] primaryKeys = ProviderUtil.getPrimaryKeys(params);
130        Object[] primaryValues = ProviderUtil.getPrimaryValues(params);
131
132        ProviderUtil.setSqlArgs(params, primaryValues);
133        return DialectFactory.getDialect().forDeleteBatchByIds(tableName, primaryKeys, primaryValues);
134    }
135
136
137    /**
138     * deleteByQuery 的 sql 构建
139     *
140     * @param params
141     * @return sql
142     * @see RowMapper#deleteByQuery(String, QueryWrapper)
143     */
144    public static String deleteByQuery(Map params) {
145        String tableName = ProviderUtil.getTableName(params);
146        QueryWrapper queryWrapper = ProviderUtil.getQueryWrapper(params);
147        CPI.setFromIfNecessary(queryWrapper, tableName);
148
149        Object[] valueArray = CPI.getValueArray(queryWrapper);
150        ProviderUtil.setSqlArgs(params, valueArray);
151
152        return DialectFactory.getDialect().forDeleteByQuery(queryWrapper);
153    }
154
155    /**
156     * updateById 的 sql 构建
157     *
158     * @param params
159     * @return sql
160     * @see RowMapper#updateById(String, Row)
161     */
162    public static String updateById(Map params) {
163        String tableName = ProviderUtil.getTableName(params);
164        Row row = ProviderUtil.getRow(params);
165        ProviderUtil.setSqlArgs(params, RowCPI.obtainAllModifyValues(row));
166        return DialectFactory.getDialect().forUpdateById(tableName, row);
167    }
168
169
170    /**
171     * updateByQuery 的 sql 构建
172     *
173     * @param params
174     * @return sql
175     * @see RowMapper#updateByQuery(String, Row, QueryWrapper)
176     */
177    public static String updateByQuery(Map params) {
178        String tableName = ProviderUtil.getTableName(params);
179        Row data = ProviderUtil.getRow(params);
180
181        QueryWrapper queryWrapper = ProviderUtil.getQueryWrapper(params);
182        CPI.setFromIfNecessary(queryWrapper, tableName);
183
184        Object[] modifyValues = RowCPI.obtainModifyValues(data);
185        Object[] valueArray = CPI.getValueArray(queryWrapper);
186
187        ProviderUtil.setSqlArgs(params, ArrayUtil.concat(modifyValues, valueArray));
188
189        return DialectFactory.getDialect().forUpdateByQuery(queryWrapper, data);
190    }
191
192
193    /**
194     * updateBatchById 的 sql 构建
195     * mysql 等链接配置需要开启 allowMultiQueries=true
196     *
197     * @param params
198     * @return sql
199     * @see RowMapper#updateBatchById(String, List)
200     */
201    public static String updateBatchById(Map params) {
202        String tableName = ProviderUtil.getTableName(params);
203        List<Row> rows = ProviderUtil.getRows(params);
204        if (CollectionUtil.isEmpty(rows)) {
205            throw FlexExceptions.wrap("rows can not be null or empty.");
206        }
207
208        Object[] values = new Object[0];
209        for (Row row : rows) {
210            values = ArrayUtil.concat(values, RowCPI.obtainAllModifyValues(row));
211        }
212        ProviderUtil.setSqlArgs(params, values);
213        return DialectFactory.getDialect().forUpdateBatchById(tableName, rows);
214    }
215
216
217    /**
218     * selectOneById 的 sql 构建
219     *
220     * @param params
221     * @return sql
222     * @see RowMapper#selectOneById(String, String, Object)
223     */
224    public static String selectOneById(Map params) {
225        String tableName = ProviderUtil.getTableName(params);
226        String[] primaryKeys = ProviderUtil.getPrimaryKeys(params);
227        Object[] primaryValues = ProviderUtil.getPrimaryValues(params);
228
229        ProviderUtil.setSqlArgs(params, primaryValues);
230
231        return DialectFactory.getDialect().forSelectOneById(tableName, primaryKeys, primaryValues);
232    }
233
234
235    /**
236     * selectListByQuery 的 sql 构建
237     *
238     * @param params
239     * @return sql
240     * @see RowMapper#selectListByQuery(String, QueryWrapper)
241     */
242    public static String selectListByQuery(Map params) {
243        String tableName = ProviderUtil.getTableName(params);
244        QueryWrapper queryWrapper = ProviderUtil.getQueryWrapper(params);
245        CPI.setFromIfNecessary(queryWrapper, tableName);
246
247        Object[] valueArray = CPI.getValueArray(queryWrapper);
248        ProviderUtil.setSqlArgs(params, valueArray);
249
250
251        return DialectFactory.getDialect().forSelectListByQuery(queryWrapper);
252    }
253
254    /**
255     * selectCountByQuery 的 sql 构建
256     *
257     * @param params
258     * @return sql
259     * @see RowMapper#selectCountByQuery(String, QueryWrapper)
260     */
261    public static String selectCountByQuery(Map params) {
262        String tableName = ProviderUtil.getTableName(params);
263
264        QueryWrapper queryWrapper = ProviderUtil.getQueryWrapper(params);
265        CPI.setFromIfNecessary(queryWrapper, tableName);
266
267        Object[] valueArray = CPI.getValueArray(queryWrapper);
268        ProviderUtil.setSqlArgs(params, valueArray);
269
270        return DialectFactory.getDialect().forSelectCountByQuery(queryWrapper);
271    }
272
273
274}