From 0d5704ba157ecf2f5bce70a7e51e1880fa77f7b5 Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Tue, 24 May 2022 22:48:17 +0200 Subject: [PATCH] feat(server): initial implementation of migrations --- CHANGELOG.md | 4 ++ src/db/db.v | 52 ++++++++++++++++++++++++-- src/db/migrations/001-initial/down.sql | 3 ++ src/db/migrations/001-initial/up.sql | 22 +++++++++++ src/server/server.v | 4 +- 5 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 src/db/migrations/001-initial/down.sql create mode 100644 src/db/migrations/001-initial/up.sql diff --git a/CHANGELOG.md b/CHANGELOG.md index 7dc0a00..8c336fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased](https://git.rustybever.be/vieter/vieter/src/branch/dev) +### Added + +* Database migrations + ## [0.3.0-alpha.2](https://git.rustybever.be/vieter/vieter/src/tag/0.3.0-alpha.2) ### Added diff --git a/src/db/db.v b/src/db/db.v index 57b437e..9a06a03 100644 --- a/src/db/db.v +++ b/src/db/db.v @@ -1,19 +1,65 @@ module db import sqlite -import models { BuildLog, GitRepo } struct VieterDb { conn sqlite.DB } +struct MigrationVersion { + id int [primary] + version int +} + +const ( + migrations_up = [$embed_file('migrations/001-initial/up.sql')] + migrations_down = [$embed_file('migrations/001-initial/down.sql')] +) + // init initializes a database & adds the correct tables. pub fn init(db_path string) ?VieterDb { conn := sqlite.connect(db_path)? sql conn { - create table GitRepo - create table BuildLog + create table MigrationVersion + } + + cur_version := sql conn { + select from MigrationVersion limit 1 + } + + // If there's no row yet, we add it here + if cur_version == MigrationVersion{} { + sql conn { + insert cur_version into MigrationVersion + } + } + + // Apply each migration in order + for i in cur_version.version .. db.migrations_up.len { + migration := db.migrations_up[i].to_string() + + version_num := i + 1 + + // vfmt does not like these dots + println('Applying migration $version_num' + '...') + + // The sqlite library seems to not like it when multiple statements are + // passed in a single exec. Therefore, we split them & run them all + // separately. + for part in migration.split(';').map(it.trim_space()).filter(it != '') { + res := conn.exec_none(part) + + if res != sqlite.sqlite_done { + return error('An error occurred while applying migration $version_num') + } + } + + // The where clause doesn't really matter, as there will always only be + // one entry anyways. + sql conn { + update MigrationVersion set version = version_num where id > 0 + } } return VieterDb{ diff --git a/src/db/migrations/001-initial/down.sql b/src/db/migrations/001-initial/down.sql new file mode 100644 index 0000000..43ad40b --- /dev/null +++ b/src/db/migrations/001-initial/down.sql @@ -0,0 +1,3 @@ +DROP TABLE IF EXISTS BuildLog; +DROP TABLE IF EXISTS GitRepoArch; +DROP TABLE IF EXISTS GitRepo; diff --git a/src/db/migrations/001-initial/up.sql b/src/db/migrations/001-initial/up.sql new file mode 100644 index 0000000..ca0aace --- /dev/null +++ b/src/db/migrations/001-initial/up.sql @@ -0,0 +1,22 @@ +CREATE TABLE IF NOT EXISTS GitRepo ( + id INTEGER PRIMARY KEY, + url TEXT NOT NULL, + branch TEXT NOT NULL, + repo TEXT NOT NULL, + schedule TEXT +); + +CREATE TABLE IF NOT EXISTS GitRepoArch ( + id INTEGER PRIMARY KEY, + repo_id INTEGER NOT NULL, + value TEXT NOT NULL +); + +CREATE TABLE IF NOT EXISTS BuildLog ( + id INTEGER PRIMARY KEY, + repo_id INTEGER NOT NULL, + start_time INTEGER NOT NULL, + end_time iNTEGER NOT NULL, + arch TEXT NOT NULL, + exit_code INTEGER NOT NULL +); diff --git a/src/server/server.v b/src/server/server.v index 090aa76..2309ee7 100644 --- a/src/server/server.v +++ b/src/server/server.v @@ -68,7 +68,9 @@ pub fn server(conf Config) ? { } db_file := os.join_path_single(conf.data_dir, server.db_file_name) - db := db.init(db_file) or { util.exit_with_message(1, 'Failed to initialize database.') } + db := db.init(db_file) or { + util.exit_with_message(1, 'Failed to initialize database: $err.msg()') + } web.run(&App{ logger: logger