All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cloud.agileframework.data.common.dao.BaseDao Maven / Gradle / Ivy

There is a newer version: 2.2.0
Show newest version
package cloud.agileframework.data.common.dao;

import cloud.agileframework.common.DataException;
import cloud.agileframework.common.util.clazz.ClassUtil;
import cloud.agileframework.common.util.clazz.TypeReference;
import cloud.agileframework.common.util.object.ObjectUtil;
import cloud.agileframework.data.common.dictionary.DataExtendManager;
import com.alibaba.druid.DbType;
import com.alibaba.druid.sql.PagerUtils;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLOrderBy;
import com.alibaba.druid.sql.ast.SQLOrderingSpecification;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator;
import com.alibaba.druid.sql.ast.statement.SQLDeleteStatement;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLInsertStatement;
import com.alibaba.druid.sql.ast.statement.SQLSelectItem;
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.alibaba.druid.sql.ast.statement.SQLUpdateSetItem;
import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.springframework.data.annotation.Id;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.PagingAndSortingRepository;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author 佟盟 on 2017/11/15
 */
public interface BaseDao {

    Map, PagingAndSortingRepository> REPOSITORY_CACHE = new HashMap<>();

    DataExtendManager dictionaryManager();

    /**
     * 根据java类型获取对应的数据库表的JpaRepository对象
     *
     * @param tableClass 表对应的实体类型
     * @param         表对应的实体类型
     * @param        主键类型
     * @return 对应的数据库表的JpaRepository对象
     */
    @SuppressWarnings("unchecked")
     PagingAndSortingRepository getRepository(Class tableClass);

    /**
     * 保存
     *
     * @param o ORM对象
     */
    default  void save(T o) {
        if (o instanceof Class) {
            throw new DataException(new IllegalArgumentException("Parameter must be of type POJO"));
        }
        saveAndReturn(o);
    }

    /**
     * 批量保存
     *
     * @param list 表对应的实体类型的对象列表
     * @param   表对应的实体类型
     * @return 是否保存成功
     */
    @SuppressWarnings("unchecked")
    default  boolean save(Iterable list) {
        boolean isTrue = false;
        Iterator iterator = list.iterator();
        if (iterator.hasNext()) {
            T obj = iterator.next();
            Class tClass = (Class) obj.getClass();
            getRepository(tClass).saveAll(list);
            isTrue = true;

        }
        return isTrue;
    }

    /**
     * 获取数据库连接
     *
     * @return Connection
     */
    Connection getConnection() throws SQLException;

    default  boolean contains(T o) {
        if (o instanceof Class) {
            throw new DataException(new IllegalArgumentException("Parameter must be of type POJO"));
        }
        Class aClass = (Class) o.getClass();
        PagingAndSortingRepository r = getRepository(aClass);

        Object id = getId(o);
        return r.existsById(id);
    }

    /**
     * 保存或更新
     *
     * @param o   已经有的对象更新,不存在的保存
     * @param  泛型
     * @return 被跟踪对象
     */
    default  T saveOrUpdate(T o) {
        if (o instanceof Class) {
            throw new DataException(new IllegalArgumentException("Parameter must be of type POJO"));
        }
        Object id = getId(o);
        if (existsById(o.getClass(), id)) {
            deleteById(o.getClass(), id);
            return saveAndReturn(o, true);
        }
        return saveAndReturn(o);
    }


    /**
     * 保存并刷新
     *
     * @param o       表对应的实体类型的对象
     * @param isFlush 是否刷新
     * @param      泛型
     * @return 保存后的对象
     */
    @SuppressWarnings("unchecked")
    default  T saveAndReturn(T o, boolean isFlush) {
        if (o instanceof Class) {
            throw new DataException(new IllegalArgumentException("Parameter must be of type POJO"));
        }
        Class aClass = (Class) o.getClass();
        PagingAndSortingRepository r = getRepository(aClass);
        T newObject = r.save(o);
        dictionaryManager().cover(newObject);
        return newObject;
    }

    /**
     * 保存
     *
     * @param o   要保存的对象
     * @param  泛型
     * @return 保存后的对象
     */
    default  T saveAndReturn(T o) {
        if (o instanceof Class) {
            throw new DataException(new IllegalArgumentException("Parameter must be of type POJO"));
        }
        return saveAndReturn(o, Boolean.FALSE);
    }

    /**
     * 批量保存
     *
     * @param list 要保存的对象列表
     * @param   表对应的实体类型
     * @return 保存后的数据集
     */
    @SuppressWarnings("unchecked")
    default  List saveAndReturn(Iterable list) {
        Iterator iterator = list.iterator();
        if (iterator.hasNext()) {
            T obj = iterator.next();
            Class clazz = (Class) obj.getClass();
            return Lists.newArrayList(getRepository(clazz).saveAll(list));
        }
        return new ArrayList<>(0);
    }

    /**
     * 根据表实体类型与主键值,判断数据是否存在
     *
     * @param tableClass 表对应的实体类型
     * @param id         数据主键
     * @return 是否存在
     */
    default  boolean existsById(Class tableClass, Object id) {
        PagingAndSortingRepository r = getRepository(tableClass);
        return r.existsById(toIdType(tableClass, id));
    }

    /**
     * 更新或新增
     *
     * @param o   ORM对象,瞬态对象时不会被跟踪
     * @param  表对应的实体类型
     * @return 是否更新成功
     */
    default  boolean update(T o) {
        if (o instanceof Class) {
            throw new DataException(new IllegalArgumentException("Parameter must be of type POJO"));
        }
        Class aClass = (Class) o.getClass();
        Object id = getId(o);
        if (existsById(aClass, id)) {
            deleteById(aClass, id);
            saveAndReturn(o, true);
            return true;
        }

        return false;
    }

    /**
     * 更新或新增非空字段,空字段不进行更新
     *
     * @param o   表映射实体类型的对象
     * @param  表映射实体类型的对象
     * @return 返回更新后的数据
     */
    @SuppressWarnings("unchecked")
    default  T updateOfNotNull(T o) {
        if (o instanceof Class) {
            throw new DataException(new IllegalArgumentException("Parameter must be of type POJO"));
        }
        Class aClass = (Class) o.getClass();
        Object id = getId(o);
        if (existsById(aClass, id)) {
            T old = findOne(aClass, id);
            ObjectUtil.copyProperties(old, o, ObjectUtil.Compare.DIFF_TARGET_NULL);
            deleteById(aClass, id);
            return saveAndReturn(o, true);
        }

        return null;
    }

    /**
     * 根据提供的对象参数,作为例子,查询出结果并删除
     *
     * @param o 表实体对象
     */
    default  void delete(T o) {
        if (o instanceof Class) {
            throw new DataException(new IllegalArgumentException("Parameter must be of type POJO"));
        }
        Class aClass = (Class) o.getClass();
        getRepository(aClass).delete(o);
    }

    /**
     * 删除
     *
     * @param tableClass 查询的目标表对应实体类型,Entity
     * @param id         删除的主键标识
     * @param         查询的目标表对应实体类型
     */
    default  boolean deleteById(Class tableClass, Object id) {
        PagingAndSortingRepository repository = getRepository(tableClass);
        try {
            repository.deleteById(toIdType(tableClass, id));
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    /**
     * 删除全部(逐一删除)
     *
     * @param tableClass 查询的目标表对应实体类型,Entity
     * @param         查询的目标表对应实体类型
     */
    default  void deleteAll(Class tableClass) {
        getRepository(tableClass).deleteAll();
    }

    /**
     * 删除全部(一次性删除)
     *
     * @param tableClass 查询的目标表对应实体类型,Entity
     * @param         查询的目标表对应实体类型
     */
    default  void deleteAllInBatch(Class tableClass) {
        deleteAll(tableClass);
    }

    /**
     * 根据主键与实体类型,部分删除,删除对象集(一次性删除)
     *
     * @param tableClass 查询的目标表对应实体类型,Entity
     * @param         查询的目标表对应实体类型
     * @param ids        主键数组
     */
    default  void deleteInBatch(Class tableClass, Object[] ids) {
        deleteInBatch(tableClass, Sets.newHashSet(ids));
    }

    default  void deleteInBatch(Class tableClass, Iterable ids) {
        if (ids == null) {
            return;
        }
        PagingAndSortingRepository repository = getRepository(tableClass);
        Set set = Sets.newHashSet();
        for (Object id : ids) {
            set.add(toIdType(tableClass, id));
        }
        repository.deleteAllById(set);
    }

    /**
     * 根据表映射类型的对象集合,部分删除,删除对象集(一次性删除),无返回值
     *
     * @param list 需要删除的对象列表
     * @param   删除对象集合的对象类型,用于生成sql语句时与对应的表进行绑定
     */
    default  void deleteInBatch(Iterable list) {
        if (Iterables.isEmpty(list)) {
            return;
        }
        PagingAndSortingRepository repository = (PagingAndSortingRepository) getRepository(list.iterator().next().getClass());
        repository.deleteAll(list);
    }

    /**
     * 根据主键,查询单条
     *
     * @param clazz 查询的目标表对应实体类型,Entity
     * @param id    主键
     * @param    查询的目标表对应实体类型
     * @return clazz类型对象
     */
    default  T findOne(Class clazz, Object id) {
        PagingAndSortingRepository repository = getRepository(clazz);
        T newObject = repository.findById(id).orElse(null);
        dictionaryManager().cover(newObject);
        return newObject;
    }

    /**
     * 按照例子查询单条
     *
     * @param     查询的表的映射实体类型
     * @param object 查询一句的例子对象
     * @return 返回查询结果
     */
    @SuppressWarnings("unchecked")
    default  T findOne(T object) {
        if (object instanceof Class) {
            throw new DataException(new IllegalArgumentException("Parameter must be of type POJO"));
        }
        PagingAndSortingRepository repository = (PagingAndSortingRepository) getRepository(object.getClass());
        T newObject = repository.findById(getId(object)).orElse(null);
        dictionaryManager().cover(newObject);
        return newObject;
    }

    default Map findOne(String sql, Object... parameters) {
        return findBySQL(sql, parameters).stream().findFirst().orElse(null);
    }

    /**
     * 根据sql查询出单条数据,并映射成指定clazz类型
     *
     * @param         查询的表的映射实体类型
     * @param sql        sql
     * @param clazz      查询的目标表对应实体类型,Entity
     * @param parameters 对象数组格式的sql语句中的参数集合,使用?方式占位
     * @return 查询的结果
     */
    @SuppressWarnings("unchecked")
    default  T findOne(String sql, Class clazz, Object... parameters) {
        T newObject = findBySQL(sql, clazz, parameters).stream().findFirst().orElse(null);
        dictionaryManager().cover(newObject);
        return newObject;
    }

    /**
     * 按照例子查询多条
     *
     * @param     查询的表的映射实体类型
     * @param object 例子对象
     * @return 查询结果数据集合
     */
    default  List findAll(T object) {
        if (object instanceof Class) {
            throw new DataException(new IllegalArgumentException("Parameter must be of type POJO"));
        }
        List content = findBySQL(toSelectSql(object, Sort.unsorted(), DbType.mysql), (Class) object.getClass(), null);
        dictionaryManager().cover(content);
        return content;
    }

    default  List findAll(T object, Sort sort) {
        if (object instanceof Class) {
            throw new DataException(new IllegalArgumentException("Parameter must be of type POJO"));
        }
        List content = findBySQL(toSelectSql(object, sort, DbType.mysql), (Class) object.getClass(), null);
        dictionaryManager().cover(content);
        return content;
    }

    /**
     * 按照例子查询多条分页
     *
     * @param     查询的表的映射实体类型
     * @param object 例子对象
     * @param page   第几页
     * @param size   每页条数
     * @return 分页对象
     */
    default  Page page(T object, int page, int size) {
        if (object instanceof Class) {
            throw new DataException(new IllegalArgumentException("Parameter must be of type POJO"));
        }
        return page(object, page, size, Sort.unsorted());
    }

    /**
     * 按照例子对象查询多条分页
     *
     * @param     查询的表的映射实体类型
     * @param object 例子对象
     * @param page   第几页
     * @param size   每页条数
     * @param sort   排序对象
     * @return 分页信息
     */
    default  Page page(T object, int page, int size, Sort sort) {
        if (object instanceof Class) {
            throw new DataException(new IllegalArgumentException("Parameter must be of type POJO"));
        }
        return page(object, PageRequest.of(page, size, sort));
    }

     Page page(T object, PageRequest pageRequest);

    /**
     * 查询指定tableClass对应表的全表分页
     *
     * @param tableClass  查询的目标表对应实体类型,Entity
     * @param pageRequest 分页信息
     * @param          目标表对应实体类型
     * @return 内容为实体的Page类型分页结果
     */
    default  Page pageByClass(Class tableClass, PageRequest pageRequest) {
        Page pageInfo = getRepository(tableClass).findAll(pageRequest);
        dictionaryManager().cover(pageInfo.getContent());
        return pageInfo;
    }

    /**
     * 查询指定tableClass对应表的全表分页
     *
     * @param tableClass 查询的目标表对应实体类型,Entity
     * @param page       第几页
     * @param size       页大小
     * @param         目标表对应实体类型
     * @return 内容为实体的Page类型分页结果
     */
    default  Page pageByClass(Class tableClass, int page, int size) {
        return pageByClass(tableClass, PageRequest.of(page - 1, size));
    }

    default Page> pageBySQL(String sql, PageRequest pageable, Object... parameters) {
        return pageBySQL(sql, pageable, null, parameters);
    }

    /**
     * 分页查询
     *
     * @param sql        查询的sql语句
     * @param pageable   分页信息
     * @param parameters 对象数组类型的参数集合
     * @return Page类型的查询结果
     */
    @SuppressWarnings("unchecked")
     Page pageBySQL(String sql, PageRequest pageable, Class clazz, Object... parameters);

    default  Page pageBySQL(String sql, int page, int size, Class clazz, Object... parameters) {
        return pageBySQL(sql, PageRequest.of(page - 1, size, Sort.unsorted()), clazz, parameters);
    }

    default Page> pageBySQL(String sql, int page, int size, Object... parameters) {
        return pageBySQL(sql, PageRequest.of(page - 1, size, Sort.unsorted()), parameters);
    }

    /**
     * 指定tableClass对应表的全表查询
     *
     * @param tableClass 查询的目标表对应实体类型,Entity
     * @param         目标表对应实体类型
     * @return 内容为实体的List类型结果集
     */
    default  List findAllByClass(Class tableClass) {
        Iterable list = getRepository(tableClass).findAll();
        dictionaryManager().cover(list);
        return Lists.newArrayList(list);
    }

    /**
     * 指定tableClass对应表的全表查询,并排序
     *
     * @param tableClass 查询的目标表对应实体类型,Entity
     * @param sort       排序信息
     * @param         目标表对应实体类型
     * @return 内容为实体的List类型结果集
     */
    default  List findAllByClass(Class tableClass, Sort sort) {
        Iterable list = getRepository(tableClass).findAll(sort);
        dictionaryManager().cover(list);
        return Lists.newArrayList(list);
    }

     List findBySQL(String sql, Class clazz, Object... parameters);

    /**
     * 根据sql语句查询指定类型clazz列表
     *
     * @param sql         查询的sql语句,参数使用?占位
     * @param clazz       希望查询结果映射成的实体类型
     * @param          指定返回类型
     * @param firstResult 第一条数据
     * @param maxResults  最大条数据
     * @param parameters  对象数组类型的参数集合
     * @return 结果集
     */
    @SuppressWarnings("unchecked")
     List findBySQL(String sql, Class clazz, Integer firstResult, Integer maxResults, Object... parameters);

    /**
     * 根据sql语句查询列表,结果类型为List>
     *
     * @param sql        查询sql语句,参数使用{Map的key值}形式占位
     * @param parameters Map类型参数集合
     * @return 结果类型为List套Map的查询结果
     */
    List> findBySQL(String sql, Object... parameters);

    /**
     * sql形式写操作
     *
     * @param sql        查询的sql语句,参数使用?占位
     * @param parameters 对象数组形式参数集合
     * @return 影响条数
     */
    int updateBySQL(String sql, Object... parameters);

    /**
     * 根据实体类型tableClass与主键值集合ids,查询实体列表
     *
     * @param tableClass 查询的目标表对应实体类型,Entity
     * @param ids        主键值集合
     * @param         目标表对应实体类型
     * @return 返回查询出的实体列表
     */
    default  List findAllById(Class tableClass, Iterable ids) {
        Iterable list = getRepository(tableClass).findAllById(ids);
        dictionaryManager().cover(list);
        return Lists.newArrayList(list);
    }

    /**
     * 根据实体类型tableClass与主键值集合ids,查询实体列表
     *
     * @param tableClass 查询的目标表对应实体类型,Entity
     * @param ids        主键值集合,数组类型
     * @param         目标表对应实体类型
     * @return 返回查询出的实体列表
     */
    default  List findAllByArrayId(Class tableClass, Object... ids) {
        Iterable list = getRepository(tableClass).findAllById(Sets.newHashSet(ids));
        dictionaryManager().cover(list);
        return Lists.newArrayList(list);
    }

    /**
     * 查询指定tableClass对应表的总数
     *
     * @param tableClass 查询的目标表对应实体类型,Entity
     * @return 查询条数
     */
    default long count(Class tableClass) {
        return getRepository(tableClass).count();
    }


    /**
     * 批量插入
     *
     * @param list 要保存的数据集合
     */
    default  void batchInsert(List list) {
        batchInsert(list, 1000);
    }

    /**
     * 批量更新
     *
     * @param list 要更新的数据集合
     */
    default  void batchUpdate(List list) {
        batchUpdate(list, 1000);
    }

    /**
     * 批量删除
     *
     * @param list 要删除的数据集合
     */
    default  void batchDelete(List list) {
        batchDelete(list, 1000);
    }

    /**
     * 批量插入
     *
     * @param list      要保存的数据集合
     * @param batchSize 多少条执行一次插入
     */
    default  void batchInsert(List list, int batchSize) {
        save(list);
    }

    /**
     * 批量更新
     *
     * @param list      要更新的数据集合
     * @param batchSize 多少条执行一次更新
     */
    default  void batchUpdate(List list, int batchSize) {
        for (Object o : list) {
            update(o);
        }
    }

    /**
     * 批量删除
     *
     * @param list      要删除的数据集合
     * @param batchSize 多少条执行一次删除
     */
    default  void batchDelete(List list, int batchSize) {
        PagingAndSortingRepository re = getRepository((Class) list.iterator().next().getClass());
        re.deleteAll(list);
    }

    /**
     * 获取ORM中的主键字段
     *
     * @param clazz 查询的目标表对应实体类型,Entity
     * @return 主键属性
     */
    default Field getIdField(Class clazz) {
        Set> e = ClassUtil.getAllEntityAnnotation(clazz, Id.class);
        Member member = e.iterator().next().getMember();
        if (member instanceof Field) {
            return (Field) member;
        }
        String methodName = member.getName();
        if (methodName.startsWith("get")) {
            return ClassUtil.getField(clazz, methodName.substring(3));
        }
        throw new DataException(new NoSuchFieldException("没找到主键字段"));
    }

    default Object getId(Object o) {
        try {
            return getIdField(o.getClass()).get(o);
        } catch (IllegalAccessException e) {
            throw new DataException(e);
        }
    }

    default void setId(Object o, Object id) {
        try {
            final Field idField = getIdField(o.getClass());
            idField.setAccessible(true);
            idField.set(o, ObjectUtil.to(id, new TypeReference<>(idField.getType())));
        } catch (IllegalAccessException e) {
            throw new DataException(e);
        }
    }

    /**
     * 根据ORM类型取主键类型
     *
     * @param clazz 主键java类型
     * @return 主键java类型
     */
    default Class getIdType(Class clazz) {
        return getIdField(clazz).getType();
    }

    /**
     * 把id转换为clazz实体的主键类型
     *
     * @param clazz 实体类型
     * @param id    主键
     * @return 转换后的主键
     */
    default Object toIdType(Class clazz, Object id) {
        return ObjectUtil.to(id, new TypeReference<>(getIdType(clazz)));
    }

    /**
     * 对象转换为sql
     *
     * @param o      对象
     * @param dbType 数据库类型
     * @param     泛型
     * @return sql
     */
    default  String toSelectSql(T o, Sort sort, DbType dbType) {
        if (o instanceof Class || o == null) {
            throw new DataException(new IllegalArgumentException("Parameter must be of type POJO"));
        }

        TableWrapper tableWrapper = new TableWrapper<>(o, this::toColumnNames, this::toTableName);

        SQLSelectQueryBlock query = new SQLSelectQueryBlock();
        query.setFrom(new SQLExprTableSource(tableWrapper.getTableName()));
        tableWrapper.getColumns().stream().map(ColumnName::getName).forEach(e -> query.addSelectItem(new SQLSelectItem(SQLUtils.toSQLExpr(e))));
        tableWrapper.getColumns().stream().filter(e -> e.getValue().isPresent())
                .map(e -> e.sql(dbType))
                .reduce((a, b) -> new SQLBinaryOpExpr(a, SQLBinaryOperator.BooleanAnd, b)).ifPresent(query::setWhere);

        sort.stream().forEach(s -> {
            query.addOrderBy(new SQLOrderBy(SQLUtils.toSQLExpr(s.getProperty()), s.getDirection().isAscending() ? SQLOrderingSpecification.ASC : SQLOrderingSpecification.DESC));
        });

        return SQLUtils.toSQLString(query, dbType);
    }

    default  String toUpdateSql(T o, DbType dbType) {
        if (o instanceof Class || o == null) {
            throw new DataException(new IllegalArgumentException("Parameter must be of type POJO"));
        }

        TableWrapper tableWrapper = new TableWrapper<>(o, this::toColumnNames, this::toTableName);

        SQLUpdateStatement update = new SQLUpdateStatement();
        //from
        update.setTableSource(new SQLExprTableSource(tableWrapper.getTableName()));

        //where
        tableWrapper.getColumns().stream().filter(ColumnName::isPrimaryKey)
                .filter(e -> e.getValue().isPresent())
                .map(e -> e.sql(dbType))
                .reduce((a, b) -> new SQLBinaryOpExpr(a, SQLBinaryOperator.BooleanAnd, b)).ifPresent(update::setWhere);

        //item
        tableWrapper.getColumns().stream().filter(e -> !e.isPrimaryKey()).filter(e -> e.getValue().isPresent())
                .forEach(f -> {
                    SQLUpdateSetItem updateSetItem = new SQLUpdateSetItem();
                    updateSetItem.setColumn(SQLUtils.toSQLExpr(f.getName(), dbType));
                    updateSetItem.setValue(f.sqlValue());
                    update.addItem(updateSetItem);
                });
        return SQLUtils.toSQLString(update, dbType);
    }

    default  String toInsertSql(T o, DbType dbType) {
        if (o instanceof Class || o == null) {
            throw new DataException(new IllegalArgumentException("Parameter must be of type POJO"));
        }

        TableWrapper tableWrapper = new TableWrapper<>(o, this::toColumnNames, this::toTableName);

        SQLInsertStatement insert = new SQLInsertStatement();
        //from
        insert.setTableSource(new SQLExprTableSource(tableWrapper.getTableName()));

        SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause();
        //item
        tableWrapper.getColumns().stream().filter(e -> e.getValue().isPresent())
                .forEach(f -> {
                    insert.addColumn(SQLUtils.toSQLExpr(f.getName(), dbType));
                    values.addValue(f.sqlValue());
                });
        insert.addValueCause(values);

        return SQLUtils.toSQLString(insert, dbType);
    }

    default  String toInsertSql(List list, DbType dbType) {
        if (list == null || list.isEmpty()) {
            throw new DataException(new IllegalArgumentException("Parameter contains at least one element"));
        }

        List> rows = list.stream().map(c -> new TableWrapper<>(c, this::toColumnNames, this::toTableName)).collect(Collectors.toList());

        SQLInsertStatement insert = new SQLInsertStatement();

        rows.forEach(row -> {
            if (insert.getTableName() == null) {
                //from
                insert.setTableSource(new SQLExprTableSource(row.getTableName()));

                SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause();
                //item
                row.getColumns().stream().filter(e -> e.getValue().isPresent())
                        .forEach(f -> {
                            insert.addColumn(SQLUtils.toSQLExpr(f.getName(), dbType));
                            values.addValue(f.sqlValue());
                        });

                insert.addValueCause(values);
            }
        });

        return SQLUtils.toSQLString(insert, dbType);
    }

    default  String toDeleteSql(T o, DbType dbType) {
        if (o instanceof Class || o == null) {
            throw new DataException(new IllegalArgumentException("Parameter must be of type POJO"));
        }

        TableWrapper tableWrapper = new TableWrapper<>(o, this::toColumnNames, this::toTableName);

        SQLDeleteStatement delete = new SQLDeleteStatement();
        //from
        delete.setTableSource(new SQLExprTableSource(tableWrapper.getTableName()));

        //where
        tableWrapper.getColumns().stream()
                .filter(e -> e.getValue().isPresent())
                .map(e -> e.sql(dbType))
                .reduce((a, b) -> new SQLBinaryOpExpr(a, SQLBinaryOperator.BooleanAnd, b)).ifPresent(delete::setWhere);

        return SQLUtils.toSQLString(delete, dbType);
    }

     List toColumnNames(Class clazz);

     String toTableName(Class clazz);

    default  String toPageSQL(T o, PageRequest pageRequest, DbType dbType) {
        if (o instanceof Class) {
            throw new DataException(new IllegalArgumentException("Parameter must be of type POJO"));
        }
        String select = toSelectSql(o, pageRequest.getSort(), dbType);
        int pageSize = pageRequest.getPageSize();
        int pageNumber = pageRequest.getPageNumber();
        return PagerUtils.limit(select, DbType.mysql, pageNumber * pageSize, pageSize);
    }

    default  String toPageCountSQL(T o, PageRequest pageRequest, DbType dbType) {
        if (o instanceof Class) {
            throw new DataException(new IllegalArgumentException("Parameter must be of type POJO"));
        }
        String select = toSelectSql(o, pageRequest.getSort(), dbType);
        return PagerUtils.count(select, DbType.mysql);
    }

    /**
     * 将对象转换为字段与值的映射结构
     *
     * @param o   需要转换的对象
     * @param  泛型
     * @return 映射
     */
    default  Map> toColumnValueMapping(T o) {
        if (o instanceof Class || o == null) {
            throw new DataException(new IllegalArgumentException("Parameter must be of type POJO"));
        }

        Class tableClass = o.getClass();
        Set fields = toColumnNames(tableClass)
                .stream()
                .filter(c -> Arrays.stream(((AccessibleObject) (c.getMember())).getAnnotations()).noneMatch(annotation ->
                        "Transient".equals(annotation.annotationType().getSimpleName())))
                .collect(Collectors.toSet());
        Map> map = fields.stream().filter(f -> f.getMember() instanceof Field)
                .collect(Collectors.toMap(ColumnName::getName, f -> Optional.ofNullable(ObjectUtil.getFieldValue(o, (Field) f.getMember()))));

        Map> map2 = fields.stream().filter(f -> f.getMember() instanceof Method)
                .collect(Collectors.toMap(ColumnName::getName, f -> {
                    try {
                        Method method = (Method) f.getMember();
                        method.setAccessible(true);
                        return Optional.ofNullable(method.invoke(o));
                    } catch (IllegalAccessException | InvocationTargetException e) {
                        e.printStackTrace();
                    }
                    return Optional.empty();
                }));

        map.putAll(map2);
        return map;
    }

    class ColumnValueMapping {
        private ColumnName column;
        private String value;
    }
}