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;
017
018import com.mybatisflex.core.exception.FlexExceptions;
019import com.mybatisflex.core.paginate.Page;
020import com.mybatisflex.core.provider.EntitySqlProvider;
021import com.mybatisflex.core.query.QueryColumn;
022import com.mybatisflex.core.query.QueryCondition;
023import com.mybatisflex.core.query.QueryWrapper;
024import com.mybatisflex.core.query.CPI;
025import com.mybatisflex.core.table.TableInfo;
026import com.mybatisflex.core.table.TableInfoFactory;
027import com.mybatisflex.core.util.ObjectUtil;
028import org.apache.ibatis.annotations.*;
029import org.apache.ibatis.builder.annotation.ProviderContext;
030
031import java.io.Serializable;
032import java.util.Collection;
033import java.util.List;
034import java.util.Map;
035
036public interface BaseMapper<T> {
037
038    /**
039     * 插入 entity 数据
040     *
041     * @param entity 实体类
042     * @return 返回影响的行数
043     */
044    default int insert(T entity){
045        return insert(entity,false);
046    }
047
048
049    /**
050     * 插入 entity 数据,但是忽略 null 的数据,只对有值的内容进行插入
051     * 这样的好处是数据库已经配置了一些默认值,这些默认值才会生效
052     *
053     * @param entity 实体类
054     * @return 返回影响的行数
055     */
056    default int insertSelective(T entity){
057        return insert(entity,true);
058    }
059
060
061
062    /**
063     * 插入 entity 数据
064     *
065     * @param entity 实体类
066     * @return 返回影响的行数
067     * @see com.mybatisflex.core.provider.EntitySqlProvider#insert(Map, ProviderContext)
068     */
069    @InsertProvider(type = EntitySqlProvider.class, method = "insert")
070    int insert(@Param(FlexConsts.ENTITY) T entity, @Param(FlexConsts.IGNORE_NULLS) boolean ignoreNulls);
071
072
073
074    /**
075     * 批量插入 entity 数据,只会根据第一条数据来构建插入的字段内容
076     *
077     * @param entities 插入的数据列表
078     * @return 返回影响的行数
079     * @see com.mybatisflex.core.provider.EntitySqlProvider#insertBatch(Map, ProviderContext)
080     * @see com.mybatisflex.core.FlexConsts#METHOD_INSERT_BATCH
081     */
082    @InsertProvider(type = EntitySqlProvider.class, method = FlexConsts.METHOD_INSERT_BATCH)
083    int insertBatch(@Param(FlexConsts.ENTITIES) List<T> entities);
084
085    /**
086     * 批量插入 entity 数据,按 size 切分
087     *
088     * @param entities 插入的数据列表
089     * @param size     切分大小
090     * @return 影响行数
091     */
092    default int insertBatch(List<T> entities, int size) {
093        if (size <= 0) {
094            size = 1000;//默认1000
095        }
096        int sum = 0;
097        int entitiesSize = entities.size();
098        int maxIndex = entitiesSize / size + (entitiesSize % size == 0 ? 0 : 1);
099        for (int i = 0; i < maxIndex; i++) {
100            List<T> list = entities.subList(i * size, Math.min(i * size + size, entitiesSize));
101            sum += insertBatch(list);
102        }
103        return sum;
104    }
105
106    /**
107     * 新增 或者 更新,若主键有值,则更新,若没有主键值,则插入
108     *
109     * @param entity 实体类
110     * @return 返回影响的行数
111     */
112    default int insertOrUpdate(T entity) {
113        TableInfo tableInfo = TableInfoFactory.ofEntityClass(entity.getClass());
114        Object[] pkArgs = tableInfo.buildPkSqlArgs(entity);
115        if (pkArgs.length == 0 || pkArgs[0] == null) {
116            return insert(entity);
117        } else {
118            return update(entity);
119        }
120    }
121
122    /**
123     * 根据 id 删除数据
124     * 如果是多个主键的情况下,需要传入数组 new Object[]{100,101}
125     *
126     * @param id 主键数据
127     * @return 返回影响的行数
128     * @see com.mybatisflex.core.provider.EntitySqlProvider#deleteById(Map, ProviderContext)
129     */
130    @DeleteProvider(type = EntitySqlProvider.class, method = "deleteById")
131    int deleteById(@Param(FlexConsts.PRIMARY_VALUE) Serializable id);
132
133
134    /**
135     * 根据多个 id 批量删除数据
136     *
137     * @param ids ids 列表
138     * @return 返回影响的行数
139     * @see com.mybatisflex.core.provider.EntitySqlProvider#deleteBatchByIds(Map, ProviderContext)
140     */
141    @DeleteProvider(type = EntitySqlProvider.class, method = "deleteBatchByIds")
142    int deleteBatchByIds(@Param(FlexConsts.PRIMARY_VALUE) Collection<? extends Serializable> ids);
143
144    /**
145     * 根据多个 id 批量删除数据
146     *
147     * @param ids ids 列表
148     * @param size 切分大小
149     * @return 返回影响的行数
150     * @see com.mybatisflex.core.provider.EntitySqlProvider#deleteBatchByIds(Map, ProviderContext)
151     */
152    default int deleteBatchByIds(@Param(FlexConsts.PRIMARY_VALUE) List<? extends Serializable> ids, int size) {
153        if (size <= 0) {
154            size = 1000;//默认1000
155        }
156        int sum = 0;
157        int entitiesSize = ids.size();
158        int maxIndex = entitiesSize / size + (entitiesSize % size == 0 ? 0 : 1);
159        for (int i = 0; i < maxIndex; i++) {
160            List<? extends Serializable> list = ids.subList(i * size, Math.min(i * size + size, entitiesSize));
161            sum += deleteBatchByIds(list);
162        }
163        return sum;
164    }
165
166
167    /**
168     * 根据 map 构建的条件来删除数据
169     *
170     * @param whereConditions 条件
171     * @return 返回影响的行数
172     */
173    default int deleteByMap(Map<String, Object> whereConditions) {
174        if (ObjectUtil.areNull(whereConditions) || whereConditions.isEmpty()) {
175            throw FlexExceptions.wrap("deleteByMap is not allow empty map.");
176        }
177        return deleteByQuery(QueryWrapper.create().where(whereConditions));
178    }
179
180    /**
181     * 根据条件来删除数据
182     *
183     * @param condition 条件
184     * @return 返回影响的行数
185     */
186    default int deleteByCondition(QueryCondition condition) {
187        return deleteByQuery(QueryWrapper.create().where(condition));
188    }
189
190    /**
191     * 根据 query 构建的条件来数据吗
192     *
193     * @param queryWrapper query 条件
194     * @return 返回影响的行数
195     * @see com.mybatisflex.core.provider.EntitySqlProvider#deleteByQuery(Map, ProviderContext)
196     */
197    @DeleteProvider(type = EntitySqlProvider.class, method = "deleteByQuery")
198    int deleteByQuery(@Param(FlexConsts.QUERY) QueryWrapper queryWrapper);
199
200
201    /**
202     * 根据主键来更新数据,若 entity 属性数据为 null,该属性不会新到数据库
203     *
204     * @param entity 数据内容,必须包含有主键
205     * @return 返回影响的行数
206     */
207    default int update(T entity) {
208        return update(entity, true);
209    }
210
211    /**
212     * 根据主键来更新数据到数据库
213     *
214     * @param entity      数据内容
215     * @param ignoreNulls 是否忽略空内容字段
216     * @return 返回影响的行数
217     * @see com.mybatisflex.core.provider.EntitySqlProvider#update(Map, ProviderContext)
218     */
219    @UpdateProvider(type = EntitySqlProvider.class, method = "update")
220    int update(@Param(FlexConsts.ENTITY) T entity, @Param(FlexConsts.IGNORE_NULLS) boolean ignoreNulls);
221
222
223    /**
224     * 根据 map 构建的条件来更新数据
225     *
226     * @param entity 数据
227     * @param map    where 条件内容
228     * @return 返回影响的行数
229     */
230    default int updateByMap(T entity, Map<String, Object> map) {
231        return updateByQuery(entity, QueryWrapper.create().where(map));
232    }
233
234    /**
235     * 根据 condition 来更新数据
236     *
237     * @param entity    数据
238     * @param condition 条件
239     * @return 返回影响的行数
240     */
241    default int updateByCondition(T entity, QueryCondition condition) {
242        return updateByQuery(entity, QueryWrapper.create().where(condition));
243    }
244
245    /**
246     * 根据 condition 来更新数据
247     *
248     * @param entity      数据
249     * @param ignoreNulls 是否忽略 null 数据,默认为 true
250     * @param condition   条件
251     * @return 返回影响的行数
252     */
253    default int updateByCondition(T entity, boolean ignoreNulls, QueryCondition condition) {
254        return updateByQuery(entity, ignoreNulls, QueryWrapper.create().where(condition));
255    }
256
257
258    /**
259     * 根据 query 构建的条件来更新数据
260     *
261     * @param entity       数据内容
262     * @param queryWrapper query 条件
263     * @return 返回影响的行数
264     */
265
266    default int updateByQuery(@Param(FlexConsts.ENTITY) T entity, @Param(FlexConsts.QUERY) QueryWrapper queryWrapper) {
267        return updateByQuery(entity, true, queryWrapper);
268    }
269
270    /**
271     * 根据 query 构建的条件来更新数据
272     *
273     * @param entity       数据内容
274     * @param ignoreNulls  是否忽略空值
275     * @param queryWrapper query 条件
276     * @see com.mybatisflex.core.provider.EntitySqlProvider#updateByQuery(Map, ProviderContext)
277     */
278    @UpdateProvider(type = EntitySqlProvider.class, method = "updateByQuery")
279    int updateByQuery(@Param(FlexConsts.ENTITY) T entity, @Param(FlexConsts.IGNORE_NULLS) boolean ignoreNulls, @Param(FlexConsts.QUERY) QueryWrapper queryWrapper);
280
281
282    /**
283     * 根据主键来选择数据
284     *
285     * @param id 多个主键
286     * @return entity
287     * @see com.mybatisflex.core.provider.EntitySqlProvider#selectOneById(Map, ProviderContext)
288     */
289    @SelectProvider(type = EntitySqlProvider.class, method = "selectOneById")
290    T selectOneById(@Param(FlexConsts.PRIMARY_VALUE) Serializable id);
291
292
293    /**
294     * 根据 map 构建的条件来查询数据
295     *
296     * @param whereConditions where 条件
297     * @return entity 数据
298     */
299    default T selectOneByMap(Map<String, Object> whereConditions) {
300        return selectOneByQuery(QueryWrapper.create().where(whereConditions));
301    }
302
303
304    /**
305     * 根据 condition 来查询数据
306     *
307     * @param condition 条件
308     * @return 1 条数据
309     */
310    default T selectOneByCondition(QueryCondition condition) {
311        return selectOneByQuery(QueryWrapper.create().where(condition));
312    }
313
314
315    /**
316     * 根据 queryWrapper 构建的条件来查询 1 条数据
317     *
318     * @param queryWrapper query 条件
319     * @return entity 数据
320     */
321    default T selectOneByQuery(@Param(FlexConsts.QUERY) QueryWrapper queryWrapper) {
322        List<T> entities = selectListByQuery(queryWrapper.limit(1));
323        return (entities == null || entities.isEmpty()) ? null : entities.get(0);
324    }
325
326    /**
327     * 根据多个主键来查询多条数据
328     *
329     * @param ids 主键列表
330     * @return 数据列表
331     * @see com.mybatisflex.core.provider.EntitySqlProvider#selectListByIds(Map, ProviderContext)
332     */
333    @SelectProvider(type = EntitySqlProvider.class, method = "selectListByIds")
334    List<T> selectListByIds(@Param(FlexConsts.PRIMARY_VALUE) Collection<? extends Serializable> ids);
335
336
337    /**
338     * 根据 map 来构建查询条件,查询多条数据
339     *
340     * @param whereConditions 条件列表
341     * @return 数据列表
342     */
343    default List<T> selectListByMap(Map<String, Object> whereConditions) {
344        return selectListByQuery(QueryWrapper.create().where(whereConditions));
345    }
346
347
348    /**
349     * 根据 map 来构建查询条件,查询多条数据
350     *
351     * @param whereConditions 条件列表
352     * @return 数据列表
353     */
354    default List<T> selectListByMap(Map<String, Object> whereConditions, int count) {
355        return selectListByQuery(QueryWrapper.create().where(whereConditions).limit(count));
356    }
357
358
359    /**
360     * 根据 condition 来查询数据
361     *
362     * @param condition condition 条件
363     * @return 数据列表
364     */
365    default List<T> selectListByCondition(QueryCondition condition) {
366        return selectListByQuery(QueryWrapper.create().where(condition));
367    }
368
369
370    /**
371     * 根据 condition 来查询数据
372     *
373     * @param condition condition 条件
374     * @param count     数据量
375     * @return 数据列表
376     */
377    default List<T> selectListByCondition(QueryCondition condition, int count) {
378        return selectListByQuery(QueryWrapper.create().where(condition).limit(count));
379    }
380
381
382    /**
383     * 根据 query 来构建条件查询数据列表
384     *
385     * @param queryWrapper 查询条件
386     * @return 数据列表
387     * @see com.mybatisflex.core.provider.EntitySqlProvider#selectListByQuery(Map, ProviderContext)
388     */
389    @SelectProvider(type = EntitySqlProvider.class, method = "selectListByQuery")
390    List<T> selectListByQuery(@Param(FlexConsts.QUERY) QueryWrapper queryWrapper);
391
392
393    /**
394     * 查询全部数据
395     *
396     * @return 数据列表
397     */
398    default List<T> selectAll() {
399        return selectListByQuery(new QueryWrapper());
400    }
401
402
403    /**
404     * 根据条件查询数据总量
405     *
406     * @param condition 条件
407     * @return 数据量
408     */
409    default long selectCountByCondition(QueryCondition condition) {
410        return selectCountByQuery(QueryWrapper.create().where(condition));
411    }
412
413
414    /**
415     * 根据 queryWrapper 来查询数据量
416     *
417     * @param queryWrapper 查询包装器
418     * @return 数据量
419     * @see EntitySqlProvider#selectCountByQuery(Map, ProviderContext)
420     */
421    @SelectProvider(type = EntitySqlProvider.class, method = "selectCountByQuery")
422    long selectCountByQuery(@Param(FlexConsts.QUERY) QueryWrapper queryWrapper);
423
424
425    /**
426     * 分页查询
427     *
428     * @param pageNumber   当前页码
429     * @param pageSize     每页的数据量
430     * @param queryWrapper 查询条件
431     * @return 返回 Page 数据
432     */
433    default Page<T> paginate(int pageNumber, int pageSize, QueryWrapper queryWrapper) {
434        Page<T> page = new Page<>(pageNumber, pageSize);
435        return paginate(page, queryWrapper);
436    }
437
438
439    /**
440     * 根据条件分页查询
441     *
442     * @param pageNumber 当前页面
443     * @param pageSize   每页的数据量
444     * @param condition  查询条件
445     * @return 返回 Page 数据
446     */
447    default Page<T> paginate(int pageNumber, int pageSize, QueryCondition condition) {
448        Page<T> page = new Page<>(pageNumber, pageSize);
449        return paginate(page, new QueryWrapper().where(condition));
450    }
451
452    /**
453     * 分页查询
454     *
455     * @param pageNumber   当前页码
456     * @param pageSize     每页的数据量
457     * @param totalRow     数据总量
458     * @param queryWrapper 查询条件
459     * @return 返回 Page 数据
460     */
461    default Page<T> paginate(int pageNumber, int pageSize, int totalRow, QueryWrapper queryWrapper) {
462        Page<T> page = new Page<>(pageNumber, pageSize, totalRow);
463        return paginate(page, queryWrapper);
464    }
465
466
467    /**
468     * 根据条件分页查询
469     *
470     * @param pageNumber 当前页面
471     * @param pageSize   每页的数据量
472     * @param totalRow   数据总量
473     * @param condition  查询条件
474     * @return 返回 Page 数据
475     */
476    default Page<T> paginate(int pageNumber, int pageSize, int totalRow, QueryCondition condition) {
477        Page<T> page = new Page<>(pageNumber, pageSize, totalRow);
478        return paginate(page, new QueryWrapper().where(condition));
479    }
480
481
482    /**
483     * 分页查询
484     *
485     * @param page         page,其包含了页码、每页的数据量,可能包含数据总量
486     * @param queryWrapper 查询条件
487     * @return page 数据
488     */
489    default Page<T> paginate(@Param("page") Page<T> page, @Param("query") QueryWrapper queryWrapper) {
490
491        List<QueryColumn> groupByColumns = null;
492
493        // 只有 totalRow 小于 0 的时候才会去查询总量
494        // 这样方便用户做总数缓存,而非每次都要去查询总量
495        // 一般的分页场景中,只有第一页的时候有必要去查询总量,第二页以后是不需要的
496        if (page.getTotalRow() < 0) {
497            groupByColumns = CPI.getGroupByColumns(queryWrapper);
498            //清除group by 去查询数据
499            CPI.setGroupByColumns(queryWrapper, null);
500            long count = selectCountByQuery(queryWrapper);
501            page.setTotalRow(count);
502        }
503
504        if (page.getTotalRow() == 0 || page.getPageNumber() > page.getTotalPage()) {
505            return page;
506        }
507
508        //恢复数量查询清除的 groupBy
509        if (groupByColumns != null) {
510            CPI.setGroupByColumns(queryWrapper, groupByColumns);
511        }
512
513        int offset = page.getPageSize() * (page.getPageNumber() - 1);
514        queryWrapper.limit(offset, page.getPageSize());
515        List<T> rows = selectListByQuery(queryWrapper);
516        page.setRecords(rows);
517        return page;
518    }
519}