From 2db6a1d4076fb84248149d9e1388d3e6ca81ab70 Mon Sep 17 00:00:00 2001 From: Adrien de Peretti Date: Wed, 7 Jun 2023 10:57:29 +0200 Subject: [PATCH] chore(medusa): Improve database loader error handling (#4254) * chore(medusa): Improve database loader error handling * Create sharp-melons-doubt.md * move the database error handling to the utils * fix unit tests * tackle feedback * fix unit tests --- .changeset/sharp-melons-doubt.md | 5 + packages/medusa/src/loaders/database.ts | 28 +---- .../handle-postgres-database-error.spec.ts | 107 ++++++++++++++++++ .../common/handle-postgres-database-error.ts | 49 ++++++++ packages/utils/src/common/index.ts | 1 + 5 files changed, 167 insertions(+), 23 deletions(-) create mode 100644 .changeset/sharp-melons-doubt.md create mode 100644 packages/utils/src/common/__tests__/handle-postgres-database-error.spec.ts create mode 100644 packages/utils/src/common/handle-postgres-database-error.ts diff --git a/.changeset/sharp-melons-doubt.md b/.changeset/sharp-melons-doubt.md new file mode 100644 index 0000000000..bfc5d9bca4 --- /dev/null +++ b/.changeset/sharp-melons-doubt.md @@ -0,0 +1,5 @@ +--- +"@medusajs/medusa": patch +--- + +chore(medusa): Improve database loader error handling diff --git a/packages/medusa/src/loaders/database.ts b/packages/medusa/src/loaders/database.ts index 21d51503c2..1f83d6ca16 100644 --- a/packages/medusa/src/loaders/database.ts +++ b/packages/medusa/src/loaders/database.ts @@ -7,6 +7,7 @@ import { } from "typeorm" import { ConfigModule } from "../types/global" import "../utils/naming-strategy" +import { handlePostgresDatabaseError } from "@medusajs/utils" type Options = { configModule: ConfigModule @@ -52,33 +53,14 @@ export default async ({ (configModule.projectConfig.database_logging || false), } as DataSourceOptions) - try { - await dataSource.initialize() - } catch (err) { - // database name does not exist - if (err.code === "3D000") { - throw new Error( - `Specified database does not exist. Please create it and try again.\n${err.message}` - ) - } - - throw err - } + await dataSource.initialize().catch(handlePostgresDatabaseError) // If migrations are not included in the config, we assume you are attempting to start the server // Therefore, throw if the database is not migrated if (!dataSource.migrations?.length) { - try { - await dataSource.query(`select * from migrations`) - } catch (err) { - if (err.code === "42P01") { - throw new Error( - `Migrations missing. Please run 'medusa migrations run' and try again.` - ) - } - - throw err - } + await dataSource + .query(`select * from migrations`) + .catch(handlePostgresDatabaseError) } return dataSource diff --git a/packages/utils/src/common/__tests__/handle-postgres-database-error.spec.ts b/packages/utils/src/common/__tests__/handle-postgres-database-error.spec.ts new file mode 100644 index 0000000000..abae66361f --- /dev/null +++ b/packages/utils/src/common/__tests__/handle-postgres-database-error.spec.ts @@ -0,0 +1,107 @@ +import { + DatabaseErrorCode, + handlePostgresDatabaseError, +} from "../handle-postgres-database-error" +import { EOL } from "os" + +describe("handlePostgresDataError", function () { + it("should throw a specific message on database does not exists", function () { + const error = new Error("database does not exist") + Object.assign(error, { code: DatabaseErrorCode.databaseDoesNotExist }) + + let outputError: any + try { + handlePostgresDatabaseError(error) + } catch (e) { + outputError = e + } + + expect(outputError.message).toEqual( + `The specified PostgreSQL database does not exist. Please create it and try again.${EOL}${error.message}` + ) + }) + + it("should throw a specific message on database connection failure", function () { + const error = new Error("database does not exist") + Object.assign(error, { code: DatabaseErrorCode.connectionFailure }) + + let outputError: any + try { + handlePostgresDatabaseError(error) + } catch (e) { + outputError = e + } + + expect(outputError.message).toEqual( + `Failed to establish a connection to PostgreSQL. Please ensure the following is true and try again: + - You have a PostgreSQL database running + - You have passed the correct credentials in medusa-config.js + - You have formatted the database connection string correctly. See below: + "postgres://[username]:[password]@[host]:[post]/[db_name]" - If there is no password, you can omit it from the connection string + ${EOL} + ${error.message}` + ) + }) + + it("should throw a specific message on database wrong credentials", function () { + const error = new Error("database does not exist") + Object.assign(error, { code: DatabaseErrorCode.wrongCredentials }) + + let outputError: any + try { + handlePostgresDatabaseError(error) + } catch (e) { + outputError = e + } + + expect(outputError.message).toEqual( + `The specified credentials does not exists for the specified PostgreSQL database.${EOL}${error.message}` + ) + }) + + it("should throw a specific message on database not found", function () { + const error = new Error("database does not exist") + Object.assign(error, { code: DatabaseErrorCode.notFound }) + + let outputError: any + try { + handlePostgresDatabaseError(error) + } catch (e) { + outputError = e + } + + expect(outputError.message).toEqual( + `The specified connection string for your PostgreSQL database might have illegal characters. Please check that it only contains allowed characters [a-zA-Z0-9]${EOL}${error.message}` + ) + }) + + it("should throw a specific message on database migration missing", function () { + const error = new Error("database does not exist") + Object.assign(error, { code: DatabaseErrorCode.migrationMissing }) + + let outputError: any + try { + handlePostgresDatabaseError(error) + } catch (e) { + outputError = e + } + + expect(outputError.message).toEqual( + `Migrations missing. Please run 'medusa migrations run' and try again.` + ) + }) + + it("should re throw unhandled error code", function () { + const error = new Error("database does not exist") + Object.assign(error, { code: "test" }) + + let outputError: any + try { + handlePostgresDatabaseError(error) + } catch (e) { + outputError = e + } + + expect(outputError.message).toEqual("database does not exist") + }) +}) diff --git a/packages/utils/src/common/handle-postgres-database-error.ts b/packages/utils/src/common/handle-postgres-database-error.ts new file mode 100644 index 0000000000..64866a5e67 --- /dev/null +++ b/packages/utils/src/common/handle-postgres-database-error.ts @@ -0,0 +1,49 @@ +import { EOL } from "os" + +export const DatabaseErrorCode = { + databaseDoesNotExist: "3D000", + connectionFailure: "ECONNREFUSED", + wrongCredentials: "28000", + notFound: "ENOTFOUND", + migrationMissing: "42P01", +} + +export function handlePostgresDatabaseError(err: any): never { + if (DatabaseErrorCode.databaseDoesNotExist === err.code) { + throw new Error( + `The specified PostgreSQL database does not exist. Please create it and try again.${EOL}${err.message}` + ) + } + + if (DatabaseErrorCode.connectionFailure === err.code) { + throw new Error( + `Failed to establish a connection to PostgreSQL. Please ensure the following is true and try again: + - You have a PostgreSQL database running + - You have passed the correct credentials in medusa-config.js + - You have formatted the database connection string correctly. See below: + "postgres://[username]:[password]@[host]:[post]/[db_name]" - If there is no password, you can omit it from the connection string + ${EOL} + ${err.message}` + ) + } + + if (DatabaseErrorCode.wrongCredentials === err.code) { + throw new Error( + `The specified credentials does not exists for the specified PostgreSQL database.${EOL}${err.message}` + ) + } + + if (DatabaseErrorCode.notFound === err.code) { + throw new Error( + `The specified connection string for your PostgreSQL database might have illegal characters. Please check that it only contains allowed characters [a-zA-Z0-9]${EOL}${err.message}` + ) + } + + if (DatabaseErrorCode.migrationMissing === err.code) { + throw new Error( + `Migrations missing. Please run 'medusa migrations run' and try again.` + ) + } + + throw err +} diff --git a/packages/utils/src/common/index.ts b/packages/utils/src/common/index.ts index 8d444ebe48..af7af561a5 100644 --- a/packages/utils/src/common/index.ts +++ b/packages/utils/src/common/index.ts @@ -11,3 +11,4 @@ export * from "./medusa-container" export * from "./set-metadata" export * from "./wrap-handler" export * from "./build-query" +export * from "./handle-postgres-database-error"