UNPKG

claire-framework

Version:

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

354 lines 31.7 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.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); } }); 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 queryConditions.push({ [f.fieldLogicName]: QueryOperator_1.regex(value) }); } else if (f.isPrimaryKey || f.isForeignKey) { //-- query is array for primary and foreign key queryConditions.push({ [f.fieldLogicName]: QueryOperator_1.belongs(value) }); } else { //-- find by equal for the rest queryConditions.push({ [f.fieldLogicName]: QueryOperator_1.eq(value) }); } } }); let result = yield provider.getMany(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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRGVmYXVsdEh0dHBSZXNvdXJjZUNvbnRyb2xsZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9saWIvZGVmYXVsdC1pbXBsZW1lbnRhdGlvbnMvRGVmYXVsdEh0dHBSZXNvdXJjZUNvbnRyb2xsZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSwwREFBNkQ7QUFDN0Qsc0ZBQWlGO0FBQ2pGLDRDQUFtRDtBQUNuRCx1REFBa0Q7QUFDbEQsNkNBQTRFO0FBQzVFLGlGQUE0RTtBQUU1RSwwREFBcUQ7QUFDckQsdUNBQWtDO0FBR2xDLHNEQUFtRztBQUNuRywrQ0FBMEM7QUFDMUMsMERBQTBEO0FBQzFELDZEQUF3RDtBQUd4RCxNQUFhLDZCQUF1RCxTQUFRLCtDQUFzQjtJQVk5RixZQUFZLEtBQStCO1FBQ3ZDLEtBQUssRUFBRSxDQUFDO1FBQ1IsSUFBSSxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUM7UUFDbkIsSUFBSSxDQUFDLGFBQWEsR0FBRyxLQUFLLENBQUMsU0FBUyxDQUFDLGVBQVEsQ0FBQyxDQUFDO1FBQy9DLElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYSxFQUFFO1lBQ3JCLE1BQU0sSUFBSSx5QkFBVyxDQUFDLGlDQUF3QixDQUFDLENBQUM7U0FDbkQ7UUFDRCxJQUFJLENBQUMsYUFBYSxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBQ3JDLENBQUM7SUFFWSxJQUFJOzs7OztZQUNiLE1BQU0sT0FBTSxJQUFJLFdBQUUsQ0FBQztRQUN2QixDQUFDO0tBQUE7SUFFRCxJQUFXLGtCQUFrQjtRQUV6QixJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRTtZQUVoQixNQUFNLGNBQWMsR0FBRztnQkFDbkIsT0FBTyxFQUFFO29CQUNMLFNBQVMsRUFBRTt3QkFDUCxDQUFDLGVBQVEsQ0FBQyxFQUFFLElBQUksNkJBQWEsRUFBRTtxQkFDbEM7aUJBQ0o7Z0JBQ0QsUUFBUSxFQUFFO29CQUNOLFNBQVMs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