First of all, I like to let the developers choose the way they want to setup their environment and in particular the database. Some prefer to start directly a postgres server, other to start a docker-compose or simply docker.
Now suppose you want to setup everything anyway. You have multiple options:
Launching the database
Using a docker
If you want to initialize everything from a docker, you can add an entry point in order to create the database. Create a folder init_script
and a file in it:
./init_scripts/init_db.sh
#!/bin/bash
set -e
set -u
function create_user_and_database() {
local database=$1
echo "Creating database '$database' with user '$POSTGRES_USER'"
psql -v ON_ERROR_STOP=1 \
--username "$POSTGRES_USER" \
--dbname=postgres <<-EOSQL
CREATE DATABASE $database;
EOSQL
}
if [ -n "$POSTGRES_MY_DB" ]; then
create_user_and_database $POSTGRES_MY_DB
echo "Database $POSTGRES_MY_DB created"
fi
Inspired from this script which enables to create multiple postgres databases. Then you can simply add other scripts to create the tables.
Now you can launch the docker with
docker start my_postgres_container || docker run \
--name my_postgres_container \
--volume "$PWD/init_scripts:/docker-entrypoint-initdb.d/" \
--env POSTGRES_USER=my_user \
--env POSTGRES_PASSWORD=my_password \
--env POSTGRES_MY_DB=my_database \
--publish 5432:5432 \
--rm \
postgres:13
A volume is mounted to the folder init_scripts
at /docker-entrypoint-initdb.d/
, docker will look at it to init the database.
This script could be executed from npm or yarn:
"scripts": {
"setup_db": "docker start ...."
}
Contrary to some databases, you cannot launch an in memory postgres.
Instantiate the database (postgres already running)
From a nodejs script
Independently of the postgres system, you can create a new database from the master connection with a script.
async function createDatabase() {
const client = new Client(masterPostgresUri);
const user = 'my_user';
const database = 'my_database';
await client.connect();
try {
await client.query(`CREATE USER ${user};`);
await client.query(`CREATE DATABASE ${database};`);
await client.query(`GRANT ALL PRIVILEGES ON DATABASE ${database} TO ${user};`);
} catch (_err) {
// The database might already exist, you may want to check before
}
client.end();
}
To create the tables, you could use the same script but use the new database connection uri instead.
This script could be launch on the setup as well.
From a migration tool
There are several tools to cope with setup and migration. If you use for example the ORM Sequelize, it could be a good choice to setup everything in migration scripts. Sequelize migrations
For me, there are no perfect solutions, even if you create a command to launch a proper configured docker, one can argue that it didn't install docker so you still have a dependency. Hence, I think let the developers choose the best solution to start the postgres is great. And concerning the table creation and migration, I thing a tool is appropriate because it's an issue you have to deal with in your production environment and it will handle it during the application's restart.