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 */
016
017package com.mybatisflex.core.activerecord;
018
019import com.mybatisflex.core.BaseMapper;
020import com.mybatisflex.core.mybatis.Mappers;
021import com.mybatisflex.core.table.TableInfo;
022import com.mybatisflex.core.table.TableInfoFactory;
023import com.mybatisflex.core.util.SqlUtil;
024
025import java.io.Serializable;
026import java.util.Optional;
027
028/**
029 * <p>使用 {@link BaseMapper} 进行 CRUD 操作的实体类的抽象接口。
030 *
031 * <p>使用接口是为了方便拓展,该接口提供了简单的根据 <b>主键</b> 操作数据的方法,
032 * 实现类可以进行其他方法的扩展。
033 *
034 * @param <T> 实体类类型
035 * @author 王帅
036 * @since 2023-07-23
037 */
038@SuppressWarnings({"unused", "unchecked"})
039public interface MapperModel<T> {
040
041    /**
042     * 获取实体类对应的 {@link BaseMapper} 接口。
043     *
044     * @return {@link BaseMapper} 接口
045     */
046    default BaseMapper<T> baseMapper() {
047        return Mappers.ofEntityClass((Class<T>) getClass());
048    }
049
050    /**
051     * <p>获取实体类主键数据。
052     *
053     * <p>可以拓展该方法提高效率,例如:
054     * <pre>{@code
055     * return new Object[]{id};
056     * }</pre>
057     *
058     * @return 主键数据数组
059     */
060    default Object pkValue() {
061        TableInfo tableInfo = TableInfoFactory.ofEntityClass(getClass());
062        return tableInfo.getPkValue(this);
063    }
064
065    /**
066     * 保存数据(自动忽略 {@code null} 值)。
067     *
068     * @return {@code true} 保存成功,{@code false} 保存失败
069     */
070    default boolean save() {
071        return save(true);
072    }
073
074    /**
075     * 保存数据(自动忽略 {@code null} 值),结果使用 {@link Optional}
076     * 返回源对象回调,保存成功返回 {@code Optional.of(this)},保存失败返回
077     * {@code Optional.empty()}。
078     *
079     * @return {@link Optional} 链式调用
080     */
081    default Optional<T> saveOpt() {
082        return saveOpt(true);
083    }
084
085    /**
086     * 保存数据,并设置是否忽略 {@code null} 值。
087     *
088     * @param ignoreNulls 是否忽略 {@code null} 值
089     * @return {@code true} 保存成功,{@code false} 保存失败
090     */
091    default boolean save(boolean ignoreNulls) {
092        return SqlUtil.toBool(baseMapper().insert((T) this, ignoreNulls));
093    }
094
095    /**
096     * 保存数据,并设置是否忽略 {@code null} 值,结果使用 {@link Optional}
097     * 返回源对象回调,保存成功返回 {@code Optional.of(this)},保存失败返回
098     * {@code Optional.empty()}。
099     *
100     * @param ignoreNulls 是否忽略 {@code null} 值
101     * @return {@link Optional} 链式调用
102     */
103    default Optional<T> saveOpt(boolean ignoreNulls) {
104        return save(ignoreNulls) ? Optional.of((T) this) : Optional.empty();
105    }
106
107    /**
108     * 保存或者更新数据,如果实体类主键没有值,则 <b>保存</b> 数据;如果实体类主键有值,则
109     * <b>更新</b> 数据(全部自动忽略 {@code null} 值)。
110     *
111     * @return {@code true} 保存或更新成功,{@code false} 保存或更新失败
112     */
113    default boolean saveOrUpdate() {
114        return saveOrUpdate(true);
115    }
116
117    /**
118     * 保存或者更新数据,如果实体类主键没有值,则 <b>保存</b> 数据;如果实体类主键有值,则
119     * <b>更新</b> 数据(全部自动忽略 {@code null} 值),结果使用 {@link Optional}
120     * 返回源对象回调,保存或更新成功返回 {@code Optional.of(this)},保存或更新失败返回
121     * {@code Optional.empty()}。
122     *
123     * @return {@link Optional} 链式调用
124     */
125    default Optional<T> saveOrUpdateOpt() {
126        return saveOrUpdateOpt(true);
127    }
128
129    /**
130     * 保存或者更新数据,如果实体类主键没有值,则 <b>保存</b> 数据;如果实体类主键有值,则
131     * <b>更新</b> 数据,并设置是否忽略 {@code null} 值。
132     *
133     * @param ignoreNulls 是否忽略 {@code null} 值
134     * @return {@code true} 保存或更新成功,{@code false} 保存或更新失败
135     */
136    default boolean saveOrUpdate(boolean ignoreNulls) {
137        return SqlUtil.toBool(baseMapper().insertOrUpdate((T) this, ignoreNulls));
138    }
139
140    /**
141     * 保存或者更新数据,如果实体类主键没有值,则 <b>保存</b> 数据;如果实体类主键有值,则
142     * <b>更新</b> 数据,并设置是否忽略 {@code null} 值,结果使用 {@link Optional}
143     * 返回源对象回调,保存或更新成功返回 {@code Optional.of(this)},保存或更新失败返回
144     * {@code Optional.empty()}。
145     *
146     * @param ignoreNulls 是否忽略 {@code null} 值
147     * @return {@link Optional} 链式调用
148     */
149    default Optional<T> saveOrUpdateOpt(boolean ignoreNulls) {
150        return saveOrUpdate(ignoreNulls) ? Optional.of((T) this) : Optional.empty();
151    }
152
153    /**
154     * 根据实体类主键删除数据。
155     *
156     * @return {@code true} 删除成功,{@code false} 删除失败
157     */
158    default boolean removeById() {
159        return SqlUtil.toBool(baseMapper().deleteById((Serializable) pkValue()));
160    }
161
162    /**
163     * 根据实体类主键删除数据,结果使用 {@link Optional} 返回源对象回调,删除成功返回
164     * {@code Optional.of(this)},删除失败返回 {@code Optional.empty()}。
165     *
166     * @return {@link Optional} 链式调用
167     */
168    default Optional<T> removeByIdOpt() {
169        return removeById() ? Optional.of((T) this) : Optional.empty();
170    }
171
172    /**
173     * 根据实体类主键更新数据(自动忽略 {@code null} 值)。
174     *
175     * @return {@code true} 更新成功,{@code false} 更新失败
176     */
177    default boolean updateById() {
178        return updateById(true);
179    }
180
181    /**
182     * 根据实体类主键更新数据(自动忽略 {@code null} 值),结果使用 {@link Optional}
183     * 返回源对象回调,更新成功返回 {@code Optional.of(this)},更新失败返回
184     * {@code Optional.empty()}。
185     *
186     * @return {@link Optional} 链式调用
187     */
188    default Optional<T> updateByIdOpt() {
189        return updateByIdOpt(true);
190    }
191
192    /**
193     * 根据实体类主键更新数据,并设置是否忽略 {@code null} 值。
194     *
195     * @param ignoreNulls 是否忽略 {@code null} 值
196     * @return {@code true} 更新成功,{@code false} 更新失败
197     */
198    default boolean updateById(boolean ignoreNulls) {
199        return SqlUtil.toBool(baseMapper().update((T) this, ignoreNulls));
200    }
201
202    /**
203     * 根据实体类主键更新数据,并设置是否忽略 {@code null} 值,结果使用 {@link Optional}
204     * 返回源对象回调,更新成功返回 {@code Optional.of(this)},更新失败返回
205     * {@code Optional.empty()}。
206     *
207     * @param ignoreNulls 是否忽略 {@code null} 值
208     * @return {@link Optional} 链式调用
209     */
210    default Optional<T> updateByIdOpt(boolean ignoreNulls) {
211        return updateById(ignoreNulls) ? Optional.of((T) this) : Optional.empty();
212    }
213
214    /**
215     * 根据实体类主键获取一条数据。
216     *
217     * @return 数据
218     */
219    default T oneById() {
220        return baseMapper().selectOneById((Serializable) pkValue());
221    }
222
223    /**
224     * 根据实体类主键获取一条数据,并封装为 {@link Optional} 返回。
225     *
226     * @return 数据
227     */
228    default Optional<T> oneByIdOpt() {
229        return Optional.ofNullable(oneById());
230    }
231
232}