# 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` — participates in the project-wide error hierarchy - Stable `DB.*` codes registered via `defineCodes` — never change between versions - `cause` threading — wraps lower-level driver errors without losing the original stack - `MigrationError.migration` field — names the exact migration file that failed - `name` property set to the concrete class name for easy identification in logs ## Usage: Basic Example ```ts 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 ```ts import { DatabaseError, DB_CODES } from "@suaveplan/db"; import { SuaveplanError } from "@suaveplan/error"; async function runQuery(sql: string): Promise { 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` ```ts class DatabaseError extends SuaveplanError { constructor(code: DbCode, message: string, options?: SuaveplanErrorOptions): void } ``` - **`code`** (`DbCode`) — one of `DB.CONNECTION_FAILED`, `DB.NOT_CONNECTED`, `DB.QUERY_FAILED`, `DB.TRANSACTION_FAILED`, `DB.MIGRATION_FAILED` - **`message`** (`string`) — human-readable description - **`options.cause`** (`Error | undefined`) — lower-level error that triggered this one ### `MigrationError` ```ts 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 '' failed: "` - Code is always `DB.MIGRATION_FAILED` ### `DB_CODES` ```ts 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.