1.3.1 • Published 2 years ago

koa-decorator-resolver v1.3.1

Weekly downloads
-
License
MIT
Repository
github
Last release
2 years ago

koa-decorator-resolver :zap:

这是一个可以在koa框架中使用装饰器的解决方案

license:MIT version:1.3.x


// 测试基于以下版本,取自2022/8/2最新版本
{
  "dependencies": {
    "@types/jest": "^27.4.1",
    "@types/request": "^2.48.8",
    "chalk": "^2.4.1",
    "console-writer": "^1.0.0-beta.1.1",
    "crypto-js": "^4.1.1",
    "exceljs": "^4.3.0",
    "fs-extra": "^10.0.0",
    "jest": "^27.5.1",
    "jest-fast-config": "^1.0.3",
    "jest-html-reporter": "^3.4.2",
    "koa": "^2.13.4",
    "koa-body": "^5.0.0",
    "koa-bodyparser": "^4.3.0",
    "koa-decorator-resolver": "^1.2.5",
    "koa-router": "^12.0.0",
    "koa-send": "^5.0.1",
    "koa-websocket": "^7.0.0",
    "lodash": "^4.17.21",
    "moment": "^2.23.0",
    "mysql2": "^2.3.3",
    "request": "^2.88.2",
    "require-all": "^3.0.0",
    "sequelize": "^6.21.3",
    "sqlite": "^4.0.23",
    "sqlite3": "^5.0.11",
    "ts-jest": "^27.1.4",
    "ts-node": "^10.9.1",
    "tsconfig-paths": "^4.0.0",
    "typescript": "^4.7.4",
    "uuid": "^8.3.2",
    "xlsx": "^0.17.4"
  },
  "devDependencies": {
    "@types/node": "^10.17.44",
    "chai": "^4.3.4",
    "copy": "^0.3.2",
    "dotenv": "^10.0.0",
    "dotenv-cli": "^6.0.0",
    "mocha": "^9.1.3",
    "nodemon": "^2.0.15",
    "npm-run-all": "^4.1.5",
    "nyc": "^15.1.0",
    "ts-mocha": "^8.0.0"
  }
}

安装

# 安装依赖
npm install koa-decorator-resolve 

数据库支持

# 如果要用到mysql数据库,则需要安装驱动,如下:
npm install mysql2@2.x.x

# 如果要用到postgres数据库,则需要安装驱动,如下:
npm install pg@7.x.x pg-hstore@2.x.x

# 如果要用到sqlite数据库,则需要安装驱动,如下:
npm install sqlite@4.x.x sqlite3@5.x.x

完全依赖于Sequelize对数据库的支持,详细参照:https://www.sequelize.com.cn/

默认请求

不需要定义restful,单纯的通过定义类和函数的方式自动解析成restful请求,请求的Url格式是“类名/函数名”,默认解析成的是Post,如果想要解析成Get或其他请求可以通过自定义插件的方式生成相应装饰器来解决。

使用方法

  • 文件: index.ts
// 这是koa工程的入口文件
import * as Koa from 'koa';
import * as Router from 'koa-router';
import { routeBinder } from 'koa-decorator-resolve';
import * as serviceModules from './serviceModules';
const router = new Router();
// 把模块注册在路由上
routeBinder(router,serviceModules);
app.use(router.routes());
app.listen(8080, () => {
    console.log('server start on 8080');
});
  • 文件: serviceModules.ts
// 这是注册在路由上的模块列表
export class serviceModule1 {
    func1(data){
        return {name:data.name + ' func1',msg:'success'}
    }
    func2(data){
        return {name:data.name + ' func2',msg:'success'}
    }
}
export class serviceModule2 {
    func3(data){
        return {name:data.name + ' func3',msg:'success'}
    }
}
  • 在前端发送几个请求
    // 通过“类名/函数”就可以发送出去
    axios.post('/serviceModule1/func1',{name:'m1f1'}).then(res=>{
        console.log(res); // 结果 : {name:'m1f1 func1',msg'success'}
    })
    axios.post('/serviceModule2/func3',{name:'m2f3'}).then(res=>{
        console.log(res); // 结果 : {name:'m2f3 func3',msg'success'}
    })

定义插件

自定义装饰器,用来扩展一些功能

1. 定义装饰器和插件函数
  • 文件: plugins.ts
// 这个文件用于配置和注册插件
import {injectorBuilder,Injector,ModuleFuncArgsType} from 'koa-decorator-resolve';
// 定义装饰器
type Option = {value:string}
// Transfer是装饰器名
export const Transfer: Injector<Option> = injectorBuilder('Transfer');
// 配置装饰器
export const config = {
    Transfer: { // Transfer是装饰器名,一定要与injectorBuilder里参数中的名字一致
        method: 'get', // 被装饰的方法反射的restful类型,默认是post,如果一个方法有多个装饰插件,则以第一个为主
        before: { // 被装饰方法执行前,所执行的钩子方法
            plugin: (ctx: any, option?: Option) => {
                return {'transfer-before':option.value};
            },
            replaceProps: true, // 是否把钩子方法的返回值替换给被装饰方法的第一个参数
        },
        after: { //  被装饰方法执行结束后,所执行的钩子方法
            plugin: (res: any, ctx: any, option?: Option) => {
                return {'transfer-after':res}
            },
            replaceProps: true, // 是否把钩子方法的返回值替换给请求返回值的body
        },
        intercept: (func: (...args: ModuleFuncArgsType) => any, args: ModuleFuncArgsType, option?: Option) => {
            // 拦截器钩子,如果多个装饰器定义了拦截器钩子,只生效第一个
            return func(...args)
        }
    }
}
2. 注册插件
  • 文件: index.ts
// the entry of project
import * as Koa from 'koa';
import * as Router from 'koa-router';
import {routeBinder} from 'koa-decorator-resolve';
import * as serviceModules from './serviceModules';
import {config} from './plugins'; // 上一步定义的插件配置
const router = new Router();
// 通过注册路由方法的第三个参数注册插件
routeBinder(router,serviceModules,config);
app.use(router.routes());
app.listen(8080, () => {
    console.log('server start on 8080');
});
3. 使用装饰器
  • 文件: serviceModules.ts
// the restful modules
import {Transfer} from './plugins';
export class serviceModule {
    // 用定义的装饰器直接注解方法
    @Transfer({value:123})
    func(data){
        // 根据上面的逻辑,data的值 : {'transfer-before':123}
        return 456
    }
    // 根据上面的逻辑,请求response的值 : {'transfer-after':456}
}

使用数据库

通过装饰器注入数据库实例

配置数据库

创建数据库连接实例

首先要创建数据库连接

  • 文件: initTables.ts
// 引入sequelize的类型
import { STRING, INTEGER, BIGINT, DATE, TIME, DATEONLY, BOOLEAN, FLOAT, DOUBLE } from 'sequelize';
// 引入定义函数
import {defineTables} from 'koa-decorator-resolve';
// 以下是表模型的构造器
export const tablesStructure = {
    ACCESS:[{
        id: {
          type: BIGINT,
          primaryKey: true,
        },
        user_name: STRING(20),
        role: STRING(4),
        access: INTEGER,
        begin_date: DATE,
        end_date: DATE,
    }, {version: true}],
    USER:[{
        user_id: {
          type: BIGINT,
          primaryKey: true,
        },
        user_name: STRING(20),
        password: STRING(20)
    }, {version: true}],
}
// 表与表的关系模型可以定义在这里,基于sequelize的关系模型定义方式
export const relationCallback = (tables) => {
    tables.ACCESS.hasOne(tables.USER);
    // ...
}
export const {
    Database, // 装饰器
    connect // 连接函数(下面参数useAlwaysConnection=true的场合需要在入口手动调用这个函数来创建连接)
} = new defineTables(tablesStructure, relationCallback, {
    // 使用长连接,短连接是每次执行方法的时候连接一次,执行完释放连接
    useAlwaysConnection: false, // 默认false
    // // 是否使用基础配置文件(基础配置方式请查看文档最后的说明)
    // useBaseConfig: false, // 默认true
    // 直接传入sequelize参数, 数组内为实例化sequelize的参数,详细参数用法,请参照sequelize库
    sequelizeArgs: [
      "default_db",
      "root",
      "root",
      {
        host: "localhost",
        port: 3306,
        dialect: "mysql",
      },
    ]
});
调用Sequelize数据库关系模型库

装饰器注入DB实例

// the restful modules
import {OrmSequelize} from 'koa-decorator-resolve';
import {Database,tablesStructure} from './initTables';
export class serviceModule extends OrmSequelize<typeof tablesStructure> {
    @Database({
        tables: ['ACCESS','USER'],
        relation: (tables) => {
            // 配合tables用于动态表关联
        }
    })
    async func(data){
        return await this.db.tables.ACCESS.findAll() // 通过表模型直接操作数据库,参照Sequelize
    }
}
开启事务

事务中,成功commit,异常rollback

// the restful modules
import {OrmSequelize} from 'koa-decorator-resolve';
import {Database,tablesStructure} from './initTables';
export class serviceModule extends OrmSequelize<typeof tablesStructure> {
    @Sqlite({
        useTransaction:true // 开启事务
    })
    async func(data){
        return await this.db.tables.ACCESS.findAll()
    }
}

文件配置数据库

通过配置文件配置数据库 1. useBaseConfig = true 使用基本配置

import {defineTables} from 'koa-decorator-resover';
export const {Database,connect} = new defineTables(tablesStructure, relationCallback, {
    // 是否使用基础配置文件
    useBaseConfig: true, // 默认true
    // 注意: sequelizeArgs参数不能添加,否则会优先于sequelizeArgs对数据库的配置
});
# 在工程根目录下的.env文件中配置当前连接到哪个数据库,每个数据库有单独的配置文件,短连接的时候支持热替换(服务运行当中替换数据库)
[base] -- .env
     | -- db.mysql.js
     | -- db.postgres.js

# 以下是.env文件的格式
--------------------------------
| # 此时加载根目录下的db.mysql.js, 如果DB_DRIVER=postgres则会加载根目录下的db.postgres.js文件
| # DB_DRIVER=mysql
--------------------------------
// db.mysql.js 和 db.postgres.js的配置方法
module.exports = {
    database: 'test_db',
    username: 'test_user',
    password: 'test_pw',
    host: 'localhost',
    port: 2001,
    pool: { // 池化参数同样参照sequelize
        max: 5,
        min: 0,
        acquire: 30000,
        idle: 10000,
    };
}
// db.sqlite.js文件的配置方法
module.exports = {
    path: '/etc/test.db',
    pool: { // 池化参数同样参照sequelize
        max: 5,
        min: 0,
        acquire: 30000,
        idle: 10000,
    };
}

注意:基本配置只支持mysql、postgres、sqlite

  1. useBaseConfig = false 使用标准配置
import {defineTables} from 'koa-decorator-resover';
export const {Database,connect} = new defineTables(tablesStructure, relationCallback, {
    // 是否使用基础配置文件
    useBaseConfig: false, // 默认true
    // 注意: sequelizeArgs参数不能添加,否则会优先于sequelizeArgs对数据库的配置
});
# 在工程根目录下只需要配置db.config.js文件
[base] -- db.config.js
// 默认标准配置,完全sequelize参数,不需要.env
module.exports = {
  driver: "mysql",
  options: {
    mysql: [
      "default_db",
      "root",
      "root",
      {
        host: "localhost",
        port: 3306,
        dialect: "mysql",
      },
    ],
    postgres: [
      "default_db",
      "postgres",
      "password",
      {
        host: "localhost",
        port: 2345,
        dialect: "postgres",
      },
    ],
    sqlite: [
      {
        dialect: "sqlite",
        storage: require("path").resolve("dbfile", "sqlite.db"),
      },
    ],
  },
};

注意:标准配置参数完全准寻sequelize参数,详细参照sequelize即可


方法、参数一览

F方法、D装饰器、C类、I接口、T类型

  • service.binder
    • FrouteBinder - 路由绑定方法
    • FrestfulBinder - 传统restful绑定方法(仅支持Get/Post装饰器,即将弃用)
  • service.injector
    • FservInjector - 服务注入器,注入插件,生成controller函数和method类别
  • decorator.builder
    • FinjectorBuilder - 函数装饰器构建器
    • FclassInjectorBuilder - 类装饰器构建器
    • FpropsInjectorBuilder - 参数装饰器构建器
  • decorator.factory
    • FinjectBind - 装饰器参数对象绑定
    • FinjectRemove - 装饰器参数对象解除绑定
  • decorator.restful
    • DGet - 传统restful装饰器(配合restfulBinder使用,即将启用)
    • DPost - 传统restful装饰器(配合restfulBinder使用,即将启用)
  • database.baseDefined (orm共通)
    • CDefineDatabase - 定义数据库入口类
    • IOrmBaseLoader - 加载器类接口
    • IOrmBaseLoaderConstructor - 加载器实例化接口
  • database.configurator(orm共通)
    • FstandardTransfor - 连接参数标准转换器
    • ITransfor - 连接参数转换器接口
    • IStandardConfigType - 配置文件内容格式接口类型
    • FloadConfig - 参数读取方法
  • database.loader.sequelize.loader
    • COrmLoader - sequelize加载器类
    • TCombine - 类型继承
    • TCombineAny - 类型继承,元素转换成any类型
    • TCombineColumnModel - 继承Model并注入column字段的类型
    • TTablesModelType - TablesStructure推断表结构
    • TDefineModel - 简化sequelize.define方法
    • TTablesStructureProps - 表结构callback中的参数
    • TTablesStructure - 表结构定义
    • TRelation - 关系函数
    • TDatabaseOptions - Database装饰器参数
    • TGlobalOptions - 全局参数,defineTables的第三个参数类型
    • TDB - 注入的db的类型,通过this.db.获取
    • IOrmSequelize - 用于Service模块db对象注入的继承类,实现this.db.tables.???自动提示,并能提示字段
    • IOrmInterface - 模块接口
    • TRewriteModelCtor - 解析重写Model方法类型
    • TRewriteModelProps - 重写Model方法的类型
    • TRewriteModelKeys - 重写Model方法名称的list
    • TBaseConfigType - 配置文件内容格式接口类型
  • database.loader.sequelize.binder
    • FdefineTables - 构建表实例入口方法
      • Fconnect - 主动连接函数
      • DDatabase - DB注入装饰器
    • FbaseTransfor - sequelize用的连接参数转换器
  • type
    • TPluginConfig - 装饰器插件配置结构
    • TInjector - 装饰器类型声明
    • TModuleFuncType - 模块函数类型
    • TModuleFuncArgsType - 模块函数参数
    • TMethodType - restful的method
1.2.0

2 years ago

1.2.5

2 years ago

1.2.4

2 years ago

1.2.3

2 years ago

1.3.1

2 years ago

1.2.2

2 years ago

1.3.0

2 years ago

1.2.1

2 years ago

1.1.1

2 years ago

1.1.0-alpha.1

2 years ago

1.1.0

2 years ago

1.0.7

2 years ago

1.0.6

2 years ago

1.0.5

2 years ago

1.0.4

2 years ago

1.0.3

2 years ago

1.0.2

2 years ago

1.0.1

2 years ago

1.0.0-beta.1.2

2 years ago

1.0.0-beta.1.1

2 years ago

1.0.0-beta.1.0

2 years ago