Last active
October 13, 2022 06:08
-
-
Save eezing/ddb2a633064a04f8aa494e299eef20bc to your computer and use it in GitHub Desktop.
Start a PostgreSQL database in Docker
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
import { execSync } from 'child_process'; | |
import postgres from 'postgres'; | |
const NAME = process.env.NAME; | |
const VERSION = process.env.VERSION ?? '14'; | |
const RESET = process.env.RESET === 'true'; | |
const PGHOST = process.env.PGHOST ?? 'localhost'; | |
const PGPORT = process.env.PGPORT; | |
const PGUSER = process.env.PGUSER; | |
const PGPASSWORD = process.env.PGPASSWORD; | |
const PGDATABASE = process.env.PGDATABASE; | |
(async () => { | |
try { | |
log( | |
`start ${bling( | |
`postgres://${PGUSER}:${PGPASSWORD}@${PGHOST}:${PGPORT}/${PGDATABASE}` | |
)} in ${bling(NAME)} docker container` | |
); | |
await createContainer(); | |
await createDatabase(); | |
} catch (error) { | |
throw error; | |
} | |
})(); | |
async function createContainer() { | |
try { | |
log('check for existing container...'); | |
execSync(`docker inspect ${NAME}`, { stdio: 'ignore' }); | |
log('ensure existing container is started...'); | |
execSync(`docker start ${NAME}`, { stdio: 'ignore' }); | |
} catch { | |
log('run new docker container...'); | |
execSync( | |
`docker run --name ${NAME} -p ${PGPORT}:5432 -e POSTGRES_USER=${PGUSER} -e POSTGRES_PASSWORD=${PGPASSWORD} -e POSTGRES_DB=postgres -d postgres:${VERSION}` | |
); | |
} | |
} | |
async function createDatabase(retryCount = 0) { | |
const sql = postgres({ | |
host: PGHOST, | |
port: PGPORT, | |
user: PGUSER, | |
password: PGPASSWORD, | |
database: 'postgres', | |
onnotice: () => {}, | |
}); | |
try { | |
const [existing] = | |
await sql`SELECT (pg_stat_file('base/'||oid ||'/PG_VERSION')).modification created, datname FROM pg_database WHERE datname = ${PGDATABASE}`; | |
if (existing) { | |
if (RESET) { | |
log('reset database...'); | |
await sql`select pg_terminate_backend(pg_stat_activity.pid) from pg_stat_activity where pid <> pg_backend_pid();`; | |
await sql`drop database if exists ${sql(PGDATABASE)};`; | |
await sql`create database ${sql(PGDATABASE)};`; | |
} else { | |
log( | |
`use existing database from ${bling( | |
new Date(existing.created).toLocaleString() | |
)}` | |
); | |
} | |
} else { | |
log('create database...'); | |
await sql`create database ${sql(PGDATABASE)};`; | |
} | |
log('database ready'); | |
} catch (error) { | |
if (error?.message?.includes('system is starting') && retryCount < 10) { | |
if (retryCount === 0) { | |
log('database server starting...'); | |
} | |
await new Promise((res) => setTimeout(res, 50)); | |
return createDatabase(retryCount++); | |
} | |
throw error; | |
} finally { | |
sql.end(); | |
} | |
} | |
function bling(value) { | |
return `\u001b[33m${value}\u001b[0m`; | |
} | |
function log(message, ...args) { | |
console.log( | |
`\u001b[36m[\u001b[34m pglocal \u001b[0m\u001b[36m]\u001b[0m ${message}`, | |
...args | |
); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "pglocal", | |
"version": "1.0.0", | |
"bin": "./index.mjs", | |
"peerDependencies": { | |
"postgres": "^3.x" | |
}, | |
"peerDependenciesMeta": { | |
"postgres": { | |
"optional": false | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment