4.0 KiB
DatabaseError / MigrationError
(no submodules)
Purpose
DatabaseError is the structured error class for all database failures in @suaveplan/db. It extends SuaveplanError from @suaveplan/error, ensuring every database error carries a stable, machine-readable DB.* code alongside a human-readable message and optional cause chain. MigrationError is a specialisation that records which named migration failed.
Using SuaveplanError as the base means consumers can perform type-safe instanceof checks, extract OTel-compatible codes from error.code, and inspect cause chains consistently across the entire Suaveplan project.
Features
- Extends
SuaveplanError<DbCode>— participates in the project-wide error hierarchy - Stable
DB.*codes registered viadefineCodes— never change between versions causethreading — wraps lower-level driver errors without losing the original stackMigrationError.migrationfield — names the exact migration file that failednameproperty set to the concrete class name for easy identification in logs
Usage: Basic Example
import { DatabaseError, MigrationError, DB_CODES } from "@suaveplan/db";
// Throw a connection failure
throw new DatabaseError(
DB_CODES.CONNECTION_FAILED,
"Could not reach postgres://localhost:5432/app"
);
// Throw a migration failure
throw new MigrationError("003_add_index", "duplicate column name: email");
Usage: Advanced Example
import { DatabaseError, DB_CODES } from "@suaveplan/db";
import { SuaveplanError } from "@suaveplan/error";
async function runQuery(sql: string): Promise<unknown[]> {
try {
return await driver.query(sql);
} catch (cause) {
throw new DatabaseError(
DB_CODES.QUERY_FAILED,
`Query failed: ${cause instanceof Error ? cause.message : String(cause)}`,
{ cause: cause instanceof Error ? cause : undefined }
);
}
}
// Narrowing in catch blocks
try {
await runQuery("SELECT * FROM users");
} catch (err) {
if (err instanceof DatabaseError) {
console.error(err.code, err.message); // "DB.QUERY_FAILED Query failed: ..."
}
}
API Reference
DatabaseError
class DatabaseError extends SuaveplanError<DbCode> {
constructor(code: DbCode, message: string, options?: SuaveplanErrorOptions): void
}
code(DbCode) — one ofDB.CONNECTION_FAILED,DB.NOT_CONNECTED,DB.QUERY_FAILED,DB.TRANSACTION_FAILED,DB.MIGRATION_FAILEDmessage(string) — human-readable descriptionoptions.cause(Error | undefined) — lower-level error that triggered this one
MigrationError
class MigrationError extends DatabaseError {
readonly migration: string;
constructor(migration: string, detail: string, options?: SuaveplanErrorOptions): void
}
migration(string) — the migration name (e.g."001_init")detail(string) — description of what went wrong- Message format:
"Migration '<migration>' failed: <detail>" - Code is always
DB.MIGRATION_FAILED
DB_CODES
const DB_CODES: {
readonly CONNECTION_FAILED: "DB.CONNECTION_FAILED";
readonly NOT_CONNECTED: "DB.NOT_CONNECTED";
readonly QUERY_FAILED: "DB.QUERY_FAILED";
readonly TRANSACTION_FAILED:"DB.TRANSACTION_FAILED";
readonly MIGRATION_FAILED: "DB.MIGRATION_FAILED";
}
Implementation Notes
Both classes pass the message string directly to SuaveplanError as a literal message key rather than an i18n key, so no message-resolver configuration is required. This keeps @suaveplan/db dependency-free of any i18n infrastructure. If localisation is needed in a future version, the message key can be replaced with an i18n key and the context option used for interpolation.
MigrationError explicitly sets this.name = "MigrationError" in the constructor because SuaveplanError sets this.name = new.target.name — the explicit assignment in the subclass constructor ensures the name is accurate when the class is transpiled or minified.