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.table.TableInfo;
023import com.mybatisflex.core.util.ArrayUtil;
024import com.mybatisflex.core.util.CollectionUtil;
025import org.apache.ibatis.builder.annotation.ProviderContext;
026
027import java.io.Serializable;
028import java.util.Collection;
029import java.util.List;
030import java.util.Map;
031
032public class EntitySqlProvider {
033
034    /**
035     * 不让实例化,使用静态方法的模式,效率更高,非静态方法每次都会实例化当前类
036     * 参考源码: {{@link org.apache.ibatis.builder.annotation.ProviderSqlSource#getBoundSql(Object)}
037     */
038    private EntitySqlProvider() {
039    }
040
041
042    /**
043     * insert 的 sql 构建
044     *
045     * @param params
046     * @param context
047     * @return sql
048     * @see com.mybatisflex.core.BaseMapper#insert(Object)
049     */
050    public static String insert(Map params, ProviderContext context) {
051        Object entity = ProviderUtil.getEntity(params);
052        if (entity == null) {
053            throw FlexExceptions.wrap("entity can not be null.");
054        }
055
056        boolean ignoreNulls = ProviderUtil.isIgnoreNulls(params);
057
058        TableInfo tableInfo = ProviderUtil.getTableInfo(context);
059
060        //设置乐观锁版本字段的初始化数据
061        tableInfo.initVersionValueIfNecessary(entity);
062
063        //设置租户ID
064        tableInfo.initTenantIdIfNecessary(entity);
065
066        //设置逻辑删除字段的出初始化数据
067        tableInfo.initLogicDeleteValueIfNecessary(entity);
068
069        //执行 onInsert 监听器
070        tableInfo.invokeOnInsertListener(entity);
071
072        Object[] values = tableInfo.buildInsertSqlArgs(entity, ignoreNulls);
073        ProviderUtil.setSqlArgs(params, values);
074
075        return DialectFactory.getDialect().forInsertEntity(tableInfo, entity, ignoreNulls);
076    }
077
078
079
080    /**
081     * insertBatch 的 sql 构建
082     *
083     * @param params
084     * @param context
085     * @return sql
086     * @see com.mybatisflex.core.BaseMapper#insertBatch(List)
087     * @see com.mybatisflex.core.FlexConsts#METHOD_INSERT_BATCH
088     */
089    public static String insertBatch(Map params, ProviderContext context) {
090        List<Object> entities = ProviderUtil.getEntities(params);
091        if (CollectionUtil.isEmpty(entities)) {
092            throw FlexExceptions.wrap("entities can not be null or empty.");
093        }
094
095        TableInfo tableInfo = ProviderUtil.getTableInfo(context);
096        for (Object entity : entities) {
097            tableInfo.initVersionValueIfNecessary(entity);
098            tableInfo.initTenantIdIfNecessary(entity);
099            tableInfo.initLogicDeleteValueIfNecessary(entity);
100
101            //执行 onInsert 监听器
102            tableInfo.invokeOnInsertListener(entity);
103        }
104
105
106        Object[] allValues = new Object[0];
107        for (Object entity : entities) {
108            allValues = ArrayUtil.concat(allValues, tableInfo.buildInsertSqlArgs(entity, false));
109        }
110
111        ProviderUtil.setSqlArgs(params, allValues);
112
113        return DialectFactory.getDialect().forInsertEntityBatch(tableInfo, entities);
114    }
115
116
117    /**
118     * deleteById 的 sql 构建
119     *
120     * @param params
121     * @param context
122     * @return sql
123     * @see com.mybatisflex.core.BaseMapper#deleteById(Serializable)
124     */
125    public static String deleteById(Map params, ProviderContext context) {
126        Object[] primaryValues = ProviderUtil.getPrimaryValues(params);
127        if (ArrayUtil.isEmpty(primaryValues)) {
128            throw FlexExceptions.wrap("primaryValues can not be null or empty.");
129        }
130
131        TableInfo tableInfo = ProviderUtil.getTableInfo(context);
132
133        Object[] allValues = ArrayUtil.concat(primaryValues, tableInfo.buildTenantIdArgs());
134        ProviderUtil.setSqlArgs(params, allValues);
135
136        return DialectFactory.getDialect().forDeleteEntityById(tableInfo);
137    }
138
139
140    /**
141     * deleteBatchByIds 的 sql 构建
142     *
143     * @param params
144     * @param context
145     * @return sql
146     * @see com.mybatisflex.core.BaseMapper#deleteBatchByIds(Collection)
147     */
148    public static String deleteBatchByIds(Map params, ProviderContext context) {
149        Object[] primaryValues = ProviderUtil.getPrimaryValues(params);
150        if (ArrayUtil.isEmpty(primaryValues)) {
151            throw FlexExceptions.wrap("primaryValues can not be null or empty.");
152        }
153
154        TableInfo tableInfo = ProviderUtil.getTableInfo(context);
155
156        Object[] tenantIdArgs = tableInfo.buildTenantIdArgs();
157        ProviderUtil.setSqlArgs(params, ArrayUtil.concat(primaryValues, tenantIdArgs));
158
159        return DialectFactory.getDialect().forDeleteEntityBatchByIds(tableInfo, primaryValues);
160    }
161
162
163    /**
164     * deleteByQuery 的 sql 构建
165     *
166     * @param params
167     * @param context
168     * @return sql
169     * @see com.mybatisflex.core.BaseMapper#deleteByQuery(QueryWrapper)
170     */
171    public static String deleteByQuery(Map params, ProviderContext context) {
172        QueryWrapper queryWrapper = ProviderUtil.getQueryWrapper(params);
173        if (queryWrapper == null) {
174            throw FlexExceptions.wrap("queryWrapper can not be null or empty.");
175        }
176
177        TableInfo tableInfo = ProviderUtil.getTableInfo(context);
178        CPI.setFromIfNecessary(queryWrapper, tableInfo.getTableName());
179
180        tableInfo.appendConditions(null, queryWrapper);
181        ProviderUtil.setSqlArgs(params, CPI.getValueArray(queryWrapper));
182
183
184        return DialectFactory.getDialect().forDeleteEntityBatchByQuery(tableInfo, queryWrapper);
185    }
186
187
188    /**
189     * update 的 sql 构建
190     *
191     * @param params
192     * @param context
193     * @return sql
194     * @see com.mybatisflex.core.BaseMapper#update(Object, boolean)
195     */
196    public static String update(Map params, ProviderContext context) {
197        Object entity = ProviderUtil.getEntity(params);
198        if (entity == null) {
199            throw FlexExceptions.wrap("entity can not be null");
200        }
201
202        boolean ignoreNulls = ProviderUtil.isIgnoreNulls(params);
203
204        TableInfo tableInfo = ProviderUtil.getTableInfo(context);
205
206        //执行 onUpdate 监听器
207        tableInfo.invokeOnUpdateListener(entity);
208
209        Object[] updateValues = tableInfo.buildUpdateSqlArgs(entity, ignoreNulls, false);
210        Object[] primaryValues = tableInfo.buildPkSqlArgs(entity);
211        Object[] tenantIdArgs = tableInfo.buildTenantIdArgs();
212
213        FlexExceptions.assertAreNotNull(primaryValues, "The value of primary key must not be null, entity[%s]", entity);
214
215        ProviderUtil.setSqlArgs(params, ArrayUtil.concat(updateValues, primaryValues, tenantIdArgs));
216
217        return DialectFactory.getDialect().forUpdateEntity(tableInfo, entity, ignoreNulls);
218    }
219
220
221    /**
222     * updateByQuery 的 sql 构建
223     *
224     * @param params
225     * @param context
226     * @return sql
227     * @see com.mybatisflex.core.BaseMapper#updateByQuery(Object, boolean, QueryWrapper)
228     */
229    public static String updateByQuery(Map params, ProviderContext context) {
230        Object entity = ProviderUtil.getEntity(params);
231        if (entity == null) {
232            throw FlexExceptions.wrap("entity can not be null");
233        }
234        boolean ignoreNulls = ProviderUtil.isIgnoreNulls(params);
235        QueryWrapper queryWrapper = ProviderUtil.getQueryWrapper(params);
236
237        TableInfo tableInfo = ProviderUtil.getTableInfo(context);
238
239        //处理逻辑删除 和 多租户等
240        tableInfo.appendConditions(entity, queryWrapper);
241
242        Object[] values = tableInfo.buildUpdateSqlArgs(entity, ignoreNulls, true);
243        Object[] queryParams = CPI.getValueArray(queryWrapper);
244
245        ProviderUtil.setSqlArgs(params, ArrayUtil.concat(values, queryParams));
246
247        return DialectFactory.getDialect().forUpdateEntityByQuery(tableInfo, entity, ignoreNulls, queryWrapper);
248    }
249
250
251    /**
252     * selectOneById 的 sql 构建
253     *
254     * @param params
255     * @param context
256     * @return sql
257     * @see com.mybatisflex.core.BaseMapper#selectOneById(Serializable)
258     */
259    public static String selectOneById(Map params, ProviderContext context) {
260        Object[] primaryValues = ProviderUtil.getPrimaryValues(params);
261        if (ArrayUtil.isEmpty(primaryValues)) {
262            throw FlexExceptions.wrap("primaryValues can not be null or empty.");
263        }
264
265        TableInfo tableInfo = ProviderUtil.getTableInfo(context);
266
267        Object[] allValues = ArrayUtil.concat(primaryValues, tableInfo.buildTenantIdArgs());
268
269        ProviderUtil.setSqlArgs(params, allValues);
270
271        return DialectFactory.getDialect().forSelectOneEntityById(tableInfo);
272    }
273
274
275    /**
276     * selectListByIds 的 sql 构建
277     *
278     * @param params
279     * @param context
280     * @return sql
281     * @see com.mybatisflex.core.BaseMapper#selectListByIds(Collection)
282     */
283    public static String selectListByIds(Map params, ProviderContext context) {
284        Object[] primaryValues = ProviderUtil.getPrimaryValues(params);
285        if (ArrayUtil.isEmpty(primaryValues)) {
286            throw FlexExceptions.wrap("primaryValues can not be null or empty.");
287        }
288
289        TableInfo tableInfo = ProviderUtil.getTableInfo(context);
290
291        Object[] allValues = ArrayUtil.concat(primaryValues, tableInfo.buildTenantIdArgs());
292        ProviderUtil.setSqlArgs(params, allValues);
293
294        return DialectFactory.getDialect().forSelectEntityListByIds(tableInfo, primaryValues);
295    }
296
297
298    /**
299     * selectListByQuery 的 sql 构建
300     *
301     * @param params
302     * @param context
303     * @return sql
304     * @see com.mybatisflex.core.BaseMapper#selectListByQuery(QueryWrapper)
305     */
306    public static String selectListByQuery(Map params, ProviderContext context) {
307        QueryWrapper queryWrapper = ProviderUtil.getQueryWrapper(params);
308        if (queryWrapper == null) {
309            throw FlexExceptions.wrap("queryWrapper can not be null.");
310        }
311
312        TableInfo tableInfo = ProviderUtil.getTableInfo(context);
313        tableInfo.appendConditions(null, queryWrapper);
314
315        Object[] values = CPI.getValueArray(queryWrapper);
316        ProviderUtil.setSqlArgs(params, values);
317
318        CPI.setSelectColumnsIfNecessary(queryWrapper, tableInfo.getDefaultQueryColumn());
319        CPI.setFromIfNecessary(queryWrapper, tableInfo.getTableName());
320
321        return DialectFactory.getDialect().forSelectListByQuery(queryWrapper);
322    }
323
324    /**
325     * selectCountByQuery 的 sql 构建
326     *
327     * @param params
328     * @param context
329     * @return sql
330     * @see com.mybatisflex.core.BaseMapper#selectCountByQuery(QueryWrapper)
331     */
332    public static String selectCountByQuery(Map params, ProviderContext context) {
333        QueryWrapper queryWrapper = ProviderUtil.getQueryWrapper(params);
334        if (queryWrapper == null) {
335            throw FlexExceptions.wrap("queryWrapper can not be null.");
336        }
337
338        TableInfo tableInfo = ProviderUtil.getTableInfo(context);
339        tableInfo.appendConditions(null, queryWrapper);
340
341        Object[] values = CPI.getValueArray(queryWrapper);
342        ProviderUtil.setSqlArgs(params, values);
343
344        CPI.setFromIfNecessary(queryWrapper, tableInfo.getTableName());
345        return DialectFactory.getDialect().forSelectCountByQuery(queryWrapper);
346    }
347
348
349}