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));
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     * <p>根据查询条件删除数据。
101     *
102     * @param query 查询条件
103     * @return {@code true} 删除成功,{@code false} 删除失败。
104     */
105    default boolean remove(QueryWrapper query) {
106        return SqlUtil.toBool(getMapper().deleteByQuery(query));
107    }
108
109    /**
110     * <p>根据查询条件删除数据。
111     *
112     * @param condition 查询条件
113     * @return {@code true} 删除成功,{@code false} 删除失败。
114     */
115    default boolean remove(QueryCondition condition) {
116        return remove(query().where(condition));
117    }
118
119    /**
120     * <p>根据数据主键删除数据。
121     *
122     * @param id 数据主键
123     * @return {@code true} 删除成功,{@code false} 删除失败。
124     */
125    default boolean removeById(Serializable id) {
126        return SqlUtil.toBool(getMapper().deleteById(id));
127    }
128
129    /**
130     * <p>根据数据主键批量删除数据。
131     *
132     * @param ids 数据主键
133     * @return {@code true} 删除成功,{@code false} 删除失败。
134     */
135    default boolean removeByIds(Collection<? extends Serializable> ids) {
136        if (CollectionUtil.isEmpty(ids)) {
137            return false;
138        }
139        return SqlUtil.toBool(getMapper().deleteBatchByIds(ids));
140    }
141
142    // ===== 更新(改)操作 =====
143
144    /**
145     * <p>根据 {@link Map} 构建查询条件删除数据。
146     *
147     * @param query 查询条件
148     * @return {@code true} 删除成功,{@code false} 删除失败。
149     */
150    default boolean removeByMap(Map<String, Object> query) {
151        // 防止全表删除
152        if (query == null || query.isEmpty()) {
153            throw FlexExceptions.wrap("deleteByMap is not allow empty map.");
154        }
155        return remove(query().where(query));
156    }
157
158    /**
159     * <p>根据数据主键更新数据。
160     *
161     * @param entity 实体类对象
162     * @return {@code true} 更新成功,{@code false} 更新失败。
163     * @apiNote 若实体类属性数据为 {@code null},该属性不会新到数据库。
164     */
165    default boolean updateById(T entity) {
166        return updateById(entity, true);
167    }
168
169    /**
170     * 根据主键更新数据
171     *
172     * @param entity      实体对象
173     * @param ignoreNulls 是否忽略 null 值
174     * @return {@code true} 更新成功,{@code false} 更新失败。
175     */
176    default boolean updateById(T entity, boolean ignoreNulls) {
177        return SqlUtil.toBool(getMapper().update(entity, ignoreNulls));
178    }
179
180    /**
181     * <p>根据 {@link Map} 构建查询条件更新数据。
182     *
183     * @param entity 实体类对象
184     * @param query  查询条件
185     * @return {@code true} 更新成功,{@code false} 更新失败。
186     */
187    default boolean update(T entity, Map<String, Object> query) {
188        return update(entity, query().where(query));
189    }
190
191    /**
192     * <p>根据查询条件更新数据。
193     *
194     * @param entity 实体类对象
195     * @param query  查询条件
196     * @return {@code true} 更新成功,{@code false} 更新失败。
197     */
198    default boolean update(T entity, QueryWrapper query) {
199        return SqlUtil.toBool(getMapper().updateByQuery(entity, query));
200    }
201
202    /**
203     * <p>根据查询条件更新数据。
204     *
205     * @param entity    实体类对象
206     * @param condition 查询条件
207     * @return {@code true} 更新成功,{@code false} 更新失败。
208     */
209    default boolean update(T entity, QueryCondition condition) {
210        return update(entity, query().where(condition));
211    }
212
213    /**
214     * <p>根据数据主键批量更新数据
215     *
216     * @param entities 实体类对象集合
217     * @return boolean {@code true} 更新成功,{@code false} 更新失败。
218     */
219    default boolean updateBatch(Collection<T> entities) {
220        return updateBatch(entities, DEFAULT_BATCH_SIZE);
221    }
222
223    /**
224     * <p>根据数据主键批量更新数据
225     *
226     * @param entities  实体类对象集合
227     * @param batchSize 每批次更新数量
228     * @return {@code true} 更新成功,{@code false} 更新失败。
229     */
230    default boolean updateBatch(Collection<T> entities, int batchSize) {
231        return Db.tx(() -> {
232            final List<T> entityList = CollectionUtil.toList(entities);
233            // BaseMapper 是经过 Mybatis 动态代理处理过的对象,需要获取原始 BaseMapper 类型
234            final Class<BaseMapper<T>> usefulClass = (Class<BaseMapper<T>>) ClassUtil.getUsefulClass(getMapper().getClass());
235            return SqlUtil.toBool(Arrays.stream(Db.executeBatch(entityList.size(), batchSize, usefulClass, (mapper, index) -> mapper.update(entityList.get(index)))).sum());
236        });
237    }
238
239
240    // ===== 查询(查)操作 =====
241
242    /**
243     * <p>根据数据主键查询一条数据。
244     *
245     * @param id 数据主键
246     * @return 查询结果数据
247     */
248    default T getById(Serializable id) {
249        return getMapper().selectOneById(id);
250    }
251
252    /**
253     * <p>根据数据主键查询一条数据。
254     *
255     * @param id 数据主键
256     * @return 查询结果数据
257     * @apiNote 该方法会将查询结果封装为 {@link Optional} 类进行返回,方便链式操作。
258     */
259    default Optional<T> getByIdOpt(Serializable id) {
260        return Optional.ofNullable(getById(id));
261    }
262
263    /**
264     * <p>根据查询条件查询一条数据。
265     *
266     * @param query 查询条件
267     * @return 查询结果数据
268     */
269    default T getOne(QueryWrapper query) {
270        return getMapper().selectOneByQuery(query);
271    }
272
273    /**
274     * <p>根据查询条件查询一条数据。
275     *
276     * @param query 查询条件
277     * @return 查询结果数据
278     * @apiNote 该方法会将查询结果封装为 {@link Optional} 类进行返回,方便链式操作。
279     */
280    default Optional<T> getOneOpt(QueryWrapper query) {
281        return Optional.ofNullable(getOne(query));
282    }
283
284    /**
285     * <p>根据查询条件查询一条数据,并通过 asType 进行接收。
286     *
287     * @param query  查询条件
288     * @param asType 接收的数据类型
289     * @return 查询结果数据
290     */
291    default <R> R getOneAs(QueryWrapper query, Class<R> asType) {
292        return getMapper().selectOneByQueryAs(query, asType);
293    }
294
295    /**
296     * <p>根据查询条件查询一条数据。
297     *
298     * @param query  查询条件
299     * @param asType 接收的数据类型
300     * @return 查询结果数据
301     * @apiNote 该方法会将查询结果封装为 {@link Optional} 类进行返回,方便链式操作。
302     */
303    default <R> Optional<R> getOneAsOpt(QueryWrapper query, Class<R> asType) {
304        return Optional.ofNullable(getOneAs(query, asType));
305    }
306
307    /**
308     * <p>根据查询条件查询一条数据。
309     *
310     * @param condition 查询条件
311     * @return 查询结果数据
312     */
313    default T getOne(QueryCondition condition) {
314        return getOne(query().where(condition));
315    }
316
317    /**
318     * <p>根据查询条件查询一条数据。
319     *
320     * @param condition 查询条件
321     * @return 查询结果数据
322     * @apiNote 该方法会将查询结果封装为 {@link Optional} 类进行返回,方便链式操作。
323     */
324    default Optional<T> getOneOpt(QueryCondition condition) {
325        return Optional.ofNullable(getOne(condition));
326    }
327
328    /**
329     * <p>查询所有数据。
330     *
331     * @return 所有数据
332     */
333    default List<T> list() {
334        return list(query());
335    }
336
337    /**
338     * <p>根据查询条件查询数据集合。
339     *
340     * @param query 查询条件
341     * @return 数据集合
342     */
343    default List<T> list(QueryWrapper query) {
344        return getMapper().selectListByQuery(query);
345    }
346
347    /**
348     * <p>根据查询条件查询数据集合。
349     *
350     * @param condition 查询条件
351     * @return 数据集合
352     */
353    default List<T> list(QueryCondition condition) {
354        return list(query().where(condition));
355    }
356
357    /**
358     * <p>根据查询条件查询数据集合,并通过 asType 进行接收。
359     *
360     * @param query  查询条件
361     * @param asType 接收的数据类型
362     * @return 数据集合
363     */
364    default <R> List<R> listAs(QueryWrapper query, Class<R> asType) {
365        return getMapper().selectListByQueryAs(query, asType);
366    }
367
368    /**
369     * <p>根据数据主键查询数据集合。
370     *
371     * @param ids 数据主键
372     * @return 数据集合
373     */
374    default List<T> listByIds(Collection<? extends Serializable> ids) {
375        return getMapper().selectListByIds(ids);
376    }
377
378    /**
379     * <p>根据 {@link Map} 构建查询条件查询数据集合。
380     *
381     * @param query 查询条件
382     * @return 数据集合
383     */
384    default List<T> listByMap(Map<String, Object> query) {
385        return list(query().where(query));
386    }
387
388    // ===== 数量查询操作 =====
389
390    /**
391     * <p>根据查询条件判断数据是否存在。
392     *
393     * @param query 查询条件
394     * @return {@code true} 数据存在,{@code false} 数据不存在。
395     */
396    default boolean exists(QueryWrapper query) {
397        return SqlUtil.toBool(count(query));
398    }
399
400    /**
401     * <p>根据查询条件判断数据是否存在。
402     *
403     * @param condition 查询条件
404     * @return {@code true} 数据存在,{@code false} 数据不存在。
405     */
406    default boolean exists(QueryCondition condition) {
407        return SqlUtil.toBool(count(condition));
408    }
409
410    /**
411     * <p>查询所有数据数量。
412     *
413     * @return 所有数据数量
414     */
415    default long count() {
416        return count(query());
417    }
418
419    /**
420     * <p>根据查询条件查询数据数量。
421     *
422     * @param query 查询条件
423     * @return 数据数量
424     */
425    default long count(QueryWrapper query) {
426        return getMapper().selectCountByQuery(query);
427    }
428
429    /**
430     * <p>根据查询条件查询数据数量。
431     *
432     * @param condition 查询条件
433     * @return 数据数量
434     */
435    default long count(QueryCondition condition) {
436        return count(query().where(condition));
437    }
438
439    // ===== 分页查询操作 =====
440
441    /**
442     * <p>分页查询所有数据。
443     *
444     * @param page 分页对象
445     * @return 分页对象
446     */
447    default Page<T> page(Page<T> page) {
448        return page(page, query());
449    }
450
451    /**
452     * <p>根据查询条件分页查询数据。
453     *
454     * @param page  分页对象
455     * @param query 查询条件
456     * @return 分页对象
457     */
458    default Page<T> page(Page<T> page, QueryWrapper query) {
459        return pageAs(page, query, null);
460    }
461
462    /**
463     * <p>根据查询条件分页查询数据。
464     *
465     * @param page      分页对象
466     * @param condition 查询条件
467     * @return 分页对象
468     */
469    default Page<T> page(Page<T> page, QueryCondition condition) {
470        return page(page, query().where(condition));
471    }
472
473    /**
474     * <p>根据查询条件分页查询数据,并通过 asType 进行接收。
475     *
476     * @param page   分页对象
477     * @param query  查询条件
478     * @param asType 接收的数据类型
479     * @return 分页对象
480     */
481    default <R> Page<R> pageAs(Page<R> page, QueryWrapper query, Class<R> asType) {
482        return getMapper().paginateAs(page, query, asType);
483    }
484
485    default QueryWrapper query() {
486        return QueryWrapper.create();
487    }
488
489}