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.*;
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     * <p>根据数据主键批量更新数据
274     *
275     * @param entities  实体类对象集合
276     * @param batchSize 每批次更新数量
277     * @return {@code true} 更新成功,{@code false} 更新失败。
278     * @apiNote 若实体类属性数据为 {@code null},该属性不会新到数据库。
279     */
280    default boolean updateBatch(Collection<T> entities, int batchSize) {
281        Class<BaseMapper<T>> usefulClass = (Class<BaseMapper<T>>) ClassUtil.getUsefulClass(getMapper().getClass());
282        return SqlUtil.toBool(Db.executeBatch(entities, batchSize, usefulClass, BaseMapper::update));
283    }
284
285    // ===== 查询(查)操作 =====
286
287    /**
288     * <p>根据数据主键查询一条数据。
289     *
290     * @param id 数据主键
291     * @return 查询结果数据
292     */
293    default T getById(Serializable id) {
294        return getMapper().selectOneById(id);
295    }
296
297    /**
298     * <p>根据实体主键查询数据。
299     *
300     * @param entity    实体对象,必须包含有主键
301     * @return 查询结果数据
302     */
303    default T getOneByEntityId(T entity) {
304        return getMapper().selectOneByEntityId(entity);
305    }
306
307    /**
308     * <p>根据实体主键查询数据。
309     *
310     * @param entity    实体对象,必须包含有主键
311     * @return 查询结果数据
312     * @apiNote 该方法会将查询结果封装为 {@link Optional} 类进行返回,方便链式操作。
313     */
314    default Optional<T> getByEntityIdOpt(T entity) {
315        return Optional.ofNullable(getOneByEntityId(entity));
316    }
317    /**
318     * <p>根据数据主键查询一条数据。
319     *
320     * @param id 数据主键
321     * @return 查询结果数据
322     * @apiNote 该方法会将查询结果封装为 {@link Optional} 类进行返回,方便链式操作。
323     */
324    default Optional<T> getByIdOpt(Serializable id) {
325        return Optional.ofNullable(getById(id));
326    }
327
328    /**
329     * <p>根据查询条件查询一条数据。
330     *
331     * @param query 查询条件
332     * @return 查询结果数据
333     */
334    default T getOne(QueryWrapper query) {
335        return getMapper().selectOneByQuery(query);
336    }
337
338    /**
339     * <p>根据查询条件查询一条数据。
340     *
341     * @param query 查询条件
342     * @return 查询结果数据
343     * @apiNote 该方法会将查询结果封装为 {@link Optional} 类进行返回,方便链式操作。
344     */
345    default Optional<T> getOneOpt(QueryWrapper query) {
346        return Optional.ofNullable(getOne(query));
347    }
348
349    /**
350     * <p>根据查询条件查询一条数据,并通过 asType 进行接收。
351     *
352     * @param query  查询条件
353     * @param asType 接收的数据类型
354     * @return 查询结果数据
355     */
356    default <R> R getOneAs(QueryWrapper query, Class<R> asType) {
357        return getMapper().selectOneByQueryAs(query, asType);
358    }
359
360    /**
361     * <p>根据查询条件查询一条数据。
362     *
363     * @param query  查询条件
364     * @param asType 接收的数据类型
365     * @return 查询结果数据
366     * @apiNote 该方法会将查询结果封装为 {@link Optional} 类进行返回,方便链式操作。
367     */
368    default <R> Optional<R> getOneAsOpt(QueryWrapper query, Class<R> asType) {
369        return Optional.ofNullable(getOneAs(query, asType));
370    }
371
372    /**
373     * <p>根据查询条件查询一条数据。
374     *
375     * @param condition 查询条件
376     * @return 查询结果数据
377     */
378    default T getOne(QueryCondition condition) {
379        return getOne(query().where(condition).limit(1));
380    }
381
382    /**
383     * <p>根据查询条件查询一条数据。
384     *
385     * @param condition 查询条件
386     * @return 查询结果数据
387     * @apiNote 该方法会将查询结果封装为 {@link Optional} 类进行返回,方便链式操作。
388     */
389    default Optional<T> getOneOpt(QueryCondition condition) {
390        return Optional.ofNullable(getOne(condition));
391    }
392
393    /**
394     * <p>查询结果集中第一列,且第一条数据。
395     *
396     * @param query 查询条件
397     * @return 数据值
398     */
399    default Object getObj(QueryWrapper query) {
400        return getMapper().selectObjectByQuery(query);
401    }
402
403    /**
404     * <p>查询结果集中第一列,且第一条数据,并封装为 {@link Optional} 返回。
405     *
406     * @param query 查询条件
407     * @return 数据值
408     */
409    default Optional<Object> getObjOpt(QueryWrapper query) {
410        return Optional.ofNullable(getObj(query));
411    }
412
413    /**
414     * <p>查询结果集中第一列,且第一条数据,并转换为指定类型,比如 {@code Long}, {@code String} 等。
415     *
416     * @param query  查询条件
417     * @param asType 接收的数据类型
418     * @return 数据值
419     */
420    default <R> R getObjAs(QueryWrapper query, Class<R> asType) {
421        return getMapper().selectObjectByQueryAs(query, asType);
422    }
423
424    /**
425     * <p>查询结果集中第一列,且第一条数据,并转换为指定类型,比如 {@code Long}, {@code String}
426     * 等,封装为 {@link Optional} 返回。
427     *
428     * @param query  查询条件
429     * @param asType 接收的数据类型
430     * @return 数据值
431     */
432    default <R> Optional<R> getObjAsOpt(QueryWrapper query, Class<R> asType) {
433        return Optional.ofNullable(getObjAs(query, asType));
434    }
435
436    /**
437     * <p>查询结果集中第一列所有数据。
438     *
439     * @param query 查询条件
440     * @return 数据列表
441     */
442    default List<Object> objList(QueryWrapper query) {
443        return getMapper().selectObjectListByQuery(query);
444    }
445
446    /**
447     * <p>查询结果集中第一列所有数据,并转换为指定类型,比如 {@code Long}, {@code String} 等。
448     *
449     * @param query  查询条件
450     * @param asType 接收的数据类型
451     * @return 数据列表
452     */
453    default <R> List<R> objListAs(QueryWrapper query, Class<R> asType) {
454        return getMapper().selectObjectListByQueryAs(query, asType);
455    }
456
457    /**
458     * <p>查询所有数据。
459     *
460     * @return 所有数据
461     */
462    default List<T> list() {
463        return list(query());
464    }
465
466    /**
467     * <p>根据查询条件查询数据集合。
468     *
469     * @param query 查询条件
470     * @return 数据集合
471     */
472    default List<T> list(QueryWrapper query) {
473        return getMapper().selectListByQuery(query);
474    }
475
476    /**
477     * <p>根据查询条件查询数据集合。
478     *
479     * @param condition 查询条件
480     * @return 数据集合
481     */
482    default List<T> list(QueryCondition condition) {
483        return list(query().where(condition));
484    }
485
486    /**
487     * <p>根据查询条件查询数据集合,并通过 asType 进行接收。
488     *
489     * @param query  查询条件
490     * @param asType 接收的数据类型
491     * @return 数据集合
492     */
493    default <R> List<R> listAs(QueryWrapper query, Class<R> asType) {
494        return getMapper().selectListByQueryAs(query, asType);
495    }
496
497    /**
498     * <p>根据数据主键查询数据集合。
499     *
500     * @param ids 数据主键
501     * @return 数据集合
502     */
503    default List<T> listByIds(Collection<? extends Serializable> ids) {
504        return getMapper().selectListByIds(ids);
505    }
506
507    /**
508     * <p>根据 {@link Map} 构建查询条件查询数据集合。
509     *
510     * @param query 查询条件
511     * @return 数据集合
512     */
513    default List<T> listByMap(Map<String, Object> query) {
514        return list(query().where(query));
515    }
516
517    // ===== 数量查询操作 =====
518
519    /**
520     * <p>根据查询条件判断数据是否存在。
521     *
522     * @param query 查询条件
523     * @return {@code true} 数据存在,{@code false} 数据不存在。
524     */
525    default boolean exists(QueryWrapper query) {
526        return exists(CPI.getWhereQueryCondition(query));
527    }
528
529    /**
530     * <p>根据查询条件判断数据是否存在。
531     *
532     * @param condition 查询条件
533     * @return {@code true} 数据存在,{@code false} 数据不存在。
534     */
535    default boolean exists(QueryCondition condition) {
536        // 根据查询条件构建 SQL 语句
537        // SELECT 1 FROM table WHERE ... LIMIT 1
538        QueryWrapper queryWrapper = QueryMethods.selectOne()
539            .where(condition)
540            .limit(1);
541        // 获取数据集合,空集合:[] 不存在数据,有一个元素的集合:[1] 存在数据
542        List<Object> objects = getMapper().selectObjectListByQuery(queryWrapper);
543        // 判断是否存在数据
544        return CollectionUtil.isNotEmpty(objects);
545    }
546
547    /**
548     * <p>查询所有数据数量。
549     *
550     * @return 所有数据数量
551     */
552    default long count() {
553        return count(query());
554    }
555
556    /**
557     * <p>根据查询条件查询数据数量。
558     *
559     * @param query 查询条件
560     * @return 数据数量
561     */
562    default long count(QueryWrapper query) {
563        return getMapper().selectCountByQuery(query);
564    }
565
566    /**
567     * <p>根据查询条件查询数据数量。
568     *
569     * @param condition 查询条件
570     * @return 数据数量
571     */
572    default long count(QueryCondition condition) {
573        return count(query().where(condition));
574    }
575
576    // ===== 分页查询操作 =====
577
578    /**
579     * <p>分页查询所有数据。
580     *
581     * @param page 分页对象
582     * @return 分页对象
583     */
584    default Page<T> page(Page<T> page) {
585        return page(page, query());
586    }
587
588    /**
589     * <p>根据查询条件分页查询数据。
590     *
591     * @param page  分页对象
592     * @param query 查询条件
593     * @return 分页对象
594     */
595    default Page<T> page(Page<T> page, QueryWrapper query) {
596        return pageAs(page, query, null);
597    }
598
599    /**
600     * <p>根据查询条件分页查询数据。
601     *
602     * @param page      分页对象
603     * @param condition 查询条件
604     * @return 分页对象
605     */
606    default Page<T> page(Page<T> page, QueryCondition condition) {
607        return page(page, query().where(condition));
608    }
609
610    /**
611     * <p>根据查询条件分页查询数据,并通过 asType 进行接收。
612     *
613     * @param page   分页对象
614     * @param query  查询条件
615     * @param asType 接收的数据类型
616     * @return 分页对象
617     */
618    default <R> Page<R> pageAs(Page<R> page, QueryWrapper query, Class<R> asType) {
619        return getMapper().paginateAs(page, query, asType);
620    }
621
622    // ===== 查询包装器操作 =====
623
624    /**
625     * 默认 {@link QueryWrapper} 构建。
626     *
627     * @return {@link QueryWrapper} 对象
628     */
629    default QueryWrapper query() {
630        return QueryWrapper.create();
631    }
632
633    /**
634     * 链式查询。
635     *
636     * @return {@link QueryChain} 对象
637     */
638    default QueryChain<T> queryChain() {
639        return QueryChain.of(getMapper());
640    }
641
642    /**
643     * 链式更新。
644     *
645     * @return {@link UpdateChain} 对象
646     */
647    default UpdateChain<T> updateChain() {
648        return UpdateChain.create(getMapper());
649    }
650
651}