Set up database migrations to run automatically on server startup

This commit is contained in:
William Brawner 2021-02-09 21:10:42 -07:00
parent a272c420cd
commit 5a8613c701
3 changed files with 44 additions and 9 deletions

View file

@ -2,15 +2,16 @@ import path from 'path';
import sqlite3 from 'sqlite3';
import * as migrations from './migrations';
export function db(dataDir: string): sqlite3.Database {
const db = new sqlite3.Database(path.join(dataDir, "twigs.db"), (err) => {
const dbPath = path.join(dataDir, "twigs.db");
console.log(`Initializing database at ${dbPath}`)
const db = new sqlite3.Database(dbPath, (err?: Error) => {
if (err != null) {
console.error("Failed to open db");
console.error(err);
throw 'Failed to open db';
}
migrations.migrate(db);
});
return db
}

View file

@ -1,7 +1,14 @@
import sqlite3 from 'sqlite3';
import path from 'path';
function migrate_0_1(db: sqlite3.Database) {
db.serialize(() => {
/**
* The current desired database version. Used to run migrations
*/
const DESIRED_DB_VERSION = 1;
const migrations: Record<number, (db: sqlite3.Database) => void> = {
0: (db: sqlite3.Database) => {
db.serialize(() => {
db.run(`
CREATE TABLE user (
id TEXT PRIMARY KEY,
@ -9,14 +16,18 @@ function migrate_0_1(db: sqlite3.Database) {
username TEXT NOT NULL UNIQUE,
password TEXT NOT NULL
);
`);
db.run(`
CREATE TABLE budget (
id TEXT PRIMARY KEY,
currency_code TEXT DEFAULT NULL,
description TEXT DEFAULT NULL,
name TEXT DEFAULT NULL
);
`);
db.run(`
CREATE TABLE category (
id TEXT PRIMARY KEY,
amount UNSIGNED BIG INT NOT NULL,
@ -27,7 +38,9 @@ function migrate_0_1(db: sqlite3.Database) {
archived BOOLEAN NOT NULL DEFAULT 0,
FOREIGN KEY (budget_id) REFERENCES budget(id)
);
`);
db.run(`
CREATE TABLE password_reset_request (
id TEXT PRIMARY KEY,
date DATETIME DEFAULT NULL,
@ -35,7 +48,9 @@ function migrate_0_1(db: sqlite3.Database) {
user_id TEXT NOT NULL,
FOREIGN KEY (user_id) REFERENCES user(id)
);
`);
db.run(`
CREATE TABLE session (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
@ -43,7 +58,9 @@ function migrate_0_1(db: sqlite3.Database) {
expiration date NOT NULL,
FOREIGN KEY (user_id) REFERENCES user(id)
);
`);
db.run(`
CREATE TABLE 'transaction' (
id TEXT PRIMARY KEY,
amount UNSIGNED BIG INT NOT NULL,
@ -58,7 +75,9 @@ function migrate_0_1(db: sqlite3.Database) {
FOREIGN KEY (category_id) REFERENCES category(id),
FOREIGN KEY (created_by_id) REFERENCES user(id)
);
`);
db.run(`
CREATE TABLE user_permission (
budget_id TEXT NOT NULL,
user_id TEXT NOT NULL,
@ -69,5 +88,19 @@ function migrate_0_1(db: sqlite3.Database) {
);
`);
db.run('PRAGMA user_version = 1');
})
}
})
}
};
export function migrate(db: sqlite3.Database) {
db.get('PRAGMA user_version;', (err?: Error, row?: any) => {
let dbVersion = row.user_version;
while (dbVersion < DESIRED_DB_VERSION) {
console.log(`Migrating database from ${dbVersion} to ${dbVersion + 1}...`);
migrations[dbVersion](db);
console.log(`Completed database migration from ${dbVersion} to ${dbVersion + 1}`)
dbVersion++;
}
console.log(`Database is up to date`)
});
}

View file

@ -4,11 +4,13 @@ import { router as categoryRouter } from './categories/controller'
import { router as permissionsRouter } from './permissions/controller'
import { router as transactionRouter } from './transactions/controller'
import { router as userRouter } from './users/controller'
import { db as _db } from './db';
const port = process.env.PORT || 3000;
const app = express();
const dataDir = process.env.TWIGS_DATA || __dirname;
const db = _db(dataDir);
app.use(express.static(__dirname + '/public'));
@ -27,7 +29,6 @@ app.get('/*', (req, res) => {
res.sendFile(__dirname + '/public/index.html');
});
app.listen(port, () => {
console.log(`Twigs server listening at http://localhost:${port}`)
console.log(`Serving static content from ${__dirname}/public`)