Skip to content
This repository has been archived by the owner on Dec 21, 2024. It is now read-only.

Commit

Permalink
chore(postgres): cleanly handle unconnectable database (#419)
Browse files Browse the repository at this point in the history
  • Loading branch information
NathanFlurry committed Sep 18, 2024
1 parent 3a75bd3 commit 801c416
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 35 deletions.
23 changes: 1 addition & 22 deletions packages/backend/toolchain/postgres/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,27 +24,13 @@ export class CommandError extends InternalError {
}
}

export class CreateDatabaseError extends InternalError {
constructor(opts?: InternalErrorOpts) {
super("An error occurred while creating the database.", opts);
this.name = "CreateDatabaseError";
}
}

export class DatabaseError extends InternalError {
constructor(opts?: InternalErrorOpts) {
super("A general database error occurred.", opts);
super(`A general database error occurred: ${opts?.originalError ?? "?"}`, opts);
this.name = "DatabaseError";
}
}

export class DatabaseExistsError extends InternalError {
constructor(opts?: InternalErrorOpts) {
super("The database already exists.", opts);
this.name = "DatabaseExistsError";
}
}

export class DatabaseInitializationError extends InternalError {
constructor(opts?: InternalErrorOpts) {
super("An error occurred during database initialization.", opts);
Expand All @@ -66,13 +52,6 @@ export class DatabaseStopError extends InternalError {
}
}

export class DropDatabaseError extends InternalError {
constructor(opts?: InternalErrorOpts) {
super("An error occurred while dropping the database.", opts);
this.name = "DropDatabaseError";
}
}

export interface InvalidUrlOpts extends InternalErrorOpts {
url: string;
}
Expand Down
41 changes: 28 additions & 13 deletions packages/backend/toolchain/postgres/manager.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import {
CreateDatabaseError,
DatabaseExistsError,
DatabaseError,
DatabaseInitializationError,
DatabaseStartError,
DatabaseStopError,
DropDatabaseError,
} from "./error.ts";
import { binaryDir, Settings } from "./settings.ts";
import { verbose } from "../term/status.ts";
Expand Down Expand Up @@ -81,8 +79,22 @@ async function isInitialized(manager: Manager): Promise<boolean> {
}

async function isStarted(manager: Manager): Promise<boolean> {
// Check if PID exists
const pidFile = manager.settings.dataDir.concat("/postmaster.pid");
return await exists(pidFile);
if (!await exists(pidFile)) return false;

// Check if connectable
let client;
try {
client = await getClient(manager, BOOTSTRAP_DATABASE);
await client.queryObject("SELECT 1");
} catch (_) {
return false;
} finally {
await client?.end();
}

return true;
}

async function install(manager: Manager): Promise<void> {
Expand Down Expand Up @@ -258,13 +270,14 @@ export async function getClient(manager: Manager, databaseName: string): Promise
export async function createDatabase<S extends string>(manager: Manager, databaseName: S): Promise<void> {
verbose(`Creating database`, databaseName);

const client = await getClient(manager, BOOTSTRAP_DATABASE);
let client;
try {
client = await getClient(manager, BOOTSTRAP_DATABASE);
await client.queryObject(`CREATE DATABASE "${databaseName}"`);
} catch (error) {
throw new CreateDatabaseError({ originalError: error as any });
throw new DatabaseError({ originalError: error as any });
} finally {
await client.end();
await client?.end();
}

verbose(`Created database`, databaseName);
Expand All @@ -273,30 +286,32 @@ export async function createDatabase<S extends string>(manager: Manager, databas
export async function databaseExists<S extends string>(manager: Manager, databaseName: S): Promise<boolean> {
verbose(`Checking database`, databaseName);

const client = await getClient(manager, BOOTSTRAP_DATABASE);
let client;
try {
client = await getClient(manager, BOOTSTRAP_DATABASE);
const rows = await client.queryObject(
"SELECT * FROM pg_database WHERE datname = $1",
[databaseName],
);
return rows.rowCount === 1;
} catch (error) {
throw new DatabaseExistsError({ originalError: error as any });
throw new DatabaseError({ originalError: error as any });
} finally {
await client.end();
await client?.end();
}
}

export async function dropDatabase<S extends string>(manager: Manager, databaseName: S): Promise<void> {
verbose(`Dropping database`, databaseName);

const client = await getClient(manager, BOOTSTRAP_DATABASE);
let client;
try {
client = await getClient(manager, BOOTSTRAP_DATABASE);
await client.queryObject(`DROP DATABASE IF EXISTS "${databaseName}"`);
} catch (error) {
throw new DropDatabaseError({ originalError: error as any });
throw new DatabaseError({ originalError: error as any });
} finally {
await client.end();
await client?.end();
}

verbose(`Dropped database`, databaseName);
Expand Down

0 comments on commit 801c416

Please sign in to comment.