Adding first working version
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
import { existsSync, readFileSync } from 'node:fs'
|
||||
import { dirname, resolve } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
function parseEnvLine(line) {
|
||||
const trimmed = line.trim()
|
||||
if (!trimmed || trimmed.startsWith('#')) return null
|
||||
|
||||
const equalsIndex = trimmed.indexOf('=')
|
||||
if (equalsIndex === -1) return null
|
||||
|
||||
const key = trimmed.slice(0, equalsIndex).trim()
|
||||
let value = trimmed.slice(equalsIndex + 1).trim()
|
||||
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) return null
|
||||
|
||||
if (
|
||||
(value.startsWith('"') && value.endsWith('"')) ||
|
||||
(value.startsWith("'") && value.endsWith("'"))
|
||||
) {
|
||||
value = value.slice(1, -1)
|
||||
}
|
||||
|
||||
return { key, value }
|
||||
}
|
||||
|
||||
function loadEnvFile(path) {
|
||||
if (!existsSync(path)) return
|
||||
|
||||
const content = readFileSync(path, 'utf8')
|
||||
for (const line of content.split(/\r?\n/)) {
|
||||
const parsed = parseEnvLine(line)
|
||||
if (!parsed || process.env[parsed.key] !== undefined) continue
|
||||
process.env[parsed.key] = parsed.value
|
||||
}
|
||||
}
|
||||
|
||||
export function loadEnv() {
|
||||
const moduleDir = dirname(fileURLToPath(import.meta.url))
|
||||
const candidatePaths = [
|
||||
resolve(process.cwd(), '.env'),
|
||||
resolve(process.cwd(), '..', '.env'),
|
||||
resolve(moduleDir, '..', '.env'),
|
||||
resolve(moduleDir, '..', '..', '.env')
|
||||
]
|
||||
|
||||
for (const path of [...new Set(candidatePaths)]) {
|
||||
loadEnvFile(path)
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,9 @@ import { readdir, readFile } from 'node:fs/promises'
|
||||
import { dirname, resolve } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { Pool } from 'pg'
|
||||
import { loadEnv } from './load-env.mjs'
|
||||
|
||||
loadEnv()
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
const migrationsDir = resolve(__dirname, '../src/migrations')
|
||||
@@ -10,6 +13,16 @@ const connectionString =
|
||||
|
||||
const pool = new Pool({ connectionString })
|
||||
|
||||
function redactConnectionString(value) {
|
||||
try {
|
||||
const url = new URL(value)
|
||||
if (url.password) url.password = '***'
|
||||
return url.toString()
|
||||
} catch {
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const migrationFiles = (await readdir(migrationsDir))
|
||||
.filter((file) => file.endsWith('.sql'))
|
||||
@@ -21,6 +34,13 @@ try {
|
||||
await pool.query(sql)
|
||||
console.log(`Applied migration ${migrationPath}`)
|
||||
}
|
||||
} catch (error) {
|
||||
if (error?.code === 'ECONNREFUSED') {
|
||||
console.error(`Unable to connect to Postgres at ${redactConnectionString(connectionString)}`)
|
||||
console.error('For the local Docker database, start it with `docker compose up -d postgres` from the repo root.')
|
||||
console.error('Then use DATABASE_URL=postgres://ca_studio:ca_studio@localhost:54329/ca_studio_test')
|
||||
}
|
||||
throw error
|
||||
} finally {
|
||||
await pool.end()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user