(dsn: string)
| 22 | * @returns Parsed connection info or null if parsing fails |
| 23 | */ |
| 24 | export function parseConnectionInfoFromDSN(dsn: string): ParsedConnectionInfo | null { |
| 25 | if (!dsn) { |
| 26 | return null; |
| 27 | } |
| 28 | |
| 29 | try { |
| 30 | const type = getDatabaseTypeFromDSN(dsn); |
| 31 | if (typeof type === 'undefined') { |
| 32 | return null; |
| 33 | } |
| 34 | |
| 35 | // Handle SQLite specially - it only has a database path |
| 36 | if (type === 'sqlite') { |
| 37 | // SQLite DSN format: sqlite:///path |
| 38 | const prefix = 'sqlite:///'; |
| 39 | if (dsn.length > prefix.length) { |
| 40 | const rawPath = dsn.substring(prefix.length); |
| 41 | // Add leading '/' for Unix absolute paths only |
| 42 | // Don't add '/' for: |
| 43 | // - Memory database: starts with ':' |
| 44 | // - Relative paths: starts with '.' or '~' |
| 45 | // - Windows absolute: second char is ':' (e.g., C:/path) |
| 46 | const firstChar = rawPath[0]; |
| 47 | const isWindowsDrive = rawPath.length > 1 && rawPath[1] === ':'; |
| 48 | const isSpecialPath = firstChar === ':' || firstChar === '.' || firstChar === '~' || isWindowsDrive; |
| 49 | return { |
| 50 | type, |
| 51 | database: isSpecialPath ? rawPath : '/' + rawPath, |
| 52 | }; |
| 53 | } |
| 54 | return { type }; |
| 55 | } |
| 56 | |
| 57 | // Parse other database DSNs using SafeURL |
| 58 | const url = new SafeURL(dsn); |
| 59 | |
| 60 | const info: ParsedConnectionInfo = { type }; |
| 61 | |
| 62 | if (url.hostname) { |
| 63 | info.host = url.hostname; |
| 64 | } |
| 65 | |
| 66 | if (url.port) { |
| 67 | info.port = parseInt(url.port, 10); |
| 68 | } |
| 69 | |
| 70 | if (url.pathname && url.pathname.length > 1) { |
| 71 | // Remove leading '/' from pathname |
| 72 | info.database = url.pathname.substring(1); |
| 73 | } |
| 74 | |
| 75 | if (url.username) { |
| 76 | info.user = url.username; |
| 77 | } |
| 78 | |
| 79 | return info; |
| 80 | } catch { |
| 81 | // If parsing fails, return null |
no test coverage detected