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
JavaScript
;
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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