thinkjs/lib/Lib/Core/Model.class.js
2013-11-20 14:05:48 +08:00

566 lines
18 KiB
JavaScript

/**
* Model类
* @type {[type]}
*/
var MODEL_INSERT = 1; // 插入模型数据
var MODEL_UPDATE = 2; // 更新模型数据
var MODEL_BOTH = 3; // 包含上面两种方式
var MUST_VALIDATE = 1; // 必须验证
var EXISTS_VALIDATE = 0; // 表单存在字段则验证
var VALUE_VALIDATE = 2; // 表单值不为空则验证
var vm = require("vm");
var model = module.exports = Class(function(){
var _linkNum = [];
var _db = {};
return {
initProps: function(){
// 当前使用的扩展模型
this._extModel = null;
// 当前数据库操作对象
this.db = null;
// 主键名称
this.pk = "id";
// 数据表前缀
this.tablePrefix = "";
// 模型名称
this.name = "";
// 数据库名称
this.dbName = "";
// 数据库配置
this.connection = "";
// 数据表名(不包含表前缀)
this.tableName = "";
// 实际数据表名(包含表前缀)
this.trueTableName = "";
// 最近错误信息
this.error = "";
// 字段信息
this.fields = [];
// 数据信息
this.data = [];
// 查询表达式参数
this.options = {};
// 自动验证定义
this._validate = [];
// 自动完成定义
this._auto = [];
// 字段映射定义
this._map = [];
// 命名范围定义
this._scope = [];
// 是否自动检测数据表字段信息
this.autoCheckFields = true;
// 是否批处理验证
this.patchValidate = false;
//初始化的promise
this.promise = null;
},
/**
* 架构函数
* 取得DB类的实例对象 字段检查
* @access public
* @param string $name 模型名称
* @param string $tablePrefix 表前缀
* @param mixed $connection 数据库连接信息
*/
init: function(name, tablePrefix, connection){
this.initProps();
// 获取模型名称
if (name) {
if (name.indexOf('.') > -1) {
name = name.split(".");
this.dbName = name[0];
this.name = name[1];
}else{
this.name = name;
}
}else if(!this.name){
this.getModelName();
}
// 设置表前缀
this.tablePrefix = tablePrefix === undefined ? (this.tablePrefix || C('db_prefix')) : tablePrefix;
// 数据库初始化操作
// 获取数据库操作对象
// 当前模型有独立的数据库连接信息
this.promise = this.initDb(0, connection || this.connection);
this.initMethod && this.initMethod();
},
/**
* 获取模型名
* @access public
* @return string
*/
getModelName: function(){
var filename = this.__filename || __filename;
if (!this.name) {
var name = filename.split("/").pop().replace(C('class_file_suffix'), "");
this.name = name.substr(0, name.length - 5);
};
return this.name;
},
/**
* 获取表名
* @return {[type]} [description]
*/
getTableName: function(){
if (!this.trueTableName) {
var tableName = this.tablePrefix || "";
if (this.tableName) {
tableName += this.tableName;
}else{
tableName += parse_name(this.name);
}
this.trueTableName = tableName.toLowerCase();
};
var tableName = (this.dbName ? this.dbName + "." : "") + this.trueTableName;
return tableName;
},
/**
* 初始化数据库连接
* @access public
* @param integer $linkNum 连接序号
* @param mixed $config 数据库连接信息
* @param array $params 模型参数
* @return Model
*/
initDb: function(linkNum, config, params){
linkNum = linkNum || 0;
if (!linkNum && this.db) {
return get_promise(this.db);
};
if (!_db[linkNum] || config && _linkNum[linkNum] != config) {
if (config && is_string(config) && config.indexOf("/") == -1) {
config = C(config);
};
_db[linkNum] = think_require("Db").getInstance(config);
}else if(config === null){
_db[linkNum].close();
delete _db[linkNum];
return get_promise(false);
}
if (params) {
extend(this, params);
};
// 记录连接信息
_linkNum[linkNum] = config;
this.db = _db[linkNum];
if (this.name && this.autoCheckFields) {
return this.checkTableInfo();
};
return get_promise(this);
},
/**
* 获取缓存数据表字段信息的缓存文件
* @return {[type]} [description]
*/
getFieldsCacheFile: function(){
var db = this.dbName || C('db_name');
return '_fields/' + db + "." + this.name;
},
/**
* 自动检测数据表信息
* @access protected
* @return void
*/
checkTableInfo: function(){
// 如果不是Model类 自动记录数据表信息
// 只在第一次执行记录
if (!this.fields) {
// 如果数据表字段没有定义则自动获取
if (C('db_fields_cache')) {
var fields = F(this.getFieldsCacheFile());
if (fields) {
return get_promise(fields);
};
};
// 每次都会读取数据表信息
return this.flushFields();
};
return get_promise(true);
},
/**
* 刷新数据表字段信息
* @return promise [description]
*/
flushFields: function(){
this.db.setModel(this.name);
var self = this;
return this.getDbFields(this.getTableName(), true).then(function(fields){
self.fields = {
"_field": Object.keys(fields),
"_autoinc": false
};
var types = {};
for(var key in fields){
var val = fields[key];
types[key] = val.type;
if (val.primary) {
self.fields['_pk'] = key;
if (val.autoinc) {
self.fields['_autoinc'] = true;
};
};
}
self.fields['_type'] = types;
if (C('db_fields_cache')) {
F(self.getFieldsCacheFile(), self.fields);
};
return self.fields;
});
},
/**
* 获取数据表里的字段信息
* @param {[type]} table [description]
* @return {[type]} [description]
*/
getDbFields: function(table, all){
table = table || this.options.table;
if (table) {
return this.db.getFields(table).then(function(fields){
return all ? fields : Object.keys(fields || {});
})
};
if (this.fields) {
return get_promise(all ? this.fields : this.fields["_field"]);
};
return get_promise(false);
},
/**
* 获取一条记录的某个字段值
* @return {[type]} [description]
*/
getField: function(field, sepa){
var options = {field: field};
options = this.parseOptions(options);
field = field.trim();
if (field.indexOf(",") > -1) {
if (options.limit === undefined && is_number(sepa)) {
options.limit = sepa;
};
return this.db.select(options).then(function(data){
if (data) {
var _field = _field.split(",");
var field = Object.keys(data[0]);
var key = field.shift();
var key2 = field.shift();
var cols = {};
var length = _field.length;
data.forEach(function(item){
var name = item[key];
if (length === 2) {
cols[name] = item[key2];
}else{
cols[name] = is_string(sepa) ? item.join(sepa) : item;
}
});
return cols;
};
return {};
})
}else{
options.limit = is_number(sepa) ? sepa : 1;
return this.db.select(options).then(function(data){
if (data) {
if (sepa !== true && options.limit == 1) {
return data[0];
};
return data.forEach(function(val){
return val[field];
})
};
return {};
})
}
},
/**
* 获取上一次操作的sql
* @return {[type]} [description]
*/
getLastSql: function(){
return this.db.getLastSql();
},
/**
* 获取主键名称
* @access public
* @return string
*/
getPk: function(){
return this.fields['_pk'] || this.pk;
},
/**
* 缓存
* @param {[type]} key [description]
* @param {[type]} expire [description]
* @param {[type]} type [description]
* @return {[type]} [description]
*/
cache: function(key, expire, type){
this.options.cache = {
key: key,
expire: expire,
type: type
};
return this;
},
/**
* 指定查询数量
* @param {[type]} offset [description]
* @param {[type]} length [description]
* @return {[type]} [description]
*/
limit: function(offset, length){
this.options.limit = length === undefined ? offset : offset + "," + length;
return this;
},
/**
* 指定分页
* @return {[type]} [description]
*/
page: function(page, listRows){
this.options.page = listRows === undefined ? page : page + "," + listRows;
return this;
},
/**
* where条件
* @return {[type]} [description]
*/
where: function(where){
if (is_string(where) && where) {
where = {
_string: where
}
};
this.options.where = extend(this.options.where || {}, where);
return this;
},
/**
* 要查询的字段
* @return {[type]} [description]
*/
field: function(field){
if (field === true) {
field = "*";
};
this.options.field = field;
return this;
},
/**
* 联合查询
* @return {[type]} [description]
*/
union: function(union){
if (!this.options.union) {
this.options.union = [];
};
this.options.union.push(union);
return this;
},
join: function(join){
if (is_array(join)) {
this.options.join = join;
}else{
if (!this.options.join) {
this.options.join = [];
};
this.options.join.push(join);
}
return this;
},
getError: function(){
return this.error;
},
rollback: function(){
return this.db.rollback();
},
commit: function(){
return this.db.commit();
},
startTrans: function(){
this.commit();
this.db.startTrans();
return this;
},
/**
* 解析参数
* @param {[type]} options [description]
* @return {[type]} [description]
*/
parseOptions: function(options){
options = extend(this.options, options);
this.options = {};
var fields = [];
if (!options.table) {
options.table = this.getTableName();
fields = this.fields;
}else{
fields = "*";
}
if (options.alias) {
options.table += " " + options.alias;
};
options.modal = this.name;
if (options.where && is_object(where) && fields) {
};
return options;
},
/**
* 数据类型检测
* @param {[type]} data [description]
* @param {[type]} key [description]
* @return {[type]} [description]
*/
parseType: function(data, key){
var fieldType = this.fields["_type"][key] || "";
if (fieldType.indexOf("bigint") === -1 && fieldType.indexOf("int") > -1) {
data[key] = parseInt(data[key], 10) || 0;
}else if(fieldType.indexOf("double") > -1 || fieldType.indexOf("float") > -1){
data[key] = parseFloat(data[key]) || 0.0;
}else if(fieldType.indexOf('bool') > -1){
data[key] = !! data[key];
}
return data;
},
/**
* 添加一条或者多条数据
* @param {[type]} data [description]
* @param {[type]} options [description]
* @param {[type]} replace [description]
*/
add: function(data, options, replace){
data = data || "";
if (!data) {
if (this.data) {
data = this.data;
this.data = {};
}else{
throw_error(L("_DATA_TYPE_INVALID_"));
return false;
}
};
options = this.parseOptions(options);
data = this.facade(data);
},
/**
* 删除数据
* @return {[type]} [description]
*/
delete: function(){
},
/**
* 更新数据
* @return {[type]} [description]
*/
update: function(){
},
save: function(options){
return this.update(options);
},
/**
* 查询一条数据
* @return 返回一个promise
*/
find: function(options){
if (typeof options == 'number' || is_string(options)) {
var where = {};
where[this.getPk()] = options;
options = {
'where': where
}
};
options.limit = 1;
options = this.parseOptions(options);
return this.db.select(options).then(function(data){
return data ? data[0] : [];
});
},
/**
* 查询数据
* @return 返回一个promise
*/
select: function(options){
if (typeof options == 'number' || is_string(options)) {
var pk = this.getPk();
options = options + "";
var where = {};
if (options.indexOf(",") > -1) {
where[pk] = ["IN", options];
}else{
where[pk] = options;
}
options = {
where: where
};
}else if(options === false){
options = this.parseOptions({});
return '( ' + this.db.buildSelectSql() + " )";
}
options = this.parseOptions(options);
return this.db.select(options);
},
/**
* 对保存的数据进行处理
* @param {[type]} data [description]
* @return {[type]} [description]
*/
facade: function(data){
return data;
},
_before_write: function(){}
}
}).extend(function(){
//追加的方法
var methods = {
initMethod: function(){
var self = this;
this.promise.then(function(data){
if (!data) {
return false;
};
var field = data["_field"];
console.log(field);
field.forEach(function(item){
var name = "getBy" + parse_name(item, 1);
self[name] = function(arg){
var where = {}
where[item] = arg;
return this.where(where).find();
}
var fieldName = "getFieldBy" + parse_name(item, 1);
self[fieldName] = function(arg, arg1){
var where = {};
where[item] = arg;
return this.where(where).getField(arg1);
}
})
})
}
};
// 链操作方法列表
var methodNameList = [
'table','order','alias','having','group',
'lock','distinct','auto','filter','validate'
];
methodNameList.forEach(function(item){
methods[item] = function(data){
this.options[item] = data;
return this;
}
});
['count','sum','min','max','avg'].forEach(function(item){
methods[item] = function(data){
var field = data || "*";
return this.getField(item.toUpperCase() + "(" + field + ") AS tp_" + item);
}
});
return methods;
})