up
This commit is contained in:
@@ -10,11 +10,9 @@
|
||||
]
|
||||
],
|
||||
"plugins": [
|
||||
[
|
||||
"babel-plugin-webpack-alias",
|
||||
{
|
||||
"config": "./webpack.config.js"
|
||||
}
|
||||
]
|
||||
["@babel/plugin-proposal-decorators",{"legacy": true}],
|
||||
// ["@babel/plugin-proposal-class-properties",{"loose": true}],
|
||||
// ["babel-plugin-webpack-alias", { "config": "./webpack.config.js" } ]
|
||||
|
||||
]
|
||||
}
|
||||
+44
-2
@@ -1,14 +1,56 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
doc : "",
|
||||
doc : "默认页面",
|
||||
path : "/",
|
||||
method : ["get", "post"],
|
||||
middleware: [],
|
||||
params : {},
|
||||
return : {},
|
||||
controller: async (ctx, app) => {
|
||||
// app.err.ParameterException()
|
||||
app.event.emit('test.event2')
|
||||
const where = {
|
||||
// id: 4
|
||||
}
|
||||
const data = {
|
||||
// id: 1,
|
||||
uid: "77",
|
||||
}
|
||||
|
||||
ctx.body = 'index,xe:' + app.utils.VERSION
|
||||
// const User = await app.table("User").where(where).findAll()
|
||||
// const User = await app.table("User").time(["2022-04-9", "2022-04-10"]).findAll()
|
||||
// const User = await app.table("User").where(where).findOrCreate(data)
|
||||
// const {count, rows} = await app.table("User").where(where).findAndCountAll()
|
||||
// const User = await app.table("User").save(data)
|
||||
// const res = {
|
||||
// "创建单个数据" : await app.table("User").data({uid: "6666"}).save(),
|
||||
// "查询单个数据" : await app.table("User").where({id: 2}).find(),
|
||||
// "查询单个数据,不存在就创建" : await app.table("User").where({id: 999}).data({uid: "6666"}).findOrCreate(),
|
||||
// "查询所有数据" : await app.table("User").where({uid: "6666"}).findAll(),
|
||||
// "查询所有数据(时间区间)" : await app.table("User").time(['2022-04-09', '2022-04-10']).findAll(),
|
||||
// "查询所有数据(当月数据)" : await app.table("User").time('month').findAll(),
|
||||
// "查询所有数据(30分钟内的数据)": await app.table("User").time(30).findAll(),
|
||||
// "查询所有数据(分页)" : await app.table("User").where({uid: "6666"}).page(1).limit(1).findAll(),
|
||||
// "查询所有数据+总行数(分页)" : await app.table("User").where({uid: "6666"}).page(1).limit(1).findAndCountAll(),
|
||||
// }
|
||||
|
||||
/*
|
||||
await app.setTransaction() // 设置事务
|
||||
await app.table("User").data({uid: "6666"}).save()
|
||||
await app.table("User").where({id: 2}).find()
|
||||
await app.table("User").data({uid: "6666"}).save()
|
||||
await app.table("User").where({id: 2}).find()
|
||||
await app.commitTransaction() //提交事务,如果设置了事务不提交,任务不会执行
|
||||
*/
|
||||
|
||||
// await app.table("User").where({id: 1032}).data({age: 1}).setInc() // 字段值+1
|
||||
// await app.table("User").where({id: 1032}).data({age: 2}).setInc() // 字段值+2
|
||||
// const {res, value} = await app.table("User").where({id: 1032}).data({age: 2}).setDec(0) // 字段值-2,不能低于0,如果低于0返回false
|
||||
// const {res, value} = await app.table("User").where({id: 1032}).data({age: 2}).setDec(0,10) // 字段值-2,不能低于0,如果低于0设置为10
|
||||
const {res, value} = await app.table("User").where({id: 1032}).data({age: 2}).setInc(20, 10) // 字段值+2,不能大于20,如果大于20设置为10
|
||||
|
||||
|
||||
ctx.body = {res, value}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,44 +1,44 @@
|
||||
class HttpException extends Error {
|
||||
// message为异常信息,errorCode为错误码(开发人员内部约定),code为HTTP状态码
|
||||
constructor(message = '服务器异常', errorCode = 10000, code = 400) {
|
||||
// message为异常信息,code 为错误码(开发人员内部约定),status 为HTTP状态码
|
||||
constructor(message, code, status) {
|
||||
super()
|
||||
this.errorCode = errorCode || 10000
|
||||
this.code = code || 400
|
||||
this.status = status || 500
|
||||
this.code = code || 500
|
||||
this.message = message || '服务器异常'
|
||||
}
|
||||
}
|
||||
|
||||
class ParameterException extends HttpException {
|
||||
constructor(message, errorCode) {
|
||||
constructor(message, code, status) {
|
||||
super()
|
||||
this.errorCode = errorCode || 10000
|
||||
this.code = 400
|
||||
this.status = status || 402
|
||||
this.code = code
|
||||
this.message = message || '参数错误'
|
||||
}
|
||||
}
|
||||
|
||||
class NotFound extends HttpException {
|
||||
constructor(message, errorCode) {
|
||||
constructor(message, code, status) {
|
||||
super()
|
||||
this.errorCode = errorCode || 10001
|
||||
this.status = status || 404
|
||||
this.code = 404
|
||||
this.message = message || '资源未找到'
|
||||
}
|
||||
}
|
||||
|
||||
class AuthFailed extends HttpException {
|
||||
constructor(message, errorCode) {
|
||||
constructor(message, code, status) {
|
||||
super()
|
||||
this.errorCode = errorCode || 10002
|
||||
this.status = status || 401
|
||||
this.message = message || '授权失败'
|
||||
this.code = 401
|
||||
}
|
||||
}
|
||||
|
||||
class Forbidden extends HttpException {
|
||||
constructor(message, errorCode) {
|
||||
constructor(message, code, status) {
|
||||
super()
|
||||
this.errorCode = errorCode || 10003
|
||||
this.status = status || 403
|
||||
this.message = message || '禁止访问'
|
||||
this.code = 403
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
'use strict';
|
||||
// 监听事件
|
||||
module.exports = {
|
||||
"event1": (args) => {
|
||||
console.log(args || 'event1')
|
||||
},
|
||||
"event2": (args) => {
|
||||
console.log(args || 'event2')
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/*系统启动后要做初始化*/
|
||||
module.exports = (app) => {
|
||||
console.log("启动完成");
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
'use strict';
|
||||
const error = require('koa-json-error')
|
||||
// 错误处理
|
||||
module.exports = error((err) => {
|
||||
return {
|
||||
status : err.status,
|
||||
message : err.message,
|
||||
code : err.code,
|
||||
res : false,
|
||||
// postFormat: (e, obj) => process.env.NODE_ENV === 'production' ? _.omit(obj, 'stack') : obj
|
||||
}
|
||||
})
|
||||
@@ -5,7 +5,6 @@ module.exports = async (ctx, next, app) => {
|
||||
// const timetaken = `${ctx.request.method}${ctx.request.url} 响应时间`
|
||||
// console.time(timetaken)
|
||||
// app.logger.debug("123")
|
||||
throw new app.err.HttpException
|
||||
await next()
|
||||
// console.timeEnd(timetaken)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
doc : "用户",
|
||||
model: {
|
||||
uid: {type: "STRING", comment: '用户id'},
|
||||
age: {type: "INTEGER", comment: '年龄', defaultValue: 0,},
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
'use strict';
|
||||
// 监听事件
|
||||
module.exports = {
|
||||
time : "*/3 * * * * *",
|
||||
run : true,//系统启动时立即执行一次
|
||||
schedule: (app) => {
|
||||
// console.log('每3秒我执行一次' + app.utils.VERSION)
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
doc : "mysql模型文件的m5记录",
|
||||
model: {
|
||||
fileName: {type: "STRING", comment: '文件名称'},
|
||||
md5 : {type: "TEXT", comment: 'md5记录'},
|
||||
md5json : {type: "JSON", comment: 'md5记录'},
|
||||
}
|
||||
}
|
||||
@@ -1 +1,57 @@
|
||||
/*数据库配置*/
|
||||
module.exports = {
|
||||
mysql: {
|
||||
database: "bamboo",
|
||||
username: "bamboo",
|
||||
password: "bamboo",
|
||||
options : {
|
||||
dialect: 'mysql',
|
||||
host : "192.168.1.26",
|
||||
port : 3306,
|
||||
// 禁用日志记录或提供自定义日志记录功能;默认值:console.log
|
||||
// logging: false,
|
||||
// model的全局配置
|
||||
define: {
|
||||
// 添加create,update,delete时间戳
|
||||
timestamps: true,
|
||||
// 添加软删除
|
||||
paranoid: false,
|
||||
// 防止修改表名为复数
|
||||
freezeTableName: true,
|
||||
// 防止驼峰式字段被默认转为下划线
|
||||
underscored: false,
|
||||
},
|
||||
// 由于orm用的UTC时间,这里必须加上东八区,否则取出来的时间相差8小时
|
||||
timezone: '+08:00',
|
||||
// 连接数 = ((核心数 * 2) + 有效磁盘数)
|
||||
pool : {// 连接池
|
||||
max : require('os').cpus().length * 2 + 1,
|
||||
min : 0,
|
||||
acquire: 60000,
|
||||
idle : 100000,
|
||||
},
|
||||
dialectOptions: {
|
||||
charset : "utf8mb4",
|
||||
collate : "utf8mb4_general_ci",
|
||||
supportBigNumbers: true,
|
||||
bigNumberStrings : true,
|
||||
dateStrings : true,
|
||||
typeCast(field, next) {// 让读取date类型数据时返回字符串而不是UTC时间
|
||||
if (field.type === 'DATETIME') {
|
||||
// console.log(field);
|
||||
return field.string();
|
||||
}
|
||||
return next();
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
redis:{},
|
||||
sqlite:{
|
||||
dialect: 'sqlite',
|
||||
storage: 'app/sqlite/database.sqlite',
|
||||
logging: false,
|
||||
},
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
/*redis配置*/
|
||||
module.exports = {
|
||||
port: 3000,
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
const Bamboo = require("./index")
|
||||
|
||||
module.exports = class DB extends Bamboo {
|
||||
|
||||
constructor() {super();}
|
||||
|
||||
|
||||
}
|
||||
+755
-11
@@ -4,25 +4,66 @@ import Koa from 'koa';
|
||||
//https://x-extends.gitee.io/xe-utils/#/
|
||||
import xe from 'xe-utils'
|
||||
|
||||
const fs = require('fs'); // 文件模块
|
||||
const log4js = require("log4js");
|
||||
const path = require('path')
|
||||
const error = require('./errorException')
|
||||
const requireDirectory = require("require-directory");
|
||||
const Router = require("koa-router");
|
||||
|
||||
const EventEmitter = require('events');
|
||||
const schedule = require("node-schedule");
|
||||
const Sequelize = require("sequelize");
|
||||
|
||||
module.exports = class Bamboo extends Koa {
|
||||
constructor(agrs, options) {
|
||||
super(options)
|
||||
super.on('error', (err, ctx) => this.serverError(err, ctx));
|
||||
this.asyncStatus = {} //异步启动状态
|
||||
this.fulfill = false //启动完成
|
||||
this.modelAmend = false //模型文件是否有改动
|
||||
this.config = {}
|
||||
this.utils = this.registeredContextUtils(xe)
|
||||
this.logger = null
|
||||
this.Sequelize = null
|
||||
this.mysql = null
|
||||
this.sqlite = null
|
||||
this.event = new EventEmitter()
|
||||
this.registeredConfig()
|
||||
this.setLogger()
|
||||
this.registeredError()
|
||||
this.initDB()
|
||||
this.registeredMiddleware()
|
||||
this.registeredRouter()
|
||||
this.listen(8884)
|
||||
this.init()
|
||||
|
||||
}
|
||||
|
||||
init() {
|
||||
const initInterval = setInterval(() => {
|
||||
console.log('启动中...');
|
||||
const asyncStatusList = xe.toArray(this.asyncStatus)
|
||||
console.log(this.asyncStatus);
|
||||
console.log(asyncStatusList);
|
||||
const asyncStatus = asyncStatusList.filter(item => item === 0)
|
||||
if (asyncStatus.length === 0) {
|
||||
this.fulfill = true
|
||||
const init = require(this.path('app/init.js'));
|
||||
init(this.application)
|
||||
this.onFulfill()
|
||||
clearInterval(initInterval)
|
||||
}
|
||||
}, 1000)
|
||||
|
||||
}
|
||||
|
||||
async initDB() {
|
||||
await this.registeredSqlite()
|
||||
await this.registeredDB()
|
||||
}
|
||||
|
||||
//启动完成事件
|
||||
onFulfill() {
|
||||
this.registeredEvent()
|
||||
this.registeredSchedule()
|
||||
}
|
||||
|
||||
listen(args) {
|
||||
@@ -42,26 +83,240 @@ module.exports = class Bamboo extends Koa {
|
||||
this.config = hash
|
||||
}
|
||||
|
||||
//注册 错误
|
||||
registeredError() {
|
||||
console.log('注册 错误');
|
||||
this.errorException = {}
|
||||
const hash = requireDirectory(module, this.path('app/err'), {
|
||||
visit: (obj) => {
|
||||
for (let key of Object.keys(obj)) {
|
||||
this.errorException[key] = (message, code) => {
|
||||
throw new obj[key](message, code)
|
||||
}
|
||||
}
|
||||
return obj
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
//注册 mysql数据库
|
||||
async registeredDB() {
|
||||
console.log('注册 数据库');
|
||||
this.asyncStatus['registeredDB'] = 0
|
||||
const {
|
||||
database,
|
||||
username,
|
||||
password,
|
||||
options,
|
||||
} = this.config.database.mysql
|
||||
this.Sequelize = Sequelize
|
||||
|
||||
const sequelize = new Sequelize(database, username, password, {
|
||||
...options,
|
||||
operatorsAliases: this.operatorsAliases
|
||||
});
|
||||
try {
|
||||
await sequelize.authenticate();
|
||||
console.log('数据库连接成功');
|
||||
} catch (error) {
|
||||
console.error('数据库连接失败', error);
|
||||
}
|
||||
|
||||
|
||||
requireDirectory(module, this.path('app/model'), {
|
||||
visit: (obj, joined, filename) => {
|
||||
const parse = path.parse(filename);
|
||||
const model = {}
|
||||
for (let key of Object.keys(obj.model)) {
|
||||
obj.model[key].type = this.Sequelize[obj.model[key].type]
|
||||
model[key] = obj.model[key]
|
||||
}
|
||||
model['id'] = {
|
||||
type : this.Sequelize.INTEGER,
|
||||
comment : '表自增id',
|
||||
allowNull : false,
|
||||
unique : 'id',
|
||||
primaryKey : true,
|
||||
autoIncrement: true,
|
||||
}
|
||||
|
||||
sequelize.define(parse.name, model)
|
||||
return obj
|
||||
}
|
||||
});
|
||||
this.mysql = sequelize
|
||||
console.log('this.modelAmend', this.modelAmend);
|
||||
if (this.modelAmend) {
|
||||
console.log('生成模型结构到数据库');
|
||||
await sequelize.sync({alter: true});
|
||||
}
|
||||
this.asyncStatus['registeredDB'] = 1
|
||||
}
|
||||
|
||||
//注册 sqlite 数据库(记录model文件是否有改动,如果有就同步模型到mysql数据库)
|
||||
async registeredSqlite() {
|
||||
console.log('注册 sqlite 数据库');
|
||||
this.asyncStatus['registeredSqlite'] = 0
|
||||
const sqlite = new Sequelize(this.config.database.sqlite);
|
||||
try {
|
||||
await sqlite.authenticate();
|
||||
console.log('sqlite数据库连接成功');
|
||||
} catch (error) {
|
||||
console.error('sqlite数据库连接失败', error);
|
||||
}
|
||||
|
||||
// const MysqlMD5 = sqlite.define('MysqlMD5', {
|
||||
// fileName: Sequelize.STRING,
|
||||
// md5 : Sequelize.TEXT
|
||||
// });
|
||||
requireDirectory(module, this.path('app/sqlite/model'), {
|
||||
visit: (obj, joined, filename) => {
|
||||
const parse = path.parse(filename);
|
||||
const model = {}
|
||||
for (let key of Object.keys(obj.model)) {
|
||||
obj.model[key].type = Sequelize[obj.model[key].type]
|
||||
model[key] = obj.model[key]
|
||||
}
|
||||
sqlite.define(parse.name, model)
|
||||
return obj
|
||||
}
|
||||
});
|
||||
await sqlite.sync({alter: true});
|
||||
const {MysqlMD5} = sqlite.models
|
||||
this.modelAmend = true
|
||||
requireDirectory(module, this.path('app/model'), {
|
||||
visit: async (obj, joined, filename) => {
|
||||
const parse = path.parse(filename);
|
||||
const md5 = this.getFileMd5(this.path('app/model/') + filename)
|
||||
const MysqlMD5Data = await MysqlMD5.findOne({where: {fileName: 'User'}})
|
||||
if (!MysqlMD5Data) {
|
||||
this.modelAmend = true
|
||||
await MysqlMD5.create({fileName: parse.name, md5: md5})
|
||||
}
|
||||
else {
|
||||
if (MysqlMD5Data.md5 !== md5) {
|
||||
console.log('有改动的模型', MysqlMD5Data.fileName);
|
||||
this.modelAmend = true
|
||||
MysqlMD5.update({md5}, {where: {fileName: 'User'}})
|
||||
|
||||
}
|
||||
}
|
||||
return obj
|
||||
}
|
||||
});
|
||||
|
||||
this.sqlite = sqlite
|
||||
this.asyncStatus['registeredSqlite'] = 1
|
||||
}
|
||||
|
||||
get operatorsAliases() {
|
||||
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
|
||||
}
|
||||
|
||||
//文件md5值
|
||||
getFileMd5(url) {
|
||||
const buffer = fs.readFileSync(url);
|
||||
const hash = require('crypto').createHash('md5');
|
||||
hash.update(buffer, 'utf8');
|
||||
const md5 = hash.digest('hex');
|
||||
return md5
|
||||
}
|
||||
|
||||
//注册 router
|
||||
registeredRouter() {
|
||||
console.log('注册 router');
|
||||
const router = new Router();
|
||||
const hash = requireDirectory(module, this.path('app/controller'), {
|
||||
visit: (c) => {
|
||||
for (let methodElement of c.method) {
|
||||
router[methodElement](c.path, async (ctx, next) => {
|
||||
visit: (obj) => {
|
||||
for (let methodElement of obj.method) {
|
||||
router[methodElement](obj.path, async (ctx, next) => {
|
||||
ctx['logger'] = this.logger
|
||||
await c.controller(ctx, this.application)
|
||||
await obj.controller(ctx, this.application)
|
||||
next();
|
||||
});
|
||||
}
|
||||
return c
|
||||
return obj
|
||||
}
|
||||
});
|
||||
super.use(router.routes())
|
||||
super.use(router.allowedMethods())
|
||||
}
|
||||
|
||||
//注册 事件
|
||||
registeredEvent() {
|
||||
console.log('注册 事件');
|
||||
const hash = requireDirectory(module, this.path('app/event'), {
|
||||
visit: (obj, joined, filename) => {
|
||||
const parse = path.parse(filename);
|
||||
// super.on(parse.name, obj);
|
||||
for (let key of Object.keys(obj)) {
|
||||
this.event.on(`${parse.name}.${key}`, obj[key]);
|
||||
}
|
||||
|
||||
return obj
|
||||
}
|
||||
});
|
||||
console.log(this.event.listeners);
|
||||
}
|
||||
|
||||
//注册 定时任务
|
||||
registeredSchedule() {
|
||||
console.log('注册 定时任务');
|
||||
const hash = requireDirectory(module, this.path('app/schedule'), {
|
||||
visit: (obj, joined, filename) => {
|
||||
//https://www.cnblogs.com/yalong/p/15601391.html
|
||||
if (!process.env.NODE_APP_INSTANCE || process.env.NODE_APP_INSTANCE === '0') { //防止pm2多个线程重复执行
|
||||
const parse = path.parse(filename);
|
||||
if (obj.run) { obj.schedule(this.application) }
|
||||
schedule.scheduleJob(parse.name, obj.time, () => obj.schedule(this.application))
|
||||
}
|
||||
return obj
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//注册 middleware
|
||||
registeredMiddleware() {
|
||||
console.log('注册 middleware');
|
||||
@@ -78,7 +333,7 @@ module.exports = class Bamboo extends Koa {
|
||||
return obj
|
||||
}
|
||||
});
|
||||
console.log(hash);
|
||||
// console.log(hash);
|
||||
}
|
||||
|
||||
//注册 utils
|
||||
@@ -119,11 +374,500 @@ module.exports = class Bamboo extends Koa {
|
||||
return xe
|
||||
}
|
||||
|
||||
resetDbData() {
|
||||
this.tableData = null
|
||||
this.tableWhere = null
|
||||
this.tablePage = null
|
||||
this.tableLimit = null
|
||||
this.tableOrder = null
|
||||
this.tableGroup = null
|
||||
this.tableAttributes = null
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定表名
|
||||
* @param {object} data 表名.
|
||||
*/
|
||||
table(data) {
|
||||
this.tableName = data
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置事务
|
||||
*/
|
||||
async setTransaction() {
|
||||
console.log("设置事务");
|
||||
this.t = await this.mysql.transaction()
|
||||
return this.t
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交事务,如果设置了事务不提交,任务不会执行
|
||||
*/
|
||||
async commitTransaction() {
|
||||
try {
|
||||
await this.t.commit()
|
||||
} catch (error) {
|
||||
await this.t.rollback()
|
||||
}
|
||||
this.t = null
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 筛选条件
|
||||
* @param {object} data 筛选条件对象.
|
||||
*/
|
||||
where(data) {
|
||||
this.tableWhere = data
|
||||
return this
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 模糊查询
|
||||
* @param {string} value 模糊查询内容.
|
||||
* @param {array} searchData 模糊查询搜索的字段(默认表的全部字段).
|
||||
*/
|
||||
search(value, searchData) {
|
||||
if (!this.tableName) { this.errorException.HttpException("请传表名") }
|
||||
if (!this.tableWhere) { this.tableWhere = {} }
|
||||
if (!this.tableWhere['$or']) {
|
||||
this.tableWhere['$or'] = []
|
||||
}
|
||||
if (!searchData) {
|
||||
searchData = Object.keys(this.mysql.models[this.tableName].rawAttributes)
|
||||
}
|
||||
for (let key of searchData) {
|
||||
const search = {}
|
||||
search[key] = {"$substring": value || ''}
|
||||
this.tableWhere['$or'].push(search)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 数据分组
|
||||
* @param {string|array} value 传需要分组的字段['createdAt'].
|
||||
*/
|
||||
group(value) {
|
||||
this.tableGroup = value
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据分组
|
||||
* @param {string|array} value 传需要分组的字段['createdAt'].
|
||||
*/
|
||||
attributes(value) {
|
||||
this.tableAttributes = value
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 页数
|
||||
* @param {int} value 页数从0开始.
|
||||
*/
|
||||
|
||||
page(value) {
|
||||
this.tablePage = value
|
||||
return this
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 条数
|
||||
* @param {int} value 条数.
|
||||
*/
|
||||
limit(value) {
|
||||
this.tableLimit = value
|
||||
return this
|
||||
}
|
||||
|
||||
get getLimit() {
|
||||
return this.tableLimit || null
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据
|
||||
* @param {any} value 数据.
|
||||
*/
|
||||
data(value) {
|
||||
this.tableData = value
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间排序
|
||||
* @param {array} value 时间排序(默认按更新时间排序).
|
||||
*/
|
||||
order(value) {
|
||||
this.tableOrder = value
|
||||
return this
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 字段值增加
|
||||
* @param {string} data 要增加的字段和值{xxx:1,xxxx:2}.
|
||||
* @param {number} max 字段增加后的值不能大于最大值
|
||||
* @param {number} setValue 如果增加后的字段大于max,设置字段值为n
|
||||
*/
|
||||
async setInc(max, setValue) {
|
||||
if (!this.tableName) { this.errorException.HttpException("请传表名") }
|
||||
if (!this.tableData) { this.errorException.HttpException("请数据") }
|
||||
if (!this.tableWhere) { this.errorException.HttpException("请筛选值") }
|
||||
|
||||
let res = await this.mysql.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.mysql.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.mysql.models[this.tableName].increment(
|
||||
this.tableData,
|
||||
{
|
||||
where : this.tableWhere,
|
||||
transaction: this.t
|
||||
}
|
||||
)
|
||||
|
||||
res = await this.mysql.models[this.tableName].findOne(
|
||||
{
|
||||
where : this.tableWhere,
|
||||
transaction: this.t
|
||||
}
|
||||
)
|
||||
return {res: true, value: res.dataValues}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 字段值减小
|
||||
* @param {string} data 要减小的字段和值{xxx:1,xxxx:2}.
|
||||
* @param {number} min 字段减小后的值不能小于最小值
|
||||
* @param {number} setValue 如果减小后的字段小于min,设置字段值为n
|
||||
*/
|
||||
async setDec(min, setValue) {
|
||||
if (!this.tableName) { this.errorException.HttpException("请传表名") }
|
||||
if (!this.tableData) { this.errorException.HttpException("请数据") }
|
||||
if (!this.tableWhere) { this.errorException.HttpException("请筛选值") }
|
||||
|
||||
let res = await this.mysql.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.mysql.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.mysql.models[this.tableName].decrement(
|
||||
this.tableData,
|
||||
{
|
||||
where : this.tableWhere,
|
||||
transaction: this.t
|
||||
}
|
||||
)
|
||||
|
||||
res = await this.mysql.models[this.tableName].findOne(
|
||||
{
|
||||
where : this.tableWhere,
|
||||
transaction: this.t
|
||||
}
|
||||
)
|
||||
return {res: true, value: res.dataValues}
|
||||
}
|
||||
|
||||
/**
|
||||
* 常用时间筛选
|
||||
* @param {string|array|Number} value 时间内容:按时间段:['2000-1-1','2000-1-2'],按常用时间:day,按最近60分钟:60.
|
||||
* @param {string} field 时间字段(默认createdAt字段)
|
||||
*/
|
||||
time(value, field) {
|
||||
if (!this.tableName) { this.errorException.HttpException("请传表名") }
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询1条数据
|
||||
* @param {Transaction} options.transaction 运行查询的事务.
|
||||
*/
|
||||
async find(options) {
|
||||
if (!this.tableName) { this.errorException.HttpException("请传表名") }
|
||||
const res = await this.mysql.models[this.tableName].findOne(
|
||||
{
|
||||
where : this.tableWhere,
|
||||
transaction: this.t
|
||||
}
|
||||
)
|
||||
this.resetDbData()
|
||||
return res && res.dataValues || null
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新数据
|
||||
* @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) { this.errorException.HttpException("请传表名") }
|
||||
if (!this.tableData) { this.errorException.HttpException("请数据") }
|
||||
const res = await this.mysql.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) { this.errorException.HttpException("请传表名") }
|
||||
const res = await this.mysql.models[this.tableName].destroy(
|
||||
{
|
||||
where: this.tableWhere,
|
||||
...options
|
||||
}
|
||||
)
|
||||
return res
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存数据,如果数据已存在就更新,否则创建数据,可以传对象或数组,如果是需要更新数据,必须包含id
|
||||
*/
|
||||
async save() {
|
||||
if (!this.tableName) { this.errorException.HttpException("请传表名") }
|
||||
if (!this.tableData) { this.errorException.HttpException("请传要保存的数据") }
|
||||
let data = this.tableData
|
||||
let updateOnDuplicate = []
|
||||
let keyData = {}
|
||||
if (xe.isArray(data)) {
|
||||
if (!data.length) { this.errorException.HttpException("请传要保存的数据") }
|
||||
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.mysql.models[this.tableName].bulkCreate(data,
|
||||
{returning: true, updateOnDuplicate: updateOnDuplicate, transaction: this.t}
|
||||
)
|
||||
this.resetDbData()
|
||||
return res
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询所有符合条件的数据
|
||||
* @return {array} dataValues 查询结果.
|
||||
*/
|
||||
async findAll() {
|
||||
if (!this.tableName) { this.errorException.HttpException("请传表名") }
|
||||
const res = await this.mysql.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.resetDbData()
|
||||
return res.map(item => item.dataValues)
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果数据不存在就创建数据,否则反查询结果
|
||||
* @return {object} dataValues 查询结果.
|
||||
*/
|
||||
async findOrCreate() {
|
||||
if (!this.tableName) { this.errorException.HttpException("请传表名") }
|
||||
if (!this.tableData) { this.errorException.HttpException("请传data") }
|
||||
const res = await this.mysql.models[this.tableName].findOrCreate(
|
||||
{
|
||||
defaults : this.tableData,
|
||||
where : this.tableWhere,
|
||||
transaction: this.t
|
||||
}
|
||||
)
|
||||
this.resetDbData()
|
||||
return res
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 分页查询数据
|
||||
* @param {array} args.include 关联查询.
|
||||
* @return {int} count 总行数.
|
||||
* @return {array} rows 数据列表.
|
||||
*/
|
||||
async findAndCountAll(args = {}) {
|
||||
if (!this.tableName) { this.errorException.HttpException("请传表名") }
|
||||
const {count, rows} = await this.mysql.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.resetDbData()
|
||||
return {count, rows: rows.map(item => item.dataValues)}
|
||||
}
|
||||
|
||||
get application() {
|
||||
return {
|
||||
config : this.config,
|
||||
utils : this.utils,
|
||||
logger: this.logger,
|
||||
err : error,
|
||||
log : this.logger,
|
||||
err : this.errorException,
|
||||
event : this.event,
|
||||
sequelize : this.Sequelize,
|
||||
mysql : this.mysql,
|
||||
sqlite : this.sqlite,
|
||||
table : this.table,
|
||||
where : this.where,
|
||||
data : this.data,
|
||||
search : this.search,
|
||||
group : this.group,
|
||||
attributes : this.attributes,
|
||||
page : this.page,
|
||||
setDec : this.setDec,
|
||||
setInc : this.setInc,
|
||||
limit : this.limit,
|
||||
time : this.time,
|
||||
setTransaction : this.setTransaction,
|
||||
commitTransaction: this.commitTransaction,
|
||||
save : this.save,
|
||||
find : this.find,
|
||||
findAll : this.findAll,
|
||||
findOrCreate : this.findOrCreate,
|
||||
findAndCountAll : this.findAndCountAll,
|
||||
resetDbData : this.resetDbData,
|
||||
//======= 简写函数
|
||||
// S: this.sqlite.models,
|
||||
// M: this.mysql.models,
|
||||
C: this.config,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.5.5",
|
||||
"@babel/plugin-proposal-class-properties": "^7.16.7",
|
||||
"@babel/plugin-proposal-decorators": "^7.17.9",
|
||||
"@babel/plugin-transform-runtime": "^7.5.5",
|
||||
"@babel/preset-env": "^7.5.5",
|
||||
"@babel/register": "^7.5.5",
|
||||
@@ -44,13 +46,18 @@
|
||||
"clean-webpack-plugin": "^4.0.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"koa-bodyparser": "^4.3.0",
|
||||
"koa-json-error": "^3.1.2",
|
||||
"koa-logger": "^2.0.1",
|
||||
"koa-redis": "^4.0.1",
|
||||
"log4js": "^6.4.4",
|
||||
"mysql2": "^2.3.3",
|
||||
"node-schedule": "^2.1.0",
|
||||
"pm2": "^5.1.2",
|
||||
"require-all": "^3.0.0",
|
||||
"require-directory": "^2.1.1",
|
||||
"sequelize": "^6.18.0",
|
||||
"shelljs": "^0.8.5",
|
||||
"sqlite3": "^5.0.2",
|
||||
"webpack": "^4.41.5",
|
||||
"webpack-cli": "3.3.10",
|
||||
"webpack-node-externals": "^3.0.0",
|
||||
|
||||
Reference in New Issue
Block a user