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