json-api-nestjs
Version:
JsonApi Plugin for NestJs
231 lines • 9.73 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExecuteService = void 0;
exports.isZodError = isZodError;
const tslib_1 = require("tslib");
const common_1 = require("@nestjs/common");
const constants_1 = require("@nestjs/common/constants");
const core_1 = require("@nestjs/core");
const nestjs_shared_1 = require("../../../utils/nestjs-shared");
const interceptors_1 = require("@nestjs/core/interceptors");
const rxjs_1 = require("rxjs");
const async_hooks_1 = require("async_hooks");
const constants_2 = require("../constants");
const constants_3 = require("../../../constants");
function isZodError(param) {
return (param instanceof Object &&
'message' in param &&
Array.isArray(param.message) &&
'path' in param.message[0]);
}
let ExecuteService = class ExecuteService {
// @Inject(CURRENT_DATA_SOURCE_TOKEN) private readonly dataSource!: DataSource;
moduleRef;
asyncIteratorFactory;
runInTransaction;
mapControllerInterceptor;
asyncLocalStorage;
_interceptorsContextCreator;
get interceptorsContextCreator() {
if (!this._interceptorsContextCreator) {
this._interceptorsContextCreator = new interceptors_1.InterceptorsContextCreator(this.moduleRef.container, this.moduleRef.applicationConfig);
}
return this._interceptorsContextCreator;
}
interceptorsConsumer = new interceptors_1.InterceptorsConsumer();
async run(params, tmpIds) {
return this.runInTransaction(() => this.executeOperations(params, tmpIds));
}
async executeOperations(params, tmpIds = []) {
const iterateParams = this.asyncIteratorFactory.createIterator(params, this.runOneOperation.bind(this));
const resultArray = [];
let i = 0;
const tmpIdsMap = {};
try {
for await (const item of iterateParams) {
const currentParams = params[i];
const controller = this.getControllerInstance(currentParams);
const methodName = currentParams.methodName;
const paramsForExecute = item;
const itemReplace = this.replaceTmpIds(paramsForExecute, tmpIdsMap);
const body = itemReplace.at(-1);
const currentTmpId = tmpIds[i];
if (methodName === 'postOne' && currentTmpId && body) {
if (typeof body === 'object' && 'attributes' in body) {
body['id'] = `${currentTmpId}`;
itemReplace[itemReplace.length - 1];
}
}
const interceptors = this.getInterceptorsArray(controller, controller[methodName], currentParams.module);
const result$ = await this.interceptorsConsumer.intercept(interceptors, [
...Object.values(this.asyncLocalStorage.getStore() || {}),
itemReplace,
], controller,
// @ts-ignore
controller[methodName],
// @ts-ignore
async () => controller[methodName](...itemReplace));
const result = interceptors.length === 0
? await result$
: await (0, rxjs_1.lastValueFrom)(result$);
if (tmpIds[i] && result && !Array.isArray(result.data) && result.data) {
tmpIdsMap[tmpIds[i]] = result.data.id;
}
if (result instanceof Object) {
resultArray.push(result);
}
i++;
}
}
catch (e) {
this.processException(e, i);
}
return resultArray;
}
getInterceptorsArray(controller, callback, module) {
let controllerFromMap = this.mapControllerInterceptor.get(controller);
if (!controllerFromMap) {
controllerFromMap = new Map();
this.mapControllerInterceptor.set(controller, controllerFromMap);
}
const interceptorsFromMap = controllerFromMap.get(callback);
if (interceptorsFromMap) {
return interceptorsFromMap;
}
const interceptorsForController = this.interceptorsContextCreator.create(controller, callback, module.token);
const interceptorsForMethode = new Set(Reflect.getMetadata(constants_1.INTERCEPTORS_METADATA, callback) || []);
const resultInterceptors = interceptorsForController.filter((i) => interceptorsForMethode.has(i.constructor));
controllerFromMap.set(callback, resultInterceptors);
return resultInterceptors;
}
replaceTmpIds(inputParams, tmpIdsMap) {
const bodyInput = inputParams.at(-1);
if (!bodyInput) {
return inputParams;
}
if (typeof bodyInput === 'string') {
return inputParams;
}
if (typeof bodyInput === 'number') {
return inputParams;
}
if (Array.isArray(bodyInput)) {
return inputParams;
}
if (!(typeof bodyInput === 'object' && 'relationships' in bodyInput)) {
return inputParams;
}
const { relationships } = bodyInput;
if (!relationships) {
return inputParams;
}
bodyInput.relationships = nestjs_shared_1.ObjectTyped.entries(relationships).reduce((acum, [name, val]) => {
if (!val)
throw new Error('Va; undefined');
const { data } = val;
if (Array.isArray(data)) {
acum[name] = {
data: data.map((i) => {
if (i === null)
return i;
return {
...i,
id: tmpIdsMap[i['id']] ? `${tmpIdsMap[i['id']]}` : i['id'],
};
}),
};
}
else {
if (!data) {
acum[name] = val;
}
else {
data['id'] = tmpIdsMap[data['id']]
? `${tmpIdsMap[data['id']]}`
: data['id'];
acum[name] = {
data,
};
}
}
return acum;
}, { ...relationships });
inputParams[inputParams.length - 1] = bodyInput;
return inputParams;
}
getControllerInstance(params) {
const controllerClass = params.controller;
const controllerInstanceWrapper = params.module.controllers.get(controllerClass);
if (!controllerInstanceWrapper) {
const error = {
code: 'invalid_arguments',
path: ['type'],
message: `Controller "${controllerClass.name}" not found`,
};
throw new common_1.NotFoundException([error]);
}
return controllerInstanceWrapper.instance;
}
processException(e, i) {
if (e instanceof common_1.HttpException) {
const response = e.getResponse();
if (isZodError(response)) {
response['message'] = response['message'].map((m) => {
m['path'] = [constants_2.KEY_MAIN_INPUT_SCHEMA, `${i}`, ...m['path']];
return m;
});
}
throw new common_1.HttpException(response, e.getStatus());
}
throw e;
}
async runOneOperation(paramForExecute) {
const { params, controller, methodName, module } = paramForExecute;
const pramsPipe = Object.values(Reflect.getMetadata(constants_1.ROUTE_ARGS_METADATA, controller, methodName));
const resultParams = new Array(params.length);
for (const { pipes, index } of pramsPipe) {
resultParams[index] = await this.runPipes(params[index], module, pipes);
}
return resultParams;
}
async runPipes(initialParams, module, pipes) {
let modifiedParams = initialParams;
for (const pipe of pipes) {
const pipeInstance = this.getPipeInstance(pipe, module);
modifiedParams = await pipeInstance.transform(modifiedParams, {});
}
return modifiedParams;
}
getPipeInstance(pipe, module) {
const instanceWrapper = module.getProviderByKey(pipe);
if (!instanceWrapper) {
return this.moduleRef.get(pipe, { strict: false });
}
return instanceWrapper.instance;
}
};
exports.ExecuteService = ExecuteService;
tslib_1.__decorate([
(0, common_1.Inject)(core_1.ModuleRef),
tslib_1.__metadata("design:type", Object)
], ExecuteService.prototype, "moduleRef", void 0);
tslib_1.__decorate([
(0, common_1.Inject)(constants_2.ASYNC_ITERATOR_FACTORY),
tslib_1.__metadata("design:type", Object)
], ExecuteService.prototype, "asyncIteratorFactory", void 0);
tslib_1.__decorate([
(0, common_1.Inject)(constants_3.RUN_IN_TRANSACTION_FUNCTION),
tslib_1.__metadata("design:type", Function)
], ExecuteService.prototype, "runInTransaction", void 0);
tslib_1.__decorate([
(0, common_1.Inject)(constants_2.MAP_CONTROLLER_INTERCEPTORS),
tslib_1.__metadata("design:type", Object)
], ExecuteService.prototype, "mapControllerInterceptor", void 0);
tslib_1.__decorate([
(0, common_1.Inject)(async_hooks_1.AsyncLocalStorage),
tslib_1.__metadata("design:type", async_hooks_1.AsyncLocalStorage)
], ExecuteService.prototype, "asyncLocalStorage", void 0);
exports.ExecuteService = ExecuteService = tslib_1.__decorate([
(0, common_1.Injectable)()
], ExecuteService);
//# sourceMappingURL=execute.service.js.map