数据库插件
This commit is contained in:
@@ -1,8 +1,11 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
doc : "用户",
|
doc: "用户",
|
||||||
api : true,//是否需要生成api接口
|
api: true,//是否需要生成api接口
|
||||||
model: {
|
model: {
|
||||||
uid: {type: "STRING", comment: '用户id'},
|
uid: {type: "STRING", comment: '用户id'},
|
||||||
age: {type: "INTEGER", comment: '年龄', defaultValue: 0,},
|
age: {type: "INTEGER", comment: '年龄', defaultValue: 0},
|
||||||
}
|
age2: {type: "INTEGER", comment: '年龄', defaultValue: 0},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,677 @@
|
|||||||
|
//封装了一些Sequelize的api
|
||||||
|
const Sequelize = require("sequelize");
|
||||||
|
const xe = require("xe-utils")
|
||||||
|
module.exports = class Api {
|
||||||
|
constructor(sequelize,models) {
|
||||||
|
this.sequelize = sequelize
|
||||||
|
this.models = models
|
||||||
|
this.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this.tableName = ""
|
||||||
|
this.tableWhere = ""
|
||||||
|
this.tableData = ""
|
||||||
|
this.tablePage = ""
|
||||||
|
this.tableLimit = ""
|
||||||
|
this.tableOrder = ""
|
||||||
|
this.tableGroup = ""
|
||||||
|
this.tableAttributes = ""
|
||||||
|
this.t = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 指定表名
|
||||||
|
* @param {object} value 表名.
|
||||||
|
*/
|
||||||
|
table(value) {
|
||||||
|
this.tableName = value
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置数据
|
||||||
|
* @param {any} value 数据.
|
||||||
|
*/
|
||||||
|
data(value) {
|
||||||
|
this.tableData = value
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置筛选条件
|
||||||
|
* @param {object} value 筛选条件对象.
|
||||||
|
*/
|
||||||
|
where(value) {
|
||||||
|
this.tableWhere = value
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置页数
|
||||||
|
* @param {int} value 页数从0开始.
|
||||||
|
*/
|
||||||
|
page(value) {
|
||||||
|
this.tablePage = value
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置条数
|
||||||
|
* @param {int} value 条数.
|
||||||
|
*/
|
||||||
|
limit(value) {
|
||||||
|
this.tableLimit = value
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置排序
|
||||||
|
* @param {array} value 排序(默认按更新时间排序).
|
||||||
|
*/
|
||||||
|
order(value) {
|
||||||
|
this.tableOrder = value
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置数据分组
|
||||||
|
* @param {string|array} value 传需要分组的字段['createdAt'].
|
||||||
|
*/
|
||||||
|
group(value) {
|
||||||
|
this.tableGroup = value
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 常用时间筛选
|
||||||
|
* @param {string|array|Number} value 时间内容:按时间段:['2000-1-1','2000-1-2'],按常用时间:day,按最近60分钟:60.
|
||||||
|
* @param {string} field 时间字段(默认createdAt字段)
|
||||||
|
*/
|
||||||
|
time(value, field) {
|
||||||
|
if (!this.tableName) {
|
||||||
|
throw "请传表名"
|
||||||
|
}
|
||||||
|
if (!field) {
|
||||||
|
field = "createdAt"
|
||||||
|
}
|
||||||
|
if (!this.tableWhere) {
|
||||||
|
this.tableWhere = {}
|
||||||
|
}
|
||||||
|
if (!this.tableWhere['$and']) {
|
||||||
|
this.tableWhere['$and'] = []
|
||||||
|
}
|
||||||
|
const {fn, col, where, literal} = Sequelize
|
||||||
|
switch (value) {
|
||||||
|
case 'yday': // 昨天
|
||||||
|
this.tableWhere['$and'].push(where(fn('TO_DAYS', col(this.tableName + '.' + field)), '-', fn('TO_DAYS', fn('NOW')), '<=', 1))
|
||||||
|
break;
|
||||||
|
case 'day': //当天
|
||||||
|
this.tableWhere['$and'].push(where(fn('TO_DAYS', col(this.tableName + '.' + field)), '=', fn('TO_DAYS', fn('NOW'))))
|
||||||
|
break;
|
||||||
|
case 'week': //本周
|
||||||
|
this.tableWhere['$and'].push(where(fn('YEARWEEK', fn('date_format', col(this.tableName + '.' + field), '%Y-%m-%d')), '=', fn('YEARWEEK', fn('now'))))
|
||||||
|
break;
|
||||||
|
case 'month': //当月
|
||||||
|
this.tableWhere['$and'].push(where(fn('DATE_FORMAT', col(this.tableName + '.' + field), '%Y%m'), '=', fn('DATE_FORMAT', fn('CURDATE'), '%Y%m')))
|
||||||
|
break;
|
||||||
|
case 'lmonth': //上个月
|
||||||
|
this.tableWhere['$and'].push(where(fn('PERIOD_DIFF', fn('date_format', fn('now'), '%Y%m'), fn('date_format', col(this.tableName + '.' + field), '%Y%m')), '=', 1))
|
||||||
|
break;
|
||||||
|
case 'year': //当年
|
||||||
|
this.tableWhere['$and'].push(where(fn('YEAR', col(this.tableName + '.' + field)), '=', fn('YEAR', fn('NOW'))))
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (xe.isArray(value)) { //时间范围筛选
|
||||||
|
const data = {}
|
||||||
|
data[field] = {"$between": value}
|
||||||
|
this.tableWhere['$and'].push(data)
|
||||||
|
}
|
||||||
|
if (xe.isNumber(value)) {
|
||||||
|
const minute = {}
|
||||||
|
minute[field] = {"$lt": new Date(), "$gt": new Date(new Date() - value * 60 * 1000)}
|
||||||
|
this.tableWhere['$and'].push(minute)
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置事务
|
||||||
|
*/
|
||||||
|
async setTransaction() {
|
||||||
|
this.t = await this.sequelize.transaction()
|
||||||
|
return this.t
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 仅选择某些属性(只返回指定字段)
|
||||||
|
* @param {array} value 仅选择某些属性['foo', ['bar', 'baz'], 'qux'].
|
||||||
|
*/
|
||||||
|
attributes(value) {
|
||||||
|
this.tableAttributes = value
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询1条数据
|
||||||
|
* @param {Transaction} options.transaction 运行查询的事务.
|
||||||
|
*/
|
||||||
|
async find(options) {
|
||||||
|
if (!this.tableName) {
|
||||||
|
throw "请传表名"
|
||||||
|
}
|
||||||
|
const res = await this.models[this.tableName].findOne(
|
||||||
|
{
|
||||||
|
where: this.tableWhere,
|
||||||
|
transaction: this.t
|
||||||
|
}
|
||||||
|
)
|
||||||
|
this.init()
|
||||||
|
return res && res.dataValues || null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询所有符合条件的数据
|
||||||
|
* @return {array} dataValues 查询结果.
|
||||||
|
*/
|
||||||
|
async findAll() {
|
||||||
|
if (!this.tableName) {
|
||||||
|
throw "请传表名"
|
||||||
|
}
|
||||||
|
const res = await this.models[this.tableName].findAll(
|
||||||
|
{
|
||||||
|
where: this.tableWhere,
|
||||||
|
offset: (this.tablePage && this.tableLimit) ? this.tablePage - 1 * this.tableLimit : null,
|
||||||
|
limit: this.tableLimit,
|
||||||
|
order: this.tableOrder || [['updatedAt', 'DESC']], // 时间排序
|
||||||
|
group: this.tableGroup,
|
||||||
|
attributes: this.tableAttributes,
|
||||||
|
transaction: this.t
|
||||||
|
}
|
||||||
|
)
|
||||||
|
this.init()
|
||||||
|
return res.map(item => item.dataValues)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 如果数据不存在就创建数据,否则反回查询结果
|
||||||
|
* @return {object} dataValues 查询结果.
|
||||||
|
*/
|
||||||
|
async findOrCreate() {
|
||||||
|
if (!this.tableName) {
|
||||||
|
throw "请传表名"
|
||||||
|
}
|
||||||
|
if (!this.tableData) {
|
||||||
|
throw "请设置data"
|
||||||
|
}
|
||||||
|
const res = await this.models[this.tableName].findOrCreate(
|
||||||
|
{
|
||||||
|
defaults: this.tableData,
|
||||||
|
where: this.tableWhere,
|
||||||
|
transaction: this.t
|
||||||
|
}
|
||||||
|
)
|
||||||
|
this.init()
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询数据
|
||||||
|
* @param {array} args.include 关联查询.
|
||||||
|
* @return {int} count 总行数.
|
||||||
|
* @return {array} rows 数据列表.
|
||||||
|
*/
|
||||||
|
async findAndCountAll(args = {}) {
|
||||||
|
if (!this.tableName) {
|
||||||
|
throw "请传表名"
|
||||||
|
}
|
||||||
|
const {count, rows} = await this.models[this.tableName].findAndCountAll(
|
||||||
|
{
|
||||||
|
where: this.tableWhere,
|
||||||
|
offset: (this.tablePage && this.tableLimit) ? this.tablePage - 1 * this.tableLimit : null,
|
||||||
|
limit: this.tableLimit,
|
||||||
|
order: this.tableOrder || [['updatedAt', 'DESC']], // 时间排序
|
||||||
|
group: this.tableGroup,
|
||||||
|
attributes: this.tableAttributes,
|
||||||
|
transaction: this.t
|
||||||
|
}
|
||||||
|
)
|
||||||
|
this.init()
|
||||||
|
return {count, rows: rows.map(item => item.dataValues)}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字段值减小
|
||||||
|
* @param {string} data 要减小的字段和值{xxx:1,xxxx:2}.
|
||||||
|
* @param {number} min 字段减小后的值不能小于最小值
|
||||||
|
* @param {number} setValue 如果减小后的字段小于min,设置字段值为n
|
||||||
|
*/
|
||||||
|
async setDec(min, setValue) {
|
||||||
|
if (!this.tableName) {
|
||||||
|
throw "请传表名"
|
||||||
|
}
|
||||||
|
if (!this.tableData) {
|
||||||
|
throw"请数据"
|
||||||
|
}
|
||||||
|
if (!this.tableWhere) {
|
||||||
|
throw"请筛选值"
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = await this.models[this.tableName].findOne(
|
||||||
|
{
|
||||||
|
where: this.tableWhere,
|
||||||
|
transaction: this.t
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
for (let key of Object.keys(this.tableData)) {
|
||||||
|
if (res[key] - this.tableData[key] < min) {
|
||||||
|
if (setValue === 0 || setValue) {
|
||||||
|
const data = {}
|
||||||
|
Object.keys(this.tableData).map(item => {
|
||||||
|
data[item] = setValue
|
||||||
|
})
|
||||||
|
await this.models[this.tableName].update(
|
||||||
|
data,
|
||||||
|
{
|
||||||
|
where: this.tableWhere,
|
||||||
|
transaction: this.t
|
||||||
|
}
|
||||||
|
)
|
||||||
|
res = {
|
||||||
|
...res.dataValues,
|
||||||
|
...data
|
||||||
|
}
|
||||||
|
return {res: true, value: res}
|
||||||
|
}
|
||||||
|
return {res: false, value: res}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.models[this.tableName].decrement(
|
||||||
|
this.tableData,
|
||||||
|
{
|
||||||
|
where: this.tableWhere,
|
||||||
|
transaction: this.t
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
res = await this.models[this.tableName].findOne(
|
||||||
|
{
|
||||||
|
where: this.tableWhere,
|
||||||
|
transaction: this.t
|
||||||
|
}
|
||||||
|
)
|
||||||
|
this.init()
|
||||||
|
return {res: true, value: res.dataValues}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字段值增加
|
||||||
|
* @param {string} data 要增加的字段和值{xxx:1,xxxx:2}.
|
||||||
|
* @param {number} max 字段增加后的值不能大于最大值
|
||||||
|
* @param {number} setValue 如果增加后的字段大于max,设置字段值为n
|
||||||
|
*/
|
||||||
|
async setInc(max, setValue) {
|
||||||
|
if (!this.tableName) {
|
||||||
|
throw "请传表名"
|
||||||
|
}
|
||||||
|
if (!this.tableData) {
|
||||||
|
throw"请数据"
|
||||||
|
}
|
||||||
|
if (!this.tableWhere) {
|
||||||
|
throw"请筛选值"
|
||||||
|
}
|
||||||
|
let res = await this.models[this.tableName].findOne(
|
||||||
|
{
|
||||||
|
where: this.tableWhere,
|
||||||
|
transaction: this.t
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
for (let key of Object.keys(this.tableData)) {
|
||||||
|
if (res[key] + this.tableData[key] > max) {
|
||||||
|
if (setValue === 0 || setValue) {
|
||||||
|
const data = {}
|
||||||
|
Object.keys(this.tableData).map(item => {
|
||||||
|
data[item] = setValue
|
||||||
|
})
|
||||||
|
await this.models[this.tableName].update(
|
||||||
|
data,
|
||||||
|
{
|
||||||
|
where: this.tableWhere,
|
||||||
|
transaction: this.t
|
||||||
|
}
|
||||||
|
)
|
||||||
|
res = {
|
||||||
|
...res.dataValues,
|
||||||
|
...data
|
||||||
|
}
|
||||||
|
return {res: true, value: res}
|
||||||
|
}
|
||||||
|
return {res: false, value: res}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.models[this.tableName].increment(
|
||||||
|
this.tableData,
|
||||||
|
{
|
||||||
|
where: this.tableWhere,
|
||||||
|
transaction: this.t
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
res = await this.models[this.tableName].findOne(
|
||||||
|
{
|
||||||
|
where: this.tableWhere,
|
||||||
|
transaction: this.t
|
||||||
|
}
|
||||||
|
)
|
||||||
|
this.init()
|
||||||
|
return {res: true, value: res.dataValues}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统计查询结果数
|
||||||
|
*/
|
||||||
|
async count() {
|
||||||
|
if (!this.tableName) {
|
||||||
|
throw "请传表名"
|
||||||
|
}
|
||||||
|
const res = await this.models[this.tableName].count(
|
||||||
|
this.tableData,
|
||||||
|
{
|
||||||
|
where: this.tableWhere,
|
||||||
|
order: this.tableOrder || [['updatedAt', 'DESC']], // 时间排序
|
||||||
|
group: this.tableGroup,
|
||||||
|
attributes: this.tableAttributes,
|
||||||
|
transaction: this.t
|
||||||
|
}
|
||||||
|
)
|
||||||
|
this.init()
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 求和
|
||||||
|
*/
|
||||||
|
async sum() {
|
||||||
|
if (!this.tableName) {
|
||||||
|
throw "请传表名"
|
||||||
|
}
|
||||||
|
const res = await this.models[this.tableName].sum(
|
||||||
|
this.tableData,
|
||||||
|
{
|
||||||
|
where: this.tableWhere,
|
||||||
|
order: this.tableOrder || [['updatedAt', 'DESC']], // 时间排序
|
||||||
|
group: this.tableGroup,
|
||||||
|
attributes: this.tableAttributes,
|
||||||
|
transaction: this.t
|
||||||
|
}
|
||||||
|
)
|
||||||
|
this.init()
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询最大值
|
||||||
|
*/
|
||||||
|
async max() {
|
||||||
|
if (!this.tableName) {
|
||||||
|
throw "请传表名"
|
||||||
|
}
|
||||||
|
const res = await this.models[this.tableName].max(
|
||||||
|
this.tableData,
|
||||||
|
{
|
||||||
|
where: this.tableWhere,
|
||||||
|
order: this.tableOrder || [['updatedAt', 'DESC']], // 时间排序
|
||||||
|
group: this.tableGroup,
|
||||||
|
attributes: this.tableAttributes,
|
||||||
|
transaction: this.t
|
||||||
|
}
|
||||||
|
)
|
||||||
|
this.init()
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询最小值
|
||||||
|
*/
|
||||||
|
async min() {
|
||||||
|
if (!this.tableName) {
|
||||||
|
throw "请传表名"
|
||||||
|
}
|
||||||
|
const res = await this.models[this.tableName].min(
|
||||||
|
this.tableData,
|
||||||
|
{
|
||||||
|
where: this.tableWhere,
|
||||||
|
order: this.tableOrder || [['updatedAt', 'DESC']], // 时间排序
|
||||||
|
group: this.tableGroup,
|
||||||
|
attributes: this.tableAttributes,
|
||||||
|
transaction: this.t
|
||||||
|
}
|
||||||
|
)
|
||||||
|
this.init()
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新数据
|
||||||
|
* @param {object} data 数据.
|
||||||
|
* @param {boolean} options.paranoid 如果为 true,则只会更新未删除的记录。如果为 false,将更新已删除和未删除的记录。仅适用于模型的 options.paranoid 为真。.
|
||||||
|
* @param {Array} options.fields 要更新的字段(默认为所有字段)
|
||||||
|
* @param {boolean} options.validate 每一行在插入之前是否应该经过验证。如果一行未通过验证,则整个插入将失败
|
||||||
|
* @param {boolean} options.hooks 在批量更新挂钩之后运行?
|
||||||
|
* @param {boolean} options.sideEffects 是否更新任何虚拟二传手的副作用。
|
||||||
|
* @param {boolean} options.individualHooks 在更新挂钩之前运行?如果为真,这将执行一个 SELECT,然后执行单独的 UPDATE。需要一个选择,因为需要将行数据传递给钩子
|
||||||
|
* @param {boolean | Array} options.returning 如果为真,则附加 RETURNING <model columns> 以取回所有定义的值;如果是列名数组,则附加 RETURNING <columns> 以获取特定列(仅限 Postgres)
|
||||||
|
* @param {number} options.limit 要更新多少行(仅适用于 mysql 和 mariadb,对于 MSSQL 实现为 TOP(n);对于 sqlite,仅当存在 rowid 时才支持)
|
||||||
|
* @param {Function} options.logging在运行查询以记录 sql 时执行的函数。
|
||||||
|
* @param {boolean} options.benchmark 将查询执行时间(以毫秒为单位)作为第二个参数传递给日志记录函数(options.logging)。
|
||||||
|
* @param {Transaction} options.transaction 运行查询的事务
|
||||||
|
* @param {boolean} options.silent 如果为 true,则不会更新 updatedAt 时间戳。
|
||||||
|
*/
|
||||||
|
async update(options) {
|
||||||
|
if (!this.tableName) {
|
||||||
|
throw "请传表名"
|
||||||
|
}
|
||||||
|
if (!this.tableData) {
|
||||||
|
throw"请传数据"
|
||||||
|
}
|
||||||
|
if (!this.tableWhere) {
|
||||||
|
throw"请传where"
|
||||||
|
}
|
||||||
|
const res = await this.models[this.tableName].update(
|
||||||
|
this.tableData,
|
||||||
|
{
|
||||||
|
where: this.tableWhere,
|
||||||
|
...options
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除数据
|
||||||
|
* @param {object} options 参数.
|
||||||
|
* @param {boolean} options.hooks 在批量销毁挂钩之前运行.
|
||||||
|
* @param {boolean} options.individualHooks 如果设置为 true,destroy 将选择与 where 参数匹配的所有记录,并将在每行上的 destroy 钩子之前执行.
|
||||||
|
* @param {number} options.limit 要删除多少行.
|
||||||
|
* @param {boolean} options.force 删除而不是将 deletedAt 设置为当前时间戳(仅在启用偏执狂时适用).
|
||||||
|
* @param {boolean} options.truncate 如果设置为 true,支持它的方言将使用 TRUNCATE 而不是 DELETE FROM。如果表被截断,则忽略 where 和 limit 选项.
|
||||||
|
* @param {boolean} options.cascade 仅与 TRUNCATE 一起使用。截断所有具有对命名表的外键引用的表,或者截断由于 CASCADE 而添加到组中的任何表.
|
||||||
|
* @param {transaction} options.transaction 运行查询的事务.
|
||||||
|
* @param {Function} options.logging 在运行查询以记录 sql 时执行的函数。
|
||||||
|
* @param {boolean} options.benchmark 将查询执行时间(以毫秒为单位)作为第二个参数传递给日志记录函数(options.logging)。
|
||||||
|
*/
|
||||||
|
async delete(options) {
|
||||||
|
if (!this.tableName) {
|
||||||
|
throw "请传表名"
|
||||||
|
}
|
||||||
|
if (!this.tableWhere) {
|
||||||
|
throw"请传where"
|
||||||
|
}
|
||||||
|
const res = await this.models[this.tableName].destroy(
|
||||||
|
{
|
||||||
|
where: this.tableWhere,
|
||||||
|
...options
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存数据,如果数据已存在就更新,否则创建数据,可以传对象或数组,如果是需要更新数据,必须包含id
|
||||||
|
*/
|
||||||
|
async save() {
|
||||||
|
if (!this.tableName) {
|
||||||
|
throw "请传表名"
|
||||||
|
}
|
||||||
|
if (!this.tableData) {
|
||||||
|
throw"请传要保存的数据"
|
||||||
|
}
|
||||||
|
let data = this.tableData
|
||||||
|
let updateOnDuplicate = []
|
||||||
|
let keyData = {}
|
||||||
|
if (xe.isArray(data)) {
|
||||||
|
if (!data.length) {
|
||||||
|
throw"请传要保存的数据"
|
||||||
|
}
|
||||||
|
keyData = data[0]
|
||||||
|
} else {
|
||||||
|
keyData = data
|
||||||
|
data = [data]
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let key of Object.keys(keyData)) {
|
||||||
|
if (key !== 'id') {
|
||||||
|
updateOnDuplicate.push(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await this.models[this.tableName].bulkCreate(data,
|
||||||
|
{returning: true, updateOnDuplicate: updateOnDuplicate, transaction: this.t}
|
||||||
|
)
|
||||||
|
this.init()
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过json执行多个数据库操作任务
|
||||||
|
* @param {array} taskList json格式的任务列表.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*jsonTasks([
|
||||||
|
{"table": "User", "where": {id: 999}, "find": "", "as": "user_data"},//as 设置结果别名
|
||||||
|
{
|
||||||
|
"table" : "UserInfo",
|
||||||
|
"data" : {
|
||||||
|
"phone": "13126000000",
|
||||||
|
"uid": "$as.user_data.id",//根据别名 user_data 返回的结果中的id值作为数据保存
|
||||||
|
}, "save": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"as": "user_info",
|
||||||
|
"table" : "UserInfo",
|
||||||
|
"where" : {
|
||||||
|
"uid": "$as.user_data.id",//根据别名 user_data 返回的结果中的id值作为条件查询
|
||||||
|
}, "find": ""
|
||||||
|
},
|
||||||
|
|
||||||
|
{"table": "User", "data": "age", "min": ""},
|
||||||
|
{
|
||||||
|
"as": "user_list", "jsonTasks": [ //整个任务设置别名
|
||||||
|
{"setTransaction": ""}, // 开始事务
|
||||||
|
{"table": "User", "data": "age", "sum": ""},
|
||||||
|
{"table": "User", "data": "age", "max": ""},
|
||||||
|
{"table": "User", "data": "age", "min": ""},
|
||||||
|
{"commitTransaction": ""}, //提交事务
|
||||||
|
]
|
||||||
|
},
|
||||||
|
])*/
|
||||||
|
async jsonTasks(taskList) {
|
||||||
|
const res = []
|
||||||
|
for (let tk of taskList) {
|
||||||
|
const tkKeys = Object.keys(tk)
|
||||||
|
for (let key of tkKeys) {
|
||||||
|
if (key === "as") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (key === "where" || key === "data") {
|
||||||
|
const findJsonRes = this.findJsonValue(tk[key], (n) => {
|
||||||
|
if (typeof n === "string") {
|
||||||
|
// console.log(tk[key],n);
|
||||||
|
if (n.indexOf("$as") !== -1) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
if (findJsonRes) {
|
||||||
|
const jsonPath = findJsonRes.path.join(".")
|
||||||
|
const jsonPath2 = objectPath.get(tk[key], jsonPath);//$as.user_data.id
|
||||||
|
const asName = jsonPath2.split(".")[1]
|
||||||
|
const asFilter = res.filter(item => {
|
||||||
|
// console.log(Object.keys(item), asName);
|
||||||
|
return Object.keys(item)[0] === asName
|
||||||
|
})
|
||||||
|
// console.log(asFilter);
|
||||||
|
// console.log(jsonPath2);
|
||||||
|
if (asFilter.length > 0) {
|
||||||
|
// console.log(objectPath.get(asFilter[0], jsonPath2.split(".").slice(1).join("."))); //999
|
||||||
|
// console.log(jsonPath2.split(".").slice(1).join("."));//user_data.id
|
||||||
|
// console.log(tk[key]);//user_data.id
|
||||||
|
objectPath.set(tk[key], jsonPath, objectPath.get(asFilter[0], jsonPath2.split(".").slice(1).join(".")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// console.log(tk[key]);
|
||||||
|
const tkRes = await this[key](tk[key])
|
||||||
|
if (
|
||||||
|
key === "save" ||
|
||||||
|
key === "count" ||
|
||||||
|
key === "sum" ||
|
||||||
|
key === "max" ||
|
||||||
|
key === "min" ||
|
||||||
|
key === "find" ||
|
||||||
|
key === "findAll" ||
|
||||||
|
key === "findOrCreate" ||
|
||||||
|
key === "jsonTasks" ||
|
||||||
|
key === "findAndCountAll"
|
||||||
|
) {
|
||||||
|
// console.log(tk["as"]);
|
||||||
|
res.push(tk["as"] ? {[tk["as"]]: tkRes} : tkRes)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
//深度遍历JSON,搜索值
|
||||||
|
findJsonValue(n, value, path) {
|
||||||
|
if (n === value || (xe.isFunction(value) && value(n))) {
|
||||||
|
return {value: n, path}
|
||||||
|
}
|
||||||
|
path = path || []
|
||||||
|
// 获取所有的子节点,并遍历
|
||||||
|
if (typeof n === "object") {
|
||||||
|
const nkeys = Object.keys(n)
|
||||||
|
for (let k of nkeys) {
|
||||||
|
// concat() 方法用于连接两个或多个数组
|
||||||
|
const res = this.findJsonValue(n[k], value, path.concat(k));
|
||||||
|
if (res) {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -43,4 +43,5 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
path:"app/*/model/*.js",
|
||||||
}
|
}
|
||||||
|
|||||||
+53
-61
@@ -2,83 +2,75 @@
|
|||||||
* mysql/sequelize
|
* mysql/sequelize
|
||||||
*
|
*
|
||||||
* 参考文档:
|
* 参考文档:
|
||||||
|
* https://sequelize.org/
|
||||||
|
* https://sequelize.org/api/v6/identifiers
|
||||||
* https://www.sequelize.com.cn/
|
* https://www.sequelize.com.cn/
|
||||||
*/
|
*/
|
||||||
const config = require("./config")
|
const config = require("./config")
|
||||||
const Sequelize = require("sequelize");
|
const Sequelize = require("sequelize");
|
||||||
|
const operatorsAliases = require("./operatorsAliases");
|
||||||
|
const Api = require("./api");
|
||||||
module.exports = async (app) => {
|
module.exports = async (app) => {
|
||||||
const {
|
const {database, username, password, options,} = config
|
||||||
database,
|
|
||||||
username,
|
|
||||||
password,
|
|
||||||
options,
|
|
||||||
} = config
|
|
||||||
|
|
||||||
const sequelize = new Sequelize(database, username, password, {
|
const sequelize = new Sequelize(database, username, password, {
|
||||||
...options,
|
...options,
|
||||||
operatorsAliases,
|
operatorsAliases,
|
||||||
});
|
});
|
||||||
try {
|
|
||||||
await sequelize.authenticate();
|
|
||||||
console.log('数据库连接成功');
|
|
||||||
} catch (error) {
|
|
||||||
console.error('数据库连接失败', error);
|
|
||||||
}
|
|
||||||
|
|
||||||
app.sql = sequelize
|
// 加载model文件
|
||||||
|
let list = await app.load(config.path)
|
||||||
|
list.forEach(item => {
|
||||||
|
const {res, parse} = item
|
||||||
|
const model = {}
|
||||||
|
for (let key of Object.keys(res.model)) {
|
||||||
|
res.model[key].type = Sequelize[res.model[key].type]
|
||||||
|
model[key] = res.model[key]
|
||||||
|
}
|
||||||
|
model['id'] = {
|
||||||
|
type: Sequelize.INTEGER,
|
||||||
|
comment: '表自增id',
|
||||||
|
allowNull: false,
|
||||||
|
unique: 'id',
|
||||||
|
primaryKey: true,
|
||||||
|
autoIncrement: true,
|
||||||
|
}
|
||||||
|
sequelize.define(parse.name, model)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
app.models = sequelize.models
|
||||||
|
const api = new Api(sequelize, sequelize.models)
|
||||||
|
app.db = api
|
||||||
|
// console.log(api);
|
||||||
|
console.log(await app.db.table("User").find());
|
||||||
|
|
||||||
//等待所有插件载入完成后,自动更新数据库字段
|
//等待所有插件载入完成后,自动更新数据库字段
|
||||||
//把所有模型的md5值存入到redis里面去,哪个文件的md5有变动就更新哪个表的字段.
|
//把所有模型的md5值存入到redis里面去,哪个文件的md5有变动就更新哪个表的字段.
|
||||||
//todo
|
app.willReadyList.push(async () => {
|
||||||
app.willReadyList.push(()=>{
|
list.forEach(async item => {
|
||||||
|
const {res, parse} = item
|
||||||
|
const md5 = await app.redis.get("md5:" + parse.name)
|
||||||
|
const newMd5 = getFileMd5(app.root + '/' + parse.dir + "/" + parse.base)
|
||||||
|
if (!md5 || newMd5 !== md5) {
|
||||||
|
//自动更新表字段
|
||||||
|
await app.models[parse.name].sync({alter: true});
|
||||||
|
console.log("自动更新表:", parse.name);
|
||||||
|
//创建新的md5
|
||||||
|
await app.redis.mset("md5:" + parse.name, newMd5)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//定义别名
|
//文件md5值
|
||||||
function operatorsAliases() {
|
function getFileMd5(url) {
|
||||||
const Op = Sequelize.Op;
|
const buffer = require('fs').readFileSync(url);
|
||||||
//操作符别名
|
const hash = require('crypto').createHash('md5');
|
||||||
const operatorsAliases = {
|
hash.update(buffer, 'utf8');
|
||||||
$eq: Op.eq,
|
const md5 = hash.digest('hex');
|
||||||
$ne: Op.ne,
|
return md5
|
||||||
$gte: Op.gte,
|
|
||||||
$gt: Op.gt,
|
|
||||||
$lte: Op.lte,
|
|
||||||
$lt: Op.lt,
|
|
||||||
$not: Op.not,
|
|
||||||
$in: Op.in,
|
|
||||||
$notIn: Op.notIn,
|
|
||||||
$is: Op.is,
|
|
||||||
$like: Op.like,
|
|
||||||
$notLike: Op.notLike,
|
|
||||||
$iLike: Op.iLike,
|
|
||||||
$notILike: Op.notILike,
|
|
||||||
$regexp: Op.regexp,
|
|
||||||
$notRegexp: Op.notRegexp,
|
|
||||||
$iRegexp: Op.iRegexp,
|
|
||||||
$notIRegexp: Op.notIRegexp,
|
|
||||||
$between: Op.between,
|
|
||||||
$notBetween: Op.notBetween,
|
|
||||||
$overlap: Op.overlap,
|
|
||||||
$contains: Op.contains,
|
|
||||||
$contained: Op.contained,
|
|
||||||
$adjacent: Op.adjacent,
|
|
||||||
$strictLeft: Op.strictLeft,
|
|
||||||
$strictRight: Op.strictRight,
|
|
||||||
$noExtendRight: Op.noExtendRight,
|
|
||||||
$noExtendLeft: Op.noExtendLeft,
|
|
||||||
$substring: Op.substring,
|
|
||||||
$startsWith: Op.startsWith,
|
|
||||||
$endsWith: Op.endsWith,
|
|
||||||
$and: Op.and,
|
|
||||||
$or: Op.or,
|
|
||||||
$any: Op.any,
|
|
||||||
$all: Op.all,
|
|
||||||
$values: Op.values,
|
|
||||||
$col: Op.col
|
|
||||||
};
|
|
||||||
return operatorsAliases
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
//定义别名
|
||||||
|
const Sequelize = require("sequelize");
|
||||||
|
module.exports = () => {
|
||||||
|
const Op = Sequelize.Op;
|
||||||
|
//操作符别名
|
||||||
|
const operatorsAliases = {
|
||||||
|
$eq: Op.eq,
|
||||||
|
$ne: Op.ne,
|
||||||
|
$gte: Op.gte,
|
||||||
|
$gt: Op.gt,
|
||||||
|
$lte: Op.lte,
|
||||||
|
$lt: Op.lt,
|
||||||
|
$not: Op.not,
|
||||||
|
$in: Op.in,
|
||||||
|
$notIn: Op.notIn,
|
||||||
|
$is: Op.is,
|
||||||
|
$like: Op.like,
|
||||||
|
$notLike: Op.notLike,
|
||||||
|
$iLike: Op.iLike,
|
||||||
|
$notILike: Op.notILike,
|
||||||
|
$regexp: Op.regexp,
|
||||||
|
$notRegexp: Op.notRegexp,
|
||||||
|
$iRegexp: Op.iRegexp,
|
||||||
|
$notIRegexp: Op.notIRegexp,
|
||||||
|
$between: Op.between,
|
||||||
|
$notBetween: Op.notBetween,
|
||||||
|
$overlap: Op.overlap,
|
||||||
|
$contains: Op.contains,
|
||||||
|
$contained: Op.contained,
|
||||||
|
$adjacent: Op.adjacent,
|
||||||
|
$strictLeft: Op.strictLeft,
|
||||||
|
$strictRight: Op.strictRight,
|
||||||
|
$noExtendRight: Op.noExtendRight,
|
||||||
|
$noExtendLeft: Op.noExtendLeft,
|
||||||
|
$substring: Op.substring,
|
||||||
|
$startsWith: Op.startsWith,
|
||||||
|
$endsWith: Op.endsWith,
|
||||||
|
$and: Op.and,
|
||||||
|
$or: Op.or,
|
||||||
|
$any: Op.any,
|
||||||
|
$all: Op.all,
|
||||||
|
$values: Op.values,
|
||||||
|
$col: Op.col
|
||||||
|
};
|
||||||
|
return operatorsAliases
|
||||||
|
}
|
||||||
+3
-3
@@ -26,7 +26,7 @@ module.exports = class Bamboo extends Koa {
|
|||||||
for (let listElement of list) {
|
for (let listElement of list) {
|
||||||
await listElement.res(this)
|
await listElement.res(this)
|
||||||
}
|
}
|
||||||
this.willReadyList.push(()=>{
|
this.willReadyList.push(() => {
|
||||||
this.startServer()
|
this.startServer()
|
||||||
})
|
})
|
||||||
await this.willReady()
|
await this.willReady()
|
||||||
@@ -36,7 +36,7 @@ module.exports = class Bamboo extends Koa {
|
|||||||
/*扩展已经加载完成触发*/
|
/*扩展已经加载完成触发*/
|
||||||
async willReady() {
|
async willReady() {
|
||||||
for (let WRL of this.willReadyList) {
|
for (let WRL of this.willReadyList) {
|
||||||
WRL()
|
await WRL()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ module.exports = class Bamboo extends Koa {
|
|||||||
if (er) {
|
if (er) {
|
||||||
reject(er)
|
reject(er)
|
||||||
}
|
}
|
||||||
console.log("获取到的文件:", files);
|
// console.log("获取到的文件:", files);
|
||||||
files = files.map(item => {
|
files = files.map(item => {
|
||||||
const parse = path.parse(item);
|
const parse = path.parse(item);
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -483,8 +483,8 @@ module.exports = class Bamboo extends Koa {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数据分组
|
* 仅选择某些属性
|
||||||
* @param {string|array} value 传需要分组的字段['createdAt'].
|
* @param {array} value 仅选择某些属性['foo', ['bar', 'baz'], 'qux'].
|
||||||
*/
|
*/
|
||||||
attributes(value) {
|
attributes(value) {
|
||||||
this.tableAttributes = value
|
this.tableAttributes = value
|
||||||
|
|||||||
Reference in New Issue
Block a user