import { AddDataStoreRowsDto, AddDataStoreColumnDto, CreateDataStoreDto, DeleteDataStoreRowsQueryDto, ListDataStoreContentQueryDto, ListDataStoreQueryDto, MoveDataStoreColumnDto, UpdateDataStoreDto, UpdateDataTableRowDto, UpsertDataStoreRowDto, } from '@n8n/api-types'; import { AuthenticatedRequest } from '@n8n/db'; import { Body, Delete, Get, Param, Patch, Post, ProjectScope, Query, RestController, } from '@n8n/decorators'; import { BadRequestError } from '@/errors/response-errors/bad-request.error'; import { ConflictError } from '@/errors/response-errors/conflict.error'; import { InternalServerError } from '@/errors/response-errors/internal-server.error'; import { NotFoundError } from '@/errors/response-errors/not-found.error'; import { DataStoreService } from './data-store.service'; import { DataStoreColumnNameConflictError } from './errors/data-store-column-name-conflict.error'; import { DataStoreColumnNotFoundError } from './errors/data-store-column-not-found.error'; import { DataStoreNameConflictError } from './errors/data-store-name-conflict.error'; import { DataStoreNotFoundError } from './errors/data-store-not-found.error'; import { DataStoreValidationError } from './errors/data-store-validation.error'; import { DataStoreRowReturn } from 'n8n-workflow'; @RestController('/projects/:projectId/data-tables') export class DataStoreController { constructor(private readonly dataStoreService: DataStoreService) {} @Post('/') @ProjectScope('dataStore:create') async createDataStore( req: AuthenticatedRequest<{ projectId: string }>, _res: Response, @Body dto: CreateDataStoreDto, ) { try { return await this.dataStoreService.createDataStore(req.params.projectId, dto); } catch (e: unknown) { if (!(e instanceof Error)) { throw e; } else if (e instanceof DataStoreNameConflictError) { throw new ConflictError(e.message); } else { throw new InternalServerError(e.message, e); } } } @Get('/') @ProjectScope('dataStore:listProject') async listProjectDataStores( req: AuthenticatedRequest<{ projectId: string }>, _res: Response, @Query payload: ListDataStoreQueryDto, ) { const providedFilter = payload?.filter ?? {}; return await this.dataStoreService.getManyAndCount({ ...payload, filter: { ...providedFilter, projectId: req.params.projectId }, }); } @Patch('/:dataStoreId') @ProjectScope('dataStore:update') async updateDataStore( req: AuthenticatedRequest<{ projectId: string }>, _res: Response, @Param('dataStoreId') dataStoreId: string, @Body dto: UpdateDataStoreDto, ) { try { return await this.dataStoreService.updateDataStore(dataStoreId, req.params.projectId, dto); } catch (e: unknown) { if (e instanceof DataStoreNotFoundError) { throw new NotFoundError(e.message); } else if (e instanceof DataStoreNameConflictError) { throw new ConflictError(e.message); } else if (e instanceof Error) { throw new InternalServerError(e.message, e); } else { throw e; } } } @Delete('/:dataStoreId') @ProjectScope('dataStore:delete') async deleteDataStore( req: AuthenticatedRequest<{ projectId: string }>, _res: Response, @Param('dataStoreId') dataStoreId: string, ) { try { return await this.dataStoreService.deleteDataStore(dataStoreId, req.params.projectId); } catch (e: unknown) { if (e instanceof DataStoreNotFoundError) { throw new NotFoundError(e.message); } else if (e instanceof Error) { throw new InternalServerError(e.message, e); } else { throw e; } } } @Get('/:dataStoreId/columns') @ProjectScope('dataStore:read') async getColumns( req: AuthenticatedRequest<{ projectId: string }>, _res: Response, @Param('dataStoreId') dataStoreId: string, ) { try { return await this.dataStoreService.getColumns(dataStoreId, req.params.projectId); } catch (e: unknown) { if (e instanceof DataStoreNotFoundError) { throw new NotFoundError(e.message); } else if (e instanceof Error) { throw new InternalServerError(e.message, e); } else { throw e; } } } @Post('/:dataStoreId/columns') @ProjectScope('dataStore:update') async addColumn( req: AuthenticatedRequest<{ projectId: string }>, _res: Response, @Param('dataStoreId') dataStoreId: string, @Body dto: AddDataStoreColumnDto, ) { try { return await this.dataStoreService.addColumn(dataStoreId, req.params.projectId, dto); } catch (e: unknown) { if (e instanceof DataStoreNotFoundError) { throw new NotFoundError(e.message); } else if (e instanceof DataStoreColumnNameConflictError) { throw new ConflictError(e.message); } else if (e instanceof Error) { throw new InternalServerError(e.message, e); } else { throw e; } } } @Delete('/:dataStoreId/columns/:columnId') @ProjectScope('dataStore:update') async deleteColumn( req: AuthenticatedRequest<{ projectId: string }>, _res: Response, @Param('dataStoreId') dataStoreId: string, @Param('columnId') columnId: string, ) { try { return await this.dataStoreService.deleteColumn(dataStoreId, req.params.projectId, columnId); } catch (e: unknown) { if (e instanceof DataStoreNotFoundError || e instanceof DataStoreColumnNotFoundError) { throw new NotFoundError(e.message); } else if (e instanceof Error) { throw new InternalServerError(e.message, e); } else { throw e; } } } @Patch('/:dataStoreId/columns/:columnId/move') @ProjectScope('dataStore:update') async moveColumn( req: AuthenticatedRequest<{ projectId: string }>, _res: Response, @Param('dataStoreId') dataStoreId: string, @Param('columnId') columnId: string, @Body dto: MoveDataStoreColumnDto, ) { try { return await this.dataStoreService.moveColumn( dataStoreId, req.params.projectId, columnId, dto, ); } catch (e: unknown) { if (e instanceof DataStoreNotFoundError || e instanceof DataStoreColumnNotFoundError) { throw new NotFoundError(e.message); } else if (e instanceof DataStoreValidationError) { throw new BadRequestError(e.message); } else if (e instanceof Error) { throw new InternalServerError(e.message, e); } else { throw e; } } } @Get('/:dataStoreId/rows') @ProjectScope('dataStore:readRow') async getDataStoreRows( req: AuthenticatedRequest<{ projectId: string }>, _res: Response, @Param('dataStoreId') dataStoreId: string, @Query dto: ListDataStoreContentQueryDto, ) { try { return await this.dataStoreService.getManyRowsAndCount( dataStoreId, req.params.projectId, dto, ); } catch (e: unknown) { if (e instanceof DataStoreNotFoundError) { throw new NotFoundError(e.message); } else if (e instanceof Error) { throw new InternalServerError(e.message, e); } else { throw e; } } } /** * @returns the IDs of the inserted rows */ async appendDataStoreRows( req: AuthenticatedRequest<{ projectId: string }>, _res: Response, dataStoreId: string, dto: AddDataStoreRowsDto & { returnData?: T }, ): Promise>>; @Post('/:dataStoreId/insert') @ProjectScope('dataStore:writeRow') async appendDataStoreRows( req: AuthenticatedRequest<{ projectId: string }>, _res: Response, @Param('dataStoreId') dataStoreId: string, @Body dto: AddDataStoreRowsDto, ) { try { return await this.dataStoreService.insertRows( dataStoreId, req.params.projectId, dto.data, dto.returnData, ); } catch (e: unknown) { if (e instanceof DataStoreNotFoundError) { throw new NotFoundError(e.message); } else if (e instanceof DataStoreValidationError) { throw new BadRequestError(e.message); } else if (e instanceof Error) { throw new InternalServerError(e.message, e); } else { throw e; } } } @Post('/:dataStoreId/upsert') @ProjectScope('dataStore:writeRow') async upsertDataStoreRow( req: AuthenticatedRequest<{ projectId: string }>, _res: Response, @Param('dataStoreId') dataStoreId: string, @Body dto: UpsertDataStoreRowDto, ) { try { return await this.dataStoreService.upsertRow( dataStoreId, req.params.projectId, dto, dto.returnData, ); } catch (e: unknown) { if (e instanceof DataStoreNotFoundError) { throw new NotFoundError(e.message); } else if (e instanceof DataStoreValidationError) { throw new BadRequestError(e.message); } else if (e instanceof Error) { throw new InternalServerError(e.message, e); } else { throw e; } } } @Patch('/:dataStoreId/rows') @ProjectScope('dataStore:writeRow') async updateDataStoreRow( req: AuthenticatedRequest<{ projectId: string }>, _res: Response, @Param('dataStoreId') dataStoreId: string, @Body dto: UpdateDataTableRowDto, ) { try { return await this.dataStoreService.updateRow( dataStoreId, req.params.projectId, dto, dto.returnData, ); } catch (e: unknown) { if (e instanceof DataStoreNotFoundError) { throw new NotFoundError(e.message); } else if (e instanceof DataStoreValidationError) { throw new BadRequestError(e.message); } else if (e instanceof Error) { throw new InternalServerError(e.message, e); } else { throw e; } } } @Delete('/:dataStoreId/rows') @ProjectScope('dataStore:writeRow') async deleteDataStoreRows( req: AuthenticatedRequest<{ projectId: string }>, _res: Response, @Param('dataStoreId') dataStoreId: string, @Query dto: DeleteDataStoreRowsQueryDto, ) { try { const { ids } = dto; return await this.dataStoreService.deleteRows(dataStoreId, req.params.projectId, ids); } catch (e: unknown) { if (e instanceof DataStoreNotFoundError) { throw new NotFoundError(e.message); } else if (e instanceof Error) { throw new InternalServerError(e.message, e); } else { throw e; } } } }