mirror of
https://github.com/thinkjs/thinkjs.git
synced 2026-01-25 14:42:47 +00:00
382 lines
13 KiB
JavaScript
382 lines
13 KiB
JavaScript
var url = require("url");
|
|
var querystring = require("querystring");
|
|
/**
|
|
* 数据库基类
|
|
* @return {[type]} [description]
|
|
*/
|
|
var db = module.exports = Class(function(){
|
|
return {
|
|
comparison: {
|
|
'eq': '=',
|
|
'neq': '<>',
|
|
'gt': '>',
|
|
'egt': '>=',
|
|
'lt': '<',
|
|
'elt': '<=',
|
|
'notlike': 'NOT LIKE',
|
|
'like': 'LIKE',
|
|
'in': 'IN',
|
|
'notin': 'NOT IN'
|
|
},
|
|
selectSql: 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT% %UNION%%COMMENT%',
|
|
initProp: function(){
|
|
// 数据库类型
|
|
this.dbType = null;
|
|
// 是否自动释放查询结果
|
|
this.autoFree = false;
|
|
// 当前操作所属的模型名
|
|
this.model = "_think_";
|
|
// 是否使用永久连接
|
|
this.pconnect = false;
|
|
// 当前SQL指令
|
|
this.queryStr = "";
|
|
this.modelSql = [];
|
|
// 最后插入ID
|
|
this.lastInsID = null;
|
|
// 返回或者影响记录数
|
|
this.numRows = 0;
|
|
// 返回字段数
|
|
this.numCols = 0;
|
|
// 事务指令数
|
|
this.transTimes = 0;
|
|
// 错误信息
|
|
this.error = "";
|
|
// 数据库连接ID 支持多个连接
|
|
this.linkID = [];
|
|
// 当前连接ID
|
|
this._linkID = null;
|
|
// 当前查询ID
|
|
this.queryId = null;
|
|
// 是否已经连接数据库
|
|
this.connected = false;
|
|
// 数据库连接参数配置
|
|
this.config = '';
|
|
// 数据库表达式
|
|
},
|
|
init: function(){
|
|
this.initProp();
|
|
},
|
|
parseSet: function(data){
|
|
data = data || {};
|
|
var set = [];
|
|
for(var key in data){
|
|
var value = this.parseValue(data[key]);
|
|
if (is_scalar(value)) {
|
|
set.push(this.parseKey(key) + "=" + value);
|
|
};
|
|
}
|
|
return "SET " + set.join(",");
|
|
},
|
|
parseKey: function(key){
|
|
return key;
|
|
},
|
|
/**
|
|
* value分析
|
|
* @param {[type]} value [description]
|
|
* @return {[type]} [description]
|
|
*/
|
|
parseValue: function(value){
|
|
if (is_string(value)) {
|
|
value = '\'' + this.escapeString(value) + '\'';
|
|
}else if(is_array(value)){
|
|
if ((value[0] + "").toLowerCase() == 'exp') {
|
|
value = this.escapeString(value[1]);
|
|
}else{
|
|
value = value.map(this.parseValue);
|
|
}
|
|
}else if(is_boolean(value)){
|
|
value = value ? "1" : "0";
|
|
}else if (value === null) {
|
|
value = 'null';
|
|
};
|
|
return value;
|
|
},
|
|
/**
|
|
* field分析
|
|
* @return {[type]} [description]
|
|
*/
|
|
parseField: function(fields){
|
|
if (is_string(fields) && fields.indexOf(',') > -1) {
|
|
fields = fields.split(",");
|
|
};
|
|
if (is_array(fields)) {
|
|
var self = this;
|
|
return fields.map(function(item){
|
|
return self.parseKey(item);
|
|
}).join(",");
|
|
}else if(is_object(fields)){
|
|
var data = [];
|
|
for(var key in fields){
|
|
data.push(this.parseKey(key) + " AS " + this.parseKey(fields[key]));
|
|
}
|
|
return data.join(",");
|
|
}else if(is_string(fields) && fields){
|
|
return this.parseKey(fields);
|
|
}
|
|
return "*";
|
|
},
|
|
/**
|
|
* table别名分析
|
|
* @param {[type]} tables [description]
|
|
* @return {[type]} [description]
|
|
*/
|
|
parseTable: function(tables){
|
|
if (is_string(tables)) {
|
|
tables = tables.split(",");
|
|
};
|
|
if (is_array(tables)) {
|
|
var self = this;
|
|
return tables.map(function(item){
|
|
return self.parseKey(item);
|
|
}).join(",");
|
|
}else if (is_object(tables)) {
|
|
var data = [];
|
|
for(var key in tables){
|
|
data.push(this.parseKey(key) + " AS " + this.parseKey(tables[key]));
|
|
}
|
|
return data.join(",");
|
|
}
|
|
},
|
|
/**
|
|
* where条件分析
|
|
* @param {[type]} where [description]
|
|
* @return {[type]} [description]
|
|
*/
|
|
parseWhere: function(where){
|
|
var whereStr = "";
|
|
var self = this;
|
|
if (is_string(where)) {
|
|
whereStr = where;
|
|
}else{
|
|
where = where || {};
|
|
var operate = (where["_logic"] + "").toUpperCase();
|
|
var oList = ["AND", "OR", "XOR"];
|
|
if (oList.indexOf(operate) > -1) {
|
|
// 定义逻辑运算规则 例如 OR XOR AND NOT
|
|
operate = " " + operate + " ";
|
|
delete where["_logic"];
|
|
}else{
|
|
operate = " AND ";
|
|
}
|
|
//key值的安全检测正则
|
|
var keySafeRegExp = /^[A-Z_\|\&\-.a-z0-9\(\)\,]+$/;
|
|
for(var key in where){
|
|
var val = where[key];
|
|
whereStr += "( ";
|
|
if (key.indexOf("_") === 0) {
|
|
// 解析特殊条件表达式
|
|
whereStr += this.parseThinkWhere(key, val);
|
|
}else{
|
|
if (!keySafeRegExp.test(key.trim())) {
|
|
throw_error(key + " is not safe");
|
|
};
|
|
var multi = where && where['_multi'];
|
|
key = key.trim();
|
|
// 支持 name|title|nickname 方式定义查询字段
|
|
if (key.indexOf('|') > -1) {
|
|
var arr = key.split("|");
|
|
whereStr += arr.map(function(item, i){
|
|
var v = multi ? val[i] : val;
|
|
return "(" + self.parseWhereItem(self.parseKey(item, v)) + ")";
|
|
}).join(" OR ");
|
|
}else if (key.indexOf("&") > -1) {
|
|
var arr = key.split("&");
|
|
whereStr += arr.map(function(item, i){
|
|
var v = multi ? val[i] : val;
|
|
return "(" + self.parseWhereItem(self.parseKey(item, v)) + ")";
|
|
}).join(" AND ");
|
|
}else{
|
|
whereStr += this.parseWhereItem(this.parseKey(key), val);
|
|
}
|
|
}
|
|
whereStr += ")" + operate;
|
|
}
|
|
whereStr = whereStr.substr(0, -operate.length);
|
|
}
|
|
return whereStr ? (" WHERE " + whereStr) : "";
|
|
},
|
|
parseWhereItem: function(key, val){
|
|
|
|
return "";
|
|
},
|
|
parseThinkWhere: function(key, val){
|
|
var whereStr = "";
|
|
switch(key){
|
|
// 字符串模式查询条件
|
|
case "_string":
|
|
return val;
|
|
// 复合查询条件
|
|
case "_complex":
|
|
return this.parseWhere(val).substr(6);
|
|
// 字符串模式查询条件
|
|
case "_query":
|
|
var where = querystring.parse(val);
|
|
var op = " AND ";
|
|
if ("_logic" in where) {
|
|
op = " " + where["_logic"].toLowerCase() + " ";
|
|
delete where["_logic"];
|
|
};
|
|
var arr = [];
|
|
for(var name in where){
|
|
var val = where[name];
|
|
val = this.parseKey(name) + " = " + this.parseValue(val);
|
|
arr.push(val);
|
|
}
|
|
whereStr = arr.join(op);
|
|
return whereStr;
|
|
default:
|
|
return "";
|
|
}
|
|
return "";
|
|
},
|
|
parseLimit: function(limit){
|
|
return limit ? (" LIMIT " + limit) : "";
|
|
},
|
|
parseJoin: function(join){
|
|
var joinStr = "";
|
|
if (join) {
|
|
if (is_object(join)) {
|
|
for(var key in join){
|
|
var val = join[key];
|
|
if (val.toLowerCase().indexOf("join") > -1) {
|
|
joinStr += val;
|
|
}else{
|
|
joinStr += " LEFT JOIN " + val;
|
|
}
|
|
}
|
|
}else{
|
|
joinStr += " LEFT JOIN " + join;
|
|
}
|
|
};
|
|
//将__TABLE_NAME__这样的字符串替换成正规的表名,并且带上前缀和后缀
|
|
joinStr = joinStr.replace(/__([A-Z_-]+)__/g, function(a, b){
|
|
return C('db_prefix') + b.toLowerCase();
|
|
});
|
|
return joinStr;
|
|
},
|
|
parseOrder: function(order){
|
|
var orderStr = "";
|
|
var self = this;
|
|
if (is_array(order)) {
|
|
orderStr = order.map(function(item){
|
|
return self.parseKey(item);
|
|
}).join(",");
|
|
}else if (is_object(order)) {
|
|
var arr = [];
|
|
for(var key in order){
|
|
var val = order[key];
|
|
val = this.parseKey(key) + " " + val;
|
|
arr.push(val);
|
|
}
|
|
orderStr = arr.join(",");
|
|
};
|
|
return order ? (" ORDER BY " + order) : "";
|
|
},
|
|
parseGroup: function(group){
|
|
return group ? (" GROUP BY " + group) : "";
|
|
},
|
|
parseHaving: function(having){
|
|
return having ? (" HAVING " + having) : "";
|
|
},
|
|
parseComment: function(comment){
|
|
return comment ? (" /* " + comment + "*/") : "";
|
|
},
|
|
parseDistinct: function(distinct){
|
|
return distinct ? (" Distinct " + distinct) : "";
|
|
},
|
|
parseUnion: function(union){
|
|
if (!union) {
|
|
return "";
|
|
};
|
|
var str = "";
|
|
if ("_all" in union) {
|
|
str = "UNION ALL ";
|
|
delete union["_all"];
|
|
}else{
|
|
str = "UNION ";
|
|
}
|
|
var sql = [];
|
|
for(var key in union){
|
|
var val = union[key];
|
|
val = str + (is_array(val) ? this.buildSelectSql(val) : val);
|
|
sql.push(sql);
|
|
}
|
|
return sql.join(" ");
|
|
}
|
|
}
|
|
});
|
|
/**
|
|
* 解析dsn
|
|
* 格式: mysql://username:passwd@localhost:3306/DbName
|
|
* @param string dsn [description]
|
|
* @return {[type]} [description]
|
|
*/
|
|
db.parseDSN = function(dsn){
|
|
if (!dsn) {
|
|
return false;
|
|
};
|
|
var info = url.parse(dsn);
|
|
var auth = (info.auth || "").split(":");
|
|
return {
|
|
"dbms": info.protocol,
|
|
"username": auth[0] || "",
|
|
"password": auth[1] || "",
|
|
"hostname": info.hostname || "",
|
|
"hostport": info.port || "",
|
|
"database": (info.pathname || "").substr(1),
|
|
"dsn": ""
|
|
}
|
|
}
|
|
/**
|
|
* 解析配置
|
|
* @param {[type]} config [description]
|
|
* @return {[type]} [description]
|
|
*/
|
|
db.parseConfig = function(config){
|
|
if (config && is_string(config)) {
|
|
return this.parseDSN(config);
|
|
}else if(is_object(config)){
|
|
return {
|
|
"dbms": config.db_type,
|
|
"username": config.db_user,
|
|
"password": config.db_pwd,
|
|
"hostname": config.db_host,
|
|
"hostport": config.db_port,
|
|
"database": config.db_name,
|
|
"dsn": config.db_dsn,
|
|
"params": config.db_params
|
|
}
|
|
}else if(!config){
|
|
if (C('db_dsn')) {
|
|
return this.parseDSN(C('db_dsn'));
|
|
};
|
|
return {
|
|
'dbms' : C('db_type'),
|
|
'username' : C('db_user'),
|
|
'password' : C('db_pwd'),
|
|
'hostname' : C('db_host'),
|
|
'hostport' : C('db_port'),
|
|
'database' : C('db_name'),
|
|
'dsn' : C('db_dsn'),
|
|
'params' : C('db_params'),
|
|
}
|
|
}
|
|
return config;
|
|
};
|
|
/**
|
|
* 根据配置获取对应的数据库实例
|
|
* @param {[type]} config [description]
|
|
* @return {[type]} [description]
|
|
*/
|
|
db.getInstance = function(config){
|
|
config = this.parseConfig(config);
|
|
if (!config.dbms) {
|
|
return throw_error("no dbms config");
|
|
};
|
|
//数据库类型
|
|
var dbType = config.dbms.toLowerCase();
|
|
dbType = dbType.substr(0, 1).toUpperCase() + dbType.substr(1);
|
|
var instance = think_require(dbType + "Db")(config);
|
|
instance.dbType = dbType.toUpperCase();
|
|
return instance;
|
|
} |