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.update;
018
019import com.mybatisflex.core.BaseMapper;
020import com.mybatisflex.core.dialect.DialectFactory;
021import com.mybatisflex.core.exception.FlexExceptions;
022import com.mybatisflex.core.mybatis.Mappers;
023import com.mybatisflex.core.query.CPI;
024import com.mybatisflex.core.query.QueryColumn;
025import com.mybatisflex.core.query.QueryWrapperAdapter;
026import com.mybatisflex.core.table.TableInfo;
027import com.mybatisflex.core.table.TableInfoFactory;
028import com.mybatisflex.core.util.*;
029
030import java.lang.reflect.ParameterizedType;
031import java.lang.reflect.Type;
032
033/**
034 * 用于数据更新、删除的链式操作
035 *
036 * @author michale
037 * @since 2023-07-25
038 */
039@SuppressWarnings("unchecked")
040public class UpdateChain<T> extends QueryWrapperAdapter<UpdateChain<T>> implements PropertySetter<UpdateChain<T>> {
041
042    private final BaseMapper<T> baseMapper;
043    private final T entity;
044    private final UpdateWrapper entityWrapper;
045
046    public static <T> UpdateChain<T> of(Class<T> entityClass) {
047        BaseMapper<T> baseMapper = Mappers.ofEntityClass(entityClass);
048        return new UpdateChain<>(baseMapper);
049    }
050
051    public static <T> UpdateChain<T> of(BaseMapper<T> baseMapper) {
052        return new UpdateChain<>(baseMapper);
053    }
054
055    public static <T> UpdateChain<T> of(T entityObject) {
056        Class<T> entityClass = (Class<T>) ClassUtil.getUsefulClass(entityObject.getClass());
057        BaseMapper<T> baseMapper = Mappers.ofEntityClass(entityClass);
058        return new UpdateChain<>(baseMapper, entityObject);
059    }
060
061    public static <T> UpdateChain<T> of(T entityObject, BaseMapper<T> baseMapper) {
062        return new UpdateChain<>(baseMapper, entityObject);
063    }
064
065
066    public UpdateChain(BaseMapper<T> baseMapper) {
067        this.baseMapper = baseMapper;
068        this.entity = createEntity(ClassUtil.getUsefulClass(baseMapper.getClass()));
069        this.entityWrapper = (UpdateWrapper) entity;
070    }
071
072
073    public UpdateChain(BaseMapper<T> baseMapper, T entityObject) {
074        this.baseMapper = baseMapper;
075        entityObject = (T) UpdateWrapper.of(entityObject);
076        this.entity = entityObject;
077        this.entityWrapper = (UpdateWrapper) entityObject;
078    }
079
080    private T createEntity(Class<?> mapperClass) {
081        Type type = mapperClass.getGenericInterfaces()[0];
082        if (type instanceof ParameterizedType) {
083            Class<T> modelClass = (Class<T>) ((ParameterizedType) type).getActualTypeArguments()[0];
084            return UpdateEntity.of(modelClass);
085        }
086        throw FlexExceptions.wrap("Can not get entity class from mapper: " + mapperClass.getName());
087    }
088
089    public static <E> UpdateChain<E> create(BaseMapper<E> baseMapper) {
090        return new UpdateChain<>(baseMapper);
091    }
092
093    @Override
094    public UpdateChain<T> set(String property, Object value, boolean isEffective) {
095        entityWrapper.set(property, value, isEffective);
096        return this;
097    }
098
099    @Override
100    public UpdateChain<T> set(QueryColumn queryColumn, Object value, boolean isEffective) {
101        entityWrapper.set(queryColumn, value, isEffective);
102        return this;
103    }
104
105    @Override
106    public <L> UpdateChain<T> set(LambdaGetter<L> getter, Object value, boolean isEffective) {
107        entityWrapper.set(getter, value, isEffective);
108        return this;
109    }
110
111
112    @Override
113    public UpdateChain<T> setRaw(String property, Object value, boolean isEffective) {
114        entityWrapper.setRaw(property, value, isEffective);
115        return this;
116    }
117
118    @Override
119    public UpdateChain<T> setRaw(QueryColumn queryColumn, Object value, boolean isEffective) {
120        entityWrapper.setRaw(queryColumn, value, isEffective);
121        return this;
122    }
123
124    @Override
125    public <L> UpdateChain<T> setRaw(LambdaGetter<L> getter, Object value, boolean isEffective) {
126        entityWrapper.setRaw(getter, value, isEffective);
127        return this;
128    }
129
130
131    public boolean remove() {
132        return SqlUtil.toBool(baseMapper.deleteByQuery(this));
133    }
134
135
136    public boolean update() {
137        return SqlUtil.toBool(baseMapper.updateByQuery(entity, this));
138    }
139
140
141    @Override
142    public String toSQL() {
143        TableInfo tableInfo = TableInfoFactory.ofMapperClass(baseMapper.getClass());
144        CPI.setFromIfNecessary(this, tableInfo.getSchema(), tableInfo.getTableName());
145        String sql = DialectFactory.getDialect().forUpdateEntityByQuery(tableInfo, entity, true, this);
146
147        Object[] values = tableInfo.buildUpdateSqlArgs(entity, true, true);
148        values = ArrayUtil.concat(values, CPI.getValueArray(this));
149
150        return SqlUtil.replaceSqlParams(sql, values);
151    }
152
153}