UNPKG

ts-api-core

Version:

Nodejs api framework core

583 lines 23.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.column = exports.Table = exports.ColumnOption = exports.DBScript = exports.UpdateOperatorType = exports.ColumnParams = void 0; const model_helper_1 = require("../utils/model.helper"); const error_1 = require("../base/error"); class ColumnParams extends model_helper_1.SrcParams { /** 字段名称 */ get field() { return this._field === undefined ? this.name : this._field; } } exports.ColumnParams = ColumnParams; /** * pdate的处理方式定义 */ var UpdateOperatorType; (function (UpdateOperatorType) { /** * 覆盖 即用新的值覆盖调原有值 */ UpdateOperatorType[UpdateOperatorType["cover"] = 1] = "cover"; /** * 累加 即用原有值的基础上增加传入的值 */ UpdateOperatorType[UpdateOperatorType["accumulation"] = 2] = "accumulation"; })(UpdateOperatorType = exports.UpdateOperatorType || (exports.UpdateOperatorType = {})); /** 类名与表名的映射 */ const tableMap = new Map(); /** * SQL 脚本生成器 */ class DBScript { static emptyFieldError(table, fieldName) { throw new error_1.SysError(`表 ${table} 的字段 ${fieldName} 不能为空`); } static joinFields(...fields) { var _a; const len = fields.length; let result = ''; for (var i = 0; i < len; i++) { let v = (_a = fields[i]) === null || _a === void 0 ? void 0 : _a.trim(); if (v === undefined || v === null || v === '') continue; const a = v.startsWith(',') ? 1 : 0; const b = v.endsWith(',') ? 1 : 0; if (a === 1) { if (result === '') { v = v.substring(a); } if (b === 1) { v = v.substring(0, v.length - b); } result = result + v; } else if (b === 1) { if (result === '') { v = v.substring(0, v.length - b); } result = v + result; } else { result = result === '' ? v : result + ',' + v; } } return result ? result : '*'; } /** 获取指定 entity 类型对应的表名称 */ static getTableName(target, tableName) { return tableName ? tableName : tableMap.get(target.name); } /** * 生成删除数据脚本 * @param table 表名 或 entity 类型 * @param fieldName ID字段名称 * @param id ID列表 * @returns */ static deleteByIds(table, fieldName, id) { const tableName = typeof table === 'string' ? table : this.getTableName(table, ''); if (!tableName || !fieldName) { return undefined; } if (Array.isArray(id)) { if (id.length === 0) { return undefined; } return `DELETE FROM \`${tableName}\` WHERE \`${fieldName}\` IN ${this.tranArrayToInSql(id)}`; } else { return `DELETE FROM \`${tableName}\` WHERE \`${fieldName}\` = '${id}'`; } } /** * 生成删除数据脚本 * @param condition 条件语句 * @returns */ static delete(target, condition, options) { const tableName = this.getTableName(target, options === null || options === void 0 ? void 0 : options.table); if (!tableName) { return ''; } return `DELETE FROM \`${tableName}\`` + (condition ? ` WHERE ${condition} ` : ''); } /** * 生成查询SQL语句 * @param target 目标 entity 类 * @param condition 条件语句 * @param options 选项 * @param options.alias 表的别名 * @param options.joinSql Join SQL 语句 * @param options.table 自定义表名称 * @param options.page 分页 页码,从 1 开始 * @param options.pageSize 分页大小 * @returns */ static query(target, condition, options) { const tableName = this.getTableName(target, options === null || options === void 0 ? void 0 : options.table); if (!tableName) { return ''; } const columns = this.joinFields(this.getColumnsStr(target, options === null || options === void 0 ? void 0 : options.alias), options === null || options === void 0 ? void 0 : options.extFields); return this.queryByTableColumns(tableName, columns, condition, options); } static queryByTableColumns(tableName, columns, condition, options) { if (!tableName) { return ''; } const alias = options === null || options === void 0 ? void 0 : options.alias; const columnsStr = typeof columns === 'string' ? columns : this.joinFields(this.columnsToStr(columns, alias), options === null || options === void 0 ? void 0 : options.extFields); let sql = `SELECT ${columnsStr} FROM ${tableName} ${alias !== null && alias !== void 0 ? alias : ''} `; if (options === null || options === void 0 ? void 0 : options.joinSql) { sql = sql + (options === null || options === void 0 ? void 0 : options.joinSql) + ' '; } if (condition) { sql = sql + ` WHERE ${condition} `; } return sql + (options === undefined ? '' : this.limit(options.page, options.pageSize)); } /** * 生成插入脚本 * @param options 选项 * @param entity 数据对象 */ static insert(target, entity, options) { const tableName = this.getTableName(target, options === null || options === void 0 ? void 0 : options.table); if (!tableName || !entity) { return undefined; } const columns = this.getColumns(target, true); return this.insertByTableColumns(tableName, columns, entity); } static insertByTableColumns(tableName, columns, entity) { if (!tableName || !entity) { return undefined; } const insertParams = []; const insertFields = []; const result = new DBScript(); result.params = []; for (const e of columns) { const key = typeof e === 'string' ? e : e.propertyName; const value = entity[key]; if (value === undefined) { const columnInfo = typeof e === 'string' ? undefined : e; if (columnInfo && columnInfo.default === true) { continue; } this.emptyFieldError(tableName, key); } insertParams.push('?'); insertFields.push(`\`${key}\``); result.params.push(value); } result.sql = `INSERT INTO \`${tableName}\` (${insertFields.join(',')}) VALUES (${insertParams.join(',')})`; return result; } /** * 生成插入或更新脚本 * @param options 选项 * @param entity 数据对象 * @param operatorType 更新操作类型 */ static insertUpdate(target, entity, options) { if (!entity) { return undefined; } const columns = this.getColumns(target, false, true, true); if (columns.length === 0) { return undefined; } // 没有可更新的列 const result = this.insert(target, entity, options); if (!result) { return undefined; } result.sql = result.sql.concat(this.getInsertUpdateSql(columns, entity, options === null || options === void 0 ? void 0 : options.operatorType)); return result; } /** * 生成批量插入脚本 * @param options 选项 * @param entity 数据对象数组 */ static batchInsert(target, entity, options) { const tableName = this.getTableName(target, options === null || options === void 0 ? void 0 : options.table); if (!tableName || !entity || entity.length === 0) { return undefined; } const columns = this.getColumns(target, true); return this.batchInsertByTableColumns(tableName, columns, entity); } static batchInsertByTableColumns(tableName, columns, entity) { if (!tableName || !entity || entity.length === 0) { return undefined; } const insertFields = columns.map(e => `\`${typeof e === 'string' ? e : e.field}\``).join(','); const result = new DBScript(); result.sql = `INSERT INTO \`${tableName}\` (${insertFields}) VALUES ?`; result.params = []; entity.forEach((item) => { const params = []; for (const e of columns) { const key = typeof e === 'string' ? e : e.propertyName; const value = item[key]; if (value === undefined) { const columnInfo = typeof e === 'string' ? undefined : e; if (columnInfo && columnInfo.default !== true) { this.emptyFieldError(tableName, key); } } params.push(value); } result.params.push(params); }); if (result.params.length === 0) { return undefined; } result.params = [result.params]; return result; } /** * 生成插入或更新脚本 */ static insertUpdateByTableColumns(tableName, columns, entity, options) { if (!entity) { return undefined; } if (columns.length === 0) { return undefined; } // 没有可更新的列 const result = this.insertByTableColumns(tableName, columns, entity); if (!result) { return undefined; } result.sql = result.sql.concat(this.getInsertUpdateSql(columns, entity, options === null || options === void 0 ? void 0 : options.operatorType)); return result; } /** * 生成批量插入或更新脚本 * @param options 选项 * @param entity 数据对象数组 */ static batchInsertUpdate(target, entity, options) { if (!entity || entity.length === 0) { return undefined; } const columns = this.getColumns(target, false, true, true); if (columns.length === 0) { return undefined; } // 没有可更新的列 const result = this.batchInsert(target, entity, options); if (!result) { return undefined; } result.sql = result.sql.concat(this.getInsertUpdateSql(columns, entity[0], options === null || options === void 0 ? void 0 : options.operatorType)); return result; } /** * 生成批量插入或更新脚本 */ static batchInsertUpdateByTableColumns(tableName, columns, entity, options) { if (!entity || entity.length === 0) { return undefined; } if (columns.length === 0) { return undefined; } // 没有可更新的列 const result = this.batchInsertByTableColumns(tableName, columns, entity); if (!result) { return undefined; } result.sql = result.sql.concat(this.getInsertUpdateSql(columns, entity[0], options === null || options === void 0 ? void 0 : options.operatorType)); return result; } /** * 生成更新脚本 * @param options 选项 * @param entity 数据对象数组 * @param condition 更新的包含条件 */ static update(target, entity, condition, options) { const tableName = this.getTableName(target, options === null || options === void 0 ? void 0 : options.table); if (!tableName || !entity) { return undefined; } const columns = this.getColumns(target, false, true); return this.updateByTableColumns(tableName, columns, entity, condition, options); } static updateByTableColumns(tableName, columns, entity, condition, options) { if (!tableName || !entity) { return undefined; } if (columns.length === 0) { return undefined; } // 没有可更新的列 const result = new DBScript(); result.sql = `UPDATE \`${tableName}\` SET `; result.params = []; let i = 0; for (const e of columns) { const key = typeof e === 'string' ? e : e.propertyName; const value = entity[key]; if (value === undefined) { const columnInfo = typeof e === 'string' ? undefined : e; if (columnInfo && columnInfo.default === true) { continue; } this.emptyFieldError(tableName, key); } const v = (options === null || options === void 0 ? void 0 : options.operatorType) === UpdateOperatorType.accumulation && (typeof e !== 'string' && e.accumulation) ? `\`${key}\` = \`${key}\` + ?` : `\`${key}\` = ?`; result.sql += (i === 0 ? '' : ',') + v; result.params.push(value); i = i + 1; } result.sql += ' WHERE ' + condition; if ((options === null || options === void 0 ? void 0 : options.conditionArgs) && (options === null || options === void 0 ? void 0 : options.conditionArgs.length) > 0) { result.params.push(...options === null || options === void 0 ? void 0 : options.conditionArgs); } return result; } /** * 获取插入更新的sql * @param updateColumns * @param entity * @param operatorType 更新操作类型, 默认 `UpdateOperatorType.cover` * @returns */ static getInsertUpdateSql(updateColumns, entity, operatorType) { const setSQL = []; // update后面的赋值语句 for (const item of Object.getOwnPropertyNames(entity)) { const i = updateColumns.findIndex((e) => { return (typeof e === 'string') ? e === item : e.propertyName === item; }); if (i < 0) { continue; } const v = updateColumns[i]; if (typeof v === 'string') { setSQL.push(`\`${v}\` = VALUES(\`${v}\`)`); } else if (v.accumulation && operatorType === UpdateOperatorType.accumulation) { setSQL.push(`\`${v.field}\` = \`${v.field}\`+ VALUES(\`${v.field}\`)`); } else { setSQL.push(`\`${v.field}\` = VALUES(\`${v.field}\`)`); } } return ' ON DUPLICATE KEY UPDATE ' + setSQL.join(','); } static getEntityKeys(entity) { const keys = this._cacheEntityKeys[entity.name]; if (keys) { return keys; } const obj = new entity(); const _keys = Object.keys(obj); const _regKeys = model_helper_1.ModelHelper.getClassMap(entity.name, obj); if (_regKeys) { // 将注册的字段加入keys中,原因是由于没有默认值,可能字段不存在 _regKeys.forEach((k) => { if (k instanceof ColumnParams) { const i = _keys.indexOf(k.propertyName); if (i < 0) { _keys.push(k); } else { _keys[i] = k; } } }); } this._cacheEntityKeys[entity.name] = _keys; return _keys; } /** * 获取数据对象对应的列信息 * @param entity 数据对象 * @param allowInsert 列必须允许插入, 排除掉不允许插入的列 * @param allowUpdate 列必须允许更新, 排除掉不允许更新的列 * @returns */ static getColumns(entity, allowInsert, allowUpdate, excludePrimary) { const keys = []; const columns = this.getEntityKeys(entity); // 将注册的字段加入keys中,原因是由于没有默认值,可能字段不存在 columns.forEach((k) => { if (k instanceof ColumnParams) { if (k.query === false) { return; } const i = keys.indexOf(k.propertyName); if ((allowInsert === true && k.inserted === false) || (allowUpdate === true && k.updated === false) || (excludePrimary === true && k.primary === true)) { if (i >= 0) { keys.splice(i, 1); } return; } if (i >= 0) { keys[i] = k; } else { keys.push(k); } } else if (typeof k === 'string') { keys.push(k); } }); return keys; } /** * 获取数据对象对应的列信息字符串 * @param entity 数据对象 * @param alias 表别名 * @param allowInsert 列必须允许插入, 排除掉不允许插入的列 * @param allowUpdate 列必须允许更新, 排除掉不允许更新的列 * @returns */ static getColumnsStr(entity, alias, allowInsert, allowUpdate, excludePrimary) { const columns = this.getColumns(entity, allowInsert, allowUpdate, excludePrimary); return this.columnsToStr(columns, alias); } static columnsToStr(columns, alias) { return columns.map((e) => { if (typeof e === 'string') { if (alias) { return alias + '.' + e; } else { return `\`${e}\``; } } else { const v = `\`${e.field}\`` + (e.axios ? ` AS ${e.axios}` : ''); return alias ? alias + '.' + v : v; } }).join(','); } /** * 生成分页需要的 Limit 条件 SQL 语句 * @param pageIndex 页码,从1开始 * @param pageSize 分页大小 */ static limit(pageIndex, pageSize) { if (pageIndex !== undefined && pageSize !== undefined && !Number.isNaN(pageIndex) && !Number.isNaN(pageSize)) { return ' LIMIT ' + ((pageIndex - 1) * pageSize).toString() + ', ' + pageSize.toString(); } return ""; } /** * 将字符串或数字的数组转化为 SQL 语句 IN 的可选值字符串 * @param ids 字符串数组 * @returns ` ('n','n1','n2',...) ` */ static tranArrayToInSql(ids) { return ids.length === 0 ? " ('') " : (typeof ids[0] === 'string') ? " ('" + ids.join("','") + "') " : " (" + ids.join(",") + ") "; } /** 正则查询最后一个 */ static lastRegFindStr(str, pattern) { const v = str.match(pattern); if (v) { const key = v[v.length - 1]; return str.lastIndexOf(key) + (key.startsWith(')') ? 1 : 0); } return -1; } /** * 获取总行数的SQL,总行数字段名 `rowCount` * @param sql sql 语句 * @param mini 简化统计行数的 sql , 默认 `0` * @returns */ static rowCountSql(sql, mini = 0) { let v; let ref = 0; let isMini = mini === 0; const sqlLowerCase = sql.toLowerCase().replace(/[\n|\r|\t]/g, ' '); const bracketPos = sqlLowerCase.lastIndexOf(')'); let limitPos = this.lastRegFindStr(sqlLowerCase, /[ |)]limit /g); let orderbyPos = this.lastRegFindStr(sqlLowerCase, /[ |)]order\s*by /g); const groupByPos = this.lastRegFindStr(sqlLowerCase, /[ |)]group\s*by /g); if (groupByPos > 0 && bracketPos < groupByPos) { isMini = false; // 存在 group by 时, 不作简化处理 } if (bracketPos > limitPos) limitPos = -1; if (bracketPos > orderbyPos) orderbyPos = -1; if (isMini) { const s = 'SELECT count(1) AS rowCount '; const i = sqlLowerCase.indexOf(' from '); v = s + sql.substring(i); ref = s.length - i; } else { const s = 'SELECT count(1) AS rowCount FROM ( '; v = s + sql; ref = s.length; } if (limitPos > 0 || orderbyPos > 0) { const j = ref + Math.min((limitPos > 0 ? Math.max(limitPos, 0) : v.length), (orderbyPos > 0 ? Math.max(0, orderbyPos) : v.length)); if (v.length > j) { v = v.substring(0, j); } } if (!isMini) { v = v + ' ) ___tab_row_count_'; } return v; } } exports.DBScript = DBScript; DBScript._cacheEntityKeys = {}; /** 列定义选项 */ class ColumnOption { } exports.ColumnOption = ColumnOption; /** 表定义 */ function Table(tableName) { return function (target) { tableMap.set(target.name, tableName); }; } exports.Table = Table; /** 列定义,适用于 entity 类 */ function column(field = undefined, options, convert, ...args) { return function (target, propertyName) { var _a, _b, _c, _d, _e, _f; const item = new ColumnParams(); if (options === null || options === void 0 ? void 0 : options.axios) { item._field = field ? field : propertyName; item.name = options.axios; } else { item.name = field ? field : propertyName; } item.propertyName = propertyName; item.primary = (_a = options === null || options === void 0 ? void 0 : options.primary) !== null && _a !== void 0 ? _a : false; item.updated = (_b = options === null || options === void 0 ? void 0 : options.updated) !== null && _b !== void 0 ? _b : true; item.inserted = (_c = options === null || options === void 0 ? void 0 : options.inserted) !== null && _c !== void 0 ? _c : true; item.query = (_d = options === null || options === void 0 ? void 0 : options.query) !== null && _d !== void 0 ? _d : true; item.default = (_e = options === null || options === void 0 ? void 0 : options.default) !== null && _e !== void 0 ? _e : false; item.accumulation = (_f = options === null || options === void 0 ? void 0 : options.accumulation) !== null && _f !== void 0 ? _f : false; item.axios = options === null || options === void 0 ? void 0 : options.axios; if (convert) { item.convert = new convert(...args); } let itemClass = model_helper_1.ModelHelper._maps.get(target.constructor.name); if (!itemClass) { itemClass = new Map(); model_helper_1.ModelHelper._maps.set(target.constructor.name, itemClass); } itemClass.set(propertyName, item); }; } exports.column = column; //# sourceMappingURL=db.script.js.map