From 543a44a9c2133b25b1c8fdc435712635ab6bfab3 Mon Sep 17 00:00:00 2001 From: mertmit Date: Fri, 19 Apr 2024 05:49:57 +0000 Subject: [PATCH] fix: db error handling --- .../global-exception.filter.ts | 2 + packages/nocodb/src/helpers/catchError.ts | 101 ++++++++++-------- 2 files changed, 59 insertions(+), 44 deletions(-) diff --git a/packages/nocodb/src/filters/global-exception/global-exception.filter.ts b/packages/nocodb/src/filters/global-exception/global-exception.filter.ts index 96df28b22b..b58adc793d 100644 --- a/packages/nocodb/src/filters/global-exception/global-exception.filter.ts +++ b/packages/nocodb/src/filters/global-exception/global-exception.filter.ts @@ -7,6 +7,7 @@ import type { Request, Response } from 'express'; import { AjvError, BadRequest, + ExternalError, extractDBError, Forbidden, NcBaseErrorv2, @@ -49,6 +50,7 @@ export class GlobalExceptionFilter implements ExceptionFilter { exception instanceof UnprocessableEntity || exception instanceof NotFoundException || exception instanceof ThrottlerException || + exception instanceof ExternalError || (exception instanceof NcBaseErrorv2 && ![ NcErrorType.INTERNAL_SERVER_ERROR, diff --git a/packages/nocodb/src/helpers/catchError.ts b/packages/nocodb/src/helpers/catchError.ts index 0d14fd0893..5e413d9e4b 100644 --- a/packages/nocodb/src/helpers/catchError.ts +++ b/packages/nocodb/src/helpers/catchError.ts @@ -1,7 +1,10 @@ import { NcErrorType } from 'nocodb-sdk'; +import { Logger } from '@nestjs/common'; import type { ErrorObject } from 'ajv'; import { defaultLimitConfig } from '~/helpers/extractLimitAndOffset'; +const dbErrorLogger = new Logger('DBError'); + export enum DBError { TABLE_EXIST = 'TABLE_EXIST', TABLE_NOT_EXIST = 'TABLE_NOT_EXIST', @@ -14,16 +17,15 @@ export enum DBError { // extract db errors using database error code export function extractDBError(error): { - type: DBError; message: string; - info: any; - extra?: Record; + error: string; + details?: any; } | void { if (!error.code) return; let message: string; - let extra: Record; - let type: DBError; + let _extra: Record; + let _type: DBError; // todo: handle not null constraint error for all databases switch (error.code) { @@ -37,7 +39,7 @@ export function extractDBError(error): { ? error.message.match(/FOREIGN KEY|UNIQUE/gi)?.join(' ') : 'constraint'; message = `A ${constraint} constraint was violated: ${error.message}`; - extra = { + _extra = { constraint, }; } @@ -69,25 +71,25 @@ export function extractDBError(error): { if (noSuchTableMatch && noSuchTableMatch[1]) { message = `The table '${noSuchTableMatch[1]}' does not exist.`; - type = DBError.TABLE_NOT_EXIST; - extra = { + _type = DBError.TABLE_NOT_EXIST; + _extra = { table: noSuchTableMatch[1], }; } else if (tableAlreadyExistsMatch && tableAlreadyExistsMatch[1]) { message = `The table '${tableAlreadyExistsMatch[1]}' already exists.`; - type = DBError.TABLE_EXIST; - extra = { + _type = DBError.TABLE_EXIST; + _extra = { table: tableAlreadyExistsMatch[1], }; } else if (unrecognizedTokenMatch && unrecognizedTokenMatch[1]) { message = `Unrecognized token: ${unrecognizedTokenMatch[1]}`; - extra = { + _extra = { token: unrecognizedTokenMatch[1], }; } else if (columnDoesNotExistMatch && columnDoesNotExistMatch[1]) { message = `The column ${columnDoesNotExistMatch[1]} does not exist.`; - type = DBError.COLUMN_NOT_EXIST; - extra = { + _type = DBError.COLUMN_NOT_EXIST; + _extra = { column: columnDoesNotExistMatch[1], }; } else if (constraintFailedMatch && constraintFailedMatch[1]) { @@ -97,8 +99,8 @@ export function extractDBError(error): { duplicateColumnExistsMatch[1] ) { message = `The column '${duplicateColumnExistsMatch[1]}' already exists.`; - type = DBError.COLUMN_EXIST; - extra = { + _type = DBError.COLUMN_EXIST; + _extra = { column: duplicateColumnExistsMatch[1], }; } else { @@ -126,8 +128,8 @@ export function extractDBError(error): { ); if (extractTableNameMatch && extractTableNameMatch[1]) { message = `The table '${extractTableNameMatch[1]}' already exists.`; - type = DBError.TABLE_EXIST; - extra = { + _type = DBError.TABLE_EXIST; + _extra = { table: extractTableNameMatch[1], }; } @@ -142,8 +144,8 @@ export function extractDBError(error): { ); if (extractColumnNameMatch && extractColumnNameMatch[1]) { message = `The column '${extractColumnNameMatch[1]}' already exists.`; - type = DBError.COLUMN_EXIST; - extra = { + _type = DBError.COLUMN_EXIST; + _extra = { column: extractColumnNameMatch[1], }; } @@ -159,8 +161,8 @@ export function extractDBError(error): { ); if (missingTableMatch && missingTableMatch[1]) { message = `The table '${missingTableMatch[1]}' does not exist`; - type = DBError.TABLE_NOT_EXIST; - extra = { + _type = DBError.TABLE_NOT_EXIST; + _extra = { table: missingTableMatch[1], }; } @@ -184,8 +186,8 @@ export function extractDBError(error): { ); if (extractColNameMatch && extractColNameMatch[1]) { message = `The column '${extractColNameMatch[1]}' cannot be null.`; - type = DBError.COLUMN_NOT_NULL; - extra = { + _type = DBError.COLUMN_NOT_NULL; + _extra = { column: extractColNameMatch[1], }; } @@ -203,8 +205,8 @@ export function extractDBError(error): { ); if (extractColNameMatch && extractColNameMatch[1]) { message = `The column '${extractColNameMatch[1]}' does not exist.`; - type = DBError.COLUMN_NOT_EXIST; - extra = { + _type = DBError.COLUMN_NOT_EXIST; + _extra = { column: extractColNameMatch[1], }; } @@ -251,6 +253,9 @@ export function extractDBError(error): { case '23506': message = 'This record is being referenced by other records.'; break; + case '3D000': + message = 'The database does not exist.'; + break; case '42P07': message = 'The table already exists.'; if (error.message) { @@ -259,8 +264,8 @@ export function extractDBError(error): { ); if (extractTableNameMatch && extractTableNameMatch[1]) { message = `The table '${extractTableNameMatch[1]}' already exists.`; - type = DBError.TABLE_EXIST; - extra = { + _type = DBError.TABLE_EXIST; + _extra = { table: extractTableNameMatch[1], }; } @@ -274,8 +279,8 @@ export function extractDBError(error): { ); if (extractTableNameMatch && extractTableNameMatch[1]) { message = `The column '${extractTableNameMatch[1]}' already exists.`; - type = DBError.COLUMN_EXIST; - extra = { + _type = DBError.COLUMN_EXIST; + _extra = { column: extractTableNameMatch[1], }; } @@ -289,8 +294,8 @@ export function extractDBError(error): { ); if (extractTableNameMatch && extractTableNameMatch[1]) { message = `The table '${extractTableNameMatch[1]}' does not exist.`; - type = DBError.TABLE_NOT_EXIST; - extra = { + _type = DBError.TABLE_NOT_EXIST; + _extra = { table: extractTableNameMatch[1], }; } @@ -304,8 +309,8 @@ export function extractDBError(error): { ); if (extractTableNameMatch && extractTableNameMatch[1]) { message = `The column '${extractTableNameMatch[1]}' does not exist.`; - type = DBError.COLUMN_NOT_EXIST; - extra = { + _type = DBError.COLUMN_NOT_EXIST; + _extra = { column: extractTableNameMatch[1], }; } @@ -330,26 +335,26 @@ export function extractDBError(error): { if (extractTableNameMatch && extractTableNameMatch[1]) { message = `The table '${extractTableNameMatch[1]}' already exists.`; - type = DBError.TABLE_EXIST; - extra = { + _type = DBError.TABLE_EXIST; + _extra = { table: extractTableNameMatch[1], }; } else if (extractDupColMatch && extractDupColMatch[1]) { message = `The column '${extractDupColMatch[1]}' already exists.`; - type = DBError.COLUMN_EXIST; - extra = { + _type = DBError.COLUMN_EXIST; + _extra = { column: extractDupColMatch[1], }; } else if (extractMissingTableMatch && extractMissingTableMatch[1]) { message = `The table '${extractMissingTableMatch[1]}' does not exist`; - type = DBError.TABLE_NOT_EXIST; - extra = { + _type = DBError.TABLE_NOT_EXIST; + _extra = { table: extractMissingTableMatch[1], }; } else if (extractMissingColMatch && extractMissingColMatch[1]) { message = `The column '${extractMissingColMatch[1]}' does not exist`; - type = DBError.COLUMN_NOT_EXIST; - extra = { + _type = DBError.COLUMN_NOT_EXIST; + _extra = { column: extractMissingColMatch[1], }; } @@ -374,6 +379,9 @@ export function extractDBError(error): { message = 'The host is down.'; break; default: + // log error for unknown error code + dbErrorLogger.error(error); + // if error message contains -- then extract message after -- if (error.message && error.message.includes('--')) { message = error.message.split('--')[1]; @@ -383,10 +391,8 @@ export function extractDBError(error): { if (message) { return { + error: NcErrorType.DATABASE_ERROR, message, - type, - extra, - info: { message: error.message, code: error.code }, }; } } @@ -407,6 +413,13 @@ export class Forbidden extends NcBaseError {} export class NotFound extends NcBaseError {} +export class ExternalError extends NcBaseError { + constructor(error: Error) { + super(error.message); + Object.assign(this, error); + } +} + export class UnprocessableEntity extends NcBaseError {} export class AjvError extends NcBaseError {