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
JavaScript
/**
* =============================================================================
* 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
;