/* * Copyright (C) 2023 Jonni Liljamo * * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for * more information. */ package db import ( "context" "fmt" "log" "github.com/jackc/pgx/v5/pgtype" ) var migrationsTable string = "schema_migrations" func RunMigrations() { log.Print("[tixe/db] Running migrations") var ranTimestamp pgtype.Timestamptz var schemaVersion int = 0 schemaVersionQuery := fmt.Sprintf( `SELECT ran_timestamp, schema_version FROM %s ORDER BY schema_version DESC LIMIT 1;`, migrationsTable) err := PgPool.QueryRow(context.Background(), schemaVersionQuery).Scan(&ranTimestamp, &schemaVersion) if err != nil { log.Print("[tixe/db] No schema version found, running all migrations") } else { log.Printf("[tixe/db] Last migration ran on %s, with schema version %d", ranTimestamp.Time, schemaVersion) } migrations := migrations() if schemaVersion != len(migrations) { for i := 0; i < len(migrations); i++ { if i >= schemaVersion { log.Printf("[tixe/db] Running migration %d", i + 1) // + 1 is just a visual thing _, err := PgPool.Exec(context.Background(), migrations[i]) if err != nil { log.Fatalf("[tixe/db] Migration %d failed to run!", i) } } } // We are now up to date schemaVersion = len(migrations) // Create a new entry in the migrations table schemaMigrationInsertQuery := fmt.Sprintf( `INSERT INTO %s(ran_timestamp, schema_version) VALUES(CURRENT_TIMESTAMP, %d);`, migrationsTable, schemaVersion) _, err = PgPool.Exec(context.Background(), schemaMigrationInsertQuery) if err != nil { log.Fatal("[tixe/db] Migrations ran, but was not able to create migration entry") } else { log.Print("[tixe/db] Migrations ran successfully") } } else { log.Printf("[tixe/db] Already on schema version %d, no migrations to run", schemaVersion) } } func migrations() []string { return []string{ fmt.Sprintf(`CREATE TABLE %s ( ran_timestamp timestamp, schema_version integer )`, migrationsTable), fmt.Sprintf(`CREATE TABLE users ( id CHAR(26) NOT NULL PRIMARY KEY, display_name TEXT NOT NULL, oidc_subject TEXT )`), fmt.Sprintf(`CREATE TABLE tags ( id CHAR(26) NOT NULL PRIMARY KEY, user_id CHAR(26) NOT NULL REFERENCES users(id), tag TEXT NOT NULL, UNIQUE (user_id, tag) )`), fmt.Sprintf(`CREATE TABLE links ( id CHAR(26) NOT NULL PRIMARY KEY, user_id CHAR(26) NOT NULL REFERENCES users(id), visual TEXT NOT NULL, link TEXT NOT NULL )`), fmt.Sprintf(`CREATE TABLE linktags ( link_id CHAR(26) NOT NULL REFERENCES links(id), tag_id CHAR(26) NOT NULL REFERENCES tags(id) )`), } }