@spfn/core 0.1.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +580 -0
  3. package/dist/auto-loader-C44TcLmM.d.ts +125 -0
  4. package/dist/bind-pssq1NRT.d.ts +34 -0
  5. package/dist/client/index.d.ts +174 -0
  6. package/dist/client/index.js +179 -0
  7. package/dist/client/index.js.map +1 -0
  8. package/dist/codegen/index.d.ts +126 -0
  9. package/dist/codegen/index.js +970 -0
  10. package/dist/codegen/index.js.map +1 -0
  11. package/dist/db/index.d.ts +83 -0
  12. package/dist/db/index.js +2099 -0
  13. package/dist/db/index.js.map +1 -0
  14. package/dist/index.d.ts +379 -0
  15. package/dist/index.js +13042 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/postgres-errors-CY_Es8EJ.d.ts +1703 -0
  18. package/dist/route/index.d.ts +72 -0
  19. package/dist/route/index.js +442 -0
  20. package/dist/route/index.js.map +1 -0
  21. package/dist/scripts/index.d.ts +24 -0
  22. package/dist/scripts/index.js +1157 -0
  23. package/dist/scripts/index.js.map +1 -0
  24. package/dist/scripts/templates/api-index.template.txt +10 -0
  25. package/dist/scripts/templates/api-tag.template.txt +11 -0
  26. package/dist/scripts/templates/contract.template.txt +87 -0
  27. package/dist/scripts/templates/entity-type.template.txt +31 -0
  28. package/dist/scripts/templates/entity.template.txt +19 -0
  29. package/dist/scripts/templates/index.template.txt +10 -0
  30. package/dist/scripts/templates/repository.template.txt +37 -0
  31. package/dist/scripts/templates/routes-id.template.txt +59 -0
  32. package/dist/scripts/templates/routes-index.template.txt +44 -0
  33. package/dist/server/index.d.ts +303 -0
  34. package/dist/server/index.js +12923 -0
  35. package/dist/server/index.js.map +1 -0
  36. package/dist/types-SlzTr8ZO.d.ts +143 -0
  37. package/package.json +119 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/logger/adapters/pino.ts","../../src/logger/logger.ts","../../src/logger/types.ts","../../src/logger/formatters.ts","../../src/logger/transports/console.ts","../../src/logger/transports/file.ts","../../src/logger/config.ts","../../src/logger/adapters/custom.ts","../../src/logger/adapter-factory.ts","../../src/errors/database-errors.ts","../../src/db/postgres-errors.ts","../../src/db/manager/connection.ts","../../src/db/manager/config.ts","../../src/db/manager/factory.ts","../../src/db/manager/manager.ts","../../src/db/manager/instance.ts","../../src/db/transaction/context.ts","../../src/db/transaction/middleware.ts","../../src/db/repository/filters.ts","../../src/db/repository/query-builder.ts","../../src/db/repository/repository.ts","../../src/db/repository/factory.ts","../../src/db/repository/request-scope.ts","../../src/db/repository/relation-registry.ts","../../src/db/manager/wrapped-db.ts","../../src/db/manager/context.ts","../../src/db/manager/config-generator.ts","../../src/db/schema/helpers.ts"],"names":["config","timestamp","dbLogger","writeClient","readClient","db","id","eq","AsyncLocalStorage","getCacheKey"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Pino Logger Adapter\n *\n * Pino를 사용하는 Logger Adapter 구현\n *\n * ✅ 구현 완료:\n * - Pino 기반 로깅\n * - Child logger 지원\n * - Error 객체 처리 (err 필드)\n * - Context 병합\n * - 환경별 설정 (pretty print)\n * - 파일 로깅 with Rotation (자체 구축용)\n *\n * 💡 배포 시나리오:\n * - K8s: Stdout만 (로그 수집기가 처리)\n * - 자체 구축: Stdout + File with Rotation\n *\n * 💡 특징:\n * - 고성능 (Winston보다 5-10배 빠름)\n * - JSON 기본 포맷\n * - 프로덕션 검증됨 (Netflix, Elastic 사용)\n *\n * 🔗 관련 파일:\n * - src/logger/adapters/types.ts (인터페이스)\n * - src/logger/index.ts (Adapter 선택)\n * - src/logger/config.ts (설정)\n */\n\nimport pino from 'pino';\nimport type { LoggerAdapter, AdapterConfig, LogLevel } from './types';\n\n/**\n * Pino Logger Adapter\n */\nexport class PinoAdapter implements LoggerAdapter\n{\n private logger: pino.Logger;\n\n constructor(config: AdapterConfig)\n {\n const isProduction = process.env.NODE_ENV === 'production';\n const isDevelopment = process.env.NODE_ENV === 'development';\n const fileLoggingEnabled = process.env.LOGGER_FILE_ENABLED === 'true';\n\n // Transport 설정\n const targets: pino.TransportTargetOptions[] = [];\n\n // 1. Stdout Transport (항상)\n if (!isProduction && isDevelopment)\n {\n // 개발: Pretty Print\n targets.push({\n target: 'pino-pretty',\n level: 'debug',\n options: {\n colorize: true,\n translateTime: 'SYS:yyyy-mm-dd HH:MM:ss.l',\n ignore: 'pid,hostname',\n },\n });\n }\n else\n {\n // 프로덕션: JSON (기본 stdout)\n // targets가 비어있으면 자동으로 stdout JSON 사용\n }\n\n // 2. File Transport (자체 구축 시)\n if (fileLoggingEnabled && isProduction)\n {\n const logDir = process.env.LOG_DIR || './logs';\n const maxFileSize = process.env.LOG_MAX_FILE_SIZE || '10M';\n const maxFiles = parseInt(process.env.LOG_MAX_FILES || '10', 10);\n\n targets.push({\n target: 'pino-roll',\n level: 'info',\n options: {\n file: `${logDir}/app.log`,\n frequency: 'daily',\n size: maxFileSize,\n limit: { count: maxFiles },\n mkdir: true,\n },\n });\n }\n\n this.logger = pino({\n level: config.level,\n\n // Transport 설정 (targets가 있으면 사용, 없으면 기본 stdout)\n transport: targets.length > 0 ? { targets } : undefined,\n\n // 기본 필드\n base: config.module ? { module: config.module } : undefined,\n });\n }\n\n child(module: string): LoggerAdapter\n {\n const childLogger = new PinoAdapter({ level: this.logger.level as LogLevel, module });\n childLogger.logger = this.logger.child({ module });\n return childLogger;\n }\n\n debug(message: string, context?: Record<string, unknown>): void\n {\n this.logger.debug(context || {}, message);\n }\n\n info(message: string, context?: Record<string, unknown>): void\n {\n this.logger.info(context || {}, message);\n }\n\n warn(message: string, errorOrContext?: Error | Record<string, unknown>, context?: Record<string, unknown>): void\n {\n if (errorOrContext instanceof Error)\n {\n this.logger.warn({ err: errorOrContext, ...context }, message);\n }\n else\n {\n this.logger.warn(errorOrContext || {}, message);\n }\n }\n\n error(message: string, errorOrContext?: Error | Record<string, unknown>, context?: Record<string, unknown>): void\n {\n if (errorOrContext instanceof Error)\n {\n this.logger.error({ err: errorOrContext, ...context }, message);\n }\n else\n {\n this.logger.error(errorOrContext || {}, message);\n }\n }\n\n fatal(message: string, errorOrContext?: Error | Record<string, unknown>, context?: Record<string, unknown>): void\n {\n if (errorOrContext instanceof Error)\n {\n this.logger.fatal({ err: errorOrContext, ...context }, message);\n }\n else\n {\n this.logger.fatal(errorOrContext || {}, message);\n }\n }\n\n async close(): Promise<void>\n {\n // Pino는 자동으로 flush됨\n // 필요시 pino.final() 사용 가능\n }\n}","/**\n * Logger Class\n *\n * Main logger class\n *\n * ✅ Implemented:\n * - 5 log level methods (debug, info, warn, error, fatal)\n * - Child logger creation (per module)\n * - Multiple Transport support\n * - Context object support\n * - Automatic Error object handling\n *\n * 💡 Future considerations:\n * - Log sampling (limit high-frequency logs)\n * - Async batch processing\n * - Memory usage monitoring\n *\n * 🔗 Related files:\n * - src/logger/types.ts (Type definitions)\n * - src/logger/transports/ (Transport implementations)\n * - src/logger/adapter-factory.ts (Singleton instance)\n */\n\nimport type { LogLevel, LogMetadata, LoggerConfig, Transport } from './types';\n\n/**\n * Logger class\n */\nexport class Logger\n{\n private config: LoggerConfig;\n private module?: string;\n\n constructor(config: LoggerConfig)\n {\n this.config = config;\n this.module = config.module;\n }\n\n /**\n * Get current log level\n */\n get level(): LogLevel\n {\n return this.config.level;\n }\n\n /**\n * Create child logger (per module)\n */\n child(module: string): Logger\n {\n return new Logger({\n ...this.config,\n module,\n });\n }\n\n /**\n * Debug log\n */\n debug(message: string, context?: Record<string, unknown>): void\n {\n this.log('debug', message, undefined, context);\n }\n\n /**\n * Info log\n */\n info(message: string, context?: Record<string, unknown>): void\n {\n this.log('info', message, undefined, context);\n }\n\n /**\n * Warn log\n */\n warn(message: string, context?: Record<string, unknown>): void;\n warn(message: string, error: Error, context?: Record<string, unknown>): void;\n warn(message: string, errorOrContext?: Error | Record<string, unknown>, context?: Record<string, unknown>): void\n {\n if (errorOrContext instanceof Error)\n {\n this.log('warn', message, errorOrContext, context);\n }\n else\n {\n this.log('warn', message, undefined, errorOrContext);\n }\n }\n\n /**\n * Error log\n */\n error(message: string, context?: Record<string, unknown>): void;\n error(message: string, error: Error, context?: Record<string, unknown>): void;\n error(message: string, errorOrContext?: Error | Record<string, unknown>, context?: Record<string, unknown>): void\n {\n if (errorOrContext instanceof Error)\n {\n this.log('error', message, errorOrContext, context);\n }\n else\n {\n this.log('error', message, undefined, errorOrContext);\n }\n }\n\n /**\n * Fatal log\n */\n fatal(message: string, context?: Record<string, unknown>): void;\n fatal(message: string, error: Error, context?: Record<string, unknown>): void;\n fatal(message: string, errorOrContext?: Error | Record<string, unknown>, context?: Record<string, unknown>): void\n {\n if (errorOrContext instanceof Error)\n {\n this.log('fatal', message, errorOrContext, context);\n }\n else\n {\n this.log('fatal', message, undefined, errorOrContext);\n }\n }\n\n /**\n * Log processing (internal)\n */\n private log(level: LogLevel, message: string, error?: Error, context?: Record<string, unknown>): void\n {\n const metadata: LogMetadata = {\n timestamp: new Date(),\n level,\n message,\n module: this.module,\n error,\n context,\n };\n\n // Pass to all enabled Transports\n this.processTransports(metadata);\n }\n\n /**\n * Process Transports\n */\n private processTransports(metadata: LogMetadata): void\n {\n const promises = this.config.transports\n .filter(transport => transport.enabled)\n .map(transport => this.safeTransportLog(transport, metadata));\n\n // Async processing to prevent Transport errors from blocking logs\n Promise.all(promises).catch(error =>\n {\n // Use stderr directly to avoid circular logging\n const errorMessage = error instanceof Error ? error.message : String(error);\n process.stderr.write(`[Logger] Transport error: ${errorMessage}\\n`);\n });\n }\n\n /**\n * Transport log (error-safe)\n */\n private async safeTransportLog(transport: Transport, metadata: LogMetadata): Promise<void>\n {\n try\n {\n await transport.log(metadata);\n }\n catch (error)\n {\n // Use stderr directly to avoid circular logging\n const errorMessage = error instanceof Error ? error.message : String(error);\n process.stderr.write(`[Logger] Transport \"${transport.name}\" failed: ${errorMessage}\\n`);\n }\n }\n\n /**\n * Close all Transports\n */\n async close(): Promise<void>\n {\n const closePromises = this.config.transports\n .filter(transport => transport.close)\n .map(transport => transport.close!());\n\n await Promise.all(closePromises);\n }\n}","/**\n * Logger Type Definitions\n *\n * 로깅 시스템 타입 정의\n *\n * ✅ 구현 완료:\n * - LogLevel 타입 정의\n * - LogMetadata 인터페이스\n * - Transport 인터페이스\n * - 환경별 설정 타입\n *\n * 🔗 관련 파일:\n * - src/logger/logger.ts (Logger 클래스)\n * - src/logger/transports/ (Transport 구현체)\n * - src/logger/config.ts (설정)\n */\n\n/**\n * 로그 레벨\n * debug < info < warn < error < fatal\n */\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'fatal';\n\n/**\n * 로그 레벨 우선순위\n */\nexport const LOG_LEVEL_PRIORITY: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n fatal: 4,\n};\n\n/**\n * 로그 메타데이터\n */\nexport interface LogMetadata\n{\n timestamp: Date;\n level: LogLevel;\n message: string;\n module?: string;\n error?: Error;\n context?: Record<string, unknown>;\n}\n\n/**\n * Transport 인터페이스\n * 모든 Transport는 이 인터페이스를 구현해야 함\n */\nexport interface Transport\n{\n /**\n * Transport 이름\n */\n name: string;\n\n /**\n * 최소 로그 레벨 (이 레벨 이상만 처리)\n */\n level: LogLevel;\n\n /**\n * 활성화 여부\n */\n enabled: boolean;\n\n /**\n * 로그 처리 함수\n */\n log(metadata: LogMetadata): Promise<void>;\n\n /**\n * Transport 종료 (리소스 정리)\n */\n close?(): Promise<void>;\n}\n\n/**\n * Logger 설정\n */\nexport interface LoggerConfig\n{\n /**\n * 기본 로그 레벨\n */\n level: LogLevel;\n\n /**\n * 모듈명 (context)\n */\n module?: string;\n\n /**\n * Transport 리스트\n */\n transports: Transport[];\n}\n\n/**\n * Transport 설정 (공통)\n */\nexport interface TransportConfig\n{\n level: LogLevel;\n enabled: boolean;\n}\n\n/**\n * Console Transport 설정\n */\nexport interface ConsoleTransportConfig extends TransportConfig\n{\n colorize?: boolean;\n}\n\n/**\n * File Transport 설정\n */\nexport interface FileTransportConfig extends TransportConfig\n{\n logDir: string;\n maxFileSize?: number; // bytes\n maxFiles?: number; // 최대 로그 파일 개수\n}\n\n/**\n * Slack Transport 설정\n */\nexport interface SlackTransportConfig extends TransportConfig\n{\n webhookUrl: string;\n channel?: string;\n username?: string;\n}\n\n/**\n * Email Transport 설정\n */\nexport interface EmailTransportConfig extends TransportConfig\n{\n from: string;\n to: string[];\n smtpHost: string;\n smtpPort: number;\n smtpUser?: string;\n smtpPassword?: string;\n}","/**\n * Logger Formatters\n *\n * 로그 포맷팅 유틸리티\n *\n * ✅ 구현 완료:\n * - 컬러 포맷터 (콘솔 출력용)\n * - JSON 포맷터 (파일/전송용)\n * - 타임스탬프 포맷터\n * - 에러 스택 트레이스 포맷팅\n *\n * 🔗 관련 파일:\n * - src/logger/types.ts (타입 정의)\n * - src/logger/transports/ (Transport 구현체)\n */\n\nimport type { LogLevel, LogMetadata } from './types';\n\n/**\n * ANSI 컬러 코드\n */\nconst COLORS = {\n reset: '\\x1b[0m',\n bright: '\\x1b[1m',\n dim: '\\x1b[2m',\n\n // 로그 레벨 컬러\n debug: '\\x1b[36m', // cyan\n info: '\\x1b[32m', // green\n warn: '\\x1b[33m', // yellow\n error: '\\x1b[31m', // red\n fatal: '\\x1b[35m', // magenta\n\n // 추가 컬러\n gray: '\\x1b[90m',\n};\n\n/**\n * 로그 레벨을 컬러 문자열로 변환\n */\nexport function colorizeLevel(level: LogLevel): string\n{\n const color = COLORS[level];\n const levelStr = level.toUpperCase().padEnd(5);\n return `${color}${levelStr}${COLORS.reset}`;\n}\n\n/**\n * 타임스탬프 포맷 (ISO 8601)\n */\nexport function formatTimestamp(date: Date): string\n{\n return date.toISOString();\n}\n\n/**\n * 타임스탬프 포맷 (사람이 읽기 쉬운 형식)\n */\nexport function formatTimestampHuman(date: Date): string\n{\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const day = String(date.getDate()).padStart(2, '0');\n const hours = String(date.getHours()).padStart(2, '0');\n const minutes = String(date.getMinutes()).padStart(2, '0');\n const seconds = String(date.getSeconds()).padStart(2, '0');\n const ms = String(date.getMilliseconds()).padStart(3, '0');\n\n return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${ms}`;\n}\n\n/**\n * 에러 객체를 문자열로 변환 (스택 트레이스 포함)\n */\nexport function formatError(error: Error): string\n{\n const lines: string[] = [];\n\n lines.push(`${error.name}: ${error.message}`);\n\n if (error.stack)\n {\n const stackLines = error.stack.split('\\n').slice(1);\n lines.push(...stackLines);\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Context 객체를 문자열로 변환\n */\nexport function formatContext(context: Record<string, unknown>): string\n{\n try\n {\n return JSON.stringify(context, null, 2);\n }\n catch (error)\n {\n return '[Context serialization failed]';\n }\n}\n\n/**\n * 콘솔용 컬러 포맷\n */\nexport function formatConsole(metadata: LogMetadata, colorize = true): string\n{\n const parts: string[] = [];\n\n // 타임스탬프\n const timestamp = formatTimestampHuman(metadata.timestamp);\n if (colorize)\n {\n parts.push(`${COLORS.gray}${timestamp}${COLORS.reset}`);\n }\n else\n {\n parts.push(timestamp);\n }\n\n // 로그 레벨\n if (colorize)\n {\n parts.push(colorizeLevel(metadata.level));\n }\n else\n {\n parts.push(metadata.level.toUpperCase().padEnd(5));\n }\n\n // 모듈명\n if (metadata.module)\n {\n if (colorize)\n {\n parts.push(`${COLORS.dim}[${metadata.module}]${COLORS.reset}`);\n }\n else\n {\n parts.push(`[${metadata.module}]`);\n }\n }\n\n // 메시지\n parts.push(metadata.message);\n\n let output = parts.join(' ');\n\n // Context 추가\n if (metadata.context && Object.keys(metadata.context).length > 0)\n {\n output += '\\n' + formatContext(metadata.context);\n }\n\n // 에러 추가\n if (metadata.error)\n {\n output += '\\n' + formatError(metadata.error);\n }\n\n return output;\n}\n\n/**\n * JSON 포맷 (파일 저장 및 전송용)\n */\nexport function formatJSON(metadata: LogMetadata): string\n{\n const obj: Record<string, unknown> = {\n timestamp: formatTimestamp(metadata.timestamp),\n level: metadata.level,\n message: metadata.message,\n };\n\n if (metadata.module)\n {\n obj.module = metadata.module;\n }\n\n if (metadata.context)\n {\n obj.context = metadata.context;\n }\n\n if (metadata.error)\n {\n obj.error = {\n name: metadata.error.name,\n message: metadata.error.message,\n stack: metadata.error.stack,\n };\n }\n\n return JSON.stringify(obj);\n}\n\n/**\n * Slack 메시지 포맷\n */\nexport function formatSlack(metadata: LogMetadata): string\n{\n const emoji = {\n debug: ':bug:',\n info: ':information_source:',\n warn: ':warning:',\n error: ':x:',\n fatal: ':fire:',\n };\n\n const parts: string[] = [];\n\n parts.push(`${emoji[metadata.level]} *${metadata.level.toUpperCase()}*`);\n\n if (metadata.module)\n {\n parts.push(`\\`[${metadata.module}]\\``);\n }\n\n parts.push(metadata.message);\n\n let message = parts.join(' ');\n\n if (metadata.context)\n {\n message += '\\n```\\n' + JSON.stringify(metadata.context, null, 2) + '\\n```';\n }\n\n if (metadata.error)\n {\n message += '\\n```\\n' + formatError(metadata.error) + '\\n```';\n }\n\n return message;\n}\n\n/**\n * Email 제목 생성\n */\nexport function formatEmailSubject(metadata: LogMetadata): string\n{\n const prefix = `[${metadata.level.toUpperCase()}]`;\n const module = metadata.module ? `[${metadata.module}]` : '';\n\n return `${prefix}${module} ${metadata.message}`;\n}\n\n/**\n * Email 본문 생성 (HTML)\n */\nexport function formatEmailBody(metadata: LogMetadata): string\n{\n const parts: string[] = [];\n\n parts.push('<html>');\n parts.push('<body style=\"font-family: monospace; padding: 20px;\">');\n\n // 헤더\n parts.push(`<h2 style=\"color: ${getEmailColor(metadata.level)};\">`);\n parts.push(`${metadata.level.toUpperCase()}`);\n parts.push('</h2>');\n\n // 시간\n parts.push('<p>');\n parts.push(`<strong>Timestamp:</strong> ${formatTimestamp(metadata.timestamp)}`);\n parts.push('</p>');\n\n // 모듈\n if (metadata.module)\n {\n parts.push('<p>');\n parts.push(`<strong>Module:</strong> ${metadata.module}`);\n parts.push('</p>');\n }\n\n // 메시지\n parts.push('<p>');\n parts.push(`<strong>Message:</strong> ${metadata.message}`);\n parts.push('</p>');\n\n // Context\n if (metadata.context)\n {\n parts.push('<h3>Context</h3>');\n parts.push('<pre style=\"background: #f4f4f4; padding: 10px; border-radius: 4px;\">');\n parts.push(JSON.stringify(metadata.context, null, 2));\n parts.push('</pre>');\n }\n\n // 에러\n if (metadata.error)\n {\n parts.push('<h3>Error Stack Trace</h3>');\n parts.push('<pre style=\"background: #fff0f0; padding: 10px; border-radius: 4px;\">');\n parts.push(formatError(metadata.error));\n parts.push('</pre>');\n }\n\n parts.push('</body>');\n parts.push('</html>');\n\n return parts.join('\\n');\n}\n\n/**\n * Email 레벨별 컬러\n */\nfunction getEmailColor(level: LogLevel): string\n{\n const colors: Record<LogLevel, string> = {\n debug: '#00BCD4',\n info: '#4CAF50',\n warn: '#FF9800',\n error: '#F44336',\n fatal: '#9C27B0',\n };\n\n return colors[level];\n}","/**\n * Console Transport\n *\n * 콘솔 출력 Transport\n *\n * ✅ 구현 완료:\n * - 콘솔 출력 (stdout/stderr)\n * - 컬러 출력 지원\n * - 로그 레벨별 스트림 분리 (warn/error/fatal → stderr)\n *\n * 🔗 관련 파일:\n * - src/logger/types.ts (Transport 인터페이스)\n * - src/logger/formatters.ts (포맷터)\n * - src/logger/config.ts (설정)\n */\n\nimport type { Transport, LogMetadata, LogLevel, ConsoleTransportConfig } from '../types';\nimport { LOG_LEVEL_PRIORITY } from '../types';\nimport { formatConsole } from '../formatters';\n\n/**\n * Console Transport\n */\nexport class ConsoleTransport implements Transport\n{\n public readonly name = 'console';\n public readonly level: LogLevel;\n public readonly enabled: boolean;\n\n private colorize: boolean;\n\n constructor(config: ConsoleTransportConfig)\n {\n this.level = config.level;\n this.enabled = config.enabled;\n this.colorize = config.colorize ?? true;\n }\n\n async log(metadata: LogMetadata): Promise<void>\n {\n // Enabled 상태 체크\n if (!this.enabled)\n {\n return;\n }\n\n // 로그 레벨 체크\n if (LOG_LEVEL_PRIORITY[metadata.level] < LOG_LEVEL_PRIORITY[this.level])\n {\n return;\n }\n\n // 포맷팅\n const message = formatConsole(metadata, this.colorize);\n\n // warn/error/fatal은 stderr로, 나머지는 stdout으로\n if (metadata.level === 'warn' || metadata.level === 'error' || metadata.level === 'fatal')\n {\n console.error(message);\n }\n else\n {\n console.log(message);\n }\n }\n}","/**\n * File Transport\n *\n * 파일 출력 Transport\n *\n * ✅ 구현 완료:\n * - 날짜별 로그 파일 생성\n * - JSON 포맷 저장\n * - 로그 디렉토리 자동 생성\n * - 비동기 쓰기 (createWriteStream)\n * - 날짜 변경 시 자동 스트림 교체\n *\n * ⚠️ 개선 필요:\n * - 파일 크기 기반 로테이션\n * - 오래된 파일 자동 삭제\n *\n * 💡 향후 고려사항:\n * - 압축된 로그 아카이빙\n * - 외부 스토리지 전송 (S3 등)\n *\n * 🔗 관련 파일:\n * - src/logger/types.ts (Transport 인터페이스)\n * - src/logger/formatters.ts (포맷터)\n * - src/logger/config.ts (설정)\n */\n\nimport { createWriteStream, existsSync, mkdirSync } from 'fs';\nimport type { WriteStream } from 'fs';\nimport { join } from 'path';\nimport type { Transport, LogMetadata, LogLevel, FileTransportConfig } from '../types';\nimport { LOG_LEVEL_PRIORITY } from '../types';\nimport { formatJSON } from '../formatters';\n\n/**\n * File Transport\n */\nexport class FileTransport implements Transport\n{\n public readonly name = 'file';\n public readonly level: LogLevel;\n public readonly enabled: boolean;\n\n private logDir: string;\n private currentStream: WriteStream | null = null;\n private currentFilename: string | null = null;\n\n constructor(config: FileTransportConfig)\n {\n this.level = config.level;\n this.enabled = config.enabled;\n this.logDir = config.logDir;\n\n // TODO: 향후 파일 로테이션 구현 시 사용\n // this.maxFileSize = config.maxFileSize ?? 10 * 1024 * 1024; // 10MB\n // this.maxFiles = config.maxFiles ?? 10;\n\n // 로그 디렉토리가 없으면 생성\n if (!existsSync(this.logDir))\n {\n mkdirSync(this.logDir, { recursive: true });\n }\n }\n\n async log(metadata: LogMetadata): Promise<void>\n {\n // Enabled 상태 체크\n if (!this.enabled)\n {\n return;\n }\n\n // 로그 레벨 체크\n if (LOG_LEVEL_PRIORITY[metadata.level] < LOG_LEVEL_PRIORITY[this.level])\n {\n return;\n }\n\n // JSON 포맷으로 변환\n const message = formatJSON(metadata);\n\n // 파일명: YYYY-MM-DD.log\n const filename = this.getLogFilename(metadata.timestamp);\n\n // 날짜가 변경되면 스트림 교체\n if (this.currentFilename !== filename)\n {\n await this.rotateStream(filename);\n }\n\n // 스트림에 쓰기\n if (this.currentStream)\n {\n return new Promise((resolve, reject) =>\n {\n this.currentStream!.write(message + '\\n', 'utf-8', (error) =>\n {\n if (error)\n {\n // 파일 쓰기 실패 시 stderr로 출력 (fallback)\n process.stderr.write(`[FileTransport] Failed to write log: ${error.message}\\n`);\n reject(error);\n }\n else\n {\n resolve();\n }\n });\n });\n }\n }\n\n /**\n * 스트림 교체 (날짜 변경 시)\n */\n private async rotateStream(filename: string): Promise<void>\n {\n // 기존 스트림 닫기\n if (this.currentStream)\n {\n await this.closeStream();\n }\n\n // 새 스트림 생성\n const filepath = join(this.logDir, filename);\n\n this.currentStream = createWriteStream(filepath, {\n flags: 'a', // append mode\n encoding: 'utf-8',\n });\n\n this.currentFilename = filename;\n\n // 스트림 에러 핸들링\n this.currentStream.on('error', (error) =>\n {\n process.stderr.write(`[FileTransport] Stream error: ${error.message}\\n`);\n // 에러 발생 시 스트림 초기화\n this.currentStream = null;\n this.currentFilename = null;\n });\n }\n\n /**\n * 현재 스트림 닫기\n */\n private async closeStream(): Promise<void>\n {\n if (!this.currentStream)\n {\n return;\n }\n\n return new Promise((resolve, reject) =>\n {\n this.currentStream!.end((error) =>\n {\n if (error)\n {\n reject(error);\n }\n else\n {\n this.currentStream = null;\n this.currentFilename = null;\n resolve();\n }\n });\n });\n }\n\n /**\n * 날짜별 로그 파일명 생성\n */\n private getLogFilename(date: Date): string\n {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const day = String(date.getDate()).padStart(2, '0');\n\n return `${year}-${month}-${day}.log`;\n }\n\n async close(): Promise<void>\n {\n // 스트림 정리\n await this.closeStream();\n }\n}","/**\n * Logger Configuration\n *\n * Logger configuration by environment\n *\n * ✅ Implemented:\n * - Environment-specific log level configuration\n * - Console Transport configuration\n * - File Transport configuration (for self-hosted)\n * - File rotation configuration\n * - Slack Transport configuration (environment variable based)\n * - Email Transport configuration (environment variable based)\n *\n * 💡 Deployment scenarios:\n * - K8s: Disable file logging (Stdout only)\n * - Self-hosted: LOGGER_FILE_ENABLED=true\n *\n * 🔗 Related files:\n * - src/logger/types.ts (Type definitions)\n * - src/logger/index.ts (Main export)\n * - .env.local (Environment variables)\n */\n\nimport type {\n LogLevel,\n ConsoleTransportConfig,\n FileTransportConfig,\n SlackTransportConfig,\n EmailTransportConfig,\n} from './types';\n\n/**\n * Check if file logging is enabled (for self-hosted)\n */\nexport function isFileLoggingEnabled(): boolean\n{\n return process.env.LOGGER_FILE_ENABLED === 'true';\n}\n\n/**\n * Get default log level by environment\n */\nexport function getDefaultLogLevel(): LogLevel\n{\n const isProduction = process.env.NODE_ENV === 'production';\n const isDevelopment = process.env.NODE_ENV === 'development';\n\n if (isDevelopment)\n {\n return 'debug';\n }\n\n if (isProduction)\n {\n return 'info';\n }\n\n // Test environment\n return 'warn';\n}\n\n/**\n * Console Transport configuration\n */\nexport function getConsoleConfig(): ConsoleTransportConfig\n{\n const isProduction = process.env.NODE_ENV === 'production';\n\n return {\n level: 'debug',\n enabled: true,\n colorize: !isProduction, // Dev: colored output, Production: plain text\n };\n}\n\n/**\n * File Transport configuration\n */\nexport function getFileConfig(): FileTransportConfig\n{\n const isProduction = process.env.NODE_ENV === 'production';\n\n return {\n level: 'info',\n enabled: isProduction, // File logging in production only\n logDir: process.env.LOG_DIR || './logs',\n maxFileSize: 10 * 1024 * 1024, // 10MB\n maxFiles: 10,\n };\n}\n\n/**\n * Slack Transport configuration\n */\nexport function getSlackConfig(): SlackTransportConfig | null\n{\n const webhookUrl = process.env.SLACK_WEBHOOK_URL;\n\n if (!webhookUrl)\n {\n return null; // Disabled if not configured\n }\n\n const isProduction = process.env.NODE_ENV === 'production';\n\n return {\n level: 'error', // Send error and above to Slack\n enabled: isProduction, // Enabled in production only\n webhookUrl,\n channel: process.env.SLACK_CHANNEL,\n username: process.env.SLACK_USERNAME || 'Logger Bot',\n };\n}\n\n/**\n * Email Transport configuration\n */\nexport function getEmailConfig(): EmailTransportConfig | null\n{\n const smtpHost = process.env.SMTP_HOST;\n const smtpPort = process.env.SMTP_PORT;\n const emailFrom = process.env.EMAIL_FROM;\n const emailTo = process.env.EMAIL_TO;\n\n // Disabled if required settings are missing\n if (!smtpHost || !smtpPort || !emailFrom || !emailTo)\n {\n return null;\n }\n\n const isProduction = process.env.NODE_ENV === 'production';\n\n return {\n level: 'fatal', // Send fatal level only via email\n enabled: isProduction, // Enabled in production only\n from: emailFrom,\n to: emailTo.split(',').map(email => email.trim()),\n smtpHost,\n smtpPort: parseInt(smtpPort, 10),\n smtpUser: process.env.SMTP_USER,\n smtpPassword: process.env.SMTP_PASSWORD,\n };\n}","/**\n * Custom Logger Adapter\n *\n * 자체 구현한 Logger를 사용하는 Adapter\n *\n * ✅ 구현 완료:\n * - 기존 Logger 클래스 래핑\n * - Transport 시스템 (Console, File)\n * - Child logger 지원\n *\n * 💡 용도:\n * - Pino 의존성 제거 필요시\n * - 커스텀 Transport 필요시\n * - 완전한 제어가 필요한 경우\n *\n * 🔗 관련 파일:\n * - src/logger/logger.ts (Logger 클래스)\n * - src/logger/transports/ (Transport 구현)\n * - src/logger/adapters/types.ts (인터페이스)\n */\n\nimport { Logger } from '../logger';\nimport { ConsoleTransport } from '../transports/console';\nimport { FileTransport } from '../transports/file';\nimport { getConsoleConfig, getFileConfig } from '../config';\nimport type { LoggerAdapter, AdapterConfig } from './types';\nimport type { Transport } from '../types';\n\n/**\n * Transport 초기화\n */\nfunction initializeTransports(): Transport[]\n{\n const transports: Transport[] = [];\n\n // Console Transport (항상 활성화)\n const consoleConfig = getConsoleConfig();\n transports.push(new ConsoleTransport(consoleConfig));\n\n // File Transport (프로덕션에서만 활성화)\n const fileConfig = getFileConfig();\n if (fileConfig.enabled)\n {\n transports.push(new FileTransport(fileConfig));\n }\n\n return transports;\n}\n\n/**\n * Custom Logger Adapter\n */\nexport class CustomAdapter implements LoggerAdapter\n{\n private logger: Logger;\n\n constructor(config: AdapterConfig)\n {\n this.logger = new Logger({\n level: config.level,\n module: config.module,\n transports: initializeTransports(),\n });\n }\n\n child(module: string): LoggerAdapter\n {\n const adapter = new CustomAdapter({ level: this.logger.level, module });\n adapter.logger = this.logger.child(module);\n return adapter;\n }\n\n debug(message: string, context?: Record<string, unknown>): void\n {\n this.logger.debug(message, context);\n }\n\n info(message: string, context?: Record<string, unknown>): void\n {\n this.logger.info(message, context);\n }\n\n warn(message: string, errorOrContext?: Error | Record<string, unknown>, context?: Record<string, unknown>): void\n {\n if (errorOrContext instanceof Error)\n {\n this.logger.warn(message, errorOrContext, context);\n }\n else\n {\n this.logger.warn(message, errorOrContext);\n }\n }\n\n error(message: string, errorOrContext?: Error | Record<string, unknown>, context?: Record<string, unknown>): void\n {\n if (errorOrContext instanceof Error)\n {\n this.logger.error(message, errorOrContext, context);\n }\n else\n {\n this.logger.error(message, errorOrContext);\n }\n }\n\n fatal(message: string, errorOrContext?: Error | Record<string, unknown>, context?: Record<string, unknown>): void\n {\n if (errorOrContext instanceof Error)\n {\n this.logger.fatal(message, errorOrContext, context);\n }\n else\n {\n this.logger.fatal(message, errorOrContext);\n }\n }\n\n async close(): Promise<void>\n {\n await this.logger.close();\n }\n}","/**\n * Logger Adapter Factory\n *\n * Adapter creation and initialization logic\n */\n\nimport { PinoAdapter } from './adapters/pino.js';\nimport { CustomAdapter } from './adapters/custom.js';\nimport { getDefaultLogLevel } from './config.js';\nimport type { LoggerAdapter } from './adapters/types.js';\n\n/**\n * Adapter type\n */\ntype AdapterType = 'pino' | 'custom';\n\n/**\n * Create adapter instance\n */\nfunction createAdapter(type: AdapterType): LoggerAdapter\n{\n const level = getDefaultLogLevel();\n\n switch (type)\n {\n case 'pino':\n return new PinoAdapter({ level });\n\n case 'custom':\n return new CustomAdapter({ level });\n\n default:\n return new PinoAdapter({ level });\n }\n}\n\n/**\n * Read adapter type from environment variable\n */\nfunction getAdapterType(): AdapterType\n{\n const adapterEnv = process.env.LOGGER_ADAPTER as AdapterType;\n\n if (adapterEnv === 'custom' || adapterEnv === 'pino')\n {\n return adapterEnv;\n }\n\n // Default: pino\n return 'pino';\n}\n\n/**\n * Singleton Logger instance\n */\nexport const logger: LoggerAdapter = createAdapter(getAdapterType());","/**\n * Database Error Classes\n *\n * Type-safe error handling with custom error class hierarchy\n * Mapped to HTTP status codes for API responses\n */\n\n/**\n * Base Database Error\n *\n * Base class for all database-related errors\n */\nexport class DatabaseError<TDetails extends Record<string, unknown> = Record<string, unknown>> extends Error\n{\n public readonly statusCode: number;\n public readonly details?: TDetails;\n public readonly timestamp: Date;\n\n constructor(\n message: string,\n statusCode: number = 500,\n details?: TDetails\n )\n {\n super(message);\n this.name = 'DatabaseError';\n this.statusCode = statusCode;\n this.details = details;\n this.timestamp = new Date();\n Error.captureStackTrace(this, this.constructor);\n }\n\n /**\n * Serialize error for API response\n */\n toJSON()\n {\n return {\n name: this.name,\n message: this.message,\n statusCode: this.statusCode,\n details: this.details,\n timestamp: this.timestamp.toISOString()\n };\n }\n}\n\n/**\n * Connection Error (503 Service Unavailable)\n *\n * Database connection failure, connection pool exhaustion, etc.\n */\nexport class ConnectionError extends DatabaseError\n{\n constructor(message: string, details?: Record<string, any>)\n {\n super(message, 503, details);\n this.name = 'ConnectionError';\n }\n}\n\n/**\n * Query Error (500 Internal Server Error)\n *\n * SQL query execution failure, syntax errors, etc.\n */\nexport class QueryError extends DatabaseError\n{\n constructor(message: string, statusCode: number = 500, details?: Record<string, any>)\n {\n super(message, statusCode, details);\n this.name = 'QueryError';\n }\n}\n\n/**\n * Not Found Error (404 Not Found)\n *\n * Requested resource does not exist\n */\nexport class NotFoundError extends QueryError\n{\n constructor(resource: string, id: string | number)\n {\n super(`${resource} with id ${id} not found`, 404, { resource, id });\n this.name = 'NotFoundError';\n }\n}\n\n/**\n * Validation Error (400 Bad Request)\n *\n * Input data validation failure\n */\nexport class ValidationError extends QueryError\n{\n constructor(message: string, details?: Record<string, any>)\n {\n super(message, 400, details);\n this.name = 'ValidationError';\n }\n}\n\n/**\n * Transaction Error (500 Internal Server Error)\n *\n * Transaction start/commit/rollback failure\n */\nexport class TransactionError extends DatabaseError\n{\n constructor(message: string, statusCode: number = 500, details?: Record<string, any>)\n {\n super(message, statusCode, details);\n this.name = 'TransactionError';\n }\n}\n\n/**\n * Deadlock Error (409 Conflict)\n *\n * Database deadlock detected\n */\nexport class DeadlockError extends TransactionError\n{\n constructor(message: string, details?: Record<string, any>)\n {\n super(message, 409, details);\n this.name = 'DeadlockError';\n }\n}\n\n/**\n * Duplicate Entry Error (409 Conflict)\n *\n * Unique constraint violation (e.g., duplicate email)\n */\nexport class DuplicateEntryError extends QueryError\n{\n constructor(field: string, value: string | number)\n {\n super(`${field} '${value}' already exists`, 409, { field, value });\n this.name = 'DuplicateEntryError';\n }\n}","/**\n * PostgreSQL Error Conversion Utilities\n *\n * Converts PostgreSQL-specific error codes to custom error types\n * @see https://www.postgresql.org/docs/current/errcodes-appendix.html\n */\n\nimport {\n DatabaseError,\n ConnectionError,\n DuplicateEntryError,\n DeadlockError,\n ValidationError,\n QueryError,\n TransactionError,\n} from '../errors/database-errors.js';\n\n/**\n * Extract field and value from PostgreSQL unique violation message\n *\n * Handles various formats:\n * - Simple: Key (email)=(test@example.com)\n * - Complex: Key (user_id, tenant_id)=(123, 456)\n * - With quotes: Key (\"field\")=('value')\n */\nfunction parseUniqueViolation(message: string): { field: string; value: string } | null\n{\n // Try multiple patterns for robustness\n const patterns = [\n // Standard format: Key (field)=(value)\n /Key \\(([^)]+)\\)=\\(([^)]+)\\)/i,\n // With quotes: Key (\"field\")=('value')\n /Key \\([\"']?([^)\"']+)[\"']?\\)=\\([\"']?([^)\"']+)[\"']?\\)/i,\n // Alternative format\n /Key `([^`]+)`=`([^`]+)`/i,\n ];\n\n for (const pattern of patterns)\n {\n const match = message.match(pattern);\n if (match)\n {\n // Clean up extracted values\n const field = match[1].trim().replace(/[\"'`]/g, '');\n const value = match[2].trim().replace(/[\"'`]/g, '');\n return { field, value };\n }\n }\n\n return null;\n}\n\n/**\n * Convert PostgreSQL error to custom DatabaseError\n *\n * Maps PostgreSQL error codes to appropriate error classes with correct status codes\n *\n * @param error - PostgreSQL error object (from pg driver or Drizzle)\n * @returns Custom DatabaseError instance\n *\n * @example\n * ```typescript\n * import { fromPostgresError } from '@spfn/core/db';\n *\n * try {\n * await db.insert(users).values(data);\n * } catch (pgError) {\n * throw fromPostgresError(pgError);\n * }\n * ```\n */\nexport function fromPostgresError(error: any): DatabaseError\n{\n const code = error?.code;\n const message = error?.message || 'Database error occurred';\n\n switch (code)\n {\n // Class 08 — Connection Exception\n case '08000': // connection_exception\n case '08001': // sqlclient_unable_to_establish_sqlconnection\n case '08003': // connection_does_not_exist\n case '08004': // sqlserver_rejected_establishment_of_sqlconnection\n case '08006': // connection_failure\n case '08007': // transaction_resolution_unknown\n case '08P01': // protocol_violation\n return new ConnectionError(message, { code });\n\n // Class 23 — Integrity Constraint Violation\n case '23000': // integrity_constraint_violation\n case '23001': // restrict_violation\n return new ValidationError(message, { code, constraint: 'integrity' });\n\n case '23502': // not_null_violation\n return new ValidationError(message, { code, constraint: 'not_null' });\n\n case '23503': // foreign_key_violation\n return new ValidationError(message, { code, constraint: 'foreign_key' });\n\n case '23505': // unique_violation\n const parsed = parseUniqueViolation(message);\n if (parsed)\n {\n return new DuplicateEntryError(parsed.field, parsed.value);\n }\n return new DuplicateEntryError('field', 'value');\n\n case '23514': // check_violation\n return new ValidationError(message, { code, constraint: 'check' });\n\n // Class 40 — Transaction Rollback\n case '40000': // transaction_rollback\n case '40001': // serialization_failure\n case '40002': // transaction_integrity_constraint_violation\n case '40003': // statement_completion_unknown\n return new TransactionError(message, 500, { code });\n\n case '40P01': // deadlock_detected\n return new DeadlockError(message, { code });\n\n // Class 42 — Syntax Error or Access Rule Violation\n case '42000': // syntax_error_or_access_rule_violation\n case '42601': // syntax_error\n case '42501': // insufficient_privilege\n case '42602': // invalid_name\n case '42622': // name_too_long\n case '42701': // duplicate_column\n case '42702': // ambiguous_column\n case '42703': // undefined_column\n case '42704': // undefined_object\n case '42P01': // undefined_table\n case '42P02': // undefined_parameter\n return new QueryError(message, 400, { code });\n\n // Class 53 — Insufficient Resources\n case '53000': // insufficient_resources\n case '53100': // disk_full\n case '53200': // out_of_memory\n case '53300': // too_many_connections\n return new ConnectionError(message, { code });\n\n // Class 57 — Operator Intervention\n case '57000': // operator_intervention\n case '57014': // query_canceled\n case '57P01': // admin_shutdown\n case '57P02': // crash_shutdown\n case '57P03': // cannot_connect_now\n return new ConnectionError(message, { code });\n\n // Default: Unknown error\n default:\n return new QueryError(message, 500, { code });\n }\n}","/**\n * Database Connection Logic\n *\n * DB 연결 생성 및 재시도 로직\n *\n * ✅ 구현 완료:\n * - Exponential Backoff 재시도 로직\n * - 연결 테스트 쿼리\n * - 상세한 에러 로깅\n * - 연결 성공/실패 로깅\n * - Logger 적용 (console.log 대체)\n *\n * ⚠️ 개선 필요:\n * - 에러 타입별 처리 (네트워크 vs 인증)\n * - Graceful Shutdown 로직\n *\n * 💡 향후 고려사항:\n * - 연결 풀 이벤트 리스너\n * - 연결 상태 메트릭 수집\n * - 연결 풀 동적 조정\n *\n * 🔗 관련 파일:\n * - src/server/core/db/config.ts (설정)\n * - src/server/core/db/index.ts (메인 export)\n * - src/server/core/logger/ (Logger)\n *\n * 📝 TODO: improvements.md 참고\n * - #7: Connection Pool 모니터링 (Pool 이벤트 리스너, 활성/유휴 연결 추적)\n * - #9: Slow Query 로깅 (쿼리 실행 시간 측정 및 임계값 로깅)\n * - #10: Graceful Shutdown (SIGTERM 처리, 진행 중인 쿼리 완료 대기)\n * - #11: Read Replica 지원 (읽기/쓰기 분리)\n */\nimport postgres from 'postgres';\n\nimport { logger } from '../../logger';\nimport { ConnectionError } from '../../errors';\nimport { fromPostgresError } from '../postgres-errors';\nimport type { PoolConfig, RetryConfig } from './config';\n\nconst dbLogger = logger.child('database');\n\n/**\n * 지연 함수\n */\nfunction delay(ms: number): Promise<void>\n{\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\n/**\n * Exponential Backoff로 DB 연결 생성\n *\n * @param connectionString - PostgreSQL 연결 문자열\n * @param poolConfig - Connection Pool 설정\n * @param retryConfig - 재시도 설정\n * @returns PostgreSQL 클라이언트\n */\nexport async function createDatabaseConnection(\n connectionString: string,\n poolConfig: PoolConfig,\n retryConfig: RetryConfig\n)\n{\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= retryConfig.maxRetries; attempt++)\n {\n try\n {\n // PostgreSQL 클라이언트 생성\n const client = postgres(connectionString, {\n max: poolConfig.max,\n idle_timeout: poolConfig.idleTimeout,\n });\n\n // 연결 테스트 쿼리\n await client`SELECT 1 as test`;\n\n // 연결 성공\n if (attempt > 0)\n {\n dbLogger.info(`Database connected successfully after ${attempt} retries`);\n }\n else\n {\n dbLogger.info('Database connected successfully');\n }\n\n return client;\n }\n catch (error)\n {\n lastError = fromPostgresError(error);\n\n // 마지막 시도가 아니면 재시도\n if (attempt < retryConfig.maxRetries)\n {\n // Exponential Backoff 계산\n const delayMs = Math.min(\n retryConfig.initialDelay * Math.pow(retryConfig.factor, attempt),\n retryConfig.maxDelay\n );\n\n dbLogger.warn(\n `Connection failed (attempt ${attempt + 1}/${retryConfig.maxRetries + 1}), retrying in ${delayMs}ms...`,\n lastError,\n {\n attempt: attempt + 1,\n maxRetries: retryConfig.maxRetries + 1,\n delayMs,\n }\n );\n\n await delay(delayMs);\n }\n }\n }\n\n // 모든 재시도 실패\n const errorMessage =\n `Failed to connect to database after ${retryConfig.maxRetries + 1} attempts: ${lastError?.message || 'Unknown error'}`;\n\n throw new ConnectionError(errorMessage);\n}\n\n/**\n * DB 연결 상태 확인\n *\n * @param client - PostgreSQL 클라이언트\n * @returns 연결 가능 여부\n */\nexport async function checkConnection(client: ReturnType<typeof postgres>): Promise<boolean>\n{\n try\n {\n await client`SELECT 1 as health_check`;\n return true;\n }\n catch (error)\n {\n dbLogger.error('Database health check failed', error as Error);\n return false;\n }\n}","/**\n * Database Configuration\n *\n * DB 연결 및 Connection Pool 설정\n *\n * ✅ 구현 완료:\n * - 환경별 Connection Pool 설정\n * - 재시도 설정 (Exponential Backoff)\n * - 환경변수 기반 설정\n *\n * 🔗 관련 파일:\n * - src/server/core/db/connection.ts (연결 로직)\n * - src/server/core/db/index.ts (메인 export)\n */\n\n/**\n * Connection Pool 설정\n */\nexport interface PoolConfig\n{\n max: number; // 최대 연결 수\n idleTimeout: number; // 유휴 연결 타임아웃 (초)\n}\n\n/**\n * 재시도 설정\n */\nexport interface RetryConfig\n{\n maxRetries: number; // 최대 재시도 횟수\n initialDelay: number; // 초기 대기 시간 (ms)\n maxDelay: number; // 최대 대기 시간 (ms)\n factor: number; // 지수 증가 배수\n}\n\n/**\n * 환경별 Connection Pool 설정\n *\n * 우선순위:\n * 1. options 파라미터 (ServerConfig에서 전달)\n * 2. 환경변수 (DB_POOL_MAX, DB_POOL_IDLE_TIMEOUT)\n * 3. 기본값 (NODE_ENV에 따라)\n *\n * @param options - Optional pool configuration from ServerConfig\n * @returns Pool configuration\n *\n * @example\n * ```typescript\n * // 1. ServerConfig priority (highest)\n * const config = getPoolConfig({ max: 50, idleTimeout: 60 });\n *\n * // 2. Environment variable priority\n * // DB_POOL_MAX=30 DB_POOL_IDLE_TIMEOUT=45\n * const config = getPoolConfig();\n *\n * // 3. Default (lowest)\n * // Production: max=20, idleTimeout=30\n * // Development: max=10, idleTimeout=20\n * ```\n */\nexport function getPoolConfig(options?: Partial<PoolConfig>): PoolConfig\n{\n const isProduction = process.env.NODE_ENV === 'production';\n\n // Priority: options > env > default\n const max = options?.max\n ?? (parseInt(process.env.DB_POOL_MAX || '', 10) || (isProduction ? 20 : 10));\n\n const idleTimeout = options?.idleTimeout\n ?? (parseInt(process.env.DB_POOL_IDLE_TIMEOUT || '', 10) || (isProduction ? 30 : 20));\n\n return { max, idleTimeout };\n}\n\n/**\n * 환경별 재시도 설정\n */\nexport function getRetryConfig(): RetryConfig\n{\n const isProduction = process.env.NODE_ENV === 'production';\n\n return {\n maxRetries: isProduction ? 5 : 3, // 프로덕션: 5회, 개발: 3회\n initialDelay: 1000, // 1초\n maxDelay: 16000, // 16초\n factor: 2, // 2배씩 증가 (1s → 2s → 4s → 8s → 16s)\n };\n}","/**\n * Database factory with automatic environment variable detection\n * Supports: Single primary, Primary + Replica\n */\n\nimport { config } from 'dotenv';\nimport { drizzle } from 'drizzle-orm/postgres-js';\nimport type { PostgresJsDatabase } from 'drizzle-orm/postgres-js';\nimport type { Sql } from 'postgres';\n\nimport { createDatabaseConnection } from './connection.js';\nimport { getPoolConfig, getRetryConfig, type PoolConfig } from './config.js';\nimport { logger } from '../../logger';\n\nconst dbLogger = logger.child('database');\n\nexport interface DatabaseClients\n{\n /** Primary database for writes (or both read/write if no replica) */\n write?: PostgresJsDatabase;\n /** Replica database for reads (optional, falls back to write) */\n read?: PostgresJsDatabase;\n /** Raw postgres client for write operations (for cleanup) */\n writeClient?: Sql;\n /** Raw postgres client for read operations (for cleanup) */\n readClient?: Sql;\n}\n\n/**\n * Check if any database configuration exists in environment\n */\nfunction hasDatabaseConfig(): boolean\n{\n return !!(\n process.env.DATABASE_URL ||\n process.env.DATABASE_WRITE_URL ||\n process.env.DATABASE_READ_URL\n );\n}\n\n/**\n * Health check configuration\n */\nexport interface HealthCheckConfig\n{\n enabled: boolean;\n interval: number;\n reconnect: boolean;\n maxRetries: number;\n retryInterval: number;\n}\n\n/**\n * Query performance monitoring configuration\n */\nexport interface MonitoringConfig\n{\n enabled: boolean;\n slowThreshold: number;\n logQueries: boolean;\n}\n\n/**\n * Database initialization options\n */\nexport interface DatabaseOptions\n{\n /**\n * Connection pool configuration\n * Overrides environment variables and defaults\n */\n pool?: Partial<PoolConfig>;\n\n /**\n * Health check configuration\n * Periodic checks to ensure database connection is alive\n */\n healthCheck?: Partial<HealthCheckConfig>;\n\n /**\n * Query performance monitoring configuration\n * Tracks slow queries and logs performance metrics\n */\n monitoring?: Partial<MonitoringConfig>;\n}\n\n/**\n * Create database client(s) from environment variables\n *\n * Supported patterns (priority order):\n * 1. Single primary: DATABASE_URL\n * 2. Primary + Replica: DATABASE_WRITE_URL + DATABASE_READ_URL\n * 3. Legacy replica: DATABASE_URL + DATABASE_REPLICA_URL\n *\n * @param options - Optional database configuration (pool settings, etc.)\n * @returns Database client(s) or undefined if no configuration found\n *\n * @example\n * ```bash\n * # Single primary (most common)\n * DATABASE_URL=postgresql://localhost:5432/mydb\n *\n * # Primary + Replica\n * DATABASE_WRITE_URL=postgresql://primary:5432/mydb\n * DATABASE_READ_URL=postgresql://replica:5432/mydb\n *\n * # Legacy (backward compatibility)\n * DATABASE_URL=postgresql://primary:5432/mydb\n * DATABASE_REPLICA_URL=postgresql://replica:5432/mydb\n * ```\n *\n * @example\n * ```typescript\n * // Custom pool configuration\n * const db = await createDatabaseFromEnv({\n * pool: { max: 50, idleTimeout: 60 }\n * });\n * ```\n */\nexport async function createDatabaseFromEnv(options?: DatabaseOptions): Promise<DatabaseClients>\n{\n // Load .env.local if needed\n if (!hasDatabaseConfig())\n {\n config({ path: '.env.local' });\n }\n\n // Quick exit if no database config\n if (!hasDatabaseConfig())\n {\n return { write: undefined, read: undefined };\n }\n\n try\n {\n const poolConfig = getPoolConfig(options?.pool);\n const retryConfig = getRetryConfig();\n\n // 1. Primary + Replica pattern (explicit separation)\n if (process.env.DATABASE_WRITE_URL && process.env.DATABASE_READ_URL)\n {\n const writeClient = await createDatabaseConnection(\n process.env.DATABASE_WRITE_URL,\n poolConfig,\n retryConfig\n );\n\n const readClient = await createDatabaseConnection(\n process.env.DATABASE_READ_URL,\n poolConfig,\n retryConfig\n );\n\n return {\n write: drizzle(writeClient),\n read: drizzle(readClient),\n writeClient,\n readClient,\n };\n }\n\n // 2. Legacy replica pattern (backward compatibility)\n if (process.env.DATABASE_URL && process.env.DATABASE_REPLICA_URL)\n {\n const writeClient = await createDatabaseConnection(\n process.env.DATABASE_URL,\n poolConfig,\n retryConfig\n );\n\n const readClient = await createDatabaseConnection(\n process.env.DATABASE_REPLICA_URL,\n poolConfig,\n retryConfig\n );\n\n return {\n write: drizzle(writeClient),\n read: drizzle(readClient),\n writeClient,\n readClient,\n };\n }\n\n // 3. Single primary (most common)\n if (process.env.DATABASE_URL)\n {\n const client = await createDatabaseConnection(\n process.env.DATABASE_URL,\n poolConfig,\n retryConfig\n );\n\n const db = drizzle(client);\n return {\n write: db,\n read: db,\n writeClient: client,\n readClient: client,\n };\n }\n\n // 4. DATABASE_WRITE_URL only (no read replica)\n if (process.env.DATABASE_WRITE_URL)\n {\n const client = await createDatabaseConnection(\n process.env.DATABASE_WRITE_URL,\n poolConfig,\n retryConfig\n );\n\n const db = drizzle(client);\n return {\n write: db,\n read: db,\n writeClient: client,\n readClient: client,\n };\n }\n\n // No valid configuration\n return { write: undefined, read: undefined };\n }\n catch (error)\n {\n const message = error instanceof Error ? error.message : 'Unknown error';\n dbLogger.error('Failed to create database connection', {\n error: message,\n stage: 'initialization',\n hasWriteUrl: !!process.env.DATABASE_WRITE_URL,\n hasReadUrl: !!process.env.DATABASE_READ_URL,\n hasUrl: !!process.env.DATABASE_URL,\n hasReplicaUrl: !!process.env.DATABASE_REPLICA_URL,\n });\n return { write: undefined, read: undefined };\n }\n}","/**\n * Global Database instance manager\n * Provides singleton access to database across all modules\n * Supports Primary + Replica pattern with separate read/write instances\n */\n\nimport type { PostgresJsDatabase } from 'drizzle-orm/postgres-js';\nimport type { Sql } from 'postgres';\n\nimport { createDatabaseFromEnv, type DatabaseOptions, type HealthCheckConfig, type MonitoringConfig } from './factory.js';\nimport { logger } from '../../logger';\n\nconst dbLogger = logger.child('database');\n\nlet writeInstance: PostgresJsDatabase | undefined;\nlet readInstance: PostgresJsDatabase | undefined;\nlet writeClient: Sql | undefined;\nlet readClient: Sql | undefined;\nlet healthCheckInterval: NodeJS.Timeout | undefined;\nlet monitoringConfig: MonitoringConfig | undefined;\n\n/**\n * DB connection type\n */\nexport type DbConnectionType = 'read' | 'write';\n\n/**\n * Get global database write instance\n *\n * @returns Database write instance or undefined if not initialized\n *\n * @example\n * ```typescript\n * import { getDatabase } from '@spfn/core/db';\n *\n * const db = getDatabase();\n * if (db) {\n * const users = await db.select().from(usersTable);\n * }\n * ```\n */\nexport function getDatabase(type?: DbConnectionType): PostgresJsDatabase | undefined\n{\n if (type === 'read')\n {\n return readInstance ?? writeInstance;\n }\n return writeInstance;\n}\n\n/**\n * Set global database instances (for testing or manual configuration)\n *\n * @param write - Database write instance\n * @param read - Database read instance (optional, defaults to write)\n *\n * @example\n * ```typescript\n * import { setDatabase } from '@spfn/core/db';\n * import { drizzle } from 'drizzle-orm/postgres-js';\n * import postgres from 'postgres';\n *\n * const writeClient = postgres('postgresql://primary:5432/mydb');\n * const readClient = postgres('postgresql://replica:5432/mydb');\n * setDatabase(drizzle(writeClient), drizzle(readClient));\n * ```\n */\nexport function setDatabase(\n write: PostgresJsDatabase | undefined,\n read?: PostgresJsDatabase | undefined\n): void\n{\n writeInstance = write;\n readInstance = read ?? write;\n}\n\n/**\n * Get health check configuration with priority resolution\n *\n * Priority: options > env > defaults\n */\nfunction getHealthCheckConfig(options?: Partial<HealthCheckConfig>): HealthCheckConfig\n{\n const parseBoolean = (value: string | undefined, defaultValue: boolean): boolean =>\n {\n if (value === undefined) return defaultValue;\n return value.toLowerCase() === 'true';\n };\n\n return {\n enabled: options?.enabled\n ?? parseBoolean(process.env.DB_HEALTH_CHECK_ENABLED, true),\n interval: options?.interval\n ?? (parseInt(process.env.DB_HEALTH_CHECK_INTERVAL || '', 10) || 60000),\n reconnect: options?.reconnect\n ?? parseBoolean(process.env.DB_HEALTH_CHECK_RECONNECT, true),\n maxRetries: options?.maxRetries\n ?? (parseInt(process.env.DB_HEALTH_CHECK_MAX_RETRIES || '', 10) || 3),\n retryInterval: options?.retryInterval\n ?? (parseInt(process.env.DB_HEALTH_CHECK_RETRY_INTERVAL || '', 10) || 5000),\n };\n}\n\n/**\n * Get monitoring configuration with priority resolution\n *\n * Priority: options > env > defaults\n */\nfunction getMonitoringConfig(options?: Partial<MonitoringConfig>): MonitoringConfig\n{\n const isDevelopment = process.env.NODE_ENV !== 'production';\n const parseBoolean = (value: string | undefined, defaultValue: boolean): boolean =>\n {\n if (value === undefined) return defaultValue;\n return value.toLowerCase() === 'true';\n };\n\n return {\n enabled: options?.enabled\n ?? parseBoolean(process.env.DB_MONITORING_ENABLED, isDevelopment),\n slowThreshold: options?.slowThreshold\n ?? (parseInt(process.env.DB_MONITORING_SLOW_THRESHOLD || '', 10) || 1000),\n logQueries: options?.logQueries\n ?? parseBoolean(process.env.DB_MONITORING_LOG_QUERIES, false),\n };\n}\n\n/**\n * Initialize database from environment variables\n * Automatically called by server startup\n *\n * Supported environment variables:\n * - DATABASE_URL (single primary)\n * - DATABASE_WRITE_URL + DATABASE_READ_URL (primary + replica)\n * - DATABASE_URL + DATABASE_REPLICA_URL (legacy replica)\n * - DB_POOL_MAX (connection pool max size)\n * - DB_POOL_IDLE_TIMEOUT (connection idle timeout in seconds)\n * - DB_HEALTH_CHECK_ENABLED (enable health checks, default: true)\n * - DB_HEALTH_CHECK_INTERVAL (health check interval in ms, default: 60000)\n * - DB_HEALTH_CHECK_RECONNECT (enable auto-reconnect, default: true)\n * - DB_HEALTH_CHECK_MAX_RETRIES (max reconnection attempts, default: 3)\n * - DB_HEALTH_CHECK_RETRY_INTERVAL (retry interval in ms, default: 5000)\n * - DB_MONITORING_ENABLED (enable query monitoring, default: true in dev, false in prod)\n * - DB_MONITORING_SLOW_THRESHOLD (slow query threshold in ms, default: 1000)\n * - DB_MONITORING_LOG_QUERIES (log actual SQL queries, default: false)\n *\n * Configuration priority:\n * 1. options parameter (ServerConfig)\n * 2. Environment variables\n * 3. Defaults (based on NODE_ENV)\n *\n * @param options - Optional database configuration (pool settings, etc.)\n * @returns Object with write and read instances\n *\n * @example\n * ```typescript\n * import { initDatabase } from '@spfn/core/db';\n *\n * // Manual initialization (not needed if using server startup)\n * const { write, read } = await initDatabase();\n * if (write) {\n * console.log('Database connected');\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Custom pool configuration\n * const { write, read } = await initDatabase({\n * pool: { max: 50, idleTimeout: 60 }\n * });\n * ```\n */\nexport async function initDatabase(options?: DatabaseOptions): Promise<{\n write?: PostgresJsDatabase;\n read?: PostgresJsDatabase;\n}>\n{\n // Already initialized\n if (writeInstance)\n {\n dbLogger.debug('Database already initialized');\n return { write: writeInstance, read: readInstance };\n }\n\n // Auto-detect from environment\n const result = await createDatabaseFromEnv(options);\n\n if (result.write)\n {\n try\n {\n // Test connection with a simple query\n await result.write.execute('SELECT 1');\n\n // Test read instance if different\n if (result.read && result.read !== result.write)\n {\n await result.read.execute('SELECT 1');\n }\n\n // Store instances\n writeInstance = result.write;\n readInstance = result.read;\n writeClient = result.writeClient;\n readClient = result.readClient;\n\n const hasReplica = result.read && result.read !== result.write;\n dbLogger.info(\n hasReplica\n ? 'Database connected (Primary + Replica)'\n : 'Database connected'\n );\n\n // Start health check (automatic)\n const healthCheckConfig = getHealthCheckConfig(options?.healthCheck);\n if (healthCheckConfig.enabled)\n {\n startHealthCheck(healthCheckConfig);\n }\n\n // Initialize monitoring configuration\n monitoringConfig = getMonitoringConfig(options?.monitoring);\n if (monitoringConfig.enabled)\n {\n dbLogger.info('Database query monitoring enabled', {\n slowThreshold: `${monitoringConfig.slowThreshold}ms`,\n logQueries: monitoringConfig.logQueries,\n });\n }\n }\n catch (error)\n {\n const message = error instanceof Error ? error.message : 'Unknown error';\n dbLogger.error('Database connection failed', { error: message });\n\n // Cleanup on failure\n await closeDatabase();\n\n return { write: undefined, read: undefined };\n }\n }\n else\n {\n dbLogger.warn('No database configuration found');\n dbLogger.warn('Set DATABASE_URL environment variable to enable database');\n }\n\n return { write: writeInstance, read: readInstance };\n}\n\n/**\n * Close all database connections and cleanup\n *\n * Properly closes postgres connection pools with timeout.\n * Should be called during graceful shutdown or after tests.\n *\n * @example\n * ```typescript\n * import { closeDatabase } from '@spfn/core/db';\n *\n * // During graceful shutdown\n * process.on('SIGTERM', async () => {\n * await closeDatabase();\n * process.exit(0);\n * });\n *\n * // In tests\n * afterAll(async () => {\n * await closeDatabase();\n * });\n * ```\n */\nexport async function closeDatabase(): Promise<void>\n{\n if (!writeInstance && !readInstance)\n {\n dbLogger.debug('No database connections to close');\n return;\n }\n\n // Stop health check\n stopHealthCheck();\n\n try\n {\n const closePromises: Promise<void>[] = [];\n\n // Close write client\n if (writeClient)\n {\n dbLogger.debug('Closing write connection...');\n closePromises.push(\n writeClient.end({ timeout: 5 })\n .then(() => dbLogger.debug('Write connection closed'))\n .catch(err => dbLogger.error('Error closing write connection', err))\n );\n }\n\n // Close read client (if different from write)\n if (readClient && readClient !== writeClient)\n {\n dbLogger.debug('Closing read connection...');\n closePromises.push(\n readClient.end({ timeout: 5 })\n .then(() => dbLogger.debug('Read connection closed'))\n .catch(err => dbLogger.error('Error closing read connection', err))\n );\n }\n\n // Wait for all connections to close\n await Promise.all(closePromises);\n\n dbLogger.info('All database connections closed');\n }\n catch (error)\n {\n dbLogger.error('Error during database cleanup', error as Error);\n throw error;\n }\n finally\n {\n // Always clear instances\n writeInstance = undefined;\n readInstance = undefined;\n writeClient = undefined;\n readClient = undefined;\n monitoringConfig = undefined;\n }\n}\n\n/**\n * Get database connection info (for debugging)\n */\nexport function getDatabaseInfo(): {\n hasWrite: boolean;\n hasRead: boolean;\n isReplica: boolean;\n}\n{\n return {\n hasWrite: !!writeInstance,\n hasRead: !!readInstance,\n isReplica: !!(readInstance && readInstance !== writeInstance),\n };\n}\n\n/**\n * Start database health check\n *\n * Periodically checks database connection health and attempts reconnection if enabled.\n * Automatically started by initDatabase() when health check is enabled.\n *\n * @param config - Health check configuration\n *\n * @example\n * ```typescript\n * import { startHealthCheck } from '@spfn/core/db';\n *\n * startHealthCheck({\n * enabled: true,\n * interval: 30000, // 30 seconds\n * reconnect: true,\n * maxRetries: 5,\n * retryInterval: 10000, // 10 seconds\n * });\n * ```\n */\nexport function startHealthCheck(config: HealthCheckConfig): void\n{\n if (healthCheckInterval)\n {\n dbLogger.debug('Health check already running');\n return;\n }\n\n dbLogger.info('Starting database health check', {\n interval: `${config.interval}ms`,\n reconnect: config.reconnect,\n });\n\n healthCheckInterval = setInterval(async () =>\n {\n try\n {\n const write = getDatabase('write');\n const read = getDatabase('read');\n\n // Check write connection\n if (write)\n {\n await write.execute('SELECT 1');\n }\n\n // Check read connection (if different)\n if (read && read !== write)\n {\n await read.execute('SELECT 1');\n }\n\n dbLogger.debug('Database health check passed');\n }\n catch (error)\n {\n const message = error instanceof Error ? error.message : 'Unknown error';\n dbLogger.error('Database health check failed', { error: message });\n\n // Attempt reconnection if enabled\n if (config.reconnect)\n {\n await attemptReconnection(config);\n }\n }\n }, config.interval);\n}\n\n/**\n * Attempt database reconnection with retry logic\n *\n * @param config - Health check configuration\n */\nasync function attemptReconnection(config: HealthCheckConfig): Promise<void>\n{\n dbLogger.warn('Attempting database reconnection', {\n maxRetries: config.maxRetries,\n retryInterval: `${config.retryInterval}ms`,\n });\n\n for (let attempt = 1; attempt <= config.maxRetries; attempt++)\n {\n try\n {\n dbLogger.debug(`Reconnection attempt ${attempt}/${config.maxRetries}`);\n\n // Close existing connections\n await closeDatabase();\n\n // Wait before retry\n await new Promise(resolve => setTimeout(resolve, config.retryInterval));\n\n // Reinitialize database\n const result = await createDatabaseFromEnv();\n\n if (result.write)\n {\n // Test connection\n await result.write.execute('SELECT 1');\n\n // Store instances\n writeInstance = result.write;\n readInstance = result.read;\n writeClient = result.writeClient;\n readClient = result.readClient;\n\n dbLogger.info('Database reconnection successful', { attempt });\n return;\n }\n }\n catch (error)\n {\n const message = error instanceof Error ? error.message : 'Unknown error';\n dbLogger.error(`Reconnection attempt ${attempt} failed`, {\n error: message,\n attempt,\n maxRetries: config.maxRetries,\n });\n\n if (attempt === config.maxRetries)\n {\n dbLogger.error('Max reconnection attempts reached, giving up');\n }\n }\n }\n}\n\n/**\n * Stop database health check\n *\n * Automatically called by closeDatabase().\n * Can also be called manually to stop health checks.\n *\n * @example\n * ```typescript\n * import { stopHealthCheck } from '@spfn/core/db';\n *\n * stopHealthCheck();\n * ```\n */\nexport function stopHealthCheck(): void\n{\n if (healthCheckInterval)\n {\n clearInterval(healthCheckInterval);\n healthCheckInterval = undefined;\n dbLogger.info('Database health check stopped');\n }\n}\n\n/**\n * Get current monitoring configuration\n *\n * Returns the monitoring configuration that was set during database initialization.\n * Used by Repository to determine if and how to monitor query performance.\n *\n * @returns Current monitoring configuration or undefined if database not initialized\n *\n * @example\n * ```typescript\n * import { getDatabaseMonitoringConfig } from '@spfn/core/db';\n *\n * const config = getDatabaseMonitoringConfig();\n * if (config?.enabled) {\n * console.log(`Slow query threshold: ${config.slowThreshold}ms`);\n * }\n * ```\n */\nexport function getDatabaseMonitoringConfig(): MonitoringConfig | undefined\n{\n return monitoringConfig;\n}","/**\n * Database Instance (Backward Compatibility Layer)\n *\n * PostgreSQL + Drizzle ORM connection - now using lazy initialization\n *\n * ✅ Implemented:\n * - Lazy initialization (no top-level await)\n * - Automatic environment variable loading\n * - Read Replica support (read/write separation)\n * - Singleton pattern via db-manager\n * - Backward compatibility with existing code\n *\n * ⚠️ Migration Note:\n * This file now wraps db-manager for backward compatibility.\n * New code should use:\n * - initDatabase() from db-manager\n * - getDatabase() from db-manager\n *\n * 🔗 Related files:\n * - src/db/db-factory.ts (Environment detection)\n * - src/db/db-manager.ts (Singleton management)\n * - src/db/db-context.ts (Transaction-aware access)\n */\nimport type { PostgresJsDatabase } from 'drizzle-orm/postgres-js';\n\nimport { getDatabase, type DbConnectionType } from './manager.js';\n\n/**\n * Default DB instance (Primary - for writes)\n *\n * ⚠️ IMPORTANT: This is a lazy getter. On first access, it will:\n * 1. Auto-initialize database from environment variables\n * 2. Throw error if DATABASE_URL is not set\n *\n * For better error handling, use initDatabase() explicitly:\n * ```typescript\n * import { initDatabase } from '@spfn/core/db';\n * const { write } = await initDatabase();\n * if (!write) throw new Error('Database not configured');\n * ```\n *\n * @example\n * ```typescript\n * import { db } from '@spfn/core/db';\n * const users = await db.select().from(usersTable);\n * ```\n */\nexport const db = new Proxy({} as PostgresJsDatabase, {\n get(_target, prop)\n {\n const instance = getDatabase('write');\n if (!instance)\n {\n throw new Error(\n 'Database not initialized. ' +\n 'Set DATABASE_URL environment variable or call initDatabase() first.'\n );\n }\n return (instance as Record<string | symbol, any>)[prop];\n },\n});\n\n/**\n * Get raw Drizzle DB instance (direct use without transaction)\n *\n * ⚠️ Warning: This function bypasses AsyncLocalStorage transaction context.\n * For normal cases, use `getDb()` from './db-context.js'.\n *\n * @param type - 'read' (Replica) or 'write' (Primary)\n * @returns Raw Drizzle DB instance\n *\n * @example\n * ```typescript\n * // Read-only query (uses Replica)\n * const users = await getRawDb('read').select().from(usersTable);\n *\n * // Write query (uses Primary)\n * await getRawDb('write').insert(usersTable).values({ email: 'test@example.com' });\n * ```\n */\nexport function getRawDb(type: DbConnectionType = 'write'): PostgresJsDatabase\n{\n const instance = getDatabase(type);\n if (!instance)\n {\n throw new Error(\n 'Database not initialized. ' +\n 'Set DATABASE_URL environment variable or call initDatabase() first.'\n );\n }\n return instance;\n}\n\n// Re-export type for backward compatibility\nexport type { DbConnectionType };\n","/**\n * AsyncLocalStorage-based Transaction Context\n *\n * Uses Node.js AsyncLocalStorage to propagate transactions throughout the async call chain.\n *\n * ✅ Implemented:\n * - AsyncLocalStorage-based context management\n * - Transaction storage/retrieval functions\n * - Type-safe transaction propagation\n * - Transaction propagation across async chains\n *\n * ⚠️ Needs improvement:\n * - Nested transaction handling (currently ignores outer transaction)\n * - Transaction timeout detection\n *\n * 💡 Future considerations:\n * - Add transaction ID (for debugging/tracing)\n * - Track transaction start time (for performance monitoring)\n * - Store transaction metadata (route info, user info, etc.)\n * - Savepoint support (nested transactions)\n * - Transaction isolation level configuration\n *\n * 🔗 Related files:\n * - src/utils/transaction.ts (Transactional middleware)\n * - src/db/db-context.ts (getDb helper)\n */\nimport { AsyncLocalStorage } from 'async_hooks';\nimport type { PostgresJsDatabase } from 'drizzle-orm/postgres-js';\n\n/**\n * Transaction database type\n * Record<string, never> represents an empty schema; actual schema is determined at runtime\n */\nexport type TransactionDB = PostgresJsDatabase;\n\n/**\n * Transaction context stored in AsyncLocalStorage\n */\nexport type TransactionContext = {\n tx: TransactionDB;\n};\n\n/**\n * Global AsyncLocalStorage instance for transaction context\n */\nexport const asyncContext = new AsyncLocalStorage<TransactionContext>();\n\n/**\n * Get current transaction from AsyncLocalStorage\n *\n * @returns Transaction if available, null otherwise\n */\nexport function getTransaction(): TransactionDB | null\n{\n const context = asyncContext.getStore();\n return context?.tx ?? null;\n}\n\n/**\n * Run a function within a transaction context\n *\n * The transaction will be available to all async operations within the callback\n * via getTransaction()\n *\n * @param tx - Drizzle transaction object\n * @param callback - Function to run within transaction context\n * @returns Result of the callback\n */\nexport function runWithTransaction<T>(\n tx: TransactionDB,\n callback: () => Promise<T>\n): Promise<T>\n{\n return asyncContext.run({ tx }, callback);\n}","/**\n * Transactional Middleware\n *\n * Wraps route handlers in a database transaction.\n * Auto-commits on success, auto-rolls back on error.\n *\n * ✅ Implemented:\n * - Automatic transaction start/commit/rollback\n * - Transaction propagation via AsyncLocalStorage\n * - Hono Context error detection\n * - Integration with getDb() helper\n * - Type safety improvements (TransactionDB type, no @ts-ignore)\n * - Transaction logging (start/commit/rollback)\n * - Execution time measurement and slow transaction warnings\n * - Transaction ID tracking (for debugging)\n * - Transaction timeout configuration (with TRANSACTION_TIMEOUT env var support)\n *\n * ⚠️ Needs improvement:\n * - Detect and warn about nested transactions\n *\n * 💡 Future considerations:\n * - Transaction isolation level configuration option\n * - Read-only transaction mode\n * - Transaction retry logic (on deadlock)\n * - Transaction event hooks (beforeCommit, afterCommit, onRollback)\n *\n * 🔗 Related files:\n * - src/utils/async-context.ts (AsyncLocalStorage)\n * - src/db/db-context.ts (getDb helper)\n * - src/utils/__tests__/transaction.test.ts (tests)\n *\n * 📝 Future improvements:\n * - Transaction isolation level setting (withTransaction({ isolationLevel: 'SERIALIZABLE' }))\n * - Nested transaction savepoint support\n */\nimport { createMiddleware } from 'hono/factory';\nimport { db } from '../index.js';\nimport { runWithTransaction, type TransactionDB } from './context.js';\nimport { logger } from '../../logger';\nimport { TransactionError } from '../../errors';\nimport { fromPostgresError } from '../postgres-errors';\n\n/**\n * Transaction middleware options\n */\nexport interface TransactionalOptions\n{\n /**\n * Slow transaction warning threshold in milliseconds\n * @default 1000 (1 second)\n */\n slowThreshold?: number;\n\n /**\n * Enable transaction logging\n * @default true\n */\n enableLogging?: boolean;\n\n /**\n * Transaction timeout in milliseconds\n *\n * If transaction exceeds this duration, it will be aborted with TransactionError.\n *\n * @default 30000 (30 seconds) or TRANSACTION_TIMEOUT environment variable\n *\n * @example\n * ```typescript\n * // Default timeout (30s or TRANSACTION_TIMEOUT env var)\n * Transactional()\n *\n * // Custom timeout for specific route (60s)\n * Transactional({ timeout: 60000 })\n *\n * // Disable timeout\n * Transactional({ timeout: 0 })\n * ```\n */\n timeout?: number;\n}\n\n/**\n * Transaction middleware for Hono routes\n *\n * Automatically wraps route handlers in a database transaction.\n * Commits on success, rolls back on error.\n *\n * @example\n * ```typescript\n * // In your route file\n * export const middlewares = [Transactional()];\n *\n * export async function POST(c: RouteContext) {\n * // All DB operations run in a transaction\n * const [user] = await db.insert(users).values(body).returning();\n * await db.insert(profiles).values({ userId: user.id });\n * // Auto-commits on success\n * return c.json(user, 201);\n * }\n * ```\n *\n * @example\n * ```typescript\n * // With custom options\n * export const middlewares = [\n * Transactional({\n * slowThreshold: 2000, // Warn if transaction takes > 2s\n * enableLogging: false, // Disable logging\n * timeout: 60000, // 60 second timeout for long operations\n * })\n * ];\n * ```\n *\n * 🔄 Transaction behavior:\n * - Success: Auto-commit\n * - Error: Auto-rollback\n * - Detects context.error to trigger rollback\n *\n * 📊 Transaction logging:\n * - Auto-logs transaction start/commit/rollback\n * - Measures and records execution time\n * - Warns about slow transactions (default: > 1s)\n */\nexport function Transactional(options: TransactionalOptions = {})\n{\n // Get default timeout from environment variable (default: 30 seconds)\n const defaultTimeout = parseInt(process.env.TRANSACTION_TIMEOUT || '30000', 10);\n\n const {\n slowThreshold = 1000,\n enableLogging = true,\n timeout = defaultTimeout,\n } = options;\n\n const txLogger = logger.child('transaction');\n\n return createMiddleware(async (c, next) =>\n {\n // Generate transaction ID for debugging\n const txId = `tx_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n const startTime = Date.now();\n const route = `${c.req.method} ${c.req.path}`;\n\n if (enableLogging)\n {\n txLogger.debug('Transaction started', { txId, route });\n }\n\n try\n {\n // Create transaction promise\n const transactionPromise = db.transaction(async (tx) =>\n {\n // Store transaction in AsyncLocalStorage\n await runWithTransaction(tx as TransactionDB, async () =>\n {\n // Execute handler\n await next();\n\n // Detect if Hono caught an error and stored it in context.error\n // Context type doesn't officially define error property, so we extend it\n type ContextWithError = typeof c & { error?: Error };\n const contextWithError = c as ContextWithError;\n if (contextWithError.error)\n {\n // Throw to rollback transaction\n throw contextWithError.error;\n }\n\n // Auto-commit on success (handled by Drizzle)\n });\n });\n\n // Apply timeout if enabled (timeout > 0)\n if (timeout > 0)\n {\n const timeoutPromise = new Promise<never>((_, reject) =>\n {\n setTimeout(() =>\n {\n reject(\n new TransactionError(\n `Transaction timeout after ${timeout}ms`,\n 500,\n {\n txId,\n route,\n timeout: `${timeout}ms`,\n }\n )\n );\n }, timeout);\n });\n\n // Race between transaction and timeout\n await Promise.race([transactionPromise, timeoutPromise]);\n }\n else\n {\n // No timeout - just await transaction\n await transactionPromise;\n }\n\n // Transaction successful (committed)\n const duration = Date.now() - startTime;\n\n if (enableLogging)\n {\n if (duration >= slowThreshold)\n {\n txLogger.warn('Slow transaction committed', {\n txId,\n route,\n duration: `${duration}ms`,\n threshold: `${slowThreshold}ms`,\n });\n }\n else\n {\n txLogger.debug('Transaction committed', {\n txId,\n route,\n duration: `${duration}ms`,\n });\n }\n }\n }\n catch (error)\n {\n // Transaction failed (rolled back)\n const duration = Date.now() - startTime;\n\n // Convert PostgreSQL error to custom error (unless it's already TransactionError)\n const customError = error instanceof TransactionError\n ? error\n : fromPostgresError(error);\n\n if (enableLogging)\n {\n txLogger.error('Transaction rolled back', {\n txId,\n route,\n duration: `${duration}ms`,\n error: customError.message,\n errorType: customError.name,\n });\n }\n\n // Re-throw for Hono's error handler\n throw customError;\n }\n });\n}","/**\n * Repository Filter Utilities\n *\n * Utilities for building Drizzle ORM WHERE, ORDER BY, and pagination conditions.\n * Moved from deprecated query module for Repository pattern usage.\n *\n * @module db/repository/filters\n */\n\nimport { and, eq, ne, gt, gte, lt, lte, like, inArray, notInArray, isNull, isNotNull, or, asc, desc, sql, SQL } from 'drizzle-orm';\n\nimport type { PgColumn, PgTable } from 'drizzle-orm/pg-core';\nimport type { PostgresJsDatabase } from 'drizzle-orm/postgres-js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Filter operators\n */\nexport type FilterOperator =\n | 'eq' // equals\n | 'ne' // not equals\n | 'gt' // greater than\n | 'gte' // greater than or equal\n | 'lt' // less than\n | 'lte' // less than or equal\n | 'like' // LIKE (partial match)\n | 'in' // IN (array)\n | 'nin' // NOT IN (array)\n | 'is'; // IS NULL / IS NOT NULL\n\n/**\n * Filter value type\n */\nexport type FilterValue = string | number | boolean | null | (string | number)[];\n\n/**\n * Filter condition\n *\n * @example { email: { eq: 'john@example.com' } }\n * @example { age: { gte: 18, lte: 65 } }\n */\nexport type FilterCondition = {\n [operator in FilterOperator]?: FilterValue;\n};\n\n/**\n * Complete filters\n *\n * @example { email: { eq: 'john@example.com' }, role: { in: ['admin', 'user'] } }\n */\nexport type Filters = {\n [field: string]: FilterCondition;\n};\n\n/**\n * Filter builder result type\n */\nexport type FilterResult = SQL<unknown> | undefined;\n\n/**\n * Sort direction\n */\nexport type SortDirection = 'asc' | 'desc';\n\n/**\n * Sort condition\n *\n * @example [{ field: 'createdAt', direction: 'desc' }, { field: 'name', direction: 'asc' }]\n */\nexport type SortCondition = {\n field: string;\n direction: SortDirection;\n};\n\n/**\n * Sort builder result type\n */\nexport type SortResult = SQL<unknown>[];\n\n/**\n * Pagination parameters\n */\nexport type PaginationParams = {\n page: number;\n limit: number;\n};\n\n/**\n * Pagination metadata\n */\nexport type PaginationMeta = {\n page: number;\n limit: number;\n total: number;\n totalPages: number;\n hasNext: boolean;\n hasPrev: boolean;\n};\n\n/**\n * Drizzle table type (generic)\n */\nexport type DrizzleTable = PgTable<any> & Record<string, PgColumn>;\n\n// ============================================================================\n// Filter Builder\n// ============================================================================\n\n/**\n * Convert filter conditions to Drizzle SQL WHERE conditions\n *\n * @param filters - Parsed filter object\n * @param table - Drizzle table schema\n * @returns SQL WHERE condition (undefined if no filters)\n *\n * @example\n * const filters = { email: { eq: 'john@example.com' }, age: { gte: 18 } };\n * const condition = buildFilters(filters, users);\n * const data = await db.select().from(users).where(condition);\n */\nexport function buildFilters(\n filters: Filters,\n table: DrizzleTable\n): FilterResult\n{\n const conditions: SQL<unknown>[] = [];\n\n for (const [field, filterCondition] of Object.entries(filters))\n {\n const column = table[field] as PgColumn;\n\n if (!column)\n {\n console.warn(`[buildFilters] Unknown field: ${field}`);\n continue;\n }\n\n // Build condition for each operator\n for (const [operator, value] of Object.entries(filterCondition))\n {\n const condition = buildCondition(column, operator as FilterOperator, value);\n if (condition)\n {\n conditions.push(condition);\n }\n }\n }\n\n // Combine all conditions with AND\n return conditions.length > 0 ? and(...conditions) : undefined;\n}\n\n/**\n * Convert single filter condition to SQL condition\n */\nfunction buildCondition(\n column: PgColumn,\n operator: FilterOperator,\n value: FilterValue\n): SQL<unknown> | undefined\n{\n switch (operator)\n {\n case 'eq':\n return eq(column, value as string | number);\n\n case 'ne':\n return ne(column, value as string | number);\n\n case 'gt':\n return gt(column, value as string | number);\n\n case 'gte':\n return gte(column, value as string | number);\n\n case 'lt':\n return lt(column, value as string | number);\n\n case 'lte':\n return lte(column, value as string | number);\n\n case 'like':\n return like(column, `%${value}%`);\n\n case 'in':\n if (Array.isArray(value))\n {\n return inArray(column, value);\n }\n console.warn(`[buildCondition] 'in' operator requires array value`);\n return undefined;\n\n case 'nin':\n if (Array.isArray(value))\n {\n return notInArray(column, value);\n }\n console.warn(`[buildCondition] 'nin' operator requires array value`);\n return undefined;\n\n case 'is':\n if (value === 'null') return isNull(column);\n if (value === 'notnull') return isNotNull(column);\n console.warn(`[buildCondition] 'is' operator requires 'null' or 'notnull'`);\n return undefined;\n\n default:\n console.warn(`[buildCondition] Unknown operator: ${operator}`);\n return undefined;\n }\n}\n\n/**\n * Combine conditions with OR\n *\n * @example\n * const conditions = [\n * buildFilters({ status: { eq: 'active' } }, users),\n * buildFilters({ role: { eq: 'admin' } }, users)\n * ];\n * const orCondition = orFilters(...conditions);\n */\nexport function orFilters(...conditions: (FilterResult)[]): FilterResult\n{\n const validConditions = conditions.filter(c => c !== undefined) as SQL<unknown>[];\n return validConditions.length > 0 ? or(...validConditions) : undefined;\n}\n\n// ============================================================================\n// Sort Builder\n// ============================================================================\n\n/**\n * Convert sort conditions to Drizzle SQL ORDER BY conditions\n *\n * @param sortConditions - Sort condition array\n * @param table - Drizzle table schema\n * @returns SQL ORDER BY condition array\n *\n * @example\n * const sort = [\n * { field: 'createdAt', direction: 'desc' },\n * { field: 'name', direction: 'asc' }\n * ];\n * const orderBy = buildSort(sort, users);\n * const data = await db.select().from(users).orderBy(...orderBy);\n */\nexport function buildSort(\n sortConditions: SortCondition[],\n table: DrizzleTable\n): SortResult\n{\n const orderByClauses: SQL<unknown>[] = [];\n\n for (const { field, direction } of sortConditions)\n {\n const column = table[field] as PgColumn;\n\n if (!column)\n {\n console.warn(`[buildSort] Unknown field: ${field}`);\n continue;\n }\n\n const clause = direction === 'desc' ? desc(column) : asc(column);\n orderByClauses.push(clause);\n }\n\n return orderByClauses;\n}\n\n// ============================================================================\n// Pagination Utilities\n// ============================================================================\n\n/**\n * Apply pagination to Drizzle query\n *\n * @param pagination - Pagination parameters\n * @returns { offset, limit } object\n *\n * @example\n * const { offset, limit } = applyPagination({ page: 2, limit: 20 });\n * const data = await db.select().from(users).limit(limit).offset(offset);\n */\nexport function applyPagination(pagination: PaginationParams)\n{\n const { page, limit } = pagination;\n const offset = (page - 1) * limit;\n\n return { offset, limit };\n}\n\n/**\n * Create pagination metadata\n *\n * @param pagination - Pagination parameters\n * @param total - Total count\n * @returns Pagination metadata\n *\n * @example\n * const meta = createPaginationMeta({ page: 2, limit: 20 }, 156);\n * // { page: 2, limit: 20, total: 156, totalPages: 8, hasNext: true, hasPrev: true }\n */\nexport function createPaginationMeta(\n pagination: PaginationParams,\n total: number\n): PaginationMeta\n{\n const { page, limit } = pagination;\n const totalPages = Math.ceil(total / limit);\n\n return {\n page,\n limit,\n total,\n totalPages,\n hasNext: page < totalPages,\n hasPrev: page > 1,\n };\n}\n\n/**\n * Count total records (count query)\n *\n * @param db - Drizzle DB instance\n * @param table - Table schema\n * @param whereCondition - WHERE condition (optional)\n * @returns Total count\n *\n * @example\n * const total = await countTotal(db, users);\n * const total = await countTotal(db, users, eq(users.status, 'active'));\n */\nexport async function countTotal(\n db: PostgresJsDatabase<Record<string, never>>,\n table: DrizzleTable,\n whereCondition?: any\n): Promise<number>\n{\n const query = db\n .select({ count: sql<number>`count(*)::int` })\n .from(table);\n\n if (whereCondition)\n {\n query.where(whereCondition);\n }\n\n const [result] = await query;\n return result?.count || 0;\n}","/**\n * Query Builder (Fluent Interface)\n *\n * Chainable query builder for Repository pattern.\n * Provides a fluent API for building complex queries.\n *\n * @example\n * ```typescript\n * const users = await userRepo\n * .query()\n * .where({ status: 'active' })\n * .where({ role: 'admin' })\n * .orderBy('createdAt', 'desc')\n * .limit(10)\n * .findMany();\n * ```\n */\n\nimport type { PgTable } from 'drizzle-orm/pg-core';\nimport type { PostgresJsDatabase } from 'drizzle-orm/postgres-js';\n\nimport type { Filters, SortCondition } from './filters.js';\n\nimport { buildFilters, buildSort } from './filters.js';\n\n/**\n * Query Builder class for chainable queries\n *\n * Supports method chaining for building complex queries in a fluent style.\n */\nexport class QueryBuilder<\n TTable extends PgTable,\n TSelect = TTable['$inferSelect']\n>\n{\n private db: PostgresJsDatabase<any>;\n private table: TTable;\n private filterConditions: Filters[] = [];\n private sortConditions: SortCondition[] = [];\n private limitValue?: number;\n private offsetValue?: number;\n\n constructor(db: PostgresJsDatabase<any>, table: TTable)\n {\n this.db = db;\n this.table = table;\n }\n\n /**\n * Add WHERE conditions\n *\n * Multiple where() calls are combined with AND logic.\n *\n * @param filters - Filter conditions\n * @returns QueryBuilder for chaining\n *\n * @example\n * ```typescript\n * query\n * .where({ status: 'active' })\n * .where({ role: 'admin' }) // AND condition\n * ```\n */\n where(filters: Filters): this\n {\n this.filterConditions.push(filters);\n return this;\n }\n\n /**\n * Add ORDER BY clause\n *\n * Multiple orderBy() calls create multi-column sorting.\n *\n * @param field - Field name to sort by\n * @param direction - Sort direction ('asc' or 'desc')\n * @returns QueryBuilder for chaining\n *\n * @example\n * ```typescript\n * query\n * .orderBy('isPremium', 'desc')\n * .orderBy('createdAt', 'desc')\n * ```\n */\n orderBy(field: string, direction: 'asc' | 'desc' = 'asc'): this\n {\n this.sortConditions.push({ field, direction });\n return this;\n }\n\n /**\n * Set LIMIT clause\n *\n * @param limit - Maximum number of records to return\n * @returns QueryBuilder for chaining\n *\n * @example\n * ```typescript\n * query.limit(10)\n * ```\n */\n limit(limit: number): this\n {\n this.limitValue = limit;\n return this;\n }\n\n /**\n * Set OFFSET clause\n *\n * @param offset - Number of records to skip\n * @returns QueryBuilder for chaining\n *\n * @example\n * ```typescript\n * query.offset(20)\n * ```\n */\n offset(offset: number): this\n {\n this.offsetValue = offset;\n return this;\n }\n\n /**\n * Execute query and return multiple records\n *\n * @returns Array of records\n *\n * @example\n * ```typescript\n * const users = await query\n * .where({ status: 'active' })\n * .orderBy('createdAt', 'desc')\n * .limit(10)\n * .findMany();\n * ```\n */\n async findMany(): Promise<TSelect[]>\n {\n // Merge all filter conditions with AND\n const mergedFilters = this.mergeFilters();\n const whereCondition = buildFilters(mergedFilters, this.table as any);\n const orderBy = buildSort(this.sortConditions, this.table as any);\n\n let query = this.db\n .select()\n .from(this.table as any)\n .where(whereCondition)\n .orderBy(...orderBy);\n\n if (this.limitValue !== undefined)\n {\n query = query.limit(this.limitValue) as any;\n }\n\n if (this.offsetValue !== undefined)\n {\n query = query.offset(this.offsetValue) as any;\n }\n\n return query as Promise<TSelect[]>;\n }\n\n /**\n * Execute query and return first record\n *\n * @returns First matching record or null\n *\n * @example\n * ```typescript\n * const user = await query\n * .where({ email: 'john@example.com' })\n * .findOne();\n * ```\n */\n async findOne(): Promise<TSelect | null>\n {\n const results = await this.limit(1).findMany();\n return results[0] ?? null;\n }\n\n /**\n * Execute query and return count\n *\n * @returns Number of matching records\n *\n * @example\n * ```typescript\n * const count = await query\n * .where({ status: 'active' })\n * .count();\n * ```\n */\n async count(): Promise<number>\n {\n const mergedFilters = this.mergeFilters();\n const whereCondition = buildFilters(mergedFilters, this.table as any);\n\n const { count } = await import('drizzle-orm');\n const result = await this.db\n .select({ count: count() })\n .from(this.table as any)\n .where(whereCondition);\n\n return Number(result[0]?.count ?? 0);\n }\n\n /**\n * Merge multiple filter conditions into single object\n *\n * Combines all where() calls into one filter object.\n */\n private mergeFilters(): Filters\n {\n if (this.filterConditions.length === 0)\n {\n return {};\n }\n\n // Merge all filter objects\n return this.filterConditions.reduce((merged, current) => {\n return { ...merged, ...current };\n }, {});\n }\n}","/**\n * Repository Pattern (JPA Style)\n *\n * Spring JPA-inspired Repository pattern for TypeScript/Drizzle ORM\n *\n * ✅ Features:\n * - Auto Read/Write Replica routing (read methods use Replica, write methods use Primary)\n * - Type-safe CRUD operations (findById, findWhere, save, update, delete, etc.)\n * - Advanced filtering with operators (eq, gt, like, in, etc.)\n * - Pagination with metadata (findPage)\n * - Batch operations (saveMany, updateWhere, deleteWhere)\n * - Transaction-aware (automatic participation in Transactional middleware)\n */\n\nimport type { SQL } from 'drizzle-orm';\nimport type { PgTable } from 'drizzle-orm/pg-core';\nimport type { PostgresJsDatabase } from 'drizzle-orm/postgres-js';\n\nimport type { Filters, SortCondition, PaginationParams, PaginationMeta } from './filters.js';\n\nimport { buildFilters, buildSort, applyPagination, createPaginationMeta, countTotal } from './filters.js';\nimport { getRawDb, getDatabaseMonitoringConfig } from '../manager';\nimport { getTransaction } from '../transaction';\nimport { QueryError } from '../../errors';\nimport { QueryBuilder } from './query-builder.js';\nimport { logger } from '../../logger';\n\n/**\n * Pageable interface (Spring Pageable style)\n */\nexport type Pageable = {\n filters?: Filters;\n sort?: SortCondition[];\n pagination?: PaginationParams;\n};\n\n/**\n * Page result (Spring Page style)\n */\nexport type Page<T> = {\n data: T[];\n meta: PaginationMeta;\n};\n\n/**\n * Repository class\n *\n * Provides JPA Repository-style CRUD methods with automatic transaction support\n *\n * ✅ Automatic Transaction Detection:\n * - Automatically participates in active Transactional() middleware context\n * - No need to pass transaction explicitly - uses AsyncLocalStorage\n * - All operations within a transaction use the same transaction DB\n *\n * ✅ Auto Read/Write Replica routing (when NOT in transaction):\n * - Read methods (findAll, findById, findOne, findPage, count) → Uses Read Replica\n * - Write methods (save, update, delete) → Uses Primary DB\n *\n * ✅ DB Priority:\n * 1. Explicit DB (if provided in constructor)\n * 2. Transaction context (if inside Transactional middleware)\n * 3. Read Replica or Primary DB (based on operation type)\n *\n * @example\n * ```typescript\n * // Simple usage - automatically detects transaction\n * class UserService {\n * private get repo() {\n * return new Repository(users); // Auto-detects transaction\n * }\n * }\n *\n * // Route with transaction\n * app.bind(contract, Transactional(), async (c) => {\n * const service = new UserService();\n * await service.createUser(data);\n * // Automatic rollback on error!\n * });\n * ```\n */\nexport class Repository<\n TTable extends PgTable,\n TSelect = TTable['$inferSelect']\n>\n{\n protected db: PostgresJsDatabase<any>;\n protected table: TTable;\n protected useReplica: boolean;\n protected explicitDb?: PostgresJsDatabase<any>; // Track if db was explicitly provided\n protected autoUpdateField?: string; // Field name to auto-update (e.g., 'updatedAt', 'modifiedAt')\n\n constructor(\n dbOrTable: PostgresJsDatabase<any> | TTable,\n tableOrUseReplica?: TTable | boolean,\n useReplica: boolean = true\n ) {\n // Overload 1: new Repository(table) - db auto-resolved\n if ('name' in dbOrTable && typeof dbOrTable.name === 'string') {\n this.db = getRawDb('write');\n this.table = dbOrTable as TTable;\n this.useReplica = typeof tableOrUseReplica === 'boolean' ? tableOrUseReplica : true;\n this.explicitDb = undefined; // No explicit db provided\n }\n // Overload 2: new Repository(db, table, useReplica?) - explicit db provided\n else {\n this.db = dbOrTable as PostgresJsDatabase<any>;\n this.table = tableOrUseReplica as TTable;\n this.useReplica = useReplica;\n this.explicitDb = this.db; // Save explicit db\n }\n\n // Detect auto-update timestamp field from schema\n this.autoUpdateField = this.detectAutoUpdateField();\n }\n\n /**\n * Detect which field (if any) should be auto-updated\n *\n * Checks all table columns for __autoUpdate metadata flag.\n * Set by autoUpdateTimestamp() or timestamps({ autoUpdate: true }) helpers.\n *\n * @returns Field name to auto-update, or undefined if none found\n */\n private detectAutoUpdateField(): string | undefined\n {\n // Guard against undefined/null table\n if (!this.table || typeof this.table !== 'object')\n {\n return undefined;\n }\n\n const tableColumns = this.table as Record<string, any>;\n\n for (const [fieldName, column] of Object.entries(tableColumns))\n {\n // Skip non-column properties (like '_', '$inferSelect', etc.)\n if (fieldName.startsWith('_') || fieldName.startsWith('$'))\n {\n continue;\n }\n\n // Check if column has __autoUpdate flag\n if (column && typeof column === 'object' && column.__autoUpdate === true)\n {\n return fieldName;\n }\n }\n\n return undefined;\n }\n\n /**\n * Inject auto-update timestamp if configured\n *\n * Only injects if:\n * 1. Table has an auto-update field configured (via autoUpdateTimestamp() or timestamps({ autoUpdate: true }))\n * 2. The field is not already explicitly provided in the data\n *\n * @param data - Update data object\n * @returns Data with auto-update timestamp injected (if applicable)\n */\n private injectAutoUpdateTimestamp(data: any): any\n {\n // No auto-update field configured\n if (!this.autoUpdateField)\n {\n return data;\n }\n\n // Field already explicitly provided, don't override\n if (data && this.autoUpdateField in data)\n {\n return data;\n }\n\n // Inject current timestamp\n return {\n ...data,\n [this.autoUpdateField]: new Date(),\n };\n }\n\n /**\n * Get id column from table\n *\n * Helper method to reduce code duplication across methods that need id column.\n *\n * @returns The id column object\n * @throws {QueryError} If table does not have an id column\n */\n private getIdColumn()\n {\n const idColumn = (this.table as Record<string, any>).id;\n\n if (!idColumn)\n {\n throw new QueryError('Table does not have an id column');\n }\n\n return idColumn;\n }\n\n /**\n * Get read-only DB\n *\n * Automatically detects and uses transaction context if available.\n * When in transaction, uses transaction DB to ensure read consistency.\n * Priority: explicitDb > transaction > replica/primary DB\n */\n private getReadDb(): PostgresJsDatabase<any>\n {\n // If db was explicitly provided, always use it\n if (this.explicitDb) {\n return this.explicitDb;\n }\n\n // Check if we're inside a transaction context\n // Use transaction for reads too to ensure consistency\n const tx = getTransaction();\n if (tx) {\n return tx;\n }\n\n // Otherwise use getRawDb for replica routing\n return this.useReplica ? getRawDb('read') : this.db;\n }\n\n /**\n * Get write-only DB\n *\n * Automatically detects and uses transaction context if available.\n * Priority: explicitDb > transaction > primary DB\n */\n private getWriteDb(): PostgresJsDatabase<any>\n {\n // If db was explicitly provided, always use it\n if (this.explicitDb) {\n return this.explicitDb;\n }\n\n // Check if we're inside a transaction context\n const tx = getTransaction();\n if (tx) {\n return tx;\n }\n\n // Otherwise use getRawDb for write operations\n return getRawDb('write');\n }\n\n /**\n * Execute operation with performance monitoring\n *\n * Wraps database operations with timing and logging for slow queries.\n * Only logs if monitoring is enabled and query exceeds threshold.\n *\n * @param operation - Name of the operation (for logging)\n * @param fn - Async function to execute\n * @returns Result of the operation\n */\n private async executeWithMonitoring<T>(\n operation: string,\n fn: () => Promise<T>\n ): Promise<T>\n {\n const config = getDatabaseMonitoringConfig();\n\n // If monitoring is disabled, just execute the operation\n if (!config?.enabled)\n {\n return fn();\n }\n\n const startTime = performance.now();\n\n try\n {\n const result = await fn();\n const duration = performance.now() - startTime;\n\n // Log slow queries\n if (duration >= config.slowThreshold)\n {\n const dbLogger = logger.child('database');\n const logData: any = {\n operation,\n table: this.table._.name,\n duration: `${duration.toFixed(2)}ms`,\n threshold: `${config.slowThreshold}ms`,\n };\n\n dbLogger.warn('Slow query detected', logData);\n }\n\n return result;\n }\n catch (error)\n {\n const duration = performance.now() - startTime;\n const dbLogger = logger.child('database');\n const message = error instanceof Error ? error.message : 'Unknown error';\n\n dbLogger.error('Query failed', {\n operation,\n table: this.table._.name,\n duration: `${duration.toFixed(2)}ms`,\n error: message,\n });\n\n throw error;\n }\n }\n\n /**\n * Find all records (uses Replica)\n *\n * @example\n * const users = await userRepo.findAll();\n */\n async findAll(): Promise<TSelect[]>\n {\n return this.executeWithMonitoring('findAll', async () =>\n {\n const readDb = this.getReadDb();\n // Type assertion needed: Drizzle's from() expects specific table signature\n return readDb.select().from(this.table as any) as Promise<TSelect[]>;\n });\n }\n\n /**\n * Find with pagination (uses Replica)\n *\n * @example\n * const result = await userRepo.findPage({\n * filters: { email: { like: 'john' } },\n * sort: [{ field: 'createdAt', direction: 'desc' }],\n * pagination: { page: 1, limit: 20 }\n * });\n */\n async findPage(pageable: Pageable): Promise<Page<TSelect>>\n {\n return this.executeWithMonitoring('findPage', async () =>\n {\n const { filters = {}, sort = [], pagination = { page: 1, limit: 20 } } = pageable;\n\n // Type assertions needed: Helper functions expect DrizzleTable type\n const whereCondition = buildFilters(filters, this.table as any);\n const orderBy = buildSort(sort, this.table as any);\n const { offset, limit } = applyPagination(pagination);\n\n // Fetch data from Replica\n const readDb = this.getReadDb();\n const data = await readDb\n .select()\n .from(this.table as any)\n .where(whereCondition)\n .orderBy(...orderBy)\n .limit(limit)\n .offset(offset) as TSelect[];\n\n // Count total (uses Replica)\n const total = await countTotal(readDb, this.table as any, whereCondition);\n const meta = createPaginationMeta(pagination, total);\n\n return { data, meta };\n });\n }\n\n /**\n * Find one record by ID (uses Replica)\n *\n * @example\n * const user = await userRepo.findById(1);\n */\n async findById(id: number | string): Promise<TSelect | null>\n {\n return this.executeWithMonitoring('findById', async () =>\n {\n const idColumn = this.getIdColumn();\n\n const { eq } = await import('drizzle-orm');\n const readDb = this.getReadDb();\n const [result] = await readDb\n .select()\n .from(this.table as any)\n .where(eq(idColumn, id)) as TSelect[];\n\n return result ?? null;\n });\n }\n\n /**\n * Find one record by condition (uses Replica)\n *\n * @example\n * const user = await userRepo.findOne(eq(users.email, 'john@example.com'));\n */\n async findOne(where: SQL<unknown>): Promise<TSelect | null>\n {\n return this.executeWithMonitoring('findOne', async () =>\n {\n const readDb = this.getReadDb();\n const [result] = await readDb\n .select()\n .from(this.table as any)\n .where(where) as TSelect[];\n\n return result ?? null;\n });\n }\n\n /**\n * Create a new record (uses Primary)\n *\n * @example\n * const user = await userRepo.save({ email: 'john@example.com', name: 'John' });\n */\n async save(data: any): Promise<TSelect>\n {\n return this.executeWithMonitoring('save', async () =>\n {\n const writeDb = this.getWriteDb();\n const [result] = await writeDb\n .insert(this.table)\n .values(data)\n .returning() as TSelect[];\n\n return result;\n });\n }\n\n /**\n * Update a record (uses Primary)\n *\n * Automatically injects current timestamp if table has auto-update field configured.\n *\n * @example\n * const user = await userRepo.update(1, { name: 'Jane' });\n */\n async update(id: number | string, data: any): Promise<TSelect | null>\n {\n return this.executeWithMonitoring('update', async () =>\n {\n const idColumn = this.getIdColumn();\n\n // Auto-inject timestamp if configured and not explicitly provided\n const updateData = this.injectAutoUpdateTimestamp(data);\n\n const { eq } = await import('drizzle-orm');\n const writeDb = this.getWriteDb();\n const [result] = await writeDb\n .update(this.table)\n .set(updateData)\n .where(eq(idColumn, id))\n .returning() as TSelect[];\n\n return result ?? null;\n });\n }\n\n /**\n * Delete a record (uses Primary)\n *\n * @example\n * const deleted = await userRepo.delete(1);\n */\n async delete(id: number | string): Promise<TSelect | null>\n {\n return this.executeWithMonitoring('delete', async () =>\n {\n const idColumn = this.getIdColumn();\n\n const { eq } = await import('drizzle-orm');\n const writeDb = this.getWriteDb();\n const [result] = await writeDb\n .delete(this.table)\n .where(eq(idColumn, id))\n .returning() as TSelect[];\n\n return result ?? null;\n });\n }\n\n /**\n * Count records (uses Replica)\n *\n * @example\n * const count = await userRepo.count();\n */\n async count(where?: SQL<unknown>): Promise<number>\n {\n return this.executeWithMonitoring('count', async () =>\n {\n const readDb = this.getReadDb();\n return countTotal(readDb, this.table as any, where);\n });\n }\n\n /**\n * Find records by filters (uses Replica)\n *\n * @example\n * const users = await userRepo.findWhere({ email: { like: '@gmail.com' }, status: 'active' });\n */\n async findWhere(filters: Filters): Promise<TSelect[]>\n {\n return this.executeWithMonitoring('findWhere', async () =>\n {\n const whereCondition = buildFilters(filters, this.table as any);\n const readDb = this.getReadDb();\n return readDb\n .select()\n .from(this.table as any)\n .where(whereCondition) as Promise<TSelect[]>;\n });\n }\n\n /**\n * Find one record by filters (uses Replica)\n *\n * @example\n * const user = await userRepo.findOneWhere({ email: 'john@example.com' });\n */\n async findOneWhere(filters: Filters): Promise<TSelect | null>\n {\n return this.executeWithMonitoring('findOneWhere', async () =>\n {\n const whereCondition = buildFilters(filters, this.table as any);\n const readDb = this.getReadDb();\n const [result] = await readDb\n .select()\n .from(this.table as any)\n .where(whereCondition) as TSelect[];\n\n return result ?? null;\n });\n }\n\n /**\n * Check if record exists by ID (uses Replica)\n *\n * @example\n * const exists = await userRepo.exists(1);\n */\n async exists(id: number | string): Promise<boolean>\n {\n return this.executeWithMonitoring('exists', async () =>\n {\n const idColumn = this.getIdColumn();\n\n const { eq } = await import('drizzle-orm');\n const readDb = this.getReadDb();\n const [result] = await readDb\n .select()\n .from(this.table as any)\n .where(eq(idColumn, id))\n .limit(1) as TSelect[];\n\n return !!result;\n });\n }\n\n /**\n * Check if record exists by filters (uses Replica)\n *\n * @example\n * const exists = await userRepo.existsBy({ email: 'john@example.com' });\n */\n async existsBy(filters: Filters): Promise<boolean>\n {\n return this.executeWithMonitoring('existsBy', async () =>\n {\n const whereCondition = buildFilters(filters, this.table as any);\n const readDb = this.getReadDb();\n const [result] = await readDb\n .select()\n .from(this.table as any)\n .where(whereCondition)\n .limit(1) as TSelect[];\n\n return !!result;\n });\n }\n\n /**\n * Count records by filters (uses Replica)\n *\n * @example\n * const count = await userRepo.countBy({ status: 'active' });\n */\n async countBy(filters: Filters): Promise<number>\n {\n return this.executeWithMonitoring('countBy', async () =>\n {\n const whereCondition = buildFilters(filters, this.table as any);\n const readDb = this.getReadDb();\n return countTotal(readDb, this.table as any, whereCondition);\n });\n }\n\n /**\n * Create multiple records (uses Primary)\n *\n * @example\n * const users = await userRepo.saveMany([\n * { email: 'user1@example.com', name: 'User 1' },\n * { email: 'user2@example.com', name: 'User 2' }\n * ]);\n */\n async saveMany(data: any[]): Promise<TSelect[]>\n {\n return this.executeWithMonitoring('saveMany', async () =>\n {\n const writeDb = this.getWriteDb();\n return writeDb\n .insert(this.table)\n .values(data)\n .returning() as Promise<TSelect[]>;\n });\n }\n\n /**\n * Update multiple records by filters (uses Primary)\n *\n * Automatically injects current timestamp if table has auto-update field configured.\n *\n * @example\n * const count = await userRepo.updateWhere({ status: 'inactive' }, { status: 'archived' });\n */\n async updateWhere(filters: Filters, data: any): Promise<number>\n {\n return this.executeWithMonitoring('updateWhere', async () =>\n {\n // Auto-inject timestamp if configured and not explicitly provided\n const updateData = this.injectAutoUpdateTimestamp(data);\n\n const whereCondition = buildFilters(filters, this.table as any);\n const writeDb = this.getWriteDb();\n const results = await writeDb\n .update(this.table)\n .set(updateData)\n .where(whereCondition)\n .returning() as TSelect[];\n\n return results.length;\n });\n }\n\n /**\n * Delete multiple records by filters (uses Primary)\n *\n * @example\n * const count = await userRepo.deleteWhere({ status: 'banned' });\n */\n async deleteWhere(filters: Filters): Promise<number>\n {\n return this.executeWithMonitoring('deleteWhere', async () =>\n {\n const whereCondition = buildFilters(filters, this.table as any);\n const writeDb = this.getWriteDb();\n const results = await writeDb\n .delete(this.table)\n .where(whereCondition)\n .returning() as TSelect[];\n\n return results.length;\n });\n }\n\n // ============================================================\n // Query Builder (Fluent Interface)\n // ============================================================\n\n /**\n * Start a chainable query builder (uses Replica)\n *\n * Returns a QueryBuilder instance for building complex queries with method chaining.\n *\n * @returns QueryBuilder instance for chaining\n *\n * @example\n * ```typescript\n * // Simple chaining\n * const users = await userRepo\n * .query()\n * .where({ status: 'active' })\n * .orderBy('createdAt', 'desc')\n * .limit(10)\n * .findMany();\n *\n * // Multiple conditions\n * const admins = await userRepo\n * .query()\n * .where({ role: 'admin' })\n * .where({ status: 'active' }) // AND condition\n * .findMany();\n *\n * // Reusable query\n * const activeQuery = userRepo.query().where({ status: 'active' });\n * const users = await activeQuery.findMany();\n * const count = await activeQuery.count();\n * ```\n */\n query(): QueryBuilder<TTable, TSelect>\n {\n const readDb = this.getReadDb();\n return new QueryBuilder<TTable, TSelect>(readDb, this.table);\n }\n}","/**\n * Repository Factory\n *\n * Provides singleton instances of Repository classes to prevent unnecessary instantiation\n * and ensure consistent instances across the application.\n *\n * ✅ Features:\n * - Singleton pattern for both base and custom Repository classes\n * - Automatic caching based on table + constructor\n * - Type-safe with full IDE autocomplete\n * - Supports multiple services accessing the same repository\n * - Memory efficient (single instance per table/class combination)\n *\n * @example\n * ```typescript\n * // Base Repository\n * const userRepo = getRepository(users);\n * await userRepo.findById(1);\n *\n * // Custom Repository\n * class UserRepository extends Repository<typeof users> {\n * async findByEmail(email: string) {\n * return this.findOneWhere({ email });\n * }\n * }\n *\n * const userRepo = getRepository(users, UserRepository);\n * await userRepo.findByEmail('john@example.com');\n * ```\n */\n\nimport { Repository } from './repository.js';\nimport type { PgTable } from 'drizzle-orm/pg-core';\n\n/**\n * Repository instance cache\n * Key format: \"tableName:ClassName\"\n */\nconst repositoryCache = new Map<string, Repository<any>>();\n\n/**\n * Generate cache key from table and constructor\n *\n * @param table - Drizzle table definition\n * @param RepositoryClass - Optional custom Repository class\n * @returns Cache key string\n */\nfunction getCacheKey<TTable extends PgTable>(\n table: TTable,\n RepositoryClass?: new (table: TTable) => Repository<TTable>\n): string\n{\n // Get table name from Drizzle's internal symbol or fallback\n const tableName = (table as any)[Symbol.for('drizzle:Name')]\n || (table as any).name\n || table.toString();\n\n const className = RepositoryClass?.name || 'Repository';\n\n return `${tableName}:${className}`;\n}\n\n/**\n * Get or create a Repository singleton instance (Global Singleton Pattern)\n *\n * This function ensures that only one instance of each Repository is created,\n * preventing memory waste and ensuring consistency across the application.\n *\n * ✅ Supports both base Repository and custom Repository classes\n * ✅ Returns the same instance on subsequent calls\n * ✅ Type-safe with full IDE autocomplete\n * ✅ Automatically detects transaction context (via Repository internals)\n *\n * ## ⚠️ Note: Global Singleton Pattern\n *\n * This uses a **global singleton cache** that persists throughout application lifecycle.\n *\n * **Tradeoffs:**\n * - ✅ Simple API, no middleware required\n * - ✅ Maximum memory efficiency\n * - ⚠️ Requires manual `clearRepositoryCache()` in tests\n * - ⚠️ Global state (harder to isolate in testing)\n *\n * **For better test isolation**, consider using **request-scoped repositories**:\n * ```typescript\n * import { getScopedRepository, RepositoryScope } from '@spfn/core/db';\n *\n * // Add middleware (once)\n * app.use(RepositoryScope());\n *\n * // Use getScopedRepository() instead - automatic per-request caching\n * const repo = getScopedRepository(users);\n * ```\n *\n * See: `request-scope.ts` for request-scoped alternative\n *\n * ## 🔄 Transaction Handling\n *\n * Repository instances are cached globally, but they automatically detect\n * and use transaction context via AsyncLocalStorage in each method call.\n * This means:\n * - **Same repository instance** can be used both inside and outside transactions\n * - **No need to create separate repository instances** per transaction\n * - **Transaction safety is guaranteed** by AsyncLocalStorage context\n *\n * The Repository internally calls `getTransaction()` on every database operation,\n * ensuring the correct DB instance (transaction or default) is always used.\n *\n * @param table - Drizzle table definition\n * @param RepositoryClass - Optional custom Repository class extending Repository\n * @returns Repository instance (cached singleton)\n *\n * @example\n * ```typescript\n * // Base Repository - simple CRUD\n * import { getRepository } from '@spfn/core/db';\n * import { users } from './entities';\n *\n * export async function getUser(id: number) {\n * const repo = getRepository(users);\n * return repo.findById(id);\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Custom Repository - with custom methods\n * import { Repository, getRepository } from '@spfn/core/db';\n * import { users } from './entities';\n *\n * class UserRepository extends Repository<typeof users> {\n * async findByEmail(email: string) {\n * return this.findOneWhere({ email });\n * }\n *\n * async findActiveUsers() {\n * return this.findWhere({ status: 'active' });\n * }\n * }\n *\n * export async function getUserByEmail(email: string) {\n * const repo = getRepository(users, UserRepository);\n * return repo.findByEmail(email);\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Multiple services - same instance\n * // services/users.ts\n * const repo = getRepository(users, UserRepository); // Instance A\n *\n * // services/auth.ts\n * const repo = getRepository(users, UserRepository); // Same Instance A\n * ```\n *\n * @example\n * ```typescript\n * // Transaction handling - same instance works everywhere\n * import { getRepository, Transactional } from '@spfn/core/db';\n * import { users } from './entities';\n *\n * const userRepo = getRepository(users);\n *\n * // Outside transaction - uses default DB\n * await userRepo.findById(1);\n *\n * // Inside Transactional() middleware - uses transaction automatically\n * app.use(Transactional());\n * app.post('/', async (c) => {\n * // Same instance, but now uses transaction DB\n * await userRepo.save({ email: 'test@example.com' });\n * return c.json({ success: true });\n * });\n * ```\n */\nexport function getRepository<\n TTable extends PgTable,\n TRepo extends Repository<TTable> = Repository<TTable>\n>(\n table: TTable,\n RepositoryClass?: new (table: TTable) => TRepo\n): TRepo\n{\n const cacheKey = getCacheKey(table, RepositoryClass as any);\n\n // Check cache\n let repo = repositoryCache.get(cacheKey);\n\n if (!repo)\n {\n // Create new instance\n if (RepositoryClass)\n {\n repo = new RepositoryClass(table);\n }\n else\n {\n repo = new Repository(table);\n }\n\n // Cache it\n repositoryCache.set(cacheKey, repo);\n }\n\n return repo as TRepo;\n}\n\n/**\n * Clear repository cache\n *\n * Removes all cached repository instances. Useful for testing scenarios\n * where you need fresh instances.\n *\n * ⚠️ Warning: Only use this in tests. In production, cached instances\n * should persist throughout the application lifecycle.\n *\n * @example\n * ```typescript\n * import { clearRepositoryCache } from '@spfn/core/db';\n *\n * beforeEach(() => {\n * clearRepositoryCache(); // Fresh instances for each test\n * });\n * ```\n */\nexport function clearRepositoryCache(): void\n{\n repositoryCache.clear();\n}\n\n/**\n * Get cache size (for debugging/monitoring)\n *\n * @returns Number of cached repository instances\n *\n * @example\n * ```typescript\n * const size = getRepositoryCacheSize();\n * console.log(`Cached repositories: ${size}`);\n * ```\n */\nexport function getRepositoryCacheSize(): number\n{\n return repositoryCache.size;\n}","/**\n * Request-Scoped Repository Pattern\n *\n * Provides request-level repository caching using AsyncLocalStorage.\n *\n * ## Benefits:\n * - ✅ **Automatic isolation**: Each request gets its own repository cache\n * - ✅ **Memory efficient**: Cache cleared automatically after request ends\n * - ✅ **Test-friendly**: No global state, tests are fully isolated\n * - ✅ **DI-compatible**: Can inject custom repositories easily\n * - ✅ **Zero overhead**: Uses existing AsyncLocalStorage infrastructure\n *\n * ## vs Global Singleton:\n *\n * | Feature | Global Singleton | Request-Scoped |\n * |---------|-----------------|----------------|\n * | Memory | Permanent cache | Request-only cache |\n * | Test isolation | Manual clearRepositoryCache() | Automatic |\n * | Thread-safety | Shared state | Isolated per request |\n * | DI support | Difficult | Easy |\n *\n * @example\n * ```typescript\n * // 1. Add middleware (routes automatically)\n * import { RepositoryScope } from '@spfn/core/db';\n *\n * app.use(RepositoryScope());\n *\n * // 2. Use in service (same request = same instance)\n * import { getScopedRepository } from '@spfn/core/db';\n *\n * export async function createPost(data) {\n * const repo = getScopedRepository(posts, PostRepository); // First call - creates\n * const existing = await repo.findBySlug(slug);\n * return repo.save(data); // Same instance\n * }\n *\n * // 3. Different request = different cache (automatic)\n * ```\n */\n\nimport { AsyncLocalStorage } from 'async_hooks';\nimport { Repository } from './repository.js';\nimport type { PgTable } from 'drizzle-orm/pg-core';\nimport type { MiddlewareHandler } from 'hono';\n\n/**\n * AsyncLocalStorage for request-scoped repository cache\n * Each request gets its own Map instance\n */\nconst repositoryStorage = new AsyncLocalStorage<Map<string, Repository<any>>>();\n\n/**\n * Generate cache key from table and repository class\n * Same logic as global singleton for consistency\n */\nfunction getCacheKey<TTable extends PgTable>(\n table: TTable,\n RepositoryClass?: new (table: TTable) => Repository<TTable>\n): string\n{\n const tableName = (table as any)[Symbol.for('drizzle:Name')]\n || (table as any).name\n || table.toString();\n\n const className = RepositoryClass?.name || 'Repository';\n\n return `${tableName}:${className}`;\n}\n\n/**\n * Execute function within a repository scope\n *\n * Creates a new request-scoped cache for the duration of the function.\n * Automatically cleaned up after function completes.\n *\n * @param fn - Async function to execute within scope\n * @returns Result of the function\n *\n * @example\n * ```typescript\n * // Middleware\n * app.use(async (c, next) => {\n * return withRepositoryScope(() => next());\n * });\n *\n * // Manual usage\n * const result = await withRepositoryScope(async () => {\n * const repo = getScopedRepository(users);\n * return repo.findAll();\n * });\n * ```\n */\nexport function withRepositoryScope<T>(fn: () => Promise<T>): Promise<T>\n{\n const cache = new Map<string, Repository<any>>();\n return repositoryStorage.run(cache, fn);\n}\n\n/**\n * Get request-scoped repository instance\n *\n * Returns cached instance within the same request, creates new instance for new requests.\n * Falls back to creating a new instance if called outside of a repository scope.\n *\n * ## Behavior:\n * - **Inside scope**: Returns cached instance (same request = same instance)\n * - **Outside scope**: Creates new instance every time (graceful degradation)\n *\n * @param table - Drizzle table definition\n * @param RepositoryClass - Optional custom Repository class\n * @returns Repository instance (cached or new)\n *\n * @example\n * ```typescript\n * // Base Repository\n * const repo = getScopedRepository(users);\n * await repo.findById(1);\n *\n * // Custom Repository\n * class UserRepository extends Repository<typeof users> {\n * async findByEmail(email: string) {\n * return this.findOneWhere({ email });\n * }\n * }\n *\n * const repo = getScopedRepository(users, UserRepository);\n * await repo.findByEmail('john@example.com');\n *\n * // Within same request - returns cached instance\n * const repo2 = getScopedRepository(users, UserRepository); // Same instance!\n * ```\n */\nexport function getScopedRepository<\n TTable extends PgTable,\n TRepo extends Repository<TTable> = Repository<TTable>\n>(\n table: TTable,\n RepositoryClass?: new (table: TTable) => TRepo\n): TRepo\n{\n const cache = repositoryStorage.getStore();\n\n // Outside scope - create new instance (graceful degradation)\n if (!cache)\n {\n return RepositoryClass\n ? new RepositoryClass(table)\n : new Repository(table) as TRepo;\n }\n\n // Inside scope - use cache\n const key = getCacheKey(table, RepositoryClass as any);\n let repo = cache.get(key);\n\n if (!repo)\n {\n repo = RepositoryClass\n ? new RepositoryClass(table)\n : new Repository(table);\n cache.set(key, repo);\n }\n\n return repo as TRepo;\n}\n\n/**\n * Hono middleware for automatic repository scope management\n *\n * Wraps each request in a repository scope, ensuring automatic cache isolation.\n * All repositories accessed via getScopedRepository() within this request will be cached.\n *\n * @returns Hono middleware handler\n *\n * @example\n * ```typescript\n * // Global middleware (recommended)\n * import { createServer } from '@spfn/core';\n * import { RepositoryScope } from '@spfn/core/db';\n *\n * const app = createServer();\n * app.use(RepositoryScope());\n *\n * // Or in server.config.ts\n * export default {\n * middlewares: [\n * { name: 'repositoryScope', handler: RepositoryScope() }\n * ]\n * };\n * ```\n */\nexport function RepositoryScope(): MiddlewareHandler\n{\n return async (_c, next) =>\n {\n return withRepositoryScope(() => next());\n };\n}\n\n/**\n * Get current repository cache size (for debugging/monitoring)\n *\n * Returns the number of cached repository instances in the current request scope.\n * Returns 0 if called outside a scope.\n *\n * @returns Number of cached repositories in current scope\n *\n * @example\n * ```typescript\n * const size = getScopedCacheSize();\n * console.log(`Cached repositories in this request: ${size}`);\n * ```\n */\nexport function getScopedCacheSize(): number\n{\n const cache = repositoryStorage.getStore();\n return cache?.size ?? 0;\n}\n\n/**\n * Check if currently inside a repository scope\n *\n * @returns true if inside scope, false otherwise\n *\n * @example\n * ```typescript\n * if (isInRepositoryScope()) {\n * console.log('Using scoped cache');\n * } else {\n * console.log('Creating new instances');\n * }\n * ```\n */\nexport function isInRepositoryScope(): boolean\n{\n return repositoryStorage.getStore() !== undefined;\n}","/**\n * Table Name Utilities\n *\n * Helper functions for extracting table names from Drizzle table objects.\n * Used by Repository for accessing db.query API with dynamic table names.\n */\n\nimport type { PgTable } from 'drizzle-orm/pg-core';\n\n/**\n * Table name cache for performance optimization\n * Prevents repeated Symbol.for lookups\n */\nconst tableNameCache = new WeakMap<PgTable, string>();\n\n/**\n * Get table name from Drizzle table object\n *\n * Uses WeakMap cache to avoid repeated Symbol lookups for better performance.\n *\n * @param table - Drizzle table schema\n * @returns Table name string\n *\n * @example\n * ```typescript\n * import { users } from './schema';\n * const name = getTableName(users); // 'users'\n * ```\n */\nexport function getTableName(table: PgTable): string\n{\n // Check cache first\n const cached = tableNameCache.get(table);\n if (cached)\n {\n return cached;\n }\n\n // Extract name from Drizzle table metadata\n // Drizzle stores table name in Symbol.for('drizzle:Name')\n const name = (table as any)[Symbol.for('drizzle:Name')] || table.constructor.name;\n\n // Cache for future lookups\n tableNameCache.set(table, name);\n\n return name;\n}","/**\n * WrappedDb - Drizzle + Repository 패턴 통합\n *\n * Drizzle의 모든 기능을 유지하면서 JPA 스타일 Repository 접근 제공\n */\n\nimport type { PgTable } from 'drizzle-orm/pg-core';\nimport type { PostgresJsDatabase } from 'drizzle-orm/postgres-js';\n\nimport { Repository } from '../repository';\n\n/**\n * WrappedDb 클래스\n *\n * Drizzle DB를 래핑하여 추가 기능 제공\n */\nexport class WrappedDb\n{\n constructor(private db: PostgresJsDatabase<Record<string, never>>) {}\n\n /**\n * Repository 패턴으로 테이블 접근\n *\n * @example\n * const db = getDb();\n * const userRepo = db.for(users);\n * const result = await userRepo.findPage(pageable);\n */\n for<TTable extends PgTable<any>, TSelect = any>(table: TTable): Repository<TTable, TSelect>\n {\n return new Repository<TTable, TSelect>(this.db, table);\n }\n\n /**\n * Drizzle의 모든 메서드를 프록시\n *\n * select, insert, update, delete, transaction 등 모든 Drizzle 메서드 사용 가능\n */\n get select()\n {\n return this.db.select.bind(this.db);\n }\n\n get insert()\n {\n return this.db.insert.bind(this.db);\n }\n\n get update()\n {\n return this.db.update.bind(this.db);\n }\n\n get delete()\n {\n return this.db.delete.bind(this.db);\n }\n\n get execute()\n {\n return this.db.execute.bind(this.db);\n }\n\n get transaction()\n {\n return this.db.transaction.bind(this.db);\n }\n\n get query()\n {\n return this.db.query;\n }\n\n get $with()\n {\n return this.db.$with.bind(this.db);\n }\n\n /**\n * Raw Drizzle DB 접근 (필요시)\n */\n get raw(): PostgresJsDatabase\n {\n return this.db;\n }\n}\n","/**\n * DB Context Helper\n *\n * Automatically detects transaction context and returns the appropriate DB instance.\n *\n * ✅ Implemented:\n * - AsyncLocalStorage-based transaction detection\n * - Returns default DB instance when no transaction\n * - JPA-style Repository pattern support\n * - Preserves Drizzle core features\n *\n * ⚠️ TODO:\n * - Nested transaction detection and warning logs\n * - Transaction timeout checks\n *\n * 💡 Future considerations:\n * - Add function to force default DB usage (useDefaultDb)\n * - Auto-select Read Replica (detect read-only queries)\n * - Transaction statistics collection (success/failure/rollback count)\n * - Return transaction ID function (for debugging)\n *\n * 🔗 Related files:\n * - src/utils/async-context.ts (AsyncLocalStorage implementation)\n * - src/utils/transaction.ts (Transactional middleware)\n * - src/db/db-instance.ts (Default DB instance)\n * - src/db/wrapped-db.ts (WrappedDb implementation)\n * - src/db/repository.ts (Repository implementation)\n */\nimport { getTransaction } from '../transaction';\n\nimport { getDatabase, type DbConnectionType } from './manager.js';\nimport { WrappedDb } from './wrapped-db.js';\n\n/**\n * Get DB instance (WrappedDb)\n *\n * - If transaction context exists: Returns transaction DB\n * - Otherwise: Returns default DB or specified connection type\n * - Wraps with WrappedDb to provide both Repository pattern + Drizzle features\n *\n * Usage 1: Direct Drizzle use\n * ```typescript\n * export async function GET(c: RouteContext) {\n * const db = getDb();\n * const users = await db.select().from(users);\n * return c.json(users);\n * }\n * ```\n *\n * Usage 2: Repository pattern\n * ```typescript\n * export async function GET(c: RouteContext) {\n * const db = getDb();\n * const userRepo = db.for(users);\n * const result = await userRepo.findPage(pageable);\n * return c.json(result);\n * }\n * ```\n *\n * Usage 3: Specify connection type\n * ```typescript\n * const readDb = getDb('read'); // Use read replica\n * const writeDb = getDb('write'); // Use primary\n * ```\n *\n * @param type - Optional connection type ('read' or 'write')\n * @returns WrappedDb instance (transaction or specified DB)\n */\nexport function getDb(type?: DbConnectionType): WrappedDb\n{\n const tx = getTransaction();\n\n // If transaction exists, always use transaction DB\n if (tx)\n {\n return new WrappedDb(tx);\n }\n\n // Otherwise use specified type or default from manager\n const rawDb = getDatabase(type);\n if (!rawDb)\n {\n throw new Error(\n 'Database not initialized. ' +\n 'Set DATABASE_URL environment variable or call initDatabase() first.'\n );\n }\n\n return new WrappedDb(rawDb);\n}","/**\n * Drizzle Kit configuration generator\n * Automatically generates drizzle.config.ts from environment variables\n */\n\nexport interface DrizzleConfigOptions\n{\n /** Database connection URL (defaults to process.env.DATABASE_URL) */\n databaseUrl?: string;\n\n /** Schema files glob pattern (defaults to './src/server/entities/*.ts') */\n schema?: string;\n\n /** Migration output directory (defaults to './drizzle/migrations') */\n out?: string;\n\n /** Database dialect (auto-detected from URL if not provided) */\n dialect?: 'postgresql' | 'mysql' | 'sqlite';\n}\n\n/**\n * Detect database dialect from connection URL\n */\nexport function detectDialect(url: string): 'postgresql' | 'mysql' | 'sqlite'\n{\n if (url.startsWith('postgres://') || url.startsWith('postgresql://'))\n {\n return 'postgresql';\n }\n\n if (url.startsWith('mysql://'))\n {\n return 'mysql';\n }\n\n if (url.startsWith('sqlite://') || url.includes('.db') || url.includes('.sqlite'))\n {\n return 'sqlite';\n }\n\n throw new Error(\n `Unsupported database URL format: ${url}. Supported: postgresql://, mysql://, sqlite://`\n );\n}\n\n/**\n * Generate Drizzle Kit configuration\n *\n * @param options - Configuration options\n * @returns Drizzle Kit configuration object\n *\n * @example\n * ```ts\n * // Zero-config (reads from process.env.DATABASE_URL)\n * const config = getDrizzleConfig();\n *\n * // Custom config\n * const config = getDrizzleConfig({\n * databaseUrl: 'postgresql://localhost/mydb',\n * schema: './src/db/schema/*.ts',\n * out: './migrations',\n * });\n * ```\n */\nexport function getDrizzleConfig(options: DrizzleConfigOptions = {})\n{\n const databaseUrl = options.databaseUrl ?? process.env.DATABASE_URL;\n\n if (!databaseUrl)\n {\n throw new Error(\n 'DATABASE_URL is required. Set it in .env or pass it to getDrizzleConfig()'\n );\n }\n\n const dialect = options.dialect ?? detectDialect(databaseUrl);\n const schema = options.schema ?? './src/server/entities/*.ts';\n const out = options.out ?? './drizzle/migrations';\n\n return {\n schema,\n out,\n dialect,\n dbCredentials: getDbCredentials(dialect, databaseUrl),\n };\n}\n\n/**\n * Get database credentials based on dialect\n */\nfunction getDbCredentials(dialect: string, url: string)\n{\n switch (dialect)\n {\n case 'postgresql':\n case 'mysql':\n return { url };\n\n case 'sqlite':\n // Extract file path from sqlite:// URL\n const dbPath = url.replace('sqlite://', '').replace('sqlite:', '');\n return { url: dbPath };\n\n default:\n throw new Error(`Unsupported dialect: ${dialect}`);\n }\n}\n\n/**\n * Generate drizzle.config.ts file content\n *\n * @param options - Configuration options\n * @returns File content as string\n */\nexport function generateDrizzleConfigFile(options: DrizzleConfigOptions = {}): string\n{\n const config = getDrizzleConfig(options);\n\n return `import { defineConfig } from 'drizzle-kit';\n\nexport default defineConfig({\n schema: '${config.schema}',\n out: '${config.out}',\n dialect: '${config.dialect}',\n dbCredentials: ${JSON.stringify(config.dbCredentials, null, 4)},\n});\n`;\n}","/**\n * Schema Helper Functions\n *\n * Common field patterns for Drizzle ORM entities to reduce boilerplate.\n *\n * @example\n * ```typescript\n * import { pgTable, text } from 'drizzle-orm/pg-core';\n * import { id, timestamps } from '@spfn/core';\n *\n * export const users = pgTable('users', {\n * id: id(),\n * email: text('email').unique(),\n * ...timestamps(),\n * });\n * ```\n */\n\nimport type { PgColumn } from 'drizzle-orm/pg-core';\nimport { bigserial, timestamp } from 'drizzle-orm/pg-core';\n\n/**\n * Standard auto-incrementing primary key\n *\n * @returns bigserial primary key column\n *\n * @example\n * ```typescript\n * export const users = pgTable('users', {\n * id: id(),\n * // ...\n * });\n * ```\n */\nexport function id()\n{\n return bigserial('id', { mode: 'number' }).primaryKey();\n}\n\n/**\n * Standard timestamp fields (createdAt, updatedAt)\n *\n * Both fields are timezone-aware, auto-set to current time on creation.\n * When autoUpdate is enabled, updatedAt will be automatically updated on record updates.\n *\n * @param options - Optional configuration\n * @param options.autoUpdate - Automatically update updatedAt on record updates (default: false)\n * @returns Object with createdAt and updatedAt columns\n *\n * @example\n * ```typescript\n * // Without auto-update\n * export const users = pgTable('users', {\n * id: id(),\n * email: text('email'),\n * ...timestamps(),\n * });\n *\n * // With auto-update\n * export const posts = pgTable('posts', {\n * id: id(),\n * title: text('title'),\n * ...timestamps({ autoUpdate: true }),\n * });\n * ```\n */\nexport function timestamps(options?: { autoUpdate?: boolean })\n{\n const updatedAtColumn = timestamp('updated_at', { withTimezone: true, mode: 'date' })\n .defaultNow()\n .notNull();\n\n // Mark column for auto-update if enabled\n if (options?.autoUpdate)\n {\n (updatedAtColumn as any).__autoUpdate = true;\n }\n\n return {\n createdAt: timestamp('created_at', { withTimezone: true, mode: 'date' })\n .defaultNow()\n .notNull(),\n updatedAt: updatedAtColumn,\n };\n}\n\n/**\n * Auto-updating timestamp field (for custom timestamp fields)\n *\n * Creates a timestamp field that automatically updates on record updates.\n * Useful when you need a custom name like 'modifiedAt', 'lastUpdated', etc.\n *\n * @param fieldName - Field name in camelCase (default: 'updatedAt')\n * @returns Object with the timestamp column (converts camelCase to snake_case)\n *\n * @example\n * ```typescript\n * // Custom field name\n * export const posts = pgTable('posts', {\n * id: id(),\n * title: text('title'),\n * ...autoUpdateTimestamp('modifiedAt'), // Creates 'modified_at' column\n * });\n *\n * // Default field name\n * export const articles = pgTable('articles', {\n * id: id(),\n * ...autoUpdateTimestamp(), // Creates 'updatedAt' -> 'updated_at'\n * });\n * ```\n */\nexport function autoUpdateTimestamp(fieldName: string = 'updatedAt')\n{\n // Convert camelCase to snake_case for column name\n const columnName = fieldName.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '');\n\n const column = timestamp(columnName, { withTimezone: true, mode: 'date' })\n .defaultNow()\n .notNull();\n\n // Mark column for auto-update\n (column as any).__autoUpdate = true;\n\n return {\n [fieldName]: column,\n };\n}\n\n/**\n * Foreign key reference to another table\n *\n * Creates a bigserial column with cascade delete.\n * Type-safe: ensures the reference points to a valid PostgreSQL column.\n *\n * @param name - Column name (e.g., 'author' creates 'author_id')\n * @param reference - Reference to parent table column\n * @param options - Optional foreign key options\n *\n * @example\n * ```typescript\n * import { users } from './users';\n *\n * export const posts = pgTable('posts', {\n * id: id(),\n * authorId: foreignKey('author', () => users.id),\n * ...timestamps(),\n * });\n * ```\n */\nexport function foreignKey<T extends PgColumn>(\n name: string,\n reference: () => T,\n options?: { onDelete?: 'cascade' | 'set null' | 'restrict' | 'no action' }\n)\n{\n return bigserial(`${name}_id`, { mode: 'number' })\n .notNull()\n .references(reference, { onDelete: options?.onDelete ?? 'cascade' });\n}\n\n/**\n * Optional foreign key reference (nullable)\n *\n * Type-safe: ensures the reference points to a valid PostgreSQL column.\n *\n * @param name - Column name (e.g., 'author' creates 'author_id')\n * @param reference - Reference to parent table column\n * @param options - Optional foreign key options\n *\n * @example\n * ```typescript\n * export const posts = pgTable('posts', {\n * id: id(),\n * authorId: optionalForeignKey('author', () => users.id),\n * });\n * ```\n */\nexport function optionalForeignKey<T extends PgColumn>(\n name: string,\n reference: () => T,\n options?: { onDelete?: 'cascade' | 'set null' | 'restrict' | 'no action' }\n)\n{\n return bigserial(`${name}_id`, { mode: 'number' })\n .references(reference, { onDelete: options?.onDelete ?? 'set null' });\n}"]}