feat(server): initial implementation of migrations

hash-on-upload
Jef Roosens 2022-05-24 22:48:17 +02:00
parent cdb88e1620
commit 0d5704ba15
Signed by: Jef Roosens
GPG Key ID: B75D4F293C7052DB
5 changed files with 81 additions and 4 deletions

View File

@ -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) ## [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) ## [0.3.0-alpha.2](https://git.rustybever.be/vieter/vieter/src/tag/0.3.0-alpha.2)
### Added ### Added

View File

@ -1,19 +1,65 @@
module db module db
import sqlite import sqlite
import models { BuildLog, GitRepo }
struct VieterDb { struct VieterDb {
conn sqlite.DB 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. // init initializes a database & adds the correct tables.
pub fn init(db_path string) ?VieterDb { pub fn init(db_path string) ?VieterDb {
conn := sqlite.connect(db_path)? conn := sqlite.connect(db_path)?
sql conn { sql conn {
create table GitRepo create table MigrationVersion
create table BuildLog }
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{ return VieterDb{

View File

@ -0,0 +1,3 @@
DROP TABLE IF EXISTS BuildLog;
DROP TABLE IF EXISTS GitRepoArch;
DROP TABLE IF EXISTS GitRepo;

View File

@ -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
);

View File

@ -68,7 +68,9 @@ pub fn server(conf Config) ? {
} }
db_file := os.join_path_single(conf.data_dir, server.db_file_name) 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{ web.run(&App{
logger: logger logger: logger