package com.yanzuoguang.dao.impl;

import com.yanzuoguang.dao.DaoConst;
import com.yanzuoguang.dao.QueryPara;
import com.yanzuoguang.dao.TableAnnotation;
import com.yanzuoguang.db.DbExecute;
import com.yanzuoguang.db.impl.DbRow;
import com.yanzuoguang.util.YzgError;
import com.yanzuoguang.util.base.ObjectHelper;
import com.yanzuoguang.util.cache.MemoryCache;
import com.yanzuoguang.util.helper.ArrayHelper;
import com.yanzuoguang.util.helper.StringFormatHandle;
import com.yanzuoguang.util.helper.StringHelper;
import com.yanzuoguang.util.vo.*;

import javax.annotation.Resource;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * SQL语句基本操作类,包括SQL语句的解析,参数的组装,查询缓存的处理
 *
 * @author 颜佐光
 */
public abstract class BaseDaoSql {

    /**
     * SQL语句支持的最大长度
     */
    public static int MAX_LEVEL = 10;
    /**
     * 缓存的表结构和SQL语句
     */
    protected final static MemoryCache<TableSqlCache> cache = new MemoryCache<>();

    /**
     * 定义列表记录缓存对象
     */
    protected MemoryCache cacheList = new MemoryCache(0);

    /**
     * 当前Dao的表结构SQL语句信息
     */
    protected TableSqlCache table = null;

    /**
     * 数据库执行类
     */
    private DbExecute db;

    /**
     * 构造函数
     */
    public BaseDaoSql() {
        this.initTable();
        this.init();
    }

    /**
     * 自己构造
     *
     * @param db
     * @param table
     */
    public BaseDaoSql(DbExecute db, TableSqlCache table) {
        this.db = db;
        this.table = table;
        this.init();
    }

    @Resource
    public void setDb(DbExecute db) {
        this.db = db;
    }

    /**
     * 获取数据库执行类
     *
     * @return
     */
    protected DbExecute getDb() {
        return db;
    }

    public TableSqlCache getTable() {
        return table;
    }

    /**
     * 初始化当前类对应的SQL语句对象
     */
    private void initTable() {
        String cls = this.getClass().getName();
        // 外检测,防止锁影响性能
        this.table = cache.get(cls);
        // 判断是否已经取到对象
        if (this.table == null) {
            this.table = new TableSqlCache();
            cache.put(cls, this.table);
        }
    }

    /**
     * 注册SQL语句
     */
    protected abstract void init();

    /**
     * 注册表结构,会根据实体以及表名自动创建Create、update、remove、Load等SQL语句
     *
     * @param clsModel 操作的实体,主键放在第一位,其他字段放到后面;需要注意的是必需和表结构对应起来,会有隐性BUG,比如说在实体中增加了字段,会导致增加修改失败
     * @return 当前的表结构
     */
    protected TableSqlCache register(Class<?> clsModel) {
        TableAnnotation annotation = clsModel.getAnnotation(TableAnnotation.class);
        if (annotation == null) {
            throw YzgError.getRuntimeException("001");
        }
        return this.register(annotation.value(), clsModel);
    }

    /**
     * 注册表结构,会根据实体以及表名自动创建Create、update、remove、Load等SQL语句
     *
     * @param tableName 表名,数据库中的表名
     * @param clsModel  操作的实体,主键放在第一位,其他字段放到后面;需要注意的是必需和表结构对应起来,会有隐性BUG,比如说在实体中增加了字段,会导致增加修改失败
     * @return 当前的表结构
     */
    protected TableSqlCache register(String tableName, Class<?> clsModel) {
        // 生成表结构
        TableStruct table = new TableStruct(tableName, clsModel);
        // 根据表结构生成基本的SQL语句
        table.init(this.table);
        return this.table;
    }

    /**
     * 获取SQL语句
     *
     * @param name 需要获取的SQL语句的名称
     * @return 对应名称的SQL语句
     */
    public SqlData getSql(String name) {
        return getSql(name, true);
    }

    /**
     * 获取SQL语句
     *
     * @param name 需要获取的SQL语句的名称
     * @return 对应名称的SQL语句
     */
    public SqlData getSql(String name, boolean isThrow) {
        if (this.table == null) {
            throw YzgError.getRuntimeException("002", this.getClass().getName());
        }
        SqlData sql = this.table.getNameCache().get(name);
        if (isThrow && sql == null) {
            throw YzgError.getRuntimeException("003", this.getClass().getName(), name);
        }
        return sql;
    }

    /**
     * 当更新数据时
     *
     * @param model 更新时的数据
     */
    protected void onUpdateSql(Object model) {
        // 删除所有查询的缓存
        cacheList.clear();
    }

    /**
     * 执行更新语句
     *
     * @param sqlData 需要执行的语句
     * @param model   执行的实体
     * @return 影响的行数
     */
    protected int updateSql(SqlData sqlData, Object model) {
        List<Object> paras = new ArrayList<Object>();
        String sql = this.getQueryPara(paras, sqlData, model);
        int ret = this.getDb().update(this.getClass(), sqlData.getName(), sql, paras.toArray());
        this.onUpdateSql(model);
        return ret;
    }

    /**
     * 更新SQL语句
     *
     * @param sqlName 参数对应的名称
     * @param model   参数对应的实体
     * @return 修改成功,返回修改条数,否则为0
     */
    public int updateSql(String sqlName, Object model) {
        SqlData sqlData = this.getSql(sqlName);
        int ret = updateSql(sqlData, model);
        return ret;
    }

    /**
     * 是否需要复制一个新的
     *
     * @param sqlData
     * @param queryPara
     * @param copy
     */
    protected SqlData getSqlQueryPara(SqlData sqlData, QueryPara queryPara, boolean copy) {
        SqlData copyTo = sqlData;
        if (queryPara != null && queryPara.isLoadRemove()) {
            if (copyTo.getField(DaoConst.REMOVE_FLAG_INPUT) != null) {
                if (copy) {
                    copyTo = sqlData.copy();
                }
                copyTo.removeField(DaoConst.REMOVE_FLAG_INPUT);
            }
        }
        return copyTo;
    }

    /**
     * 根据SQL语句信息查询数据
     *
     * @param sqlData SQL语句信息
     * @param model   前台参数
     * @return 查询的结果
     */
    protected List<MapRow> queryData(SqlData sqlData, Object model) {
        return this.queryData(MapRow.class, sqlData, model);
    }

    /**
     * 根据SQL语句信息查询数据
     *
     * @param cls     数据结果类型
     * @param sqlData SQL语句信息
     * @param model   前台参数
     * @param <T>     返回数据类型
     * @return 查询的结果
     */
    protected <T extends Object> List<T> queryData(Class<T> cls, SqlData sqlData, Object model) {
        List<Object> paras = new ArrayList<Object>();
        String sql = this.getQueryPara(paras, sqlData, model);
        List<T> list = this.queryWithCache(cls, sqlData.getName(), sql, paras.toArray());
        return list;
    }

    /**
     * 查询不分页数据
     *
     * @param cls     数据结果类型
     * @param sqlData SQL数据
     * @param model   前台参数
     * @param <T>     返回数据类型
     */
    protected <T extends Object> void queryData(Class<T> cls, DbRow<T> handle, SqlData sqlData, Object model) {
        List<Object> paras = new ArrayList<>();
        String sql = this.getQueryPara(paras, sqlData, model);
        // 查询数据
        this.getDb().query(this.getClass(), cls, handle, sqlData.getName(), sql, paras.toArray());
    }

    /**
     * 根据SQL名称获取第一个单元格
     *
     * @param sqlName 需要执行的SQL语句的名称
     * @param model   需要转化的实体
     * @return 处理参数
     */
    public Object queryCell(String sqlName, Object model) {
        return this.queryCell(this.getSql(sqlName), model);
    }


    /**
     * 根据SQL语句信息查询第一个单元格
     *
     * @param sqlData SQL语句信息
     * @param model   前台参数
     * @return 查询的结果
     */
    protected Object queryCell(SqlData sqlData, Object model) {
        return this.queryCell(sqlData, model, null);
    }

    /**
     * 根据SQL语句信息查询第一个单元格
     *
     * @param sqlData SQL语句信息
     * @param model   前台参数
     * @return 查询的结果
     */
    protected Object queryCell(SqlData sqlData, Object model, QueryPara queryPara) {
        sqlData = getSqlQueryPara(sqlData, queryPara, true);

        List<Object> paras = new ArrayList<>();
        String sql = this.getQueryPara(paras, sqlData, model);
        Object cell = this.queryCellWithCache(sqlData.getName(), sql, paras.toArray());
        return cell;
    }


    /**
     * 查询不分页数据
     *
     * @param sqlName SQL语句名称
     * @param model   前台参数
     * @return 查询的结果
     */
    public List<MapRow> query(String sqlName, Object model) {
        return this.query(MapRow.class, sqlName, model);
    }

    /**
     * 查询不分页数据
     *
     * @param cls     数据结果类型
     * @param sqlName SQL语句名称
     * @param model   前台参数
     * @param <T>     返回数据类型
     * @return 查询的结果
     */
    public <T extends Object> List<T> query(Class<T> cls, String sqlName, Object model) {
        return this.query(cls, sqlName, model, null);
    }

    /**
     * 查询不分页数据
     *
     * @param cls     数据结果类型
     * @param sqlName SQL语句名称
     * @param model   前台参数
     * @param <T>     返回数据类型
     * @return 查询的结果
     */
    public <T extends Object> List<T> query(Class<T> cls, String sqlName, Object model, QueryPara queryPara) {
        SqlData sqlData = this.getSql(sqlName);

        sqlData = getSqlQueryPara(sqlData, queryPara, true);

        return queryData(cls, sqlData, model);
    }

    /**
     * 查询不分页数据
     *
     * @param cls     数据结果类型
     * @param handle  需要处理的数据
     * @param sqlName SQL语句名称
     * @param model   前台参数
     * @return 查询的结果
     */
    public <T extends Object> void query(Class<T> cls, DbRow<T> handle, String sqlName, Object model) {
        this.query(cls, handle, sqlName, model, null);
    }

    /**
     * 查询不分页数据
     *
     * @param cls     数据结果类型
     * @param handle  需要处理的数据
     * @param sqlName SQL语句名称
     * @param model   前台参数
     * @return 查询的结果
     */
    public <T extends Object> void query(Class<T> cls, DbRow<T> handle, String sqlName, Object model, QueryPara queryPara) {
        SqlData sqlData = this.getSql(sqlName);
        // 获取查询参数处理后的SQL语句
        sqlData = getSqlQueryPara(sqlData, queryPara, true);

        queryData(cls, handle, sqlData, model);
    }


    /**
     * 查询第一条数据
     *
     * @param sqlName SQL语句名称
     * @param model   前台参数
     * @return 查询的结果
     */
    public MapRow queryFirst(String sqlName, Object model) {
        return this.queryFirst(MapRow.class, sqlName, model);
    }

    /**
     * 查询第一条数据
     *
     * @param cls     数据结果类型
     * @param sqlName SQL语句名称
     * @param model   前台参数
     * @param <T>     返回数据类型
     * @return 查询的结果
     */
    public <T extends Object> T queryFirst(Class<T> cls, String sqlName, Object model) {
        return this.queryFirst(cls, sqlName, model, null);
    }

    /**
     * 查询第一条数据
     *
     * @param cls     数据结果类型
     * @param sqlName SQL语句名称
     * @param model   前台参数
     * @param <T>     返回数据类型
     * @return 查询的结果
     */
    public <T extends Object> T queryFirst(Class<T> cls, String sqlName, Object model, QueryPara queryPara) {
        PageSizeReq pageSize = new PageSizeReqVo();
        pageSize.setPageIndex(1);
        pageSize.setPageSize(1);
        List<T> list = this.queryPageData(cls, pageSize, sqlName, model, queryPara);
        T retVal = list.size() > 0 ? list.get(0) : null;
        return retVal;
    }

    /**
     * 查询分页数据,仅仅只是查询分页中的数据,不查询分页信息。如:包含的总数据数量
     *
     * @param pageSize 分页参数
     * @param sqlName  SQL语句名称
     * @param model    前台参数
     * @return 查询的结果
     */
    public List<MapRow> queryPageData(PageSizeReqVo pageSize, String sqlName, Object model) {
        return this.queryPageData(MapRow.class, pageSize, sqlName, model);
    }


    /**
     * 查询分页数据,仅仅只是查询分页中的数据,不查询分页信息。如:包含的总数据数量
     *
     * @param cls      数据结果类型
     * @param pageSize 分页参数
     * @param sqlName  SQL语句名称
     * @param model    前台参数
     * @param <T>      返回数据类型
     * @return 查询的结果
     */
    public <T extends Object> List<T> queryPageData(Class<T> cls, PageSizeReq pageSize, String sqlName, Object model) {
        return this.queryPageData(cls, pageSize, sqlName, model, null);
    }

    /**
     * 查询分页数据,仅仅只是查询分页中的数据,不查询分页信息。如:包含的总数据数量
     *
     * @param cls      数据结果类型
     * @param pageSize 分页参数
     * @param sqlName  SQL语句名称
     * @param model    前台参数
     * @param <T>      返回数据类型
     * @return 查询的结果
     */
    public <T extends Object> List<T> queryPageData(Class<T> cls, PageSizeReq pageSize, String sqlName, Object model, QueryPara queryPara) {
        SqlData from = this.getSql(sqlName);
        // 对SQL语句进行分页处理
        SqlData to = from.copy();
        // 获取sql语句
        to = getSqlQueryPara(to, queryPara, false);

        to.setSql(from.getSql());
        to.addCode("{LIMIT}", " LIMIT " + pageSize.getPageStart() + "," + pageSize.getPageSize());
        return queryData(cls, to, model);
    }

    /**
     * 查询分页数据,仅仅只是查询分页中的数据,不查询分页信息。如:包含的总数据数量
     *
     * @param pageSize 分页参数
     * @param sqlName  SQL语句名称
     * @param model    前台参数
     * @return 查询的结果
     */
    public PageSizeData<MapRow> queryPage(PageSizeReqVo pageSize, String sqlName, Object model) {
        return this.queryPage(MapRow.class, pageSize, sqlName, model);
    }

    /**
     * 查询分页数据,仅仅只是查询分页中的数据。如:包含的总数据数量
     *
     * @param cls      数据结果类型
     * @param pageSize 分页参数
     * @param sqlName  SQL语句名称
     * @param model    前台参数
     * @param <T>      返回数据类型
     * @return 查询的结果
     */
    public <T extends Object> PageSizeData<T> queryPage(Class<T> cls, PageSizeReqVo pageSize, String sqlName, Object model) {
        return queryPage(cls, pageSize, sqlName, model, null);
    }

    /**
     * 查询分页数据,仅仅只是查询分页中的数据。如:包含的总数据数量
     *
     * @param cls      数据结果类型
     * @param pageSize 分页参数
     * @param sqlName  SQL语句名称
     * @param model    前台参数
     * @param <T>      返回数据类型
     * @return 查询的结果
     */
    public <T extends Object> PageSizeData<T> queryPage(Class<T> cls, PageSizeReqVo pageSize, String sqlName, Object model, QueryPara queryPara) {

        PageSizeData<T> data = new PageSizeData<T>();
        data.setPageIndex(pageSize.getPageIndex());
        data.setPageSize(pageSize.getPageSize());

        // 设置基本参数值
        {
            // 获取需要执行的SQL语句
            SqlData from = this.getSql(sqlName);
            // 对SQL语句进行分页处理
            SqlData to = from.copy();
            to = getSqlQueryPara(to, queryPara, false);
            to.addCode("{LIMIT}", " LIMIT " + pageSize.getPageStart() + "," + pageSize.getPageSize());

            // 按照分页查询数据
            List<Object> baseParas = new ArrayList<Object>();
            String sql = this.getQueryPara(baseParas, to, model);
            // 查询实体数据
            List<T> list = this.queryWithCache(cls, sqlName, sql, baseParas.toArray());
            data.setList(list);
        }

        // 获取分页查询的SQL语句
        {
            SqlData fromPageSize = getSql(sqlName + TableSqlCache.PAGE_SIZE_TAG, false);
            if (fromPageSize == null) {
                // 获取需要执行的SQL语句
                fromPageSize = this.getSql(sqlName);
            }
            fromPageSize = fromPageSize.copy();

            // 按照分页查询数据
            List<Object> baseParas = new ArrayList<Object>();
            String sql = this.getQueryPara(baseParas, fromPageSize, model);
            sql = sql.trim();
            // 查询总数据量
            String sqlSize = "SELECT COUNT(1) FROM (" +
                    // 去掉最后一个order by
                    sql.replaceAll("(?i)(ORDER\\s+BY\\s+[^)]+){0,1}(limit\\s+\\d+,\\d+\\s*){0,1}$", "")
                            // 去掉第一个 SELECT a.*
                            .replaceAll("(^SELECT)\\s+a\\.\\*", "$1 1 AS __id")
                    + ") t";

            data.setPageTotal(StringHelper.toInt(queryCellWithCache(String.format("%s.Size", sqlName), sqlSize, baseParas.toArray())));
        }

        return data;
    }


    /**
     * 获取SQL语句的参数
     *
     * @param paras   SQL语句
     * @param sqlData SQL语句的参数
     * @param model   参数的实体
     * @return SQL条件
     */
    protected String getQueryPara(List<Object> paras, SqlData sqlData, Object model) {

        // 将SQL语句进行代码片段追加
        StringBuilder sb = new StringBuilder(sqlData.getSql());
        for (String code : DaoConst.LAST_AUTO_ADD) {
            if (sb.indexOf(code) == -1) {
                sb.append(code);
            }
        }
        // 代码片段缓存
        Map<String, List<String>> codeMap = new HashMap<>(DaoConst.COLLECTION_INIT_SIZE);

        // 处理字段以及代码片段
        String sql = sb.toString();
        // 对查询条件进行初始化
        if (model instanceof InitDaoQuery) {
            ((InitDaoQuery) model).initCond();
        }
        sql = handleCodeRelease(sql, sqlData, model, codeMap);
        sql = handleCodeReplace(sqlData, sql, codeMap);

        // 通过正则表达式处理参数 @name  并替换SQL语句成 ?
        sql = handlePara(sql, paras, model);

        return sql;
    }

    /**
     * 处理代码片段替换
     *
     * @param sql     代码片段
     * @param codeMap 替换内容
     * @return Sql语句值
     */
    protected String handleCodeReplace(SqlData sqlData, String sql, Map<String, List<String>> codeMap) {
        // 最大处理层数量,默认最小1层
        int level = Math.max(1, MAX_LEVEL);
        for (int i = 0; i < level; i++) {
            // 判断是否寻找到标签
            final boolean[] find = {false};

            sql = StringHelper.getFormat(sql, StringHelper.EMPTY, new StringFormatHandle() {
                @Override
                public void addPos(StringBuilder sb, String group, String fieldFull, String field, String command) {
                    // 设置寻找到标签
                    find[0] = true;
                    // 寻找到的代码片段 不包含分括号
                    String name = group.trim().toLowerCase();
                    List<String> codes = codeMap.containsKey(name) ? codeMap.get(name) : new ArrayList<>();
                    for (String code : codes) {
                        sb.append(" ");
                        sb.append(code);
                    }
                    sb.append(" ");
                }
            });

            // 当没有寻找到时,则进行其他处理
            if (!find[0]) {
                break;
            }
        }

        sql = sql.replaceAll("\\s+", " ");

        return sql;
    }

    /**
     * 生成代码片段缓存
     *
     * @param sql     sql语句
     * @param sqlData sql语句实体
     * @param model    实体参数
     * @param codeMap  缓存对象
     * @return
     */
    private String handleCodeRelease(String sql, SqlData sqlData, Object model, Map<String, List<String>> codeMap) {
        // 循环处理字段
        for (SqlDataField field : sqlData.getSqlDataFields()) {
            sql = field.getCond().getSql(sql, sqlData, field, model, codeMap);
        }
        return sql;
    }

    /**
     * 通过正则表达式处理参数 @name  并替换SQL语句成 ?
     *
     * @param sql   需要处理的SQL语句
     * @param paras 需要添加的参数
     * @param model 需要获取的参数实体
     * @return 处理后的SQL语句
     */
    private String handlePara(String sql, List<Object> paras, Object model) {
        String regex = "@([a-zA-Z0-9_]+)";
        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(sql);
        // 寻找到的代码片段 不包含分括号
        while (m.find()) {
            // SQL参数名称 @name\s
            String name = m.group();
            // 对应的前台输入字段 name
            String field = m.group(1);
            // 根据输入字段从参数中取值
            Object val = ObjectHelper.get(model, field);
            if (val instanceof SqlCodeParameter) {
                sql = getSqlCodeParameter(paras, sql, name, (SqlCodeParameter) val);
            } else {
                // 判断是否为数组
                boolean isArray = ArrayHelper.isArrayOrList(val);
                if (isArray) {
                    sql = getListSql(paras, sql, name, val);
                } else {
                    // 当参数不为数组时,则直接增加
                    sql = sql.replaceFirst(name, "?");
                    val = this.getParaValue(val);
                    paras.add(val);
                }
            }
        }
        return sql;
    }

    /**
     * 获取处理后的参数值
     *
     * @param val 获取参数值
     * @return 处理后的参数值
     */
    private Object getParaValue(Object val) {
        if (val instanceof Boolean) {
            val = (Boolean) val ? 1 : 0;
        } else if (val instanceof Double || val instanceof Float) {
            val = StringHelper.toDouble(val);
        }
        val = StringHelper.toString(val);
        return val;
    }

    /**
     * 获取列表的SQL语句
     *
     * @param paras 参数
     * @param sql   SQL语句
     * @param name  名称
     * @param val   值
     * @return 获取包含列表的SQL语句的值
     */
    private String getListSql(List<Object> paras, String sql, String name, Object val) {
        List list = ArrayHelper.getList(val);
        int length = list.size();

        //  进行循环
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++) {
            Object item = list.get(i);
            // 判断列表是否为常规对象
            if (item == null || item instanceof Number || item.getClass().isEnum() || item instanceof String || item instanceof Date) {
                addArrayIn(paras, sb, i, item);
            } else if (item instanceof CaseSqlModel) {
                addArrayCase(paras, sb, i, (CaseSqlModel) item);
            } else {
                addArrayTable(paras, sb, i, item);
            }
        }

        // 生成最终的SQL语句
        sql = sql.replaceFirst(name, sb.toString());
        return sql;
    }

    /**
     * 获取代码片段
     *
     * @param paras
     * @param sql
     * @param name
     * @param val
     * @return
     */
    protected String getSqlCodeParameter(List<Object> paras, String sql, String name, SqlCodeParameter val) {
        StringBuilder sb = new StringBuilder();
        for (Object item : val.getLatitude()) {
            String codeTo = StringHelper.getCodeString(val.getLatitudeCode(), item);
            sb.append(codeTo);
        }
        sql = sql.replaceFirst(name, sb.toString());
        return sql;
    }

    /**
     * 添加数组型参数
     *
     * @param paras 参数列表
     * @param sb    字符串数组
     * @param i     序号
     * @param from  参数值
     */
    private void addArrayIn(List<Object> paras, StringBuilder sb, int i, Object from) {
        // 添加连接字符串
        if (i > 0) {
            sb.append(",");
        }

        // 添加参数SQL语句
        sb.append("?");
        Object to = this.getParaValue(from);
        paras.add(to);
    }

    /**
     * 添加 CASE型字段
     *
     * @param paras 参数列表
     * @param sb    字符串数组
     * @param i     序号
     * @param from  参数值
     */
    private void addArrayCase(List<Object> paras, StringBuilder sb, int i, CaseSqlModel from) {
        // 添加连接字符串
        if (i > 0) {
            sb.append(",");
        }
        sb.append(from.getFrom());
        switch (from.getGroupType()) {
            case CaseSqlModel.GROUP_TYPE_SUM:
                sb.append("SUM");
                break;
            case CaseSqlModel.GROUP_TYPE_COUNT:
                sb.append("COUNT");
                break;
            case CaseSqlModel.GROUP_TYPE_MAX:
                sb.append("MAX");
                break;
            case CaseSqlModel.GROUP_TYPE_MIN:
                sb.append("MIN");
                break;
            case CaseSqlModel.GROUP_TYPE_AVG:
                sb.append("AVG");
                break;
            default:
                throw YzgError.getRuntimeException("031", from.getGroupType());
        }
        sb.append("( CASE WHEN ");
        sb.append(from.getCaseField());
        sb.append(" ");
        if (from.getCaseValue() != null) {
            sb.append("=?");
            paras.add(from.getCaseValue());
        }
        sb.append(from.getAndWhere());
        sb.append(" THEN ");
        if (!StringHelper.isEmpty(from.getValueField())) {
            sb.append(from.getValueField());
        } else if (!StringHelper.isEmpty(from.getValue())) {
            sb.append("?");
            paras.add(from.getValue());
        }
        sb.append(" ELSE 0 END )");
        sb.append(from.getTo());
        sb.append(" AS ");
        sb.append(from.getToName());
    }

    /**
     * 添加表格型参数,将列表转换成表格
     *
     * @param paras 参数列表
     * @param sb    字符串数组
     * @param i     序号
     * @param from  参数值
     */
    private void addArrayTable(List<Object> paras, StringBuilder sb, int i, Object from) {
        // 添加连接字符串
        if (i > 0) {
            sb.append(" UNION ALL ");
        }

        // 将对象转换为 Map 对象
        Map<String, Object> to = new HashMap<>(DaoConst.COLLECTION_INIT_SIZE);
        if (from instanceof Map) {
            to = (Map) from;
        } else {
            ObjectHelper.writeWithFromClass(to, from);
        }

        // 生成SQL语句
        int column = 0;
        sb.append(" SELECT ");

        // 处理列
        for (Map.Entry<String, Object> oItemKey : to.entrySet()) {
            if (column > 0) {
                sb.append(",");
            }

            String itemKey = oItemKey.getKey();
            sb.append("? AS " + itemKey);

            // 处理参数
            Object itemValue = oItemKey.getValue();
            itemValue = this.getParaValue(itemValue);
            paras.add(itemValue);
            column++;
        }
    }

    /**
     * 根据缓存查询第一个单元格
     *
     * @param sqlName 需要执行的SQL语句名称
     * @param sql     需要执行的SQL语句
     * @param paras   SQL语句的参数
     * @return 查询的结果
     */
    protected Object queryCellWithCache(String sqlName, String sql, Object... paras) {

        // 生成缓存的主键
        String cacheKey = getCacheKey(Object.class, sql, paras);

        // 获取缓存
        Object cache = this.cacheList.get(cacheKey);

        // 返回缓存
        if (cache != null) {
            return cache;
        }

        // 查询数据
        Object ret = this.getDb().queryCell(this.getClass(), sqlName, sql, paras);
        // 写入缓存
        this.cacheList.put(cacheKey, ret);

        return ret;
    }

    /**
     * 执行查询SQL语句,并将数据缓存起来
     *
     * @param cls     返回的类型
     * @param sqlName 需要执行的SQL语句名称
     * @param sql     需要执行的SQL语句
     * @param paras   执行的SQL语句的参数
     * @param <T>     返回的泛型
     * @return 需要返回的数据
     */
    protected <T> List<T> queryWithCache(Class<T> cls, String sqlName, String sql, Object... paras) {
        // 生成缓存的主键
        String cacheKey = getCacheKey(cls, sql, paras);

        // 获取缓存
        Object cache = this.cacheList.get(cacheKey);

        // 返回缓存
        if (cache != null) {
            return (List<T>) cache;
        }

        // 查询数据
        List<T> ret = this.getDb().query(this.getClass(), cls, sqlName, sql, paras);

        // 写入缓存
        this.cacheList.put(cacheKey, ret);
        return ret;
    }

    /**
     * 获取缓存的键值对
     *
     * @param cls   结果类型
     * @param sql   SQL语句
     * @param paras SQL语句参数
     * @return 返回的结果
     */
    protected String getCacheKey(Class<?> cls, String sql, Object... paras) {
        StringBuilder sb = new StringBuilder();
        sb.append(cls.getName());
        sb.append(":");
        sb.append(sql);
        for (Object para : paras) {
            sb.append(":");
            sb.append(para);
        }
        return StringHelper.md5(sb.toString());
    }
}