UNPKG

miter

Version:

A typescript web framework based on ExpressJs based loosely on SailsJs

512 lines 21.6 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) { 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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); const routes_1 = require("../decorators/router/routes"); const pluralize_1 = require("../util/pluralize"); const http_status_type_1 = require("../util/http-status-type"); class CrudController { constructor(staticModel, modelName, pluralName, singularName) { this.staticModel = staticModel; this.modelName = modelName; this._singularName = singularName || this.getSingularPath(modelName); this._pluralName = pluralName || this.getPluralPath(modelName); } *splitOnWords(name) { let currentWord = ''; for (let q = 0; q < name.length; q++) { let chr = name[q]; if (chr.match(/[A-Z]/)) { if (currentWord) yield currentWord; currentWord = chr; } else if (chr == '_') { if (currentWord) yield currentWord; currentWord = ''; } else currentWord += chr; } if (currentWord) yield currentWord; } getSingularPath(name) { let parts = [...this.splitOnWords(name)].filter(Boolean); if (!parts.length) return name; parts[parts.length - 1] = pluralize_1.pluralize(parts[parts.length - 1], false); return parts.map(pt => pt.toLowerCase()).join('-'); } getPluralPath(name) { let parts = [...this.splitOnWords(name)].filter(Boolean); if (!parts.length) return name; parts[parts.length - 1] = pluralize_1.pluralize(parts[parts.length - 1]); return parts.map(pt => pt.toLowerCase()).join('-'); } get singularName() { return this._singularName; } get pluralName() { return this._pluralName; } transformRoutePathPart(routeFnName, part) { return part.replace(/%%PLURAL_NAME%%/g, this._pluralName).replace(/%%SINGULAR_NAME%%/g, this._singularName); } transformRoutePolicies(routeFnName, fullPath, policies) { switch (routeFnName) { case 'destroy': return [...policies, ...this.getDestroyPolicies()]; case 'create': return [...policies, ...this.getCreatePolicies()]; case 'update': return [...policies, ...this.getMutatePolicies()]; case 'get': return [...policies, ...this.getReadPolicies()]; case 'find': case 'count': return [...policies, ...this.getQueryPolicies()]; default: return policies; } } getReadPolicies() { return []; } getQueryPolicies() { return []; } getCreatePolicies() { return []; } getMutatePolicies() { return []; } getDestroyPolicies() { return []; } transformInclude(req, res, include) { return __awaiter(this, void 0, void 0, function* () { }); } transformQuery(req, res, query) { return __awaiter(this, void 0, void 0, function* () { return query; }); } performQuery(req, res, query) { return __awaiter(this, void 0, void 0, function* () { return yield this.staticModel.db.findAndCountAll(query); }); } performFindOneQuery(req, res, query) { return __awaiter(this, void 0, void 0, function* () { return yield this.staticModel.db.findOne(query); }); } transformQueryResults(req, res, results) { return __awaiter(this, void 0, void 0, function* () { let initialStatusCode = res.statusCode; let oldResults = results.results; let newResults = []; let filteredCount = 0; for (let q = 0; q < oldResults.length; q++) { let transformed = yield this.transformResult(req, res, oldResults[q]); if (res.statusCode !== initialStatusCode || res.headersSent) return; if (transformed) newResults.push(transformed); else filteredCount++; } let count = (typeof results.count === 'number' ? results.count : typeof results.total === 'number' ? results.total : oldResults.length); count -= filteredCount; return { results: newResults, count: count, page: results.page, perPage: results.perPage }; }); } transformResult(req, res, result) { return __awaiter(this, void 0, void 0, function* () { return result; }); } transformCreateQuery(req, res, query) { return __awaiter(this, void 0, void 0, function* () { return query; }); } performCreate(req, res, data) { return __awaiter(this, void 0, void 0, function* () { return yield this.staticModel.db.create(data); }); } transformCreateResult(req, res, result) { return __awaiter(this, void 0, void 0, function* () { return result; }); } transformUpdateQuery(req, res, query) { return __awaiter(this, void 0, void 0, function* () { return query; }); } performUpdate(req, res, id, data, returning) { return __awaiter(this, void 0, void 0, function* () { return yield this.staticModel.db.update(id, data, returning); }); } transformUpdateResult(req, res, result) { return __awaiter(this, void 0, void 0, function* () { return result; }); } performDestroy(req, res, id) { return __awaiter(this, void 0, void 0, function* () { return yield this.staticModel.db.destroy(id); }); } beforeCreate(req, res, data) { return __awaiter(this, void 0, void 0, function* () { }); } afterCreate(req, res, result) { return __awaiter(this, void 0, void 0, function* () { }); } beforeUpdate(req, res, updateId, data) { return __awaiter(this, void 0, void 0, function* () { }); } afterUpdate(req, res, updateId, result) { return __awaiter(this, void 0, void 0, function* () { }); } beforeDestroy(req, res, destroyId) { return __awaiter(this, void 0, void 0, function* () { }); } afterDestroy(req, res, destroyId) { return __awaiter(this, void 0, void 0, function* () { }); } create(req, res) { return __awaiter(this, void 0, void 0, function* () { let initialStatusCode = res.statusCode; let data = (yield this.transformCreateQuery(req, res, req.body)) || req.body; if (res.statusCode !== initialStatusCode || res.headersSent) return; if (!data) { res.status(http_status_type_1.HTTP_STATUS_ERROR).send(`You haven't sent any data to create the ${this.modelName} with!`); return; } if (data.constructor == Array) { throw new Error("createMany not supported"); } yield this.beforeCreate(req, res, data); if (res.statusCode !== initialStatusCode || res.headersSent) return; let result = yield this.performCreate(req, res, data); if (res.statusCode !== initialStatusCode || res.headersSent) return; result = yield this.transformCreateResult(req, res, result); if (res.statusCode !== initialStatusCode || res.headersSent) return; yield this.afterCreate(req, res, result); if (res.statusCode !== initialStatusCode || res.headersSent) return; res.status(http_status_type_1.HTTP_STATUS_OK).json(result); }); } find(req, res) { return __awaiter(this, void 0, void 0, function* () { let query = {}; let include = []; let order = []; try { if (req.query['query']) { if (typeof req.query['query'] === 'string') query = JSON.parse(req.query['query'] || '{}'); else query = req.query['query']; } if (req.query['include']) { if (typeof req.query['include'] === 'string') include = JSON.parse(req.query['include'] || '[]'); else include = req.query['include']; } if (req.query['order']) { if (typeof req.query['order'] === 'string') order = JSON.parse(req.query['order'] || '[]'); else order = req.query['order']; } } catch (e) { res.status(http_status_type_1.HTTP_STATUS_ERROR).send(`Could not parse request parameters.`); return; } if ((!include || !include.length) && query.include) { include = query.include; delete query.include; } if ((!order || !order.length) && query.order) { order = query.order; delete query.order; } let initialStatusCode = res.statusCode; query = (yield this.transformQuery(req, res, query)) || query; if (res.statusCode !== initialStatusCode || res.headersSent) return; include = include || []; include = (yield this.transformInclude(req, res, include)) || include; if (res.statusCode !== initialStatusCode || res.headersSent) return; let findOne = req.path.endsWith('find-one'); if (findOne) { let result = yield this.performFindOneQuery(req, res, { where: query, include: include, order: order }); if (res.statusCode !== initialStatusCode || res.headersSent) return; result = yield this.transformResult(req, res, result); if (res.statusCode !== initialStatusCode || res.headersSent) return; res.status(http_status_type_1.HTTP_STATUS_OK).json(result); } else { let perPage = req.query['perPage']; if (!perPage || !(perPage = parseInt('' + perPage, 10)) || isNaN(perPage) || perPage <= 0) perPage = 10; let page = req.query['page']; if (!page || !(page = parseInt('' + page, 10)) || isNaN(page) || page < 0) page = 0; let results = yield this.performQuery(req, res, { where: query, include: include, order: order, offset: page * perPage, limit: perPage }); if (res.statusCode !== initialStatusCode || res.headersSent) return; results = (yield this.transformQueryResults(req, res, results)); if (res.statusCode !== initialStatusCode || res.headersSent || !results) return; res.status(http_status_type_1.HTTP_STATUS_OK).json({ results: results.results, page: results.page || page, perPage: results.perPage || perPage, total: results.count }); } }); } count(req, res) { return __awaiter(this, void 0, void 0, function* () { let query = {}; try { if (req.query['query']) { if (typeof req.query['query'] === 'string') query = JSON.parse(req.query['query'] || '{}'); else query = req.query['query']; } } catch (e) { res.status(http_status_type_1.HTTP_STATUS_ERROR).send(`Could not parse query parameters`); return; } let initialStatusCode = res.statusCode; query = (yield this.transformQuery(req, res, query)) || query; if (res.statusCode !== initialStatusCode || res.headersSent) return; let count = yield this.staticModel.db.count({ where: query }); res.status(http_status_type_1.HTTP_STATUS_OK).send(`${count}`); }); } get(req, res) { return __awaiter(this, void 0, void 0, function* () { let id = parseInt(req.params['id'], 10); if (!id || isNaN(id)) { res.status(http_status_type_1.HTTP_STATUS_ERROR).send(`Invalid ${this.modelName} id: ${req.params['id']}`); return; } let include = []; try { if (req.query['include']) { if (typeof req.query['include'] === 'string') include = JSON.parse(req.query['include'] || '[]'); else include = req.query['include']; } } catch (e) { res.status(http_status_type_1.HTTP_STATUS_ERROR).send(`Could not parse request parameters.`); return; } let initialStatusCode = res.statusCode; include = include || []; include = (yield this.transformInclude(req, res, include)) || include; if (res.statusCode !== initialStatusCode || res.headersSent) return; let result = yield this.staticModel.db.findById(id, { include: include }); result = yield this.transformResult(req, res, result); if (res.statusCode !== initialStatusCode || res.headersSent) return; res.status(http_status_type_1.HTTP_STATUS_OK).json(result); }); } update(req, res) { return __awaiter(this, void 0, void 0, function* () { let id = parseInt(req.params['id'], 10); if (!id || isNaN(id)) { res.status(http_status_type_1.HTTP_STATUS_ERROR).send(`Invalid ${this.modelName} id: ${req.params['id']}`); return; } let initialStatusCode = res.statusCode; let data = (yield this.transformUpdateQuery(req, res, req.body)) || req.body; if (res.statusCode !== initialStatusCode || res.headersSent) return; if (!data) { res.status(http_status_type_1.HTTP_STATUS_ERROR).send(`You haven't sent any data to update the ${this.modelName} with!`); return; } let returning = false; let returningParam = req.query['returning']; if (returningParam) { if (returningParam === true || returningParam === 'true') returning = true; else if (returningParam === false || returningParam === 'false') returning = false; else { res.status(http_status_type_1.HTTP_STATUS_ERROR).send(`Invalid ${this.modelName} returning parameter: ${returningParam}; must be boolean`); return; } } yield this.beforeUpdate(req, res, id, data); if (res.statusCode !== initialStatusCode || res.headersSent) return; let performUpdateResults = yield this.performUpdate(req, res, id, data, returning); if (res.statusCode !== initialStatusCode || res.headersSent) return; let [updated, results] = performUpdateResults; if (results && results.length > 1) throw new Error(`performUpdate returned multiple results`); if (updated) { results = yield Promise.all(results.map((result) => this.transformUpdateResult(req, res, result))); if (res.statusCode !== initialStatusCode || res.headersSent) return; let result; if (returning) { result = results[0]; if (result) { result = (yield this.transformResult(req, res, result)); if (res.statusCode !== initialStatusCode || res.headersSent) return; } } yield this.afterUpdate(req, res, id, result); if (res.statusCode !== initialStatusCode || res.headersSent) return; res.status(http_status_type_1.HTTP_STATUS_OK).json(result); } else { res.status(http_status_type_1.HTTP_STATUS_ERROR).send(`Can't find the ${this.modelName} with id ${id} to update it.`); return; } }); } destroy(req, res) { return __awaiter(this, void 0, void 0, function* () { let id = parseInt(req.params['id'], 10); if (!id || isNaN(id)) { res.status(http_status_type_1.HTTP_STATUS_ERROR).send(`Invalid ${this.modelName} id: ${req.params['id']}`); return; } let initialStatusCode = res.statusCode; yield this.beforeDestroy(req, res, id); if (res.statusCode !== initialStatusCode || res.headersSent) return; let destroyed = yield this.performDestroy(req, res, id); if (res.statusCode !== initialStatusCode || res.headersSent) return; if (destroyed) { yield this.afterDestroy(req, res, id); if (res.statusCode !== initialStatusCode || res.headersSent) return; res.status(http_status_type_1.HTTP_STATUS_OK).end(); } else { res.status(http_status_type_1.HTTP_STATUS_ERROR).send({ msg: `Failed to delete ${this._singularName} with ID ${id}.` }); } }); } } __decorate([ routes_1.Post(`/%%PLURAL_NAME%%/create`), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, Object]), __metadata("design:returntype", Promise) ], CrudController.prototype, "create", null); __decorate([ routes_1.Get(`/%%PLURAL_NAME%%/find`), routes_1.Get(`/%%PLURAL_NAME%%/find-one`), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, Object]), __metadata("design:returntype", Promise) ], CrudController.prototype, "find", null); __decorate([ routes_1.Get(`/%%PLURAL_NAME%%/count`), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, Object]), __metadata("design:returntype", Promise) ], CrudController.prototype, "count", null); __decorate([ routes_1.Get(`/%%SINGULAR_NAME%%/:id`), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, Object]), __metadata("design:returntype", Promise) ], CrudController.prototype, "get", null); __decorate([ routes_1.Put(`/%%SINGULAR_NAME%%/:id`), routes_1.Patch(`/%%SINGULAR_NAME%%/:id`), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, Object]), __metadata("design:returntype", Promise) ], CrudController.prototype, "update", null); __decorate([ routes_1.Delete(`/%%SINGULAR_NAME%%/:id`), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, Object]), __metadata("design:returntype", Promise) ], CrudController.prototype, "destroy", null); exports.CrudController = CrudController; //# sourceMappingURL=crud-controller.js.map