UNPKG

claire-framework

Version:

- được viết bằng TypeScript - hỗ trợ websocket và HTTP request - hỗ trợ CLI để generate base project (claire-cli)

380 lines 35.5 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); const AbstractModel_1 = require("../model/AbstractModel"); const AbstractHttpController_1 = require("../controller/http/AbstractHttpController"); const core_1 = require("../decorator/core"); const ClaireError_1 = require("../system/ClaireError"); const errors_1 = require("../system/errors"); const AbstractDatabaseAdapter_1 = require("../database/AbstractDatabaseAdapter"); const ModelMetadata_1 = require("../model/ModelMetadata"); const HTTP_1 = require("../enum/HTTP"); const TableMapper_1 = require("../model/TableMapper"); const DataType_1 = require("../enum/DataType"); const QueryOperator_1 = require("../model/QueryOperator"); const AbstractLogger_1 = require("../logger/AbstractLogger"); class DefaultHttpResourceController extends AbstractHttpController_1.AbstractHttpController { constructor(model) { super(); this.NUMERIC_OPERATORS = [">=", "<=", "==", "!="]; this.model = model; this.modelMetadata = model.prototype[core_1.METADATA]; if (!this.modelMetadata) { throw new ClaireError_1.ClaireError(errors_1.MODEL_METADATA_NOT_FOUND); } this.modelMetadata.assertValid(); } init() { const _super = Object.create(null, { init: { get: () => super.init } }); return __awaiter(this, void 0, void 0, function* () { yield _super.init.call(this); }); } get controllerMetadata() { if (!this.metadata) { const createResource = { request: { prototype: { [core_1.METADATA]: new ModelMetadata_1.ModelMetadata() } }, response: { prototype: { [core_1.METADATA]: new ModelMetadata_1.ModelMetadata() } }, }; const getResource = { params: { prototype: { [core_1.METADATA]: new ModelMetadata_1.ModelMetadata() } }, response: { prototype: { [core_1.METADATA]: new ModelMetadata_1.ModelMetadata() } }, query: { prototype: { [core_1.METADATA]: new ModelMetadata_1.ModelMetadata() } }, }; const updateResource = { request: { prototype: { [core_1.METADATA]: new ModelMetadata_1.ModelMetadata() } }, }; const getAllResources = { query: { prototype: { [core_1.METADATA]: new ModelMetadata_1.ModelMetadata() } }, }; //-- prototyping createResource request { // @ts-ignore TableMapper_1.Validate()(createResource.request); this.modelMetadata.fields.filter(f => !f.isAutoGen).forEach((field) => { if (!field.isPrimaryKey || !field.isAutoIncrement) { TableMapper_1.check_for_field(createResource.request.prototype, field.fieldLogicName, field); } }); } //-- prototyping createResource response { // @ts-ignore // Validate()(createResource.response); // let field = this.modelMetadata.getPrimaryKey(); // check_for_field(createResource.response.prototype, field.fieldLogicName!, field); } //-- prototyping getResource params { // @ts-ignore TableMapper_1.Validate()(getResource.params); let field = this.modelMetadata.getPrimaryKey(); TableMapper_1.check_for_field(getResource.params.prototype, field.fieldLogicName, field); } //-- prototyping getResource query { // @ts-ignore TableMapper_1.Validate()(getResource.query); TableMapper_1.SubSet(this.modelMetadata.fields.map(f => f.fieldLogicName), false)(getResource.query.prototype, "filter"); TableMapper_1.Comment("Select the fields to be retrieved")(getResource.query.prototype, "filter"); TableMapper_1.Optional()(getResource.query.prototype, "filter"); } //-- prototyping getAllResources query { // @ts-ignore TableMapper_1.Validate()(getAllResources.query); TableMapper_1.SubSet(this.modelMetadata.fields.map(f => f.fieldLogicName), false)(getAllResources.query.prototype, "filter"); TableMapper_1.Comment("Select the fields to be retrieved")(getAllResources.query.prototype, "filter"); TableMapper_1.Optional()(getAllResources.query.prototype, "filter"); this.modelMetadata.fields.forEach((f) => { TableMapper_1.check_for_field(getAllResources.query.prototype, f.fieldLogicName, Object.assign(Object.assign({}, f), { nullable: true })); if (f.isPrimaryKey || f.isForeignKey) { TableMapper_1.IsArray(false)(getAllResources.query.prototype, f.fieldLogicName); TableMapper_1.Comment("Array of ids of records to retrieve")(getAllResources.query.prototype, f.fieldLogicName); } else if ([DataType_1.DataType.INTEGER, DataType_1.DataType.BIGINT, DataType_1.DataType.FLOAT].includes(f.dataType)) { //-- allow number to be string prefixed by operator ==, !=, >=, <= TableMapper_1.check_for_field(getAllResources.query.prototype, f.fieldLogicName, { dataType: DataType_1.DataType.STRING }); } }); TableMapper_1.check_for_field(getAllResources.query.prototype, "limit", { dataType: DataType_1.DataType.INTEGER, nullable: true, isInteger: true, greaterThan: 0, }); TableMapper_1.check_for_field(getAllResources.query.prototype, "page", { dataType: DataType_1.DataType.INTEGER, nullable: true, isInteger: true, greaterThan: 0, }); } //-- prototyping getResource response { // @ts-ignore // Validate()(getResource.response); // this.modelMetadata.fields.forEach((field) => { // check_for_field(getResource.response.prototype, field.fieldLogicName!, field); // }); } //-- prototyping updateResource request // @ts-ignore TableMapper_1.Validate()(updateResource.request); this.modelMetadata.fields.filter(f => !f.isAutoGen).forEach((field) => { //skip primary key if (!field.isPrimaryKey) { TableMapper_1.check_for_field(updateResource.request.prototype, field.fieldLogicName, field); TableMapper_1.Optional()(updateResource.request.prototype, field.fieldLogicName); } }); const permissionGroup = super.controllerMetadata.permissionGroup || `${this.model.name} Management`; const handlers = [ { method: HTTP_1.HTTP.POST, url: `/${this.modelMetadata.modelName.toLowerCase()}`, handlerFn: "createResource", responder: undefined, middleware: undefined, paramsValidator: undefined, bodyValidator: createResource.request.prototype[core_1.METADATA], override: false, permissionName: `create${this.model.name}`, permissionGroup, }, { method: HTTP_1.HTTP.GET, url: `/${this.modelMetadata.modelName.toLowerCase()}/:${this.modelMetadata.getPrimaryKey().fieldLogicName}`, handlerFn: "getResource", responder: undefined, middleware: undefined, paramsValidator: getResource.params.prototype[core_1.METADATA], bodyValidator: undefined, queryValidator: getResource.query.prototype[core_1.METADATA], override: false, permissionName: `get${this.model.name}`, permissionGroup, }, { method: HTTP_1.HTTP.GET, url: `/${this.modelMetadata.modelName.toLowerCase()}`, handlerFn: "getAllResources", responder: undefined, middleware: undefined, paramsValidator: undefined, bodyValidator: undefined, queryValidator: getAllResources.query.prototype[core_1.METADATA], override: false, permissionName: `getAll${this.model.name}`, permissionGroup, }, { method: HTTP_1.HTTP.PUT, url: `/${this.modelMetadata.modelName.toLowerCase()}/:${this.modelMetadata.getPrimaryKey().fieldLogicName}`, handlerFn: "updateResource", responder: undefined, middleware: undefined, paramsValidator: getResource.params.prototype[core_1.METADATA], bodyValidator: updateResource.request.prototype[core_1.METADATA], override: false, permissionName: `update${this.model.name}`, permissionGroup, }, { method: HTTP_1.HTTP.DEL, url: `/${this.modelMetadata.modelName.toLowerCase()}/:${this.modelMetadata.getPrimaryKey().fieldLogicName}`, handlerFn: "deleteResource", responder: undefined, middleware: undefined, paramsValidator: getResource.params.prototype[core_1.METADATA], bodyValidator: undefined, override: false, permissionName: `delete${this.model.name}`, permissionGroup, }, ]; // this.logger.debug("--------resource----------", this.model.name); // this.logger.debug("this handlers", handlers); // this.logger.debug("super handlers", super.controllerMetadata); this.metadata = Object.assign(Object.assign({}, super.controllerMetadata), { handlers: AbstractHttpController_1.AbstractHttpController.mergeWithSuperHandlers(super.controllerMetadata, handlers) }); } return this.metadata; } createResource(request, transaction) { return __awaiter(this, void 0, void 0, function* () { let provider = transaction ? transaction.use(this.model) : this.databaseAdapter.use(this.model); let body = request.getBody(); let instance = new this.model(); //-- append all properties this.modelMetadata.fields.forEach((field) => { // @ts-ignore instance[field.fieldLogicName] = body[field.fieldLogicName]; }); instance = yield provider.saveOne(instance); return AbstractModel_1.toJSON(instance); }); } getResource(request, transaction) { return __awaiter(this, void 0, void 0, function* () { let provider = transaction ? transaction.use(this.model) : this.databaseAdapter.use(this.model); let primaryKey = this.modelMetadata.getPrimaryKey().fieldLogicName; // @ts-ignore let resource = yield provider.getOne([{ [primaryKey]: QueryOperator_1.eq(request.getParams()[primaryKey]) }], { projection: request.getQuery()["filter"] }); if (!resource) { throw new ClaireError_1.ClaireError(errors_1.RECORD_NOT_FOUND); } return AbstractModel_1.toJSON(resource); }); } getAllResources(request, transaction) { return __awaiter(this, void 0, void 0, function* () { let provider = transaction ? transaction.use(this.model) : this.databaseAdapter.use(this.model); let queryConditions = {}; this.modelMetadata.fields.forEach((f) => { //@ts-ignore let value = request.getQuery()[f.fieldLogicName]; if (value !== undefined) { if ([DataType_1.DataType.STRING, DataType_1.DataType.TEXT].includes(f.dataType)) { //-- if string then find by regex Object.assign(queryConditions, { [f.fieldLogicName]: QueryOperator_1.regex(value) }); } else if (f.isPrimaryKey || f.isForeignKey) { //-- query is array for primary and foreign key Object.assign(queryConditions, { [f.fieldLogicName]: QueryOperator_1.belongs(value) }); } else { const operator = String(value).substr(0, 2); if ([DataType_1.DataType.BIGINT, DataType_1.DataType.INTEGER, DataType_1.DataType.FLOAT].includes(f.dataType) && this.NUMERIC_OPERATORS.includes(operator)) { const realValue = Number(String(value).substr(2)); switch (operator) { case "<=": Object.assign(queryConditions, { [f.fieldLogicName]: QueryOperator_1.lte(realValue) }); break; case ">=": Object.assign(queryConditions, { [f.fieldLogicName]: QueryOperator_1.gte(realValue) }); break; case "==": Object.assign(queryConditions, { [f.fieldLogicName]: QueryOperator_1.eq(realValue) }); break; case "!=": Object.assign(queryConditions, { [f.fieldLogicName]: QueryOperator_1.neq(realValue) }); break; } } else { //-- find by equal for the rest Object.assign(queryConditions, { [f.fieldLogicName]: QueryOperator_1.eq(value) }); } } } }); let result = yield provider.getMany(Object.keys(queryConditions).length ? [queryConditions] : [], { //@ts-ignore projection: request.getQuery()["filter"], //@ts-ignore limit: request.getQuery()["limit"], //@ts-ignore page: request.getQuery()["page"] }); return result.map(model => AbstractModel_1.toJSON(model)); }); } updateResource(request, transaction) { return __awaiter(this, void 0, void 0, function* () { let provider = transaction ? transaction.use(this.model) : this.databaseAdapter.use(this.model); let primaryKey = this.modelMetadata.getPrimaryKey().fieldLogicName; let body = request.getBody(); let params = request.getParams(); let instance = new this.model(); //-- append all properties this.modelMetadata.fields.forEach((field) => { const fieldUpdatedValue = body[field.fieldLogicName]; if (fieldUpdatedValue !== undefined) { if (field.getSetField) { // @ts-ignore //-- try to trigger the setter instance[field.fieldLogicName] = fieldUpdatedValue; } else { // @ts-ignore instance[field.fieldDataName] = fieldUpdatedValue; } } }); // @ts-ignore instance[primaryKey] = params[primaryKey]; instance = yield provider.updateOne(instance); return; }); } deleteResource(request, transaction) { return __awaiter(this, void 0, void 0, function* () { let provider = transaction ? transaction.use(this.model) : this.databaseAdapter.use(this.model); let primaryKey = this.modelMetadata.getPrimaryKey().fieldLogicName; // @ts-ignore let instance = yield provider.deleteMany([{ [primaryKey]: QueryOperator_1.eq(request.getParams()[primaryKey]) }]); if (instance === 0) { throw new ClaireError_1.ClaireError(errors_1.RECORD_NOT_FOUND); } return; }); } } __decorate([ core_1.Inject(), __metadata("design:type", AbstractDatabaseAdapter_1.AbstractDatabaseAdapter) ], DefaultHttpResourceController.prototype, "databaseAdapter", void 0); __decorate([ core_1.Inject(), __metadata("design:type", AbstractLogger_1.AbstractLogger) ], DefaultHttpResourceController.prototype, "logger", void 0); exports.DefaultHttpResourceController = DefaultHttpResourceController; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRGVmYXVsdEh0dHBSZXNvdXJjZUNvbnRyb2xsZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9saWIvZGVmYXVsdC1pbXBsZW1lbnRhdGlvbnMvRGVmYXVsdEh0dHBSZXNvdXJjZUNvbnRyb2xsZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSwwREFBNkQ7QUFDN0Qsc0ZBQWlGO0FBQ2pGLDRDQUFtRDtBQUNuRCx1REFBa0Q7QUFDbEQsNkNBQTRFO0FBQzVFLGlGQUE0RTtBQUU1RSwwREFBcUQ7QUFDckQsdUNBQWtDO0FBR2xDLHNEQUFtRztBQUNuRywrQ0FBMEM7QUFDMUMsMERBQXlFO0FBQ3pFLDZEQUF3RDtBQUd4RCxNQUFhLDZCQUF1RCxTQUFRLCtDQUFzQjtJQWM5RixZQUFZLEtBQStCO1FBQ3ZDLEtBQUssRUFBRSxDQUFDO1FBYkssc0JBQWlCLEdBQUcsQ0FBQyxJQUFJLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQztRQWMxRCxJQUFJLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQztRQUNuQixJQUFJLENBQUMsYUFBYSxHQUFHLEtBQUssQ0FBQyxTQUFTLENBQUMsZUFBUSxDQUFDLENBQUM7UUFDL0MsSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhLEVBQUU7WUFDckIsTUFBTSxJQUFJLHlCQUFXLENBQUMsaUNBQXdCLENBQUMsQ0FBQztTQUNuRDtRQUNELElBQUksQ0FBQyxhQUFhLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDckMsQ0FBQztJQUVZLElBQUk7Ozs7O1lBQ2IsTUFBTSxPQUFNLElBQUksV0FBRSxDQUFDO1FBQ3ZCLENBQUM7S0FBQTtJQUVELElBQVcsa0JBQWtCO1FBRXpCLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFO1lBRWhCLE1BQU0sY0FBYyxHQUFHO2dCQUNuQixPQUFPLEVBQUU7b0JBQ0wsU0FBUyxFQUFFO3dCQUNQLENBQUMsZUFB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