"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BoundSql = void 0;
const crypto = require("crypto");
const utils_1 = require("../../utils");
const mybatis_1 = require("./mybatis");
class BoundSql {
    constructor({ sqlOrXml, parameters, bindParameters, sqlModule, }) {
        this.REPLACE_MULTI_WHITE_LINE = new RegExp('(\r?\n(\\s*\r?\n)+)', 'g');
        this.MYBATIS_TAGS = ['</where>', '</if>', '</trim>', '</set>', '</foreach>'];
        this.parameters = [];
        this.sqlOrXml = sqlOrXml;
        this.sqlModule = sqlModule;
        if (parameters != undefined) {
            this.parameters = parameters;
        }
        if (bindParameters != undefined) {
            this.bindParameters = bindParameters;
        }
    }
    async init() {
        const varMap = {};
        if (this.bindParameters != null) {
            const keys = Object.keys(this.bindParameters);
            for (const key of keys) {
                const value = this.bindParameters[key];
                varMap[key] = value;
            }
        }
        else {
            // varMap.putAll(runtimeContext.getVarMap());
        }
        if (this.MYBATIS_TAGS.filter(it => this.sqlOrXml.includes(it)).length > 0) {
            const sqlNode = mybatis_1.MybatisParser.parse(this.sqlOrXml);
            this.sqlOrXml = await sqlNode.getSql(varMap);
            this.parameters = sqlNode.getParameters();
        }
        else {
            await this.normal(varMap);
        }
    }
    async normal(varMap) {
        this.sqlOrXml = await mybatis_1.TextSqlNode.parseSql(this.sqlOrXml, varMap, this.parameters);
        this.sqlOrXml =
            this.sqlOrXml == null
                ? null
                : this.sqlOrXml.trim().replace(this.REPLACE_MULTI_WHITE_LINE, '\r\n');
    }
    copy(newSqlOrXml) {
        const boundSql = new BoundSql({
            parameters: this.parameters,
            bindParameters: this.bindParameters,
            sqlModule: this.sqlModule,
            sqlOrXml: newSqlOrXml,
        });
        boundSql.excludeColumns = this.excludeColumns;
        return boundSql;
    }
    addParameter(value) {
        this.parameters.push(value);
    }
    getSql() {
        return this.sqlOrXml;
    }
    setSql(sql) {
        this.sqlOrXml = sql;
    }
    buildSqlCacheKey(sql, params = []) {
        return crypto
            .createHash('md5')
            .update(sql + ':' + params.toString())
            .digest('hex');
    }
    /**
     * 获取环出值
     * @param sql sql
     * @param params 参数
     * @param supplier 执行回调
     */
    async getCacheValue(sql, params, supplier) {
        if ((0, utils_1.isBlank)(this.sqlModule.cacheName)) {
            return await supplier();
        }
        const cacheKey = this.sqlModule.cacheName + ':' + this.buildSqlCacheKey(sql, params);
        const cacheValue = await this.sqlModule.sqlCache.get(cacheKey);
        if (cacheValue != null) {
            return cacheValue;
        }
        const value = await supplier();
        await this.sqlModule.sqlCache.set(cacheKey, value, this.sqlModule.ttl === 0 ? null : this.sqlModule.ttl);
        return value;
    }
    /**
     * 执行sql查询
     * @param interceptors 拦截器
     * @param supplier 回调
     */
    async execute(interceptors, supplier) {
        interceptors.forEach(interceptor => interceptor.preHandle(this));
        const newSupplier = async () => {
            let result = supplier();
            for (const interceptor of interceptors) {
                result = interceptor.postHandle(this, result);
            }
            return result;
        };
        return await this.getCacheValue(this.getSql(), this.parameters, newSupplier);
    }
}
exports.BoundSql = BoundSql;
//# sourceMappingURL=BoundSql.js.map