From ab39fa9a7f7fa62872332841f7d17f5986ed23ae Mon Sep 17 00:00:00 2001 From: Arjun Komath Date: Thu, 16 Oct 2025 19:21:58 +1100 Subject: [PATCH] Reuse DB connection --- lib/utils/useDatabase.ts | 21 +++++++++++++++------ trpc/init.ts | 5 ++--- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/lib/utils/useDatabase.ts b/lib/utils/useDatabase.ts index 7104fd3..f9e2a5a 100644 --- a/lib/utils/useDatabase.ts +++ b/lib/utils/useDatabase.ts @@ -1,11 +1,12 @@ import { sql } from "drizzle-orm"; import { drizzle } from "drizzle-orm/node-postgres"; import { err, ok, type Result } from "neverthrow"; -import { cache } from "react"; import type { Database } from "@/drizzle/types"; import * as schema from "../../drizzle/schema"; import { getOwner } from "./useOwner"; +const dbInstances = new Map(); + export function getDatabaseName(ownerId: string): Result { if (!ownerId.startsWith("org_") && !ownerId.startsWith("user_")) { return err("Invalid owner ID"); @@ -13,14 +14,14 @@ export function getDatabaseName(ownerId: string): Result { return ok(ownerId.toLowerCase().replace(/ /g, "_")); } -export const database = cache(async (): Promise => { +export async function database(): Promise { const { ownerId } = await getOwner(); if (!ownerId) { throw new Error("Owner ID not found"); } return getDatabaseForOwner(ownerId); -}); +} export async function getDatabaseForOwner(ownerId: string): Promise { const databaseName = getDatabaseName(ownerId).match( @@ -31,10 +32,18 @@ export async function getDatabaseForOwner(ownerId: string): Promise { ); const sslMode = process.env.DATABASE_SSL === "true" ? "?sslmode=require" : ""; + const connectionString = `${process.env.DATABASE_URL}/${databaseName}${sslMode}`; - return drizzle(`${process.env.DATABASE_URL}/${databaseName}${sslMode}`, { - schema, - }); + if (!dbInstances.has(ownerId)) { + dbInstances.set( + ownerId, + drizzle(connectionString, { + schema, + }), + ); + } + + return dbInstances.get(ownerId)!; } export async function deleteDatabase(ownerId: string) { diff --git a/trpc/init.ts b/trpc/init.ts index 13287b4..31cb39c 100644 --- a/trpc/init.ts +++ b/trpc/init.ts @@ -1,13 +1,12 @@ import { auth } from "@clerk/nextjs/server"; import { initTRPC, TRPCError } from "@trpc/server"; -import { cache } from "react"; import superjson from "superjson"; import { ZodError } from "zod"; import { SearchService } from "@/lib/search"; import { database } from "@/lib/utils/useDatabase"; import { getOwner, getTimezone } from "@/lib/utils/useOwner"; -export const createTRPCContext = cache(async () => { +export const createTRPCContext = async () => { const timezone = await getTimezone(); const { orgSlug, ownerId } = await getOwner(); const db = await database(); @@ -18,7 +17,7 @@ export const createTRPCContext = cache(async () => { ownerId, orgSlug, }; -}); +}; export type Context = Awaited>; // Avoid exporting the entire t-object