2024-06-27 01:11:39 +02:00
|
|
|
import { getLogger } from "@logtape/logtape";
|
2025-04-19 14:15:08 +02:00
|
|
|
import { SQL } from "bun";
|
2024-08-26 18:04:22 +02:00
|
|
|
import chalk from "chalk";
|
2025-04-19 14:15:08 +02:00
|
|
|
import { type BunSQLDatabase, drizzle } from "drizzle-orm/bun-sql";
|
2024-08-26 18:04:22 +02:00
|
|
|
import { withReplicas } from "drizzle-orm/pg-core";
|
2024-04-14 12:36:25 +02:00
|
|
|
import { migrate } from "drizzle-orm/postgres-js/migrator";
|
2025-02-15 02:47:29 +01:00
|
|
|
import { config } from "~/config.ts";
|
2024-10-04 15:22:48 +02:00
|
|
|
import * as schema from "./schema.ts";
|
2024-04-11 13:39:07 +02:00
|
|
|
|
2025-04-19 14:15:08 +02:00
|
|
|
const primaryDb = new SQL({
|
2025-02-15 02:47:29 +01:00
|
|
|
host: config.postgres.host,
|
|
|
|
|
port: config.postgres.port,
|
|
|
|
|
user: config.postgres.username,
|
|
|
|
|
password: config.postgres.password,
|
|
|
|
|
database: config.postgres.database,
|
2024-04-11 13:39:07 +02:00
|
|
|
});
|
|
|
|
|
|
2025-02-15 02:47:29 +01:00
|
|
|
const replicas = config.postgres.replicas.map(
|
|
|
|
|
(replica) =>
|
2025-04-19 14:15:08 +02:00
|
|
|
new SQL({
|
2025-02-15 02:47:29 +01:00
|
|
|
host: replica.host,
|
|
|
|
|
port: replica.port,
|
|
|
|
|
user: replica.username,
|
|
|
|
|
password: replica.password,
|
|
|
|
|
database: replica.database,
|
|
|
|
|
}),
|
|
|
|
|
);
|
2024-08-26 18:04:22 +02:00
|
|
|
|
|
|
|
|
export const db =
|
|
|
|
|
(replicas.length ?? 0) > 0
|
|
|
|
|
? withReplicas(
|
|
|
|
|
drizzle(primaryDb, { schema }),
|
|
|
|
|
replicas.map((r) => drizzle(r, { schema })) as [
|
2024-10-11 15:40:54 +02:00
|
|
|
// biome-ignore lint/style/useNamingConvention: <explanation>
|
2025-04-19 14:15:08 +02:00
|
|
|
BunSQLDatabase<typeof schema> & { $client: SQL },
|
2024-10-11 15:40:54 +02:00
|
|
|
// biome-ignore lint/style/useNamingConvention: <explanation>
|
2025-04-19 14:15:08 +02:00
|
|
|
...(BunSQLDatabase<typeof schema> & { $client: SQL })[],
|
2024-08-26 18:04:22 +02:00
|
|
|
],
|
|
|
|
|
)
|
|
|
|
|
: drizzle(primaryDb, { schema });
|
|
|
|
|
|
2024-11-02 00:43:33 +01:00
|
|
|
export const setupDatabase = async (info = true): Promise<void> => {
|
2024-06-27 01:11:39 +02:00
|
|
|
const logger = getLogger("database");
|
|
|
|
|
|
2024-08-26 18:04:22 +02:00
|
|
|
for (const dbPool of [primaryDb, ...replicas]) {
|
|
|
|
|
try {
|
|
|
|
|
await dbPool.connect();
|
|
|
|
|
} catch (e) {
|
|
|
|
|
if (
|
|
|
|
|
(e as Error).message ===
|
|
|
|
|
"Client has already been connected. You cannot reuse a client."
|
|
|
|
|
) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2024-05-13 23:36:46 +02:00
|
|
|
|
2024-08-26 18:04:22 +02:00
|
|
|
logger.fatal`Failed to connect to database ${chalk.bold(
|
|
|
|
|
// Index of the database in the array
|
|
|
|
|
replicas.indexOf(dbPool) === -1
|
|
|
|
|
? "primary"
|
|
|
|
|
: `replica-${replicas.indexOf(dbPool)}`,
|
|
|
|
|
)}. Please check your configuration.`;
|
2024-06-14 11:44:46 +02:00
|
|
|
|
2024-10-03 11:59:26 +02:00
|
|
|
throw e;
|
2024-08-26 18:04:22 +02:00
|
|
|
}
|
2024-04-14 10:12:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Migrate the database
|
2024-06-27 01:11:39 +02:00
|
|
|
info && logger.info`Migrating database...`;
|
2024-04-14 10:12:41 +02:00
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
await migrate(db, {
|
2024-06-13 01:10:40 +02:00
|
|
|
migrationsFolder: "./drizzle/migrations",
|
2024-04-14 10:12:41 +02:00
|
|
|
});
|
|
|
|
|
} catch (e) {
|
2024-06-27 01:11:39 +02:00
|
|
|
logger.fatal`Failed to migrate database. Please check your configuration.`;
|
2024-06-14 11:44:46 +02:00
|
|
|
|
2024-10-03 11:59:26 +02:00
|
|
|
throw e;
|
2024-04-14 10:12:41 +02:00
|
|
|
}
|
|
|
|
|
|
2024-06-27 01:11:39 +02:00
|
|
|
info && logger.info`Database migrated`;
|
2024-04-14 10:12:41 +02:00
|
|
|
};
|