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.service;
017
018import com.mybatisflex.core.BaseMapper;
019import com.mybatisflex.core.exception.FlexExceptions;
020import com.mybatisflex.core.paginate.Page;
021import com.mybatisflex.core.query.QueryCondition;
022import com.mybatisflex.core.query.QueryWrapper;
023import com.mybatisflex.core.row.Db;
024import com.mybatisflex.core.util.ClassUtil;
025import com.mybatisflex.core.util.CollectionUtil;
026import com.mybatisflex.core.util.SqlUtil;
027
028import java.io.Serializable;
029import java.util.*;
030
031
032/**
033 * 由 Mybatis-Flex 提供的顶级增强 Service 接口。
034 *
035 * @param <T> 实体类(Entity)类型
036 * @author 王帅
037 * @since 2023-05-01
038 */
039@SuppressWarnings({"unused", "unchecked"})
040public interface IService<T> {
041
042    int DEFAULT_BATCH_SIZE = 1000;
043
044    // ===== 保存(增)操作 =====
045
046    /**
047     * <p>获取对应实体类(Entity)的基础映射类(BaseMapper)。
048     *
049     * @return 基础映射类(BaseMapper)
050     */
051    BaseMapper<T> getMapper();
052
053    /**
054     * <p>保存实体类对象数据。
055     *
056     * @param entity 实体类对象
057     * @return {@code true} 保存成功,{@code false} 保存失败。
058     * @apiNote 默认调用的是 {@link BaseMapper#insertSelective(Object)} 方法,忽略
059     * {@code null} 字段的数据,使数据库配置的默认值生效。
060     */
061    default boolean save(T entity) {
062        return SqlUtil.toBool(getMapper().insertSelective(entity));
063    }
064
065    /**
066     * <p>保存或者更新实体类对象数据。
067     *
068     * @param entity 实体类对象
069     * @return {@code true} 保存或更新成功,{@code false} 保存或更新失败。
070     * @apiNote 如果实体类对象主键有值,则更新数据,若没有值,则保存数据。
071     */
072    default boolean saveOrUpdate(T entity) {
073        return SqlUtil.toBool(getMapper().insertOrUpdate(entity, true));
074    }
075
076    /**
077     * <p>批量保存实体类对象数据。
078     *
079     * @param entities 实体类对象
080     * @return {@code true} 保存成功,{@code false} 保存失败。
081     */
082    default boolean saveBatch(Collection<T> entities) {
083        return saveBatch(entities, DEFAULT_BATCH_SIZE);
084    }
085
086    // ===== 删除(删)操作 =====
087
088    /**
089     * <p>批量保存实体类对象数据。
090     *
091     * @param entities  实体类对象
092     * @param batchSize 每次保存切分的数量
093     * @return {@code true} 保存成功,{@code false} 保存失败。
094     */
095    default boolean saveBatch(Collection<T> entities, int batchSize) {
096        return SqlUtil.toBool(getMapper().insertBatch(CollectionUtil.toList(entities), batchSize));
097    }
098
099
100    /**
101     * <p>批量保存实体类对象数据。
102     *
103     * @param entities 实体类对象
104     * @return {@code true} 保存成功,{@code false} 保存失败。
105     */
106    default boolean saveBatchSelective(Collection<T> entities) {
107        return saveBatchSelective(entities, DEFAULT_BATCH_SIZE);
108    }
109
110    // ===== 删除(删)操作 =====
111
112    /**
113     * <p>批量保存实体类对象数据。
114     *
115     * @param entities  实体类对象
116     * @param batchSize 每次保存切分的数量
117     * @return {@code true} 保存成功,{@code false} 保存失败。
118     */
119    default boolean saveBatchSelective(Collection<T> entities, int batchSize) {
120        List<T> entityList = CollectionUtil.toList(entities);
121        Class<BaseMapper<T>> usefulClass = (Class<BaseMapper<T>>) ClassUtil.getUsefulClass(getMapper().getClass());
122        return SqlUtil.toBool(
123            Db.executeBatch(entities.size(), batchSize, usefulClass, (mapper, integer) -> mapper.insertSelective(entityList.get(integer)))
124        );
125    }
126
127
128    /**
129     * <p>根据查询条件删除数据。
130     *
131     * @param query 查询条件
132     * @return {@code true} 删除成功,{@code false} 删除失败。
133     */
134    default boolean remove(QueryWrapper query) {
135        return SqlUtil.toBool(getMapper().deleteByQuery(query));
136    }
137
138    /**
139     * <p>根据查询条件删除数据。
140     *
141     * @param condition 查询条件
142     * @return {@code true} 删除成功,{@code false} 删除失败。
143     */
144    default boolean remove(QueryCondition condition) {
145        return remove(query().where(condition));
146    }
147
148    /**
149     * <p>根据数据主键删除数据。
150     *
151     * @param id 数据主键
152     * @return {@code true} 删除成功,{@code false} 删除失败。
153     */
154    default boolean removeById(Serializable id) {
155        return SqlUtil.toBool(getMapper().deleteById(id));
156    }
157
158    /**
159     * <p>根据数据主键批量删除数据。
160     *
161     * @param ids 数据主键
162     * @return {@code true} 删除成功,{@code false} 删除失败。
163     */
164    default boolean removeByIds(Collection<? extends Serializable> ids) {
165        if (CollectionUtil.isEmpty(ids)) {
166            return false;
167        }
168        return SqlUtil.toBool(getMapper().deleteBatchByIds(ids));
169    }
170
171    // ===== 更新(改)操作 =====
172
173    /**
174     * <p>根据 {@link Map} 构建查询条件删除数据。
175     *
176     * @param query 查询条件
177     * @return {@code true} 删除成功,{@code false} 删除失败。
178     */
179    default boolean removeByMap(Map<String, Object> query) {
180        // 防止全表删除
181        if (query == null || query.isEmpty()) {
182            throw FlexExceptions.wrap("deleteByMap is not allow empty map.");
183        }
184        return remove(query().where(query));
185    }
186
187    /**
188     * <p>根据数据主键更新数据。
189     *
190     * @param entity 实体类对象
191     * @return {@code true} 更新成功,{@code false} 更新失败。
192     * @apiNote 若实体类属性数据为 {@code null},该属性不会新到数据库。
193     */
194    default boolean updateById(T entity) {
195        return updateById(entity, true);
196    }
197
198    /**
199     * 根据主键更新数据
200     *
201     * @param entity      实体对象
202     * @param ignoreNulls 是否忽略 null 值
203     * @return {@code true} 更新成功,{@code false} 更新失败。
204     */
205    default boolean updateById(T entity, boolean ignoreNulls) {
206        return SqlUtil.toBool(getMapper().update(entity, ignoreNulls));
207    }
208
209    /**
210     * <p>根据 {@link Map} 构建查询条件更新数据。
211     *
212     * @param entity 实体类对象
213     * @param query  查询条件
214     * @return {@code true} 更新成功,{@code false} 更新失败。
215     */
216    default boolean update(T entity, Map<String, Object> query) {
217        return update(entity, query().where(query));
218    }
219
220    /**
221     * <p>根据查询条件更新数据。
222     *
223     * @param entity 实体类对象
224     * @param query  查询条件
225     * @return {@code true} 更新成功,{@code false} 更新失败。
226     */
227    default boolean update(T entity, QueryWrapper query) {
228        return SqlUtil.toBool(getMapper().updateByQuery(entity, query));
229    }
230
231    /**
232     * <p>根据查询条件更新数据。
233     *
234     * @param entity    实体类对象
235     * @param condition 查询条件
236     * @return {@code true} 更新成功,{@code false} 更新失败。
237     */
238    default boolean update(T entity, QueryCondition condition) {
239        return update(entity, query().where(condition));
240    }
241
242    /**
243     * <p>根据数据主键批量更新数据
244     *
245     * @param entities 实体类对象集合
246     * @return boolean {@code true} 更新成功,{@code false} 更新失败。
247     */
248    default boolean updateBatch(Collection<T> entities) {
249        return updateBatch(entities, DEFAULT_BATCH_SIZE);
250    }
251
252    /**
253     * <p>根据数据主键批量更新数据
254     *
255     * @param entities  实体类对象集合
256     * @param batchSize 每批次更新数量
257     * @return {@code true} 更新成功,{@code false} 更新失败。
258     */
259    default boolean updateBatch(Collection<T> entities, int batchSize) {
260        List<T> entityList = CollectionUtil.toList(entities);
261        // BaseMapper 是经过 Mybatis 动态代理处理过的对象,需要获取原始 BaseMapper 类型
262        Class<BaseMapper<T>> usefulClass = (Class<BaseMapper<T>>) ClassUtil.getUsefulClass(getMapper().getClass());
263        return SqlUtil.toBool(
264            Db.executeBatch(
265                entityList.size()
266                , batchSize
267                , usefulClass
268                , (mapper, index) -> mapper.update(entityList.get(index)))
269        );
270    }
271
272
273    // ===== 查询(查)操作 =====
274
275    /**
276     * <p>根据数据主键查询一条数据。
277     *
278     * @param id 数据主键
279     * @return 查询结果数据
280     */
281    default T getById(Serializable id) {
282        return getMapper().selectOneById(id);
283    }
284
285    /**
286     * <p>根据数据主键查询一条数据。
287     *
288     * @param id 数据主键
289     * @return 查询结果数据
290     * @apiNote 该方法会将查询结果封装为 {@link Optional} 类进行返回,方便链式操作。
291     */
292    default Optional<T> getByIdOpt(Serializable id) {
293        return Optional.ofNullable(getById(id));
294    }
295
296    /**
297     * <p>根据查询条件查询一条数据。
298     *
299     * @param query 查询条件
300     * @return 查询结果数据
301     */
302    default T getOne(QueryWrapper query) {
303        return getMapper().selectOneByQuery(query);
304    }
305
306    /**
307     * <p>根据查询条件查询一条数据。
308     *
309     * @param query 查询条件
310     * @return 查询结果数据
311     * @apiNote 该方法会将查询结果封装为 {@link Optional} 类进行返回,方便链式操作。
312     */
313    default Optional<T> getOneOpt(QueryWrapper query) {
314        return Optional.ofNullable(getOne(query));
315    }
316
317    /**
318     * <p>根据查询条件查询一条数据,并通过 asType 进行接收。
319     *
320     * @param query  查询条件
321     * @param asType 接收的数据类型
322     * @return 查询结果数据
323     */
324    default <R> R getOneAs(QueryWrapper query, Class<R> asType) {
325        return getMapper().selectOneByQueryAs(query, asType);
326    }
327
328    /**
329     * <p>根据查询条件查询一条数据。
330     *
331     * @param query  查询条件
332     * @param asType 接收的数据类型
333     * @return 查询结果数据
334     * @apiNote 该方法会将查询结果封装为 {@link Optional} 类进行返回,方便链式操作。
335     */
336    default <R> Optional<R> getOneAsOpt(QueryWrapper query, Class<R> asType) {
337        return Optional.ofNullable(getOneAs(query, asType));
338    }
339
340    /**
341     * <p>根据查询条件查询一条数据。
342     *
343     * @param condition 查询条件
344     * @return 查询结果数据
345     */
346    default T getOne(QueryCondition condition) {
347        return getOne(query().where(condition));
348    }
349
350    /**
351     * <p>根据查询条件查询一条数据。
352     *
353     * @param condition 查询条件
354     * @return 查询结果数据
355     * @apiNote 该方法会将查询结果封装为 {@link Optional} 类进行返回,方便链式操作。
356     */
357    default Optional<T> getOneOpt(QueryCondition condition) {
358        return Optional.ofNullable(getOne(condition));
359    }
360
361    /**
362     * <p>查询所有数据。
363     *
364     * @return 所有数据
365     */
366    default List<T> list() {
367        return list(query());
368    }
369
370    /**
371     * <p>根据查询条件查询数据集合。
372     *
373     * @param query 查询条件
374     * @return 数据集合
375     */
376    default List<T> list(QueryWrapper query) {
377        return getMapper().selectListByQuery(query);
378    }
379
380    /**
381     * <p>根据查询条件查询数据集合。
382     *
383     * @param condition 查询条件
384     * @return 数据集合
385     */
386    default List<T> list(QueryCondition condition) {
387        return list(query().where(condition));
388    }
389
390    /**
391     * <p>根据查询条件查询数据集合,并通过 asType 进行接收。
392     *
393     * @param query  查询条件
394     * @param asType 接收的数据类型
395     * @return 数据集合
396     */
397    default <R> List<R> listAs(QueryWrapper query, Class<R> asType) {
398        return getMapper().selectListByQueryAs(query, asType);
399    }
400
401    /**
402     * <p>根据数据主键查询数据集合。
403     *
404     * @param ids 数据主键
405     * @return 数据集合
406     */
407    default List<T> listByIds(Collection<? extends Serializable> ids) {
408        return getMapper().selectListByIds(ids);
409    }
410
411    /**
412     * <p>根据 {@link Map} 构建查询条件查询数据集合。
413     *
414     * @param query 查询条件
415     * @return 数据集合
416     */
417    default List<T> listByMap(Map<String, Object> query) {
418        return list(query().where(query));
419    }
420
421    // ===== 数量查询操作 =====
422
423    /**
424     * <p>根据查询条件判断数据是否存在。
425     *
426     * @param query 查询条件
427     * @return {@code true} 数据存在,{@code false} 数据不存在。
428     */
429    default boolean exists(QueryWrapper query) {
430        return SqlUtil.toBool(count(query));
431    }
432
433    /**
434     * <p>根据查询条件判断数据是否存在。
435     *
436     * @param condition 查询条件
437     * @return {@code true} 数据存在,{@code false} 数据不存在。
438     */
439    default boolean exists(QueryCondition condition) {
440        return SqlUtil.toBool(count(condition));
441    }
442
443    /**
444     * <p>查询所有数据数量。
445     *
446     * @return 所有数据数量
447     */
448    default long count() {
449        return count(query());
450    }
451
452    /**
453     * <p>根据查询条件查询数据数量。
454     *
455     * @param query 查询条件
456     * @return 数据数量
457     */
458    default long count(QueryWrapper query) {
459        return getMapper().selectCountByQuery(query);
460    }
461
462    /**
463     * <p>根据查询条件查询数据数量。
464     *
465     * @param condition 查询条件
466     * @return 数据数量
467     */
468    default long count(QueryCondition condition) {
469        return count(query().where(condition));
470    }
471
472    // ===== 分页查询操作 =====
473
474    /**
475     * <p>分页查询所有数据。
476     *
477     * @param page 分页对象
478     * @return 分页对象
479     */
480    default Page<T> page(Page<T> page) {
481        return page(page, query());
482    }
483
484    /**
485     * <p>根据查询条件分页查询数据。
486     *
487     * @param page  分页对象
488     * @param query 查询条件
489     * @return 分页对象
490     */
491    default Page<T> page(Page<T> page, QueryWrapper query) {
492        return pageAs(page, query, null);
493    }
494
495    /**
496     * <p>根据查询条件分页查询数据。
497     *
498     * @param page      分页对象
499     * @param condition 查询条件
500     * @return 分页对象
501     */
502    default Page<T> page(Page<T> page, QueryCondition condition) {
503        return page(page, query().where(condition));
504    }
505
506    /**
507     * <p>根据查询条件分页查询数据,并通过 asType 进行接收。
508     *
509     * @param page   分页对象
510     * @param query  查询条件
511     * @param asType 接收的数据类型
512     * @return 分页对象
513     */
514    default <R> Page<R> pageAs(Page<R> page, QueryWrapper query, Class<R> asType) {
515        return getMapper().paginateAs(page, query, asType);
516    }
517
518    default QueryWrapper query() {
519        return QueryWrapper.create();
520    }
521
522}