@deepkit/framework
Version:
232 lines • 14.8 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);
};
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
;