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 */
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(T entityObject) {
052        Class<T> entityClass = (Class<T>) ClassUtil.getUsefulClass(entityObject.getClass());
053        BaseMapper<T> baseMapper = Mappers.ofEntityClass(entityClass);
054        return new UpdateChain<>(baseMapper, entityObject);
055    }
056
057
058    public UpdateChain(BaseMapper<T> baseMapper) {
059        this.baseMapper = baseMapper;
060        this.entity = createEntity(ClassUtil.getUsefulClass(baseMapper.getClass()));
061        this.entityWrapper = (UpdateWrapper) entity;
062    }
063
064
065    public UpdateChain(BaseMapper<T> baseMapper, T entityObject) {
066        this.baseMapper = baseMapper;
067        entityObject = (T) UpdateWrapper.of(entityObject);
068        this.entity = entityObject;
069        this.entityWrapper = (UpdateWrapper) entityObject;
070    }
071
072    private T createEntity(Class<?> mapperClass) {
073        Type type = mapperClass.getGenericInterfaces()[0];
074        if (type instanceof ParameterizedType) {
075            Class<T> modelClass = (Class<T>) ((ParameterizedType) type).getActualTypeArguments()[0];
076            return UpdateEntity.of(modelClass);
077        }
078        throw FlexExceptions.wrap("Can not get entity class from mapper: " + mapperClass.getName());
079    }
080
081    public static <E> UpdateChain<E> create(BaseMapper<E> baseMapper) {
082        return new UpdateChain<>(baseMapper);
083    }
084
085    @Override
086    public UpdateChain<T> set(String property, Object value, boolean isEffective) {
087        entityWrapper.set(property, value, isEffective);
088        return this;
089    }
090
091    @Override
092    public UpdateChain<T> set(QueryColumn queryColumn, Object value, boolean isEffective) {
093        entityWrapper.set(queryColumn, value, isEffective);
094        return this;
095    }
096
097    @Override
098    public <L> UpdateChain<T> set(LambdaGetter<L> getter, Object value, boolean isEffective) {
099        entityWrapper.set(getter, value, isEffective);
100        return this;
101    }
102
103
104    @Override
105    public UpdateChain<T> setRaw(String property, Object value, boolean isEffective) {
106        entityWrapper.setRaw(property, value, isEffective);
107        return this;
108    }
109
110    @Override
111    public UpdateChain<T> setRaw(QueryColumn queryColumn, Object value, boolean isEffective) {
112        entityWrapper.setRaw(queryColumn, value, isEffective);
113        return this;
114    }
115
116    @Override
117    public <L> UpdateChain<T> setRaw(LambdaGetter<L> getter, Object value, boolean isEffective) {
118        entityWrapper.setRaw(getter, value, isEffective);
119        return this;
120    }
121
122
123    public boolean remove() {
124        return SqlUtil.toBool(baseMapper.deleteByQuery(this));
125    }
126
127
128    public boolean update() {
129        return SqlUtil.toBool(baseMapper.updateByQuery(entity, this));
130    }
131
132
133    @Override
134    public String toSQL() {
135        TableInfo tableInfo = TableInfoFactory.ofMapperClass(baseMapper.getClass());
136        CPI.setFromIfNecessary(this, tableInfo.getSchema(), tableInfo.getTableName());
137        String sql = DialectFactory.getDialect().forUpdateEntityByQuery(tableInfo, entity, true, this);
138
139        Object[] values = tableInfo.buildUpdateSqlArgs(entity, true, true);
140        values = ArrayUtil.concat(values, CPI.getValueArray(this));
141
142        return SqlUtil.replaceSqlParams(sql, values);
143    }
144
145}