"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const xmldoc_1 = require("xmldoc");
const core_1 = require("@midwayjs/core");
const TextSqlNode_1 = require("./TextSqlNode");
const NodeStream_1 = require("./NodeStream");
const IfSqlNode_1 = require("./IfSqlNode");
const ForeachSqlNode_1 = require("./ForeachSqlNode");
const TrimSqlNode_1 = require("./TrimSqlNode");
const SetSqlNode_1 = require("./SetSqlNode");
const WhereSqlNode_1 = require("./WhereSqlNode");
class MybatisParser {
    static parse(xml) {
        try {
            xml = '<magic-node>' + MybatisParser.escapeXml(xml) + '</magic-node>';
            const document = new xmldoc_1.XmlDocument(xml);
            const sqlNode = new TextSqlNode_1.default('');
            MybatisParser.parseNodeList(sqlNode, new NodeStream_1.default(document.children));
            return sqlNode;
        }
        catch (e) {
            throw new core_1.MidwayCommonError('SQL解析错误');
        }
    }
    static escapeXml(xml) {
        return xml.replace(MybatisParser.ESCAPE_LT_PATTERN, MybatisParser.ESCAPE_LT_REPLACEMENT);
    }
    static parseNodeList(sqlNode, stream) {
        while (stream.hasMore()) {
            let childNode;
            if (stream.matchNodeType('text')) {
                childNode = new TextSqlNode_1.default(stream.consume().text.trim());
            }
            else {
                if (stream.matchNodeName('foreach')) {
                    childNode = MybatisParser.parseForeachSqlNode(stream);
                }
                else if (stream.matchNodeName('if')) {
                    childNode = MybatisParser.parseIfSqlNode(stream);
                }
                else if (stream.matchNodeName('trim')) {
                    childNode = MybatisParser.parseTrimSqlNode(stream);
                }
                else if (stream.matchNodeName('set')) {
                    childNode = MybatisParser.parseSetSqlNode(stream);
                }
                else if (stream.matchNodeName('where')) {
                    childNode = MybatisParser.parseWhereSqlNode(stream);
                }
                else {
                    throw new core_1.MidwayCommonError('Unsupported tags :' + stream.consume().name);
                }
            }
            sqlNode.addChildNode(childNode);
        }
    }
    static parseIfSqlNode(stream) {
        const ifNode = stream.consume();
        const test = MybatisParser.getNodeAttributeValue(ifNode, 'test');
        let nextNode = null;
        if (stream.matchNodeName('else')) {
            nextNode = new TextSqlNode_1.default('');
            MybatisParser.parseNodeList(nextNode, new NodeStream_1.default(stream.consume().children));
        }
        else if (stream.matchNodeName('elseif')) {
            nextNode = MybatisParser.parseIfSqlNode(stream);
        }
        return MybatisParser.processChildren(new IfSqlNode_1.default(test, nextNode), ifNode);
    }
    static processChildren(sqlNode, node) {
        if ('children' in node && node.children.length > 0) {
            MybatisParser.parseNodeList(sqlNode, new NodeStream_1.default(node.children));
        }
        return sqlNode;
    }
    static getNodeAttributeValue(node, attributeKey) {
        if ('attr' in node) {
            const item = node.attr[attributeKey];
            return item != null ? item : null;
        }
        return null;
    }
    /**
     * 解析foreach节点
     */
    static parseForeachSqlNode(stream) {
        const node = stream.consume();
        const foreachSqlNode = new ForeachSqlNode_1.default();
        foreachSqlNode.collection = MybatisParser.getNodeAttributeValue(node, 'collection');
        foreachSqlNode.separator = MybatisParser.getNodeAttributeValue(node, 'separator');
        foreachSqlNode.close = MybatisParser.getNodeAttributeValue(node, 'close');
        foreachSqlNode.open = MybatisParser.getNodeAttributeValue(node, 'open');
        foreachSqlNode.item = MybatisParser.getNodeAttributeValue(node, 'item');
        foreachSqlNode.index = MybatisParser.getNodeAttributeValue(node, 'index');
        return MybatisParser.processChildren(foreachSqlNode, node);
    }
    /**
     * 解析trim节点
     */
    static parseTrimSqlNode(stream) {
        const node = stream.consume();
        const trimSqlNode = new TrimSqlNode_1.default();
        trimSqlNode.prefix = MybatisParser.getNodeAttributeValue(node, 'prefix');
        trimSqlNode.prefixOverrides = MybatisParser.getNodeAttributeValue(node, 'prefixOverrides');
        trimSqlNode.suffix = MybatisParser.getNodeAttributeValue(node, 'suffix');
        trimSqlNode.suffixOverrides = MybatisParser.getNodeAttributeValue(node, 'suffixOverrides');
        return MybatisParser.processChildren(trimSqlNode, node);
    }
    /**
     * 解析set节点
     */
    static parseSetSqlNode(stream) {
        return MybatisParser.processChildren(new SetSqlNode_1.default(), stream.consume());
    }
    /**
     * 解析where节点
     */
    static parseWhereSqlNode(stream) {
        return MybatisParser.processChildren(new WhereSqlNode_1.default(), stream.consume());
    }
}
exports.default = MybatisParser;
MybatisParser.ESCAPE_LT_PATTERN = new RegExp('<([\\d\'"\\s=>#$?(])', 'g');
MybatisParser.ESCAPE_LT_REPLACEMENT = '&lt;$1';
//# sourceMappingURL=MybatisParser.js.map