mm_os
Version:
MM_OS服务端架构,用于快速构建应用程序,支持网站建设、小程序后台、AI应用、物联网(IOT/AIOT)、游戏服务端等多种场景。
272 lines (252 loc) • 7.2 kB
JavaScript
const {
Drive
} = require('mm_machine');
const Mod = require('./model.js');
/**
* 数据模型基类
* 提供数据存储、查询、修改等核心功能
*/
class Model extends Drive {
static config = {
// 模型名称
'name': 'default',
// 标题
'title': '用户账户模型',
// 描述
'description': '定于用户账户模型的组件',
// 主文件
'main': '',
// 状态 0:禁用 1:启用
'state': 1,
// 排序,越小越靠前
'sort': 100,
// 模型包含字段
'fields': {}
};
/**
* 构造函数
* @param {object} config 配置参数
* @param {object} parent 父对象
*/
constructor(config, parent) {
super({ ...Model.config, ...config || {} }, parent);
}
}
/**
* 获取模板目录
* @returns {string} 模板目录
*/
Model.prototype.getTplDir = function() {
return __dirname;
};
/**
* 初始化核心组件
* @param {object} eventer 事件管理器
* @param {object} logger 日志管理器
*/
Model.prototype._initCore = async function (eventer, logger) {
// 初始化依赖项
if (logger) {
this.setLogger(logger);
}
if (eventer) {
this.getEventer = function () {
return eventer;
};
}
};
/**
* 校验字段值是否在范围内
* @param {number} value 要校验的值
* @param {object} rule 字段配置对象
* @param {string} key 字段名
* @throws {TypeError} 校验失败时抛出错误
*/
Model.prototype._checkRange = function (value, rule, key) {
// 参数校验
if (typeof rule !== 'object' || Array.isArray(rule)) {
throw new TypeError('字段配置必须是对象');
}
if (typeof key !== 'string') {
throw new TypeError('字段名必须是字符串');
}
if (rule.min !== undefined && value < rule.min) {
throw new TypeError(`字段 ${key} 必须大于等于 ${rule.min}`);
}
if (rule.max !== undefined && value > rule.max) {
throw new TypeError(`字段 ${key} 必须小于等于 ${rule.max}`);
}
// 校验枚举值
if (rule.enum !== undefined && !rule.enum.includes(value)) {
throw new TypeError(`字段 ${key} 的值必须是 ${rule.enum.join('、')}`);
}
};
/**
* 验证必填字段
* @param {object} fields 字段配置
* @param {object} data 数据
*/
Model.prototype._checkRequired = function (fields, data) {
for (var key in fields) {
var rule = fields[key];
if (rule.required && (data[key] === undefined || data[key] === null)) {
throw new TypeError(`字段 ${key} 是必填字段`);
}
}
};
/**
* 验证字段类型
* @param {*} value 字段值
* @param {object} rule 规则
* @param {string} key 字段名
*/
Model.prototype._checkType = function (value, rule, key) {
const TYPE_CHECKS = {
'number': typeof value === 'number',
'string': typeof value === 'string',
'boolean': typeof value === 'boolean',
'object': typeof value === 'object' && !Array.isArray(value),
'array': Array.isArray(value)
};
if (!TYPE_CHECKS[rule.type]) {
const TYPE_NAMES = {
'number': '数字',
'string': '字符串',
'boolean': '布尔值',
'object': '对象',
'array': '数组'
};
throw new TypeError(`字段 ${key} 必须是${TYPE_NAMES[rule.type]}`);
}
};
/**
* 验证字符串长度
* @param {string} value 字段值
* @param {object} rule 规则
* @param {string} key 字段名
*/
Model.prototype._checkStringLength = function (value, rule, key) {
if (rule.min_length !== undefined && value.length < rule.min_length) {
throw new TypeError(`字段 ${key} 长度不能小于 ${rule.min_length}`);
}
if (rule.max_length !== undefined && value.length > rule.max_length) {
throw new TypeError(`字段 ${key} 长度不能大于 ${rule.max_length}`);
}
};
/**
* 验证单个字段
* @param {*} value 字段值
* @param {object} rule 规则
* @param {string} key 字段名
*/
Model.prototype._checkField = function (value, rule, key) {
this._checkType(value, rule, key);
if (rule.type === 'string') {
this._checkStringLength(value, rule, key);
if (rule.pattern && !rule.pattern.test(value)) {
throw new TypeError(`字段 ${key} 格式不正确`);
}
}
if (rule.min !== undefined || rule.max !== undefined || rule.enum !== undefined) {
this._checkRange(value, rule, key);
}
};
/**
* 数据校验方法
* @param {object} data 要校验的数据
* @param {string} type 校验类型
* @returns {boolean} 校验结果
* @throws {TypeError} 校验失败时抛出错误
*/
Model.prototype._check = function (data, type = 'add') {
if (typeof data !== 'object' || Array.isArray(data)) {
throw new TypeError('校验数据必须是对象');
}
if (typeof type !== 'string') {
throw new TypeError('校验类型必须是字符串');
}
var fields = this.config.fields;
if (!fields || typeof fields !== 'object') {
throw new TypeError('字段配置不存在');
}
if (type === 'add') {
this._checkRequired(fields, data);
}
for (var key in data) {
var rule = fields[key];
if (rule) {
this._checkField(data[key], rule, key);
}
}
return true;
};
/**
* 创建模型实例
* @param {object} data 实例数据
* @returns {object} 新实例
* @throws {TypeError} 参数类型错误时抛出
*/
Model.prototype.create = function (data = {}) {
// 参数校验
if (typeof data !== 'object' || Array.isArray(data)) {
throw new TypeError('实例数据必须是对象');
}
var model = new Mod();
var fields = this.config.fields;
// 数据校验
if (this._check(data, 'add')) {
for (var key in fields) {
model[key] = this._getDefaultValue(data[key], fields[key]);
}
}
return model;
};
/**
* 获取默认值
* @param {any} dataValue 数据值
* @param {object} rule 字段规则
* @returns {any} 默认值
* @private
*/
Model.prototype._getDefaultValue = function (dataValue, rule) {
if (dataValue !== undefined) {
return dataValue;
}
if (rule.default !== undefined) {
return rule.default;
}
var typeDefaults = {
'number': 0,
'string': '',
'boolean': false,
'object': {},
'array': []
};
return typeDefaults[rule.type] || null;
};
/**
* 更新模型实例
* @param {object} model 要更新的模型实例
* @param {object} data 更新数据
* @returns {object} 更新后的实例
* @throws {TypeError} 参数类型错误时抛出
*/
Model.prototype.update = function (model, data = {}) {
// 参数校验
if (typeof model !== 'object' || Array.isArray(model)) {
throw new TypeError('模型实例必须是对象');
}
if (typeof data !== 'object' || Array.isArray(data)) {
throw new TypeError('更新数据必须是对象');
}
// 数据校验
if (this._check(data, 'update')) {
for (var key in data) {
if (key in model) {
model[key] = data[key];
}
}
}
return model;
};
exports.Model = Model;