Started adding migrations
continuous-integration/drone/push Build is failing
Details
continuous-integration/drone/push Build is failing
Details
This commit is contained in:
parent
5e16a77b7b
commit
94eea2f32f
|
@ -0,0 +1,17 @@
|
|||
// Vikunja is a todo-list application to facilitate your life.
|
||||
// Copyright 2019 Vikunja and contributors. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package migration
|
|
@ -16,6 +16,14 @@
|
|||
|
||||
package migration
|
||||
|
||||
import "src.techknowlogick.com/xormigrate"
|
||||
|
||||
// You can get the id string for new migrations by running `date +%Y%m%d%H%M%S` on a unix system.
|
||||
|
||||
var migrations []*xormigrate.Migration
|
||||
|
||||
func Migrate() {
|
||||
// Because init() does not guarantee the order in which these are added to the slice,
|
||||
// we need to sort them to ensure that they are in order
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,214 @@
|
|||
package migrate
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/go-xorm/xorm"
|
||||
)
|
||||
|
||||
// MigrateFunc is the func signature for migrating.
|
||||
type MigrateFunc func(*xorm.Engine) error
|
||||
|
||||
// RollbackFunc is the func signature for rollbacking.
|
||||
type RollbackFunc func(*xorm.Engine) error
|
||||
|
||||
// InitSchemaFunc is the func signature for initializing the schema.
|
||||
type InitSchemaFunc func(*xorm.Engine) error
|
||||
|
||||
// Options define options for all migrations.
|
||||
type Options struct {
|
||||
// TableName is the migration table.
|
||||
TableName string
|
||||
// IDColumnName is the name of column where the migration id will be stored.
|
||||
IDColumnName string
|
||||
}
|
||||
|
||||
// Migration represents a database migration (a modification to be made on the database).
|
||||
type Migration struct {
|
||||
// ID is the migration identifier. Usually a timestamp like "201601021504".
|
||||
ID string
|
||||
// Migrate is a function that will br executed while running this migration.
|
||||
Migrate MigrateFunc
|
||||
// Rollback will be executed on rollback. Can be nil.
|
||||
Rollback RollbackFunc
|
||||
}
|
||||
|
||||
// Migrate represents a collection of all migrations of a database schema.
|
||||
type Migrate struct {
|
||||
db *xorm.Engine
|
||||
options *Options
|
||||
migrations []*Migration
|
||||
initSchema InitSchemaFunc
|
||||
}
|
||||
|
||||
var (
|
||||
// DefaultOptions can be used if you don't want to think about options.
|
||||
DefaultOptions = &Options{
|
||||
TableName: "migrations",
|
||||
IDColumnName: "id",
|
||||
}
|
||||
|
||||
// ErrRollbackImpossible is returned when trying to rollback a migration
|
||||
// that has no rollback function.
|
||||
ErrRollbackImpossible = errors.New("It's impossible to rollback this migration")
|
||||
|
||||
// ErrNoMigrationDefined is returned when no migration is defined.
|
||||
ErrNoMigrationDefined = errors.New("No migration defined")
|
||||
|
||||
// ErrMissingID is returned when the ID od migration is equal to ""
|
||||
ErrMissingID = errors.New("Missing ID in migration")
|
||||
|
||||
// ErrNoRunnedMigration is returned when any runned migration was found while
|
||||
// running RollbackLast
|
||||
ErrNoRunnedMigration = errors.New("Could not find last runned migration")
|
||||
)
|
||||
|
||||
// New returns a new Gormigrate.
|
||||
func New(db *xorm.Engine, options *Options, migrations []*Migration) *Migrate {
|
||||
return &Migrate{
|
||||
db: db,
|
||||
options: options,
|
||||
migrations: migrations,
|
||||
}
|
||||
}
|
||||
|
||||
// InitSchema sets a function that is run if no migration is found.
|
||||
// The idea is preventing to run all migrations when a new clean database
|
||||
// is being migrating. In this function you should create all tables and
|
||||
// foreign key necessary to your application.
|
||||
func (m *Migrate) InitSchema(initSchema InitSchemaFunc) {
|
||||
m.initSchema = initSchema
|
||||
}
|
||||
|
||||
// Migrate executes all migrations that did not run yet.
|
||||
func (m *Migrate) Migrate() error {
|
||||
if err := m.createMigrationTableIfNotExists(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if m.initSchema != nil && m.isFirstRun() {
|
||||
if err := m.runInitSchema(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, migration := range m.migrations {
|
||||
if err := m.runMigration(migration); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RollbackLast undo the last migration
|
||||
func (m *Migrate) RollbackLast() error {
|
||||
if len(m.migrations) == 0 {
|
||||
return ErrNoMigrationDefined
|
||||
}
|
||||
|
||||
lastRunnedMigration, err := m.getLastRunnedMigration()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := m.RollbackMigration(lastRunnedMigration); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Migrate) getLastRunnedMigration() (*Migration, error) {
|
||||
for i := len(m.migrations) - 1; i >= 0; i-- {
|
||||
migration := m.migrations[i]
|
||||
if m.migrationDidRun(migration) {
|
||||
return migration, nil
|
||||
}
|
||||
}
|
||||
return nil, ErrNoRunnedMigration
|
||||
}
|
||||
|
||||
// RollbackMigration undo a migration.
|
||||
func (m *Migrate) RollbackMigration(mig *Migration) error {
|
||||
if mig.Rollback == nil {
|
||||
return ErrRollbackImpossible
|
||||
}
|
||||
|
||||
if err := mig.Rollback(m.db); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sql := fmt.Sprintf("DELETE FROM %s WHERE %s = ?", m.options.TableName, m.options.IDColumnName)
|
||||
if _, err := m.db.Exec(sql, mig.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Migrate) runInitSchema() error {
|
||||
if err := m.initSchema(m.db); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, migration := range m.migrations {
|
||||
if err := m.insertMigration(migration.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Migrate) runMigration(migration *Migration) error {
|
||||
if len(migration.ID) == 0 {
|
||||
return ErrMissingID
|
||||
}
|
||||
|
||||
if !m.migrationDidRun(migration) {
|
||||
if err := migration.Migrate(m.db); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := m.insertMigration(migration.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Migrate) createMigrationTableIfNotExists() error {
|
||||
exists, err := m.db.IsTableExist(m.options.TableName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exists {
|
||||
return nil
|
||||
}
|
||||
|
||||
sql := fmt.Sprintf("CREATE TABLE %s (%s VARCHAR(255) PRIMARY KEY)", m.options.TableName, m.options.IDColumnName)
|
||||
if _, err := m.db.Exec(sql); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Migrate) migrationDidRun(mig *Migration) bool {
|
||||
row := m.db.DB().QueryRow(fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE %s = ?", m.options.TableName, m.options.IDColumnName), mig.ID)
|
||||
var count int
|
||||
row.Scan(&count)
|
||||
return count > 0
|
||||
}
|
||||
|
||||
func (m *Migrate) isFirstRun() bool {
|
||||
row := m.db.DB().QueryRow(fmt.Sprintf("SELECT COUNT(*) FROM %s", m.options.TableName))
|
||||
var count int
|
||||
row.Scan(&count)
|
||||
return count == 0
|
||||
}
|
||||
|
||||
func (m *Migrate) insertMigration(id string) error {
|
||||
sql := fmt.Sprintf("INSERT INTO %s (%s) VALUES (?)", m.options.TableName, m.options.IDColumnName)
|
||||
_, err := m.db.Exec(sql, id)
|
||||
return err
|
||||
}
|
|
@ -54,6 +54,7 @@ github.com/go-xorm/builder
|
|||
# github.com/go-xorm/core v0.5.8
|
||||
github.com/go-xorm/core
|
||||
# github.com/go-xorm/xorm v0.0.0-20170930012613-29d4a0330a00
|
||||
github.com/go-xorm/xorm/migrate
|
||||
github.com/go-xorm/xorm
|
||||
# github.com/go-xorm/xorm-redis-cache v0.0.0-20180727005610-859b313566b2
|
||||
github.com/go-xorm/xorm-redis-cache
|
||||
|
|
Loading…
Reference in New Issue