Created
September 19, 2019 14:57
-
-
Save Diluka/1d326621ce60d63572f58fc42843c518 to your computer and use it in GitHub Desktop.
CRUD common query for sequelize with routing-controllers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
Authorized, | |
BadRequestError, | |
BodyParam, | |
ForbiddenError, | |
JsonController, | |
NotFoundError, | |
Put, | |
QueryParam | |
} from "routing-controllers"; | |
import {IIncludeOptions, Sequelize} from "sequelize-typescript"; | |
import {Inject} from "typedi"; | |
import {BaseModel} from "../../common/domain/base-model"; | |
import {Role, User} from "../../model/User"; | |
import * as _ from "lodash"; | |
import {Pageable, PageInfo} from "../../common/query/pagination"; | |
import {plainToClass} from "class-transformer"; | |
import {validateOrReject} from "class-validator"; | |
import {Transaction} from "../../decorator/transaction.decorator"; | |
import {LogInvoke} from "../../decorator/log-invoke.decorator"; | |
const DO_NOT_MODIFIED_MODELS = ["User", "WxUser", "SysVar", "ACL"]; | |
@Authorized(Role.ADMIN) | |
@JsonController("/commons/crud") | |
export class CrudController { | |
@Inject() | |
db: Sequelize; | |
@LogInvoke("创建") | |
@Transaction() | |
@Put("/create") | |
async create(@BodyParam("data", {required: true}) data: any, | |
@BodyParam("options", {required: true}) options: any, | |
@QueryParam("method", {required: true}) method: string, | |
@QueryParam("model", {required: true}) model: string) { | |
this.filterModels(model); | |
const M = this.getModel(model); | |
this.processOptions(options); | |
if (_.isArray(data)) { | |
let entities = plainToClass(M, data); | |
for (const entity of entities) { | |
await validateOrReject(entity); | |
} | |
switch (method) { | |
case "bulkCreate": | |
return M.bulkCreate(data, options); | |
default: | |
throw new BadRequestError(`不支持的创建方法:${method}`); | |
} | |
} else { | |
let entity = plainToClass(M, data); | |
await validateOrReject(entity); | |
switch (method) { | |
case "create": | |
case "insert": | |
return M.create(data, options); | |
case "findOrCreate": | |
return M.findOrCreate({defaults: data, ...options}); | |
default: | |
throw new BadRequestError(`不支持的创建方法:${method}`); | |
} | |
} | |
} | |
@LogInvoke("取回") | |
@Transaction() | |
@Put("/retrieve") | |
async retrieve(@BodyParam("data") data: any, | |
@BodyParam("options", {required: true}) options: any, | |
@QueryParam("method", {required: true}) method: string, | |
@QueryParam("model", {required: true}) model: string) { | |
const M = this.getModel(model); | |
this.processOptions(options); | |
switch (method) { | |
case "findById": | |
case "findByPrimary": | |
return M.findById(data, options); | |
case "findOne": | |
return M.findOne(options); | |
case "findAll": | |
return M.findAll(options); | |
case "findAndCountAll": | |
let page = await M.findAndCountAll(options); | |
let pageable = new Pageable(); | |
pageable.type = "row"; | |
pageable.limit = options.limit || page.count; | |
pageable.offset = options.offset || 0; | |
pageable.normalize(); | |
return new PageInfo(page, pageable); | |
case "count": | |
let count = await M.count(options); | |
return {count}; | |
case "max": | |
let max = await M.max(data, options); | |
return {max}; | |
case "min": | |
let min = await M.min(data, options); | |
return {min}; | |
case "sum": | |
let sum = await M.sum(data, options); | |
return {sum}; | |
case "avg": | |
let value = await M.aggregate(data, method, options); | |
return {[method]: value}; | |
default: | |
throw new BadRequestError(`不支持的查询方法:${method}`); | |
} | |
} | |
@LogInvoke("更新") | |
@Transaction() | |
@Put("/update") | |
async update(@BodyParam("data", {required: true}) data: any, | |
@BodyParam("options", {required: true}) options: any, | |
@QueryParam("method", {required: true}) method: string, | |
@QueryParam("model", {required: true}) model: string) { | |
this.filterModels(model); | |
const M = this.getModel(model); | |
this.processOptions(options); | |
switch (method) { | |
case "update": | |
return {result: await M.update(data, options)}; | |
case "insertOrUpdate": | |
case "upsert": | |
return {result: await M.upsert(data, options)}; | |
case "increment": | |
return {result: await M.increment(data, options)}; | |
default: | |
throw new BadRequestError(`不支持的更新方法:${method}`); | |
} | |
} | |
@LogInvoke("销毁") | |
@Transaction() | |
@Put("/destroy") | |
async destroy(@BodyParam("data") data: any, | |
@BodyParam("options", {required: true}) options: any, | |
@QueryParam("method", {required: true}) method: string, | |
@QueryParam("model", {required: true}) model: string) { | |
this.filterModels(model); | |
const M = this.getModel(model); | |
this.processOptions(options); | |
switch (method) { | |
case "destroy": | |
return {result: await M.destroy(options)}; | |
case "truncate": | |
return M.truncate(options); | |
case "restore": | |
return M.restore(options); | |
default: | |
throw new BadRequestError(`不支持的删除方法:${method}`); | |
} | |
} | |
private getModel(model: string) { | |
const M: typeof BaseModel & (new() => BaseModel<any>) = this.db._[model] as any; | |
if (!M) { | |
throw new NotFoundError(`实体不存在:${model}`); | |
} | |
return M; | |
} | |
private processOptions(options: any) { | |
if (options) { | |
let include = _.get(options, "include") as IIncludeOptions[]; | |
if (include) { | |
this.processInclude(include); | |
} | |
delete options.transaction; | |
} | |
} | |
private processInclude(include: IIncludeOptions[]) { | |
if (_.isArray(include)) { | |
for (let o of include) { | |
if (_.isString(o.model)) { | |
o.model = this.getModel(o.model); | |
} | |
this.processInclude(o.include as any[]); | |
} | |
} | |
} | |
private filterModels(model: string) { | |
if (DO_NOT_MODIFIED_MODELS.includes(model)) { | |
throw new ForbiddenError(`不允许修改的实体:${model}`); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment