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