001/*
002 *  Copyright (c) 2022-2025, 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.*;
022import com.mybatisflex.core.row.Db;
023import com.mybatisflex.core.update.UpdateChain;
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.Collection;
030import java.util.List;
031import java.util.Map;
032import java.util.Optional;
033
034
035/**
036 * 由 Mybatis-Flex 提供的顶级增强 Service 接口。
037 *
038 * @param <T> 实体类(Entity)类型
039 * @author 王帅
040 * @since 2023-05-01
041 */
042@SuppressWarnings({"unused", "unchecked"})
043public interface IService<T> {
044
045    int DEFAULT_BATCH_SIZE = 1000;
046
047    /**
048     * <p>获取对应实体类(Entity)的基础映射类(BaseMapper)。
049     *
050     * @return 基础映射类(BaseMapper)
051     */
052    BaseMapper<T> getMapper();
053
054    // ===== 保存(增)操作 =====
055
056    /**
057     * <p>保存实体类对象数据。
058     *
059     * @param entity 实体类对象
060     * @return {@code true} 保存成功,{@code false} 保存失败。
061     * @apiNote 默认调用的是 {@link BaseMapper#insertSelective(Object)} 方法,忽略实体类
062     * {@code null} 属性的数据,使数据库配置的默认值生效。
063     */
064    default boolean save(T entity) {
065        return SqlUtil.toBool(getMapper().insert(entity, true));
066    }
067
068    /**
069     * <p>批量保存实体类对象数据。
070     *
071     * @param entities 实体类对象
072     * @return {@code true} 保存成功,{@code false} 保存失败。
073     * @apiNote 默认调用的是 {@link BaseMapper#insertSelective(Object)} 方法,忽略实体类
074     * {@code null} 属性的数据,使数据库配置的默认值生效。
075     */
076    default boolean saveBatch(Collection<T> entities) {
077        return saveBatch(entities, DEFAULT_BATCH_SIZE);
078    }
079
080    /**
081     * <p>批量保存实体类对象数据。
082     *
083     * @param entities  实体类对象
084     * @param batchSize 每次保存切分的数量
085     * @return {@code true} 保存成功,{@code false} 保存失败。
086     * @apiNote 默认调用的是 {@link BaseMapper#insertSelective(Object)} 方法,忽略实体类
087     * {@code null} 属性的数据,使数据库配置的默认值生效。
088     */
089    default boolean saveBatch(Collection<T> entities, int batchSize) {
090        Class<BaseMapper<T>> usefulClass = (Class<BaseMapper<T>>) ClassUtil.getUsefulClass(getMapper().getClass());
091        return SqlUtil.toBool(Db.executeBatch(entities, batchSize, usefulClass, BaseMapper::insertSelective));
092    }
093
094    /**
095     * <p>保存或者更新实体类对象数据。
096     *
097     * @param entity 实体类对象
098     * @return {@code true} 保存或更新成功,{@code false} 保存或更新失败。
099     * @apiNote 如果实体类对象主键有值,则更新数据,若没有值,则保存数据,无论新增还是更新都会忽略实体类
100     * {@code null} 属性的数据。
101     */
102    default boolean saveOrUpdate(T entity) {
103        return SqlUtil.toBool(getMapper().insertOrUpdate(entity, true));
104    }
105
106    /**
107     * <p>保存或者更新实体类对象数据。
108     *
109     * @param entities 实体类对象
110     * @return {@code true} 保存或更新成功,{@code false} 保存或更新失败。
111     * @apiNote 如果实体类对象主键有值,则更新数据,若没有值,则保存数据,无论新增还是更新都会忽略实体类
112     * {@code null} 属性的数据。
113     */
114    default boolean saveOrUpdateBatch(Collection<T> entities) {
115        return saveOrUpdateBatch(entities, DEFAULT_BATCH_SIZE);
116    }
117
118    /**
119     * <p>保存或者更新实体类对象数据。
120     *
121     * @param entities  实体类对象
122     * @param batchSize 每次操作切分的数量
123     * @return {@code true} 保存或更新成功,{@code false} 保存或更新失败。
124     * @apiNote 如果实体类对象主键有值,则更新数据,若没有值,则保存数据,无论新增还是更新都会忽略实体类
125     * {@code null} 属性的数据。
126     */
127    default boolean saveOrUpdateBatch(Collection<T> entities, int batchSize) {
128        Class<BaseMapper<T>> usefulClass = (Class<BaseMapper<T>>) ClassUtil.getUsefulClass(getMapper().getClass());
129        return SqlUtil.toBool(Db.executeBatch(entities, batchSize, usefulClass, BaseMapper::insertOrUpdateSelective));
130    }
131
132    // ===== 删除(删)操作 =====
133
134    /**
135     * <p>根据查询条件删除数据。
136     *
137     * @param query 查询条件
138     * @return {@code true} 删除成功,{@code false} 删除失败。
139     */
140    default boolean remove(QueryWrapper query) {
141        return SqlUtil.toBool(getMapper().deleteByQuery(query));
142    }
143
144    /**
145     * <p>根据查询条件删除数据。
146     *
147     * @param condition 查询条件
148     * @return {@code true} 删除成功,{@code false} 删除失败。
149     */
150    default boolean remove(QueryCondition condition) {
151        return remove(query().where(condition));
152    }
153
154    /**
155     * <p>根据实体主键删除数据。
156     *
157     * @param entity 实体类对象
158     * @return {@code true} 删除成功,{@code false} 删除失败。
159     */
160    default boolean removeById(T entity) {
161        return SqlUtil.toBool(getMapper().delete(entity));
162    }
163
164    /**
165     * <p>根据数据主键删除数据。
166     *
167     * @param id 数据主键
168     * @return {@code true} 删除成功,{@code false} 删除失败。
169     */
170    default boolean removeById(Serializable id) {
171        return SqlUtil.toBool(getMapper().deleteById(id));
172    }
173
174    /**
175     * <p>根据数据主键批量删除数据。
176     *
177     * @param ids 数据主键
178     * @return {@code true} 删除成功,{@code false} 删除失败。
179     */
180    default boolean removeByIds(Collection<? extends Serializable> ids) {
181        if (CollectionUtil.isEmpty(ids)) {
182            return false;
183        }
184        return SqlUtil.toBool(getMapper().deleteBatchByIds(ids));
185    }
186
187    /**
188     * <p>根据 {@link Map} 构建查询条件删除数据。
189     *
190     * @param query 查询条件
191     * @return {@code true} 删除成功,{@code false} 删除失败。
192     */
193    default boolean removeByMap(Map<String, Object> query) {
194        // 防止全表删除
195        if (query == null || query.isEmpty()) {
196            throw FlexExceptions.wrap("deleteByMap is not allow empty map.");
197        }
198        return remove(query().where(query));
199    }
200
201    // ===== 更新(改)操作 =====
202
203    /**
204     * <p>根据数据主键更新数据。
205     *
206     * @param entity 实体类对象
207     * @return {@code true} 更新成功,{@code false} 更新失败。
208     * @apiNote 若实体类属性数据为 {@code null},该属性不会新到数据库。
209     */
210    default boolean updateById(T entity) {
211        return updateById(entity, true);
212    }
213
214    /**
215     * 根据主键更新数据
216     *
217     * @param entity      实体对象
218     * @param ignoreNulls 是否忽略 null 值
219     * @return {@code true} 更新成功,{@code false} 更新失败。
220     */
221    default boolean updateById(T entity, boolean ignoreNulls) {
222        return SqlUtil.toBool(getMapper().update(entity, ignoreNulls));
223    }
224
225    /**
226     * <p>根据 {@link Map} 构建查询条件更新数据。
227     *
228     * @param entity 实体类对象
229     * @param query  查询条件
230     * @return {@code true} 更新成功,{@code false} 更新失败。
231     * @apiNote 若实体类属性数据为 {@code null},该属性不会新到数据库。
232     */
233    default boolean update(T entity, Map<String, Object> query) {
234        return update(entity, query().where(query));
235    }
236
237    /**
238     * <p>根据查询条件更新数据。
239     *
240     * @param entity 实体类对象
241     * @param query  查询条件
242     * @return {@code true} 更新成功,{@code false} 更新失败。
243     * @apiNote 若实体类属性数据为 {@code null},该属性不会新到数据库。
244     */
245    default boolean update(T entity, QueryWrapper query) {
246        return SqlUtil.toBool(getMapper().updateByQuery(entity, query));
247    }
248
249    /**
250     * <p>根据查询条件更新数据。
251     *
252     * @param entity    实体类对象
253     * @param condition 查询条件
254     * @return {@code true} 更新成功,{@code false} 更新失败。
255     * @apiNote 若实体类属性数据为 {@code null},该属性不会新到数据库。
256     */
257    default boolean update(T entity, QueryCondition condition) {
258        return update(entity, query().where(condition));
259    }
260
261    /**
262     * <p>根据数据主键批量更新数据
263     *
264     * @param entities 实体类对象集合
265     * @return boolean {@code true} 更新成功,{@code false} 更新失败。
266     * @apiNote 若实体类属性数据为 {@code null},该属性不会新到数据库。
267     */
268    default boolean updateBatch(Collection<T> entities) {
269        return updateBatch(entities, DEFAULT_BATCH_SIZE);
270    }
271
272
273    /**
274     * <p>根据数据主键批量更新数据
275     *
276     * @param entities    实体类对象集合
277     * @param ignoreNulls 是否忽略空字段
278     *                    {@code true} 表示忽略实体类中为 {@code null} 的字段,不更新这些字段。
279     *                    {@code false} 表示不忽略空字段,允许将对应字段更新为 {@code null}。
280     * @return boolean {@code true} 更新成功,{@code false} 更新失败。
281     * @apiNote 若 {@code ignoreNulls} 为 {@code true},实体类中为 {@code null} 的属性不会更新到数据库。
282     */
283    default boolean updateBatch(Collection<T> entities, boolean ignoreNulls) {
284        return updateBatch(entities, DEFAULT_BATCH_SIZE, ignoreNulls);
285    }
286
287    /**
288     * <p>根据数据主键批量更新数据
289     *
290     * @param entities  实体类对象集合
291     * @param batchSize 每批次更新数量
292     * @return {@code true} 更新成功,{@code false} 更新失败。
293     * @apiNote 若实体类属性数据为 {@code null},该属性不会新到数据库。
294     */
295    default boolean updateBatch(Collection<T> entities, int batchSize) {
296        Class<BaseMapper<T>> usefulClass = (Class<BaseMapper<T>>) ClassUtil.getUsefulClass(getMapper().getClass());
297        return SqlUtil.toBool(Db.executeBatch(entities, batchSize, usefulClass, BaseMapper::update));
298    }
299
300
301    /**
302     * <p>根据数据主键批量更新数据
303     *
304     * @param entities    实体类对象集合
305     * @param batchSize   每批次更新数量
306     * @param ignoreNulls 是否忽略空字段
307     *                    {@code true} 表示忽略实体类中为 {@code null} 的字段,不更新这些字段。
308     *                    {@code false} 表示不忽略空字段,允许将对应字段更新为 {@code null}。
309     * @return {@code true} 更新成功,{@code false} 更新失败。
310     * @apiNote 若 {@code ignoreNulls} 为 {@code true},实体类中为 {@code null} 的属性不会更新到数据库。
311     */
312    default boolean updateBatch(Collection<T> entities, int batchSize, boolean ignoreNulls) {
313        Class<BaseMapper<T>> usefulClass = (Class<BaseMapper<T>>) ClassUtil.getUsefulClass(getMapper().getClass());
314        return SqlUtil.toBool(Db.executeBatch(entities, batchSize, usefulClass, (mapper, entity) -> mapper.update(entity, ignoreNulls)));
315    }
316
317    // ===== 查询(查)操作 =====
318
319    /**
320     * <p>根据数据主键查询一条数据。
321     *
322     * @param id 数据主键
323     * @return 查询结果数据
324     */
325    default T getById(Serializable id) {
326        return getMapper().selectOneById(id);
327    }
328
329    /**
330     * <p>根据实体主键查询数据。
331     *
332     * @param entity 实体对象,必须包含有主键
333     * @return 查询结果数据
334     */
335    default T getOneByEntityId(T entity) {
336        return getMapper().selectOneByEntityId(entity);
337    }
338
339    /**
340     * <p>根据实体主键查询数据。
341     *
342     * @param entity 实体对象,必须包含有主键
343     * @return 查询结果数据
344     * @apiNote 该方法会将查询结果封装为 {@link Optional} 类进行返回,方便链式操作。
345     */
346    default Optional<T> getByEntityIdOpt(T entity) {
347        return Optional.ofNullable(getOneByEntityId(entity));
348    }
349
350    /**
351     * <p>根据数据主键查询一条数据。
352     *
353     * @param id 数据主键
354     * @return 查询结果数据
355     * @apiNote 该方法会将查询结果封装为 {@link Optional} 类进行返回,方便链式操作。
356     */
357    default Optional<T> getByIdOpt(Serializable id) {
358        return Optional.ofNullable(getById(id));
359    }
360
361    /**
362     * <p>根据查询条件查询一条数据。
363     *
364     * @param query 查询条件
365     * @return 查询结果数据
366     */
367    default T getOne(QueryWrapper query) {
368        return getMapper().selectOneByQuery(query);
369    }
370
371    /**
372     * <p>根据查询条件查询一条数据。
373     *
374     * @param query 查询条件
375     * @return 查询结果数据
376     * @apiNote 该方法会将查询结果封装为 {@link Optional} 类进行返回,方便链式操作。
377     */
378    default Optional<T> getOneOpt(QueryWrapper query) {
379        return Optional.ofNullable(getOne(query));
380    }
381
382    /**
383     * <p>根据查询条件查询一条数据,并通过 asType 进行接收。
384     *
385     * @param query  查询条件
386     * @param asType 接收的数据类型
387     * @return 查询结果数据
388     */
389    default <R> R getOneAs(QueryWrapper query, Class<R> asType) {
390        return getMapper().selectOneByQueryAs(query, asType);
391    }
392
393    /**
394     * <p>根据查询条件查询一条数据。
395     *
396     * @param query  查询条件
397     * @param asType 接收的数据类型
398     * @return 查询结果数据
399     * @apiNote 该方法会将查询结果封装为 {@link Optional} 类进行返回,方便链式操作。
400     */
401    default <R> Optional<R> getOneAsOpt(QueryWrapper query, Class<R> asType) {
402        return Optional.ofNullable(getOneAs(query, asType));
403    }
404
405    /**
406     * <p>根据查询条件查询一条数据。
407     *
408     * @param condition 查询条件
409     * @return 查询结果数据
410     */
411    default T getOne(QueryCondition condition) {
412        return getOne(query().where(condition).limit(1));
413    }
414
415    /**
416     * <p>根据查询条件查询一条数据。
417     *
418     * @param condition 查询条件
419     * @return 查询结果数据
420     * @apiNote 该方法会将查询结果封装为 {@link Optional} 类进行返回,方便链式操作。
421     */
422    default Optional<T> getOneOpt(QueryCondition condition) {
423        return Optional.ofNullable(getOne(condition));
424    }
425
426    /**
427     * <p>查询结果集中第一列,且第一条数据。
428     *
429     * @param query 查询条件
430     * @return 数据值
431     */
432    default Object getObj(QueryWrapper query) {
433        return getMapper().selectObjectByQuery(query);
434    }
435
436    /**
437     * <p>查询结果集中第一列,且第一条数据,并封装为 {@link Optional} 返回。
438     *
439     * @param query 查询条件
440     * @return 数据值
441     */
442    default Optional<Object> getObjOpt(QueryWrapper query) {
443        return Optional.ofNullable(getObj(query));
444    }
445
446    /**
447     * <p>查询结果集中第一列,且第一条数据,并转换为指定类型,比如 {@code Long}, {@code String} 等。
448     *
449     * @param query  查询条件
450     * @param asType 接收的数据类型
451     * @return 数据值
452     */
453    default <R> R getObjAs(QueryWrapper query, Class<R> asType) {
454        return getMapper().selectObjectByQueryAs(query, asType);
455    }
456
457    /**
458     * <p>查询结果集中第一列,且第一条数据,并转换为指定类型,比如 {@code Long}, {@code String}
459     * 等,封装为 {@link Optional} 返回。
460     *
461     * @param query  查询条件
462     * @param asType 接收的数据类型
463     * @return 数据值
464     */
465    default <R> Optional<R> getObjAsOpt(QueryWrapper query, Class<R> asType) {
466        return Optional.ofNullable(getObjAs(query, asType));
467    }
468
469    /**
470     * <p>查询结果集中第一列所有数据。
471     *
472     * @param query 查询条件
473     * @return 数据列表
474     */
475    default List<Object> objList(QueryWrapper query) {
476        return getMapper().selectObjectListByQuery(query);
477    }
478
479    /**
480     * <p>查询结果集中第一列所有数据,并转换为指定类型,比如 {@code Long}, {@code String} 等。
481     *
482     * @param query  查询条件
483     * @param asType 接收的数据类型
484     * @return 数据列表
485     */
486    default <R> List<R> objListAs(QueryWrapper query, Class<R> asType) {
487        return getMapper().selectObjectListByQueryAs(query, asType);
488    }
489
490    /**
491     * <p>查询所有数据。
492     *
493     * @return 所有数据
494     */
495    default List<T> list() {
496        return list(query());
497    }
498
499    /**
500     * <p>根据查询条件查询数据集合。
501     *
502     * @param query 查询条件
503     * @return 数据集合
504     */
505    default List<T> list(QueryWrapper query) {
506        return getMapper().selectListByQuery(query);
507    }
508
509    /**
510     * <p>根据查询条件查询数据集合。
511     *
512     * @param condition 查询条件
513     * @return 数据集合
514     */
515    default List<T> list(QueryCondition condition) {
516        return list(query().where(condition));
517    }
518
519    /**
520     * <p>根据查询条件查询数据集合,并通过 asType 进行接收。
521     *
522     * @param query  查询条件
523     * @param asType 接收的数据类型
524     * @return 数据集合
525     */
526    default <R> List<R> listAs(QueryWrapper query, Class<R> asType) {
527        return getMapper().selectListByQueryAs(query, asType);
528    }
529
530    /**
531     * <p>根据数据主键查询数据集合。
532     *
533     * @param ids 数据主键
534     * @return 数据集合
535     */
536    default List<T> listByIds(Collection<? extends Serializable> ids) {
537        return getMapper().selectListByIds(ids);
538    }
539
540    /**
541     * <p>根据 {@link Map} 构建查询条件查询数据集合。
542     *
543     * @param query 查询条件
544     * @return 数据集合
545     */
546    default List<T> listByMap(Map<String, Object> query) {
547        return list(query().where(query));
548    }
549
550    // ===== 数量查询操作 =====
551
552    /**
553     * <p>根据查询条件判断数据是否存在。
554     *
555     * @param query 查询条件
556     * @return {@code true} 数据存在,{@code false} 数据不存在。
557     */
558    default boolean exists(QueryWrapper query) {
559        return exists(CPI.getWhereQueryCondition(query));
560    }
561
562    /**
563     * <p>根据查询条件判断数据是否存在。
564     *
565     * @param condition 查询条件
566     * @return {@code true} 数据存在,{@code false} 数据不存在。
567     */
568    default boolean exists(QueryCondition condition) {
569        // 根据查询条件构建 SQL 语句
570        // SELECT 1 FROM table WHERE ... LIMIT 1
571        QueryWrapper queryWrapper = QueryMethods.selectOne()
572            .where(condition)
573            .limit(1);
574        // 获取数据集合,空集合:[] 不存在数据,有一个元素的集合:[1] 存在数据
575        List<Object> objects = getMapper().selectObjectListByQuery(queryWrapper);
576        // 判断是否存在数据
577        return CollectionUtil.isNotEmpty(objects);
578    }
579
580    /**
581     * <p>查询所有数据数量。
582     *
583     * @return 所有数据数量
584     */
585    default long count() {
586        return count(query());
587    }
588
589    /**
590     * <p>根据查询条件查询数据数量。
591     *
592     * @param query 查询条件
593     * @return 数据数量
594     */
595    default long count(QueryWrapper query) {
596        return getMapper().selectCountByQuery(query);
597    }
598
599    /**
600     * <p>根据查询条件查询数据数量。
601     *
602     * @param condition 查询条件
603     * @return 数据数量
604     */
605    default long count(QueryCondition condition) {
606        return count(query().where(condition));
607    }
608
609    // ===== 分页查询操作 =====
610
611    /**
612     * <p>分页查询所有数据。
613     *
614     * @param page 分页对象
615     * @return 分页对象
616     */
617    default Page<T> page(Page<T> page) {
618        return page(page, query());
619    }
620
621    /**
622     * <p>根据查询条件分页查询数据。
623     *
624     * @param page  分页对象
625     * @param query 查询条件
626     * @return 分页对象
627     */
628    default Page<T> page(Page<T> page, QueryWrapper query) {
629        return pageAs(page, query, null);
630    }
631
632    /**
633     * <p>根据查询条件分页查询数据。
634     *
635     * @param page      分页对象
636     * @param condition 查询条件
637     * @return 分页对象
638     */
639    default Page<T> page(Page<T> page, QueryCondition condition) {
640        return page(page, query().where(condition));
641    }
642
643    /**
644     * <p>根据查询条件分页查询数据,并通过 asType 进行接收。
645     *
646     * @param page   分页对象
647     * @param query  查询条件
648     * @param asType 接收的数据类型
649     * @return 分页对象
650     */
651    default <R> Page<R> pageAs(Page<R> page, QueryWrapper query, Class<R> asType) {
652        return getMapper().paginateAs(page, query, asType);
653    }
654
655    // ===== 查询包装器操作 =====
656
657    /**
658     * 默认 {@link QueryWrapper} 构建。
659     *
660     * @return {@link QueryWrapper} 对象
661     */
662    default QueryWrapper query() {
663        return QueryWrapper.create();
664    }
665
666    /**
667     * 链式查询。
668     *
669     * @return {@link QueryChain} 对象
670     */
671    default QueryChain<T> queryChain() {
672        return QueryChain.of(getMapper());
673    }
674
675    /**
676     * 链式更新。
677     *
678     * @return {@link UpdateChain} 对象
679     */
680    default UpdateChain<T> updateChain() {
681        return UpdateChain.create(getMapper());
682    }
683
684}