UNPKG

eggi-ai-db-schema

Version:

Type-safe database schema and ORM client for Eggi.AI with direct RDS connection

242 lines (236 loc) 9.76 kB
"use strict"; /** * ============================================================================= * DRIZZLE DATABASE CLIENT - FULLY TYPED SDK * ============================================================================= * This provides a fully type-safe database client with all your schema types */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.debugLogDbOperation = debugLogDbOperation; exports.testDatabaseConnectivity = testDatabaseConnectivity; exports.getDb = getDb; exports.closeDb = closeDb; const postgres_js_1 = require("drizzle-orm/postgres-js"); const postgres_1 = __importDefault(require("postgres")); const aws_config_1 = require("../config/aws-config"); const schema = __importStar(require("./schema")); // ============================================================================= // DEBUG LOGGING UTILITIES // ============================================================================= /** * Debug log database operations with structured data * @param operation - The type of operation (e.g., 'insert', 'upsert', 'select', 'update', 'delete') * @param tableName - Name of the table being operated on * @param data - The data being used (for inserts/updates) or conditions (for selects/deletes) * @param result - The result from the database operation (optional) * @param metadata - Additional metadata about the operation (optional) */ function debugLogDbOperation(operation, tableName, data, result, metadata) { // Only log DB operations in debug mode or when explicitly enabled const logLevel = (process.env.LOG_LEVEL || "info").toLowerCase(); const shouldLogDebug = logLevel === "debug" || process.env.NODE_ENV === "development"; if (shouldLogDebug) { const logData = { operation, table: tableName, timestamp: new Date().toISOString(), }; // Add data information if (Array.isArray(data)) { logData.data_type = "array"; logData.data_count = data.length; logData.sample_data = data.length > 0 ? data[0] : null; if (data.length > 1) { logData.data_preview = `[${data.length} items: ${JSON.stringify(data[0])}, ...]`; } else { logData.data_preview = JSON.stringify(data); } } else { logData.data_type = "object"; logData.data_count = 1; logData.data_preview = JSON.stringify(data); } // Add result information if provided if (result) { if (Array.isArray(result)) { logData.result_count = result.length; logData.result_sample = result.length > 0 ? result[0] : null; } else { logData.result_count = 1; logData.result_sample = result; } } // Add metadata if provided if (metadata) { logData.metadata = metadata; } console.debug(`📊 DB_OPERATION: ${operation.toUpperCase()} ${tableName}`, logData); } } // ============================================================================= // DATABASE CONNECTION // ============================================================================= let connection = null; let db = null; /** * Test database connectivity with comprehensive logging * @returns {Promise<boolean>} True if connection successful, false otherwise */ async function testDatabaseConnectivity() { if (!connection || !db) { console.error("❌ Cannot test connectivity: connection not initialized"); return false; } try { console.log("🔍 Testing database connectivity..."); const startTime = Date.now(); // Test basic connectivity with a simple query const result = await db.execute("SELECT NOW() as current_time, version() as db_version"); const executionTime = Date.now() - startTime; const dbInfo = result[0]; console.log("✅ Database connectivity test successful", { executionTime: `${executionTime}ms`, currentTime: dbInfo?.current_time, dbVersion: typeof dbInfo?.db_version === "string" ? dbInfo.db_version.substring(0, 50) + "..." : dbInfo?.db_version, connectionStatus: "success", }); return true; } catch (error) { console.error("❌ Database connectivity test failed", { error: error.message, errorCode: error.code, errorDetail: error.detail, connectionStatus: "failed", stack: typeof error.stack === "string" ? error.stack.substring(0, 200) + "..." : error.stack, }); return false; } } async function getDb() { if (!db) { console.log("⚡ Initializing database connection..."); const connectionStartTime = Date.now(); // Log connection type for debugging const isLocal = !process.env.AWS_REGION && !process.env.AWS_LAMBDA_FUNCTION_NAME; const useProxy = isLocal ? false // Local: default to direct connection : process.env.USE_DIRECT_CONNECTION !== "true"; // Production: default to proxy console.log("🔧 Database connection configuration", { environment: isLocal ? "local" : "cloud/lambda", connectionType: useProxy ? "proxy" : "direct", useDirectConnection: process.env.USE_DIRECT_CONNECTION, awsRegion: process.env.AWS_REGION, }); const databaseUrl = await (0, aws_config_1.getDatabaseUrl)(); connection = (0, postgres_1.default)(databaseUrl, { ssl: { rejectUnauthorized: false }, transform: { undefined: null }, max: 20, // Increase connection pool for concurrent auth requests idle_timeout: 120, // 2 minutes (shorter for Lambda) max_lifetime: 60 * 30, // 30 minutes (shorter for Lambda) connect_timeout: 60, // 60 seconds connection timeout }); db = (0, postgres_js_1.drizzle)(connection, { schema }); const initTime = Date.now() - connectionStartTime; console.log("🔗 Database connection initialized", { initializationTime: `${initTime}ms`, }); // Automatically test connectivity on first connection const connectivityTest = await testDatabaseConnectivity(); if (!connectivityTest) { console.warn("⚠️ Database connectivity test failed, but proceeding with initialized connection"); } } return db; } async function closeDb() { if (connection) { await connection.end(); connection = null; db = null; } } // ============================================================================= // EXAMPLE USAGE WITH FULL TYPE SAFETY // ============================================================================= /* // Example 1: Type-safe queries const users = await db.select().from(schema.authenticatedUsers); // Type: AuthenticatedUser[] // Example 2: Type-safe inserts const newUser = await db.insert(schema.authenticatedUsers).values({ cognitoUserId: "cognito-123", email: "user@example.com", name: "John Doe" }).returning(); // Type: AuthenticatedUser[] // Example 3: Type-safe joins with relations const usersWithAccounts = await db.query.authenticatedUsers.findMany({ with: { unipileAccounts: true } }); // Type: (AuthenticatedUser & { unipileAccounts: UnipileAccount[] })[] // Example 4: Prepared statements (for performance) const getUserById = db.select().from(schema.authenticatedUsers) .where(eq(schema.authenticatedUsers.id, placeholder("id"))) .prepare(); const user = await getUserById.execute({ id: 123 }); // Type: AuthenticatedUser[] // Example 5: Transactions await db.transaction(async (tx) => { const user = await tx.insert(schema.authenticatedUsers).values({ cognitoUserId: "cognito-456", email: "user2@example.com", name: "Jane Doe" }).returning(); await tx.insert(schema.unipileAccounts).values({ userId: user[0].id, unipileAccountId: "unipile-789", platformType: "linkedin" }); }); */ //# sourceMappingURL=db.js.map