@wolfx/nodebatis-lite
Version:
a sql style orm for nodejs
171 lines (162 loc) • 4.55 kB
JavaScript
const Rule = require("./rule");
const replaceAndFix = require("./replaceAndFix");
const path = require("path");
const vm = require("vm");
const fs = require("fs");
const _ = require("lodash");
const keyReg = /[$|:]([\w._]+)/g;
const ddlKeyReg = /::([\w._]+)/g;
const childKeyReg = /{{\s*([\w._]+)\s*}}/g;
class SqlContainer {
constructor(dir) {
this.container = new Map();
let files = fs.readdirSync(dir),
rule = null;
for (let file of files) {
let temp = file.toLowerCase();
if (temp.indexOf(".yml") !== -1 || temp.indexOf(".yaml") !== -1) {
rule = new Rule(path.join(dir, file));
this.container.set(rule.namespace, rule.rawSql);
}
}
}
get(key, data) {
let sqlArray = this.getRaw(key, data);
return this._parseRawSql(sqlArray, data);
}
getRaw(key, data) {
let keys = key.split("."),
sql = null;
if (keys.length < 2) {
throw new Error("wrong key, the right key is xxx.xxx");
}
let namespace = keys[0];
let sqlKey = keys.slice(1).join("");
let sqlMap = this.container.get(namespace);
if (sqlMap) {
sql = sqlMap.get(sqlKey);
if (!sql) {
throw new Error("The sql: " + key + " not exists!");
} else {
//fill {{key}}
for (let i = 0; i < sql.length; i++) {
let tempSql = new Map();
if (typeof sql[i] === "string") {
sql[i] = sql[i].replace(childKeyReg, (match, key) => {
// let index = `___${tempSql.size}`;
tempSql.set(key, this.getRaw(key));
return match;
});
}
if (tempSql.size > 0) {
let tempArray = sql[i].split(childKeyReg);
for (let [key, value] of tempSql) {
for (let s = 0; s < tempArray.length; s++) {
if (key === tempArray[s]) {
tempArray[s] = value;
}
}
}
sql[i] = tempArray;
}
}
}
} else {
throw new Error("The namespace: " + namespace + " not exists!");
}
// 格式化 sql 数组
return _.flattenDeep(sql);
}
_parseRawSql(sqlArray, data) {
let sqls = [],
result,
condSql = "";
let rawSql = [],
params = [];
for (let sql of sqlArray) {
if (typeof sql === "string") {
sqls.push(this._fillParams(sql, data));
} else {
// 只判断 test ,验证通过后拼接 sql,但是参数填充统一在后面处理
condSql = this._parseCond(sql, data);
if (condSql) {
sqls.push(condSql);
}
}
}
//combine sql and params
for (let item of sqls) {
rawSql.push(item.sql);
if (item.params) {
params = params.concat(item.params);
}
}
result = rawSql.join(" ");
result = replaceAndFix(result);
return {
sql: result,
params,
};
}
_parseCond(node, data) {
let sql = null,
statements = "";
data = data || {};
const context = new vm.createContext(data);
if (node.name.toLowerCase() === "if") {
if (node.test && typeof node.test === "string") {
statements = node.test.replace(keyReg, (match, key) => {
if (data[key] === undefined || data[key] === "") {
data[key] = null;
}
return key;
});
let isTrue = false;
try {
isTrue = new vm.Script(statements).runInContext(context);
} catch (e) {
isTrue = false;
}
if (isTrue) {
sql = this._fillParams(node.sql, data);
}
}
}
if (node.name.toLowerCase() === "for") {
if (node.array) {
let sqlArray = [],
rawSql = [],
params = [];
if (node.array) {
for (let item of data[node.array]) {
sqlArray.push(this._fillParams(node.sql, item));
}
}
for (let item of sqlArray) {
rawSql.push(item.sql);
params = params.concat(item.params);
}
sql = {
sql: rawSql.join(node.seperator),
params,
};
}
}
return sql;
}
_fillParams(sql, data) {
let params = [];
let _sql = sql.replace(ddlKeyReg, (match, key) => {
return data[key];
});
_sql = _sql.replace(keyReg, (match, key) => {
params.push(data[key]);
return "?";
});
return {
sql: _sql,
params: params.length > 0 ? params : null,
};
}
}
module.exports = SqlContainer;