UNPKG

@deepkit/framework

Version:

232 lines 14.8 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); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.CrudAppModule = void 0; exports.createCrudRoutes = createCrudRoutes; const __ΩPartial = ['T', 'Partial', 'l+e#!e"!fRb!Pde"!gN#"w"y']; /*@ts-ignore*/ const { __ΩHttpQueries } = require('@deepkit/http'); /*@ts-ignore*/ const { __ΩHttpBody } = require('@deepkit/http'); /*@ts-ignore*/ const { __ΩClassType } = require('@deepkit/core'); /*@ts-ignore*/ const { __ΩPositive } = require('@deepkit/type'); /*@ts-ignore*/ const { __ΩMaximum } = require('@deepkit/type'); function __assignType(fn, args) { fn.__type = args; return fn; } var Ωr; const core_1 = require("@deepkit/core"); const app_1 = require("@deepkit/app"); const http_1 = require("@deepkit/http"); const orm_1 = require("@deepkit/orm"); const type_1 = require("@deepkit/type"); function applySelect(query, select) { const names = (0, core_1.isArray)(select) ? select.map(__assignType(v => v.trim(), ['v', '', 'P"2!"/"'])) : select.replace(/\s+/g, '').split(','); try { return query.select(...names); } catch (error) { throw type_1.ValidationError.from([{ message: String(error.message), path: 'select', code: 'invalid_select' }]); } } applySelect.__type = [() => orm_1.Query, 'query', 'select', () => orm_1.Query, 'applySelect', 'PP"7!2"P&F&J2#P"7$/%']; function applyJoins(query, joins) { for (const [field, projection] of Object.entries(joins)) { if (!query.classSchema.hasProperty(field)) throw new Error(`Join '${field}' does not exist`); let join = query.useJoinWith(field); if (projection.length && projection !== '*') { join = join.select(...projection.split(',')); } query = join.end(); } return query; } applyJoins.__type = [() => orm_1.Query, 'query', 'joins', () => orm_1.Query, 'applyJoins', 'PP"7!2"P&&LM2#P"7$/%']; const __ΩAutoCrudOptions = ["create", "read", "readMany", "update", "updateMany", "delete", "deleteMany", 'limitOperations', 'identifier', 'selectableFields', 'sortFields', true, 'identifierChangeable', 'joins', 'maxLimit', 'defaultLimit', 'AutoCrudOptions', 'PP.!.".#.$.%.&.\'JF4(8&4)8&F4*8&F4+8.,4-8&F4.8\'4/8\'408Mw1y']; function createController(schema, options = {}) { if (!schema.name) throw new Error(`Class ${schema.getClassName()} needs an entity name via @entity.name()`); const joinNames = options.joins || schema.getProperties().filter(__assignType(v => v.isReference() || v.isBackReference(), ['v', '', 'P"2!"/"'])).map(__assignType(v => v.name, ['v', '', 'P"2!"/"'])); const sortNames = options.sortFields || schema.getProperties().filter(__assignType(v => !v.isReference() && !v.isBackReference(), ['v', '', 'P"2!"/"'])).map(__assignType(v => v.name, ['v', '', 'P"2!"/"'])); const selectNames = options.selectableFields || schema.getProperties().filter(__assignType(v => !v.isReference() && !v.isBackReference(), ['v', '', 'P"2!"/"'])).map(__assignType(v => v.name, ['v', '', 'P"2!"/"'])); const joinNamesType = { kind: type_1.ReflectionKind.union, types: joinNames.map(__assignType(v => ({ kind: type_1.ReflectionKind.literal, literal: v }), ['v', '', 'P"2!"/"'])) }; const sortNamesType = { kind: type_1.ReflectionKind.union, types: sortNames.map(__assignType(v => ({ kind: type_1.ReflectionKind.literal, literal: v }), ['v', '', 'P"2!"/"'])) }; const selectNamesType = { kind: type_1.ReflectionKind.union, types: selectNames.map(__assignType(v => ({ kind: type_1.ReflectionKind.literal, literal: v }), ['v', '', 'P"2!"/"'])) }; const __ΩJoinNames = [joinNamesType, 'JoinNames', 'a!w"y']; const __ΩSortNames = [sortNamesType, 'SortNames', 'a!w"y']; const __ΩSelectNames = [selectNamesType, 'SelectNames', 'a!w"y']; //note: only shallows clone (including members shallow copy) const selectSchema = schema.clone(); //make sure references are `PrimaryKey<T> | T` for (const property of selectSchema.getProperties().slice()) { if ((property.isReference() || property.isBackReference()) && !property.isArray()) { selectSchema.removeProperty(property.name); const foreign = property.getResolvedReflectionClass(); selectSchema.addProperty({ ...property.property, type: { kind: type_1.ReflectionKind.union, types: [foreign.getPrimary().type, property.type] } }); } } const __ΩSchemaType = [selectSchema, 'SchemaType', 'a!w"y']; const identifier = options.identifier ? schema.getProperty(options.identifier) : schema.getPrimary(); const identifierType = identifier.type; const __ΩIdentifierType = [identifierType, 'IdentifierType', 'a!w"y']; const maxLimit = options.maxLimit || 1000; const __ΩListQuery = [() => __ΩPartial, () => __ΩSchemaType, 'filter', () => __ΩSelectNames, 'select', 'List of or string of comma separated field names', () => __ΩSortNames, "asc", "desc", 'orderBy', () => __ΩJoinNames, 'joins', '\'.', () => __ΩPositive, 'offset', () => __ΩPositive, () => __ΩMaximum, maxLimit, 'limit', 'ListQuery', 'l,P.(.)JR&RPn"o!"4#8Pn$F&J4%8?&Pdn\'N#"4*8Pdn+N*"4,8?-P\'n.K4/8P\'n0a2o1"K438Mw4y']; const __ΩGetQuery = [() => __ΩSelectNames, 'select', 'List of or string of comma separated field names.', () => __ΩJoinNames, 'joins', 'GetQuery', 'l%&RPPn!F&J4"8?#Pdn$N#"4%8Mw&y']; const __ΩErrorMessage = ['message', 'ErrorMessage', 'P&4!Mw"y']; const identifierChangeable = options && options.identifierChangeable ? true : false; let RestController = class RestController { constructor(registry) { this.registry = registry; } getDatabase() { return this.registry.getDatabaseForEntity(schema); } async readMany(listQuery) { listQuery.limit = Math.min(options.maxLimit || 1000, listQuery.limit || options.defaultLimit || 30); let query = this.getDatabase().query(schema); if (listQuery.joins) query = applyJoins(query, listQuery.joins); if (listQuery.select) query = applySelect(query, listQuery.select); if (listQuery.orderBy && (0, core_1.getObjectKeysSize)(listQuery.orderBy) > 0) { for (const field of Object.keys(listQuery.orderBy)) { if (!schema.hasProperty(field)) throw new Error(`Can not order by '${field}' since it does not exist.`); } query.model.sort = listQuery.orderBy; } return await query .filter(listQuery.filter) .limit(listQuery.limit ? listQuery.limit : undefined) .skip(listQuery.offset) .find(); } async create(body) { //body is automatically validated //is cast really necessary? // const item = cast(body, undefined, undefined, schema.type); const item = body; try { await this.getDatabase().persist(item); } catch (e) { if (e instanceof orm_1.UniqueConstraintFailure) { return new http_1.JSONResponse({ message: `This ${schema.name} already exists` }).status(409); } throw e; } return new http_1.JSONResponse(item).status(201); } async delete(id) { const result = await this.getDatabase().query(schema).filter({ [identifier.name]: id }).deleteOne(); return { deleted: result.modified }; } async read(id, options) { let query = this.getDatabase().query(schema).filter({ [identifier.name]: id }); if (options.select) query = applySelect(query, options.select); if (options.joins) query = applyJoins(query, options.joins); const item = await query.findOneOrUndefined(); if (item) return item; return new http_1.JSONResponse({ message: `${schema.name} not found` }).status(404); } async update(id, body) { let query = this.getDatabase().query(schema).filter({ [identifier.name]: id }); const item = await query.findOneOrUndefined(); if (!item) return new http_1.JSONResponse({ message: `${schema.name} not found` }).status(404); if (!identifierChangeable && identifier.name in body) delete body[identifier.name]; Object.assign(item, body); await this.getDatabase().persist(item); return item; } }; RestController.__type = [() => orm_1.DatabaseRegistry, 'registry', 'constructor', () => orm_1.Database, 'getDatabase', () => __ΩHttpQueries, () => __ΩListQuery, 'listQuery', 'readMany', () => __ΩHttpBody, () => __ΩSchemaType, 'body', 'create', () => __ΩIdentifierType, 'id', 'delete', () => __ΩIdentifierType, () => __ΩHttpQueries, () => __ΩGetQuery, 'options', 'read', () => __ΩIdentifierType, () => __ΩHttpBody, () => __ΩPartial, () => __ΩSchemaType, 'update', 'RestController', 'PP7!2"<"0#PP7$0%<Pn\'o&"2("0)Pn+o*"2,"0-Pn.2/"00Pn12/n3o2"24"05Pn62/n9o8"o7"2,"0:5w;']; __decorate([ ((Ωr = (Ωr = http_1.http.GET('') .description(`A list of ${schema.name}.`), Ωr.response.Ω = [[() => __ΩSchemaType, 'n!F']], Ωr).response(200, `List of ${schema.name}.`), Ωr.response.Ω = [[() => type_1.ValidationError, 'P7!']], Ωr).response(400, `When parameter validation failed.`)), __metadata("design:type", Function), __metadata("design:paramtypes", [Object]), __metadata("design:returntype", Promise) ], RestController.prototype, "readMany", null); __decorate([ ((Ωr = (Ωr = (Ωr = http_1.http.POST('') .description(`Add a new ${schema.name}.`), Ωr.response.Ω = [[() => __ΩSchemaType, 'n!']], Ωr).response(201, 'When successfully created.'), Ωr.response.Ω = [[() => type_1.ValidationError, 'P7!']], Ωr).response(400, `When parameter validation failed`), Ωr.response.Ω = [[() => __ΩErrorMessage, 'n!']], Ωr).response(409, 'When unique entity already exists.')), __metadata("design:type", Function), __metadata("design:paramtypes", [Object]), __metadata("design:returntype", Promise) ], RestController.prototype, "create", null); __decorate([ ((Ωr = (Ωr = http_1.http.DELETE(':' + identifier.name) .description(`Delete a single ${schema.name}.`), Ωr.response.Ω = [[() => type_1.ValidationError, 'P7!']], Ωr).response(400, `When parameter validation failed`), Ωr.response.Ω = [['deleted', 'P\'4!M']], Ωr).response(200, `When deletion was successful`)), __metadata("design:type", Function), __metadata("design:paramtypes", [Object]), __metadata("design:returntype", Promise) ], RestController.prototype, "delete", null); __decorate([ ((Ωr = (Ωr = (Ωr = http_1.http.GET(':' + identifier.name) .description(`Get a single ${schema.name}.`), Ωr.response.Ω = [[() => __ΩSchemaType, 'n!']], Ωr).response(200, `When ${schema.name} was found.`), Ωr.response.Ω = [[() => type_1.ValidationError, 'P7!']], Ωr).response(400, `When parameter validation failed`), Ωr.response.Ω = [[() => __ΩErrorMessage, 'n!']], Ωr).response(404, `When ${schema.name} was not found.`)), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, Object]), __metadata("design:returntype", Promise) ], RestController.prototype, "read", null); __decorate([ ((Ωr = (Ωr = (Ωr = http_1.http.PUT(':' + identifier.name) .description(`Update a single ${schema.name}.`), Ωr.response.Ω = [[() => __ΩSchemaType, 'n!']], Ωr).response(200, `When ${schema.name} was successfully updated.`), Ωr.response.Ω = [[() => type_1.ValidationError, 'P7!']], Ωr).response(400, `When parameter validation failed`), Ωr.response.Ω = [[() => __ΩErrorMessage, 'n!']], Ωr).response(404, `When ${schema.name} was not found.`)), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, Object]), __metadata("design:returntype", Promise) ], RestController.prototype, "update", null); RestController = __decorate([ (http_1.http.controller('/entity/' + schema.name).group('crud')), __metadata("design:paramtypes", [orm_1.DatabaseRegistry]) ], RestController); Object.defineProperty(RestController, 'name', { value: 'RestController' + schema.getClassName() }); if (options.limitOperations) { const data = http_1.httpClass._fetch(RestController); if (!data) throw new Error('httpClass has no RestController'); for (const action of data.actions) { if (!options.limitOperations.includes(action.methodName)) { data.removeAction(action.methodName); } } } return RestController; } createController.__type = [() => type_1.ReflectionClass, 'schema', () => __ΩAutoCrudOptions, 'options', () => ({}), () => __ΩClassType, 'createController', 'PP"7!2"n#2$>%n&/\'']; class CrudAppModule extends app_1.AppModule { } exports.CrudAppModule = CrudAppModule; CrudAppModule.__type = ['T', () => app_1.AppModule, 'CrudAppModule', 'b!Pe"!7"5e!!6"w#']; /** * Create a module that provides CRUD routes for given entities. */ function createCrudRoutes(schemas, options = {}) { const controllers = schemas.map(__assignType(v => type_1.ReflectionClass.from(v), ['v', '', 'P"2!"/"'])).map(__assignType(v => createController(v, options), ['v', '', 'P"2!"/"'])); return new CrudAppModule({}, { name: 'autoCrud', controllers: controllers }); } createCrudRoutes.__type = [() => __ΩClassType, () => type_1.ReflectionClass, 'schemas', () => __ΩAutoCrudOptions, 'options', () => ({}), 'createCrudRoutes', 'PPn!P"7"JF2#n$2%>&"/\'']; //# sourceMappingURL=crud.js.map