40
loading...
This website collects cookies to deliver better user experience
migrations
table in PostgreSQL, which will be updated on every migration run ... and, of course, we will be setting that up using a migration!00000001-init-migrations.sql
-- Migrations
-- This table will keep a list of migrations that have been run on this database.
--
CREATE TABLE IF NOT EXISTS migrations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
file TEXT,
created_at TIMESTAMP DEFAULT NOW()
);
00000002-init-basic-schema.sql
-- Users
-- This table will hold the users' information.
CREATE TABLE IF NOT EXISTS users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email TEXT,
created_at TIMESTAMP DEFAULT NOW()
);
-- Settings
-- This table holds all users' settings
CREATE TABLE IF NOT EXISTS settings (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
lang TEXT,
currency TEXT,
user_id UUID REFERENCES users (id),
created_at TIMESTAMP DEFAULT NOW()
);
...
00000003-add-test-data.sql
CREATE TABLE IF NOT EXISTS test (
name TEXT
);
INSERT INTO test (name) VALUES ('bonjour'), ('hola'), ('nihao');
getClient()
method as described in https://node-postgres.com/guides/project-structure using pg.async function getOutstandingMigrations(migrations = []) {
const files = await promisify(fs.readdir)(__dirname);
const sql = await Promise.all(
files
.filter((file) => file.split(".")[1] === "sql")
.filter((file) => !migrations.includes(file))
.map(async (file) => ({
file,
query: await promisify(fs.readFile)(`${__dirname}/${file}`, {
encoding: "utf-8",
}),
}))
);
return sql;
}
fs
utility functions to increase the efficiency of this function.migrate()
function like follows:async function migrate() {
...
// Check previous migrations
let existingMigrations = [];
try {
let result = await client.query("SELECT * FROM migrations");
existingMigrations = result.rows.map(r => r.file)
} catch {
console.warn("First migration");
}
// Get outstanding migrations
const outstandingMigrations = await getOutstandingMigrations(
existingMigrations
);
...
}
async function migrate() {
const client = await getClient();
...
try {
// Start transaction
await client.query("BEGIN");
// Run each migration sequentially in a transaction
for (let migration of outstandingMigrations) {
// Run the migration
await client.query(migration.query.toString());
// Keep track of the migration
await client.query("INSERT INTO migrations (file) VALUES ($1)", [
migration.file,
]);
}
// All good, we can commit the transaction
await client.query("COMMIT");
} catch (err) {
// Oops, something went wrong, rollback!
await client.query("ROLLBACK");
} finally {
// Don't forget to release the client!
client.release();
}
}
migrate()
function anywhere in our code, like on app start, or in a cron job.