mirror of
https://github.com/thinkjs/thinkjs.git
synced 2026-01-25 14:42:47 +00:00
427 lines
13 KiB
JavaScript
427 lines
13 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;
|
|
// 链操作方法列表
|
|
this.methods = ['table','order','alias','having','group','lock','distinct','auto','filter','validate'];
|
|
// deferred
|
|
this.deferred = when.defer();
|
|
},
|
|
/**
|
|
* 重置promise
|
|
* @return {[type]} [description]
|
|
*/
|
|
resetDeferred: function(){
|
|
this.deferred.reject();
|
|
this.deferred = when.defer();
|
|
},
|
|
/**
|
|
* 架构函数
|
|
* 取得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.initDb(0, connection || this.connection);
|
|
},
|
|
/**
|
|
* 获取模型名
|
|
* @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();
|
|
};
|
|
return (this.dbName ? this.dbName + "." : "") + this.trueTableName;
|
|
},
|
|
/**
|
|
* 初始化数据库连接
|
|
* @access public
|
|
* @param integer $linkNum 连接序号
|
|
* @param mixed $config 数据库连接信息
|
|
* @param array $params 模型参数
|
|
* @return Model
|
|
*/
|
|
initDb: function(linkNum, config, params){
|
|
if (!linkNum && this.db) {
|
|
return 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;
|
|
}
|
|
if (params) {
|
|
extend(this, params);
|
|
};
|
|
// 记录连接信息
|
|
_linkNum[linkNum] = config;
|
|
this.db = _db[linkNum];
|
|
if (this.name && this.autoCheckFields) {
|
|
this._checkTableInfo();
|
|
};
|
|
return this;
|
|
},
|
|
/**
|
|
* 自动检测数据表信息
|
|
* @access protected
|
|
* @return void
|
|
*/
|
|
_checkTableInfo: function(){
|
|
// 如果不是Model类 自动记录数据表信息
|
|
// 只在第一次执行记录
|
|
if (!this.fields) {
|
|
// 如果数据表字段没有定义则自动获取
|
|
if (C('db_fields_cache')) {
|
|
var db = this.dbName || C('db_name');
|
|
var fields = F('_fields/' + db + "." + this.name);
|
|
if (fields) {
|
|
var version = C('db_field_version');
|
|
if (!version || fields._version == version) {
|
|
this.fields = fields;
|
|
this.deferred.resolve();
|
|
this.resetDeferred();
|
|
return this;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
// 每次都会读取数据表信息
|
|
this.flush();
|
|
},
|
|
|
|
flush: function(){
|
|
// 缓存不存在则查询数据表信息
|
|
|
|
},
|
|
/**
|
|
* 获取上一次操作的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 = {
|
|
_string: where
|
|
}
|
|
};
|
|
if (this.options.where) {
|
|
this.options.where = extend(this.options.where, where);
|
|
}else{
|
|
this.options.where = where;
|
|
}
|
|
return this;
|
|
},
|
|
/**
|
|
* 要查询的字段
|
|
* @return {[type]} [description]
|
|
*/
|
|
field: function(field){
|
|
if (field === true) {
|
|
field = this.getDbField() || "*";
|
|
};
|
|
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 = this.getDbField();
|
|
}
|
|
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 || "";
|
|
options = options || [];
|
|
replace = replace || false;
|
|
},
|
|
/**
|
|
* 删除数据
|
|
* @return {[type]} [description]
|
|
*/
|
|
delete: function(){
|
|
|
|
},
|
|
/**
|
|
* 更新数据
|
|
* @return {[type]} [description]
|
|
*/
|
|
update: function(){
|
|
|
|
},
|
|
save: function(options){
|
|
return this.update(options);
|
|
}
|
|
/**
|
|
* 查询一条数据
|
|
* @return 返回一个promise
|
|
*/
|
|
find: function(options){
|
|
var deferred = when.defer();
|
|
if (typeof options == 'number' || is_string(options)) {
|
|
var where = {};
|
|
where[this.getPk()] = options;
|
|
options = {
|
|
'where': where
|
|
}
|
|
};
|
|
options.limit = 1;
|
|
options = this.parseOptions(options);
|
|
this.db.select(options).then(function(data){
|
|
data = data ? data[0] : [];
|
|
deferred.resolve(data);
|
|
}).otherwise(function(err){
|
|
deferred.reject(err);
|
|
})
|
|
return deferred.promise;
|
|
},
|
|
/**
|
|
* 查询数据
|
|
* @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);
|
|
}
|
|
}
|
|
}); |