Skip to content

Instantly share code, notes, and snippets.

@eezing
Last active October 13, 2022 06:08
Show Gist options
  • Save eezing/ddb2a633064a04f8aa494e299eef20bc to your computer and use it in GitHub Desktop.
Save eezing/ddb2a633064a04f8aa494e299eef20bc to your computer and use it in GitHub Desktop.
Start a PostgreSQL database in Docker
#!/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
);
}
{
"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