mirror of
https://github.com/writefreely/writefreely
synced 2024-11-25 01:50:17 +00:00
117 lines
2.6 KiB
Go
117 lines
2.6 KiB
Go
|
/*
|
||
|
* Copyright © 2019 A Bunch Tell LLC.
|
||
|
*
|
||
|
* This file is part of WriteFreely.
|
||
|
*
|
||
|
* WriteFreely is free software: you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU Affero General Public License, included
|
||
|
* in the LICENSE file in this source code package.
|
||
|
*/
|
||
|
|
||
|
// Package migrations contains database migrations for WriteFreely
|
||
|
package migrations
|
||
|
|
||
|
import (
|
||
|
"database/sql"
|
||
|
"github.com/writeas/web-core/log"
|
||
|
)
|
||
|
|
||
|
// TODO: refactor to use the datastore struct from writefreely pkg
|
||
|
type datastore struct {
|
||
|
*sql.DB
|
||
|
driverName string
|
||
|
}
|
||
|
|
||
|
func NewDatastore(db *sql.DB, dn string) *datastore {
|
||
|
return &datastore{db, dn}
|
||
|
}
|
||
|
|
||
|
// TODO: use these consts from writefreely pkg
|
||
|
const (
|
||
|
driverMySQL = "mysql"
|
||
|
driverSQLite = "sqlite3"
|
||
|
)
|
||
|
|
||
|
type Migration interface {
|
||
|
Description() string
|
||
|
Migrate(db *datastore) error
|
||
|
}
|
||
|
|
||
|
type migration struct {
|
||
|
description string
|
||
|
migrate func(db *datastore) error
|
||
|
}
|
||
|
|
||
|
func New(d string, fn func(db *datastore) error) Migration {
|
||
|
return &migration{d, fn}
|
||
|
}
|
||
|
|
||
|
func (m *migration) Description() string {
|
||
|
return m.description
|
||
|
}
|
||
|
|
||
|
func (m *migration) Migrate(db *datastore) error {
|
||
|
return m.migrate(db)
|
||
|
}
|
||
|
|
||
|
var migrations = []Migration{}
|
||
|
|
||
|
func Migrate(db *datastore) error {
|
||
|
var version int
|
||
|
var err error
|
||
|
if db.tableExists("appmigrations") {
|
||
|
err = db.QueryRow("SELECT MAX(version) FROM appmigrations").Scan(&version)
|
||
|
} else {
|
||
|
log.Info("Initializing appmigrations table...")
|
||
|
version = 0
|
||
|
_, err = db.Exec(`CREATE TABLE appmigrations (
|
||
|
version ` + db.typeInt() + ` NOT NULL,
|
||
|
migrated ` + db.typeDateTime() + ` NOT NULL,
|
||
|
result ` + db.typeText() + ` NOT NULL
|
||
|
) ` + db.engine() + `;`)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if len(migrations[version:]) > 0 {
|
||
|
for i, m := range migrations[version:] {
|
||
|
curVer := version + i + 1
|
||
|
log.Info("Migrating to V%d: %s", curVer, m.Description())
|
||
|
err = m.Migrate(db)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// Update migrations table
|
||
|
_, err = db.Exec("INSERT INTO appmigrations (version, migrated, result) VALUES (?, "+db.now()+", ?)", curVer, "")
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
log.Info("Database up-to-date. No migrations to run.")
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (db *datastore) tableExists(t string) bool {
|
||
|
var dummy string
|
||
|
var err error
|
||
|
if db.driverName == driverSQLite {
|
||
|
err = db.QueryRow("SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?", t).Scan(&dummy)
|
||
|
} else {
|
||
|
err = db.QueryRow("SHOW TABLES LIKE ?", t).Scan(&dummy)
|
||
|
}
|
||
|
switch {
|
||
|
case err == sql.ErrNoRows:
|
||
|
return false
|
||
|
case err != nil:
|
||
|
log.Error("Couldn't SHOW TABLES: %v", err)
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
return true
|
||
|
}
|