n8n/packages/cli/src/evaluation.ee/metrics.controller.ts

130 lines
3.9 KiB
TypeScript

import express from 'express';
import { TestMetricRepository } from '@/databases/repositories/test-metric.repository.ee';
import { Delete, Get, Patch, Post, RestController } from '@/decorators';
import { NotFoundError } from '@/errors/response-errors/not-found.error';
import {
testMetricCreateRequestBodySchema,
testMetricPatchRequestBodySchema,
} from '@/evaluation.ee/metric.schema';
import { getSharedWorkflowIds } from '@/public-api/v1/handlers/workflows/workflows.service';
import { TestDefinitionService } from './test-definition.service.ee';
import { TestMetricsRequest } from './test-definitions.types.ee';
@RestController('/evaluation/test-definitions')
export class TestMetricsController {
constructor(
private readonly testDefinitionService: TestDefinitionService,
private readonly testMetricRepository: TestMetricRepository,
) {}
// This method is used in multiple places in the controller to get the test definition
// (or just check that it exists and the user has access to it).
private async getTestDefinition(
req:
| TestMetricsRequest.GetOne
| TestMetricsRequest.GetMany
| TestMetricsRequest.Patch
| TestMetricsRequest.Delete
| TestMetricsRequest.Create,
) {
const { testDefinitionId } = req.params;
const userAccessibleWorkflowIds = await getSharedWorkflowIds(req.user, ['workflow:read']);
const testDefinition = await this.testDefinitionService.findOne(
testDefinitionId,
userAccessibleWorkflowIds,
);
if (!testDefinition) throw new NotFoundError('Test definition not found');
return testDefinition;
}
@Get('/:testDefinitionId/metrics')
async getMany(req: TestMetricsRequest.GetMany) {
const { testDefinitionId } = req.params;
await this.getTestDefinition(req);
return await this.testMetricRepository.find({
where: { testDefinition: { id: testDefinitionId } },
});
}
@Get('/:testDefinitionId/metrics/:id')
async getOne(req: TestMetricsRequest.GetOne) {
const { id: metricId, testDefinitionId } = req.params;
await this.getTestDefinition(req);
const metric = await this.testMetricRepository.findOne({
where: { id: metricId, testDefinition: { id: testDefinitionId } },
});
if (!metric) throw new NotFoundError('Metric not found');
return metric;
}
@Post('/:testDefinitionId/metrics')
async create(req: TestMetricsRequest.Create, res: express.Response) {
const bodyParseResult = testMetricCreateRequestBodySchema.safeParse(req.body);
if (!bodyParseResult.success) {
res.status(400).json({ errors: bodyParseResult.error.errors });
return;
}
const testDefinition = await this.getTestDefinition(req);
const metric = this.testMetricRepository.create({
...req.body,
testDefinition,
});
return await this.testMetricRepository.save(metric);
}
@Patch('/:testDefinitionId/metrics/:id')
async patch(req: TestMetricsRequest.Patch, res: express.Response) {
const { id: metricId, testDefinitionId } = req.params;
const bodyParseResult = testMetricPatchRequestBodySchema.safeParse(req.body);
if (!bodyParseResult.success) {
res.status(400).json({ errors: bodyParseResult.error.errors });
return;
}
await this.getTestDefinition(req);
const metric = await this.testMetricRepository.findOne({
where: { id: metricId, testDefinition: { id: testDefinitionId } },
});
if (!metric) throw new NotFoundError('Metric not found');
await this.testMetricRepository.update(metricId, bodyParseResult.data);
// Respond with the updated metric
return await this.testMetricRepository.findOneBy({ id: metricId });
}
@Delete('/:testDefinitionId/metrics/:id')
async delete(req: TestMetricsRequest.Delete) {
const { id: metricId, testDefinitionId } = req.params;
await this.getTestDefinition(req);
const metric = await this.testMetricRepository.findOne({
where: { id: metricId, testDefinition: { id: testDefinitionId } },
});
if (!metric) throw new NotFoundError('Metric not found');
await this.testMetricRepository.delete(metricId);
return { success: true };
}
}