From b060459f60f74973986bd23c039429350464896a Mon Sep 17 00:00:00 2001 From: ilia Date: Sun, 4 Jan 2026 13:24:05 -0500 Subject: [PATCH] refactor: Implement lazy initialization for Prisma client - Introduced a lazy initialization function for the Prisma client to optimize resource usage by only initializing when first accessed. - Enhanced error handling for parsing Prisma Postgres connection strings, providing clearer error messages and logging for debugging. - Updated the export to use a Proxy for lazy loading, improving performance and maintaining the existing interface. --- lib/prisma.ts | 90 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 35 deletions(-) diff --git a/lib/prisma.ts b/lib/prisma.ts index 0125d7b..cf5150f 100644 --- a/lib/prisma.ts +++ b/lib/prisma.ts @@ -6,41 +6,61 @@ const globalForPrisma = globalThis as unknown as { prisma: PrismaClient | undefined } -const connectionString = process.env.DATABASE_URL - -if (!connectionString) { - throw new Error('DATABASE_URL environment variable is not set') -} - -// Handle Prisma Postgres URLs (prisma+postgres://) vs standard PostgreSQL URLs -let pool: Pool -if (connectionString.startsWith('prisma+postgres://')) { - // For Prisma managed Postgres, extract the actual postgres URL from the API key - try { - const urlMatch = connectionString.match(/api_key=([^"&]+)/) - if (urlMatch) { - const apiKey = decodeURIComponent(urlMatch[1]) - const decoded = JSON.parse(Buffer.from(apiKey, 'base64').toString()) - if (decoded.databaseUrl) { - pool = new Pool({ connectionString: decoded.databaseUrl }) - } else if (decoded.shadowDatabaseUrl) { - pool = new Pool({ connectionString: decoded.shadowDatabaseUrl }) - } else { - throw new Error('Could not extract database URL from Prisma Postgres connection string') - } - } else { - throw new Error('Invalid Prisma Postgres connection string format') - } - } catch (error) { - console.error('Error parsing Prisma Postgres URL:', error) - throw new Error('Failed to parse Prisma Postgres connection string. Consider using a standard PostgreSQL connection string.') +// Lazy initialization function - only initializes when prisma is first accessed +function getPrismaClient(): PrismaClient { + if (globalForPrisma.prisma) { + return globalForPrisma.prisma } -} else { - // Standard PostgreSQL connection - pool = new Pool({ connectionString }) + + const connectionString = process.env.DATABASE_URL + + if (!connectionString) { + throw new Error('DATABASE_URL environment variable is not set') + } + + // Handle Prisma Postgres URLs (prisma+postgres://) vs standard PostgreSQL URLs + let pool: Pool + if (connectionString.startsWith('prisma+postgres://')) { + // For Prisma managed Postgres, extract the actual postgres URL from the API key + try { + const urlMatch = connectionString.match(/api_key=([^"&]+)/) + if (urlMatch) { + const apiKey = decodeURIComponent(urlMatch[1]) + const decoded = JSON.parse(Buffer.from(apiKey, 'base64').toString()) + if (decoded.databaseUrl) { + pool = new Pool({ connectionString: decoded.databaseUrl }) + } else if (decoded.shadowDatabaseUrl) { + pool = new Pool({ connectionString: decoded.shadowDatabaseUrl }) + } else { + throw new Error('Could not extract database URL from Prisma Postgres connection string') + } + } else { + throw new Error('Invalid Prisma Postgres connection string format') + } + } catch (error) { + console.error('Error parsing Prisma Postgres URL:', error) + throw new Error('Failed to parse Prisma Postgres connection string. Consider using a standard PostgreSQL connection string.') + } + } else { + // Standard PostgreSQL connection + pool = new Pool({ connectionString }) + } + + const adapter = new PrismaPg(pool) + const prisma = new PrismaClient({ adapter }) + + if (process.env.NODE_ENV !== 'production') { + globalForPrisma.prisma = prisma + } + + return prisma } -const adapter = new PrismaPg(pool) -export const prisma = globalForPrisma.prisma ?? new PrismaClient({ adapter }) - -if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma +// Export a proxy that lazily initializes Prisma on first access +export const prisma = new Proxy({} as PrismaClient, { + get(_target, prop) { + const client = getPrismaClient() + const value = (client as any)[prop] + return typeof value === 'function' ? value.bind(client) : value + } +})