ts-api-core
Version:
Nodejs api framework core
583 lines • 23.5 kB
JavaScript
"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