UNPKG

mm_os

Version:

MM_OS服务端架构,用于快速构建应用程序,支持网站建设、小程序后台、AI应用、物联网(IOT/AIOT)、游戏服务端等多种场景。

272 lines (252 loc) 7.2 kB
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;