1
0

DB Migrations (#67)

This commit is contained in:
konrad
2019-03-29 17:54:35 +00:00
committed by Gitea
parent e21471a193
commit be5a17e993
127 changed files with 7917 additions and 1456 deletions

38
vendor/src.techknowlogick.com/xormigrate/.drone.yml generated vendored Normal file
View File

@ -0,0 +1,38 @@
kind: pipeline
name: default
workspace:
base: /go
path: src/src.techknowlogick.com/xormigrate
steps:
- name: fetch-and-test
image: golang:1.12
environment:
GO111MODULE: on
commands:
- go get ./...
- go test -v -tags sqlite
- go test -v -tags mysql
- go test -v -tags postgresql
- go test -v -tags sqlserver
services:
- name: pgsql
image: postgres:9.5
environment:
POSTGRES_DB: test
POSTGRES_PASSWORD: postgres
- name: mysql
image: mysql:5.7
environment:
MYSQL_DATABASE: test
MYSQL_ALLOW_EMPTY_PASSWORD: yes
- name: mssql
image: microsoft/mssql-server-linux:latest
environment:
ACCEPT_EULA: Y
SA_PASSWORD: MwantsaSecurePassword1
MSSQL_PID: Standard

4
vendor/src.techknowlogick.com/xormigrate/.env generated vendored Normal file
View File

@ -0,0 +1,4 @@
SQLITE_CONN_STRING=file::memory:?cache=shared
PG_CONN_STRING="user=postgres password=postgres host=pgsql dbname=test sslmode=disable"
MYSQL_CONN_STRING="root:@(mysql)/test?multiStatements=true"
SQLSERVER_CONN_STRING="server=mssql; database=master; user id=sa; password=MwantsaSecurePassword1; encrypt=disable"

19
vendor/src.techknowlogick.com/xormigrate/LICENSE generated vendored Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) 2019 Matti Ranta (@techknowlogick)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

162
vendor/src.techknowlogick.com/xormigrate/README.md generated vendored Normal file
View File

@ -0,0 +1,162 @@
# Xormigrate
[![Build Status](https://cloud.drone.io/api/badges/techknowlogick/xormigrate/status.svg)](https://cloud.drone.io/techknowlogick/xormigrate)
[![Go Report Card](https://goreportcard.com/badge/src.techknowlogick.com/xormigrate)](https://goreportcard.com/report/src.techknowlogick.com/xormigrate)
[![GoDoc](https://godoc.org/src.techknowlogick.com/xormigrate?status.svg)](https://godoc.org/src.techknowlogick.com/xormigrate)
## Supported databases
It supports any of the databases Xorm supports:
- PostgreSQL
- MySQL
- SQLite
- Microsoft SQL Server
## Installing
```bash
go get -u src.techknowlogick.com/xormigrate
```
## Usage
```go
package main
import (
"log"
"src.techknowlogick.com/xormigrate"
"github.com/go-xorm/xorm"
_ "github.com/mattn/go-sqlite3"
)
func main() {
db, err := xorm.NewEngine("sqlite3", "mydb.sqlite3")
if err != nil {
log.Fatal(err)
}
m := xormigrate.New(db, []*xormigrate.Migration{
// create persons table
{
ID: "201608301400",
// An optional description to print out to the Xormigrate logger
Description: "Create the Person table",
Migrate: func(tx *xorm.Engine) error {
// it's a good pratice to copy the struct inside the function,
// so side effects are prevented if the original struct changes during the time
type Person struct {
Name string
}
return tx.Sync2(&Person{})
},
Rollback: func(tx *xorm.Engine) error {
return tx.DropTables(&Person{})
},
},
// add age column to persons
{
ID: "201608301415",
Migrate: func(tx *xorm.Engine) error {
// when table already exists, it just adds fields as columns
type Person struct {
Age int
}
return tx.Sync2(&Person{})
},
Rollback: func(tx *xorm.Engine) error {
// Note: Column dropping in sqlite is not support, and you will need to do this manually
_, err = tx.Exec("ALTER TABLE person DROP COLUMN age")
if err != nil {
return fmt.Errorf("Drop column failed: %v", err)
}
return nil
},
},
// add pets table
{
ID: "201608301430",
Migrate: func(tx *xorm.Engine) error {
type Pet struct {
Name string
PersonID int
}
return tx.Sync2(&Pet{})
},
Rollback: func(tx *xorm.Engine) error {
return tx.DropTables(&Pet{})
},
},
})
if err = m.Migrate(); err != nil {
log.Fatalf("Could not migrate: %v", err)
}
log.Printf("Migration did run successfully")
}
```
## Having a separated function for initializing the schema
If you have a lot of migrations, it can be a pain to run all them, as example,
when you are deploying a new instance of the app, in a clean database.
To prevent this, you can set a function that will run if no migration was run
before (in a new clean database). Remember to create everything here, all tables,
foreign keys and what more you need in your app.
```go
type Person struct {
Name string
Age int
}
type Pet struct {
Name string
PersonID int
}
m := xormigrate.New(db, []*xormigrate.Migration{
// your migrations here
})
m.InitSchema(func(tx *xorm.Engine) error {
err := tx.sync2(
&Person{},
&Pet{},
// all other tables of your app
)
if err != nil {
return err
}
return nil
})
```
## Adding migration descriptions to your logging
Xormigrate's logger defaults to stdout, but it can be changed to suit your needs.
```go
m := xormigrate.New(db, []*xormigrate.Migration{
// your migrations here
})
// Don't log anything
m.NilLogger()
// This is the default logger
// No need to initialize this unless it was changed
// [xormigrate] message
m.DefaultLogger()
// Or, create a logger with any io.Writer you want
m.NewLogger(os.Stdout)
```
## Credits
* Based on [Gormigrate][gormmigrate]
* Uses [Xorm][xorm]
[xorm]: http://github.com/go-xorm/xorm/
[gormmigrate]: https://github.com/go-gormigrate/gormigrate

9
vendor/src.techknowlogick.com/xormigrate/go.mod generated vendored Normal file
View File

@ -0,0 +1,9 @@
module src.techknowlogick.com/xormigrate
go 1.12
require (
github.com/go-xorm/xorm v0.7.1
github.com/joho/godotenv v1.3.0
github.com/stretchr/testify v1.3.0
)

34
vendor/src.techknowlogick.com/xormigrate/go.sum generated vendored Normal file
View File

@ -0,0 +1,34 @@
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.0.0-20181014144952-4e0d7dc8888f/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-xorm/builder v0.3.2 h1:pSsZQRRzJNapKEAEhigw3xLmiLPeAYv5GFlpYZ8+a5I=
github.com/go-xorm/builder v0.3.2/go.mod h1:v8mE3MFBgtL+RGFNfUnAMUqqfk/Y4W5KuwCFQIEpQLk=
github.com/go-xorm/core v0.6.0 h1:tp6hX+ku4OD9khFZS8VGBDRY3kfVCtelPfmkgCyHxL0=
github.com/go-xorm/core v0.6.0/go.mod h1:d8FJ9Br8OGyQl12MCclmYBuBqqxsyeedpXciV5Myih8=
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM=
github.com/go-xorm/xorm v0.7.1 h1:Kj7mfuqctPdX60zuxP6EoEut0f3E6K66H6hcoxiHUMc=
github.com/go-xorm/xorm v0.7.1/go.mod h1:EHS1htMQFptzMaIHKyzqpHGw6C9Rtug75nsq6DA9unI=
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/stretchr/testify.v1 v1.2.2/go.mod h1:QI5V/q6UbPmuhtm10CaFZxED9NreB8PnFYN9JcR6TxU=

92
vendor/src.techknowlogick.com/xormigrate/logger.go generated vendored Normal file
View File

@ -0,0 +1,92 @@
package xormigrate
import (
"io"
"io/ioutil"
"log"
"os"
)
type LoggerInterface interface {
Debug(v ...interface{})
Debugf(format string, v ...interface{})
Info(v ...interface{})
Infof(format string, v ...interface{})
Warn(v ...interface{})
Warnf(format string, v ...interface{})
Error(v ...interface{})
Errorf(format string, v ...interface{})
}
var (
logger LoggerInterface = defaultLogger()
)
// SetLogger sets the Xormigrate logger
func (x *Xormigrate) SetLogger(l LoggerInterface) {
logger = l
}
func defaultLogger() *XormigrateLogger {
return &XormigrateLogger{log.New(os.Stdout, "[xormigrate] ", 0)}
}
// DefaultLogger sets a Xormigrate logger with default settings
// e.g. "[xormigrate] message"
func (x *Xormigrate) DefaultLogger() {
x.SetLogger(defaultLogger())
}
// NilLogger sets a Xormigrate logger that discards all messages
func (x *Xormigrate) NilLogger() {
x.SetLogger(&XormigrateLogger{log.New(ioutil.Discard, "", 0)})
}
// NewLogger sets a Xormigrate logger with a specified io.Writer
func (x *Xormigrate) NewLogger(writer io.Writer) {
x.SetLogger(&XormigrateLogger{log.New(writer, "", 0)})
}
type XormigrateLogger struct {
*log.Logger
}
// Debug prints a Debug message
func (l *XormigrateLogger) Debug(v ...interface{}) {
l.Logger.Print(v...)
}
// Debugf prints a formatted Debug message
func (l *XormigrateLogger) Debugf(format string, v ...interface{}) {
l.Logger.Printf(format, v...)
}
// Info prints an Info message
func (l *XormigrateLogger) Info(v ...interface{}) {
l.Logger.Print(v...)
}
// Infof prints a formatted Info message
func (l *XormigrateLogger) Infof(format string, v ...interface{}) {
l.Logger.Printf(format, v...)
}
// Warn prints a Warning message
func (l *XormigrateLogger) Warn(v ...interface{}) {
l.Logger.Print(v...)
}
// Warnf prints a formatted Warning message
func (l *XormigrateLogger) Warnf(format string, v ...interface{}) {
l.Logger.Printf(format, v...)
}
// Error prints an Error message
func (l *XormigrateLogger) Error(v ...interface{}) {
l.Logger.Print(v...)
}
// Errorf prints a formatted Error message
func (l *XormigrateLogger) Errorf(format string, v ...interface{}) {
l.Logger.Printf(format, v...)
}

View File

@ -0,0 +1,5 @@
{
"extends": [
"config:base"
]
}

322
vendor/src.techknowlogick.com/xormigrate/xormigrate.go generated vendored Normal file
View File

@ -0,0 +1,322 @@
package xormigrate // import "src.techknowlogick.com/xormigrate"
import (
"errors"
"fmt"
"github.com/go-xorm/xorm"
)
const (
initSchemaMigrationId = "SCHEMA_INIT"
)
// MigrateFunc is the func signature for migratinx.
type MigrateFunc func(*xorm.Engine) error
// RollbackFunc is the func signature for rollbackinx.
type RollbackFunc func(*xorm.Engine) error
// InitSchemaFunc is the func signature for initializing the schema.
type InitSchemaFunc func(*xorm.Engine) error
// 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 `xorm:"id"`
// Description is the migration description, which is optionally printed out when the migration is ran.
Description string
// Migrate is a function that will br executed while running this migration.
Migrate MigrateFunc `xorm:"-"`
// Rollback will be executed on rollback. Can be nil.
Rollback RollbackFunc `xorm:"-"`
}
// Xormigrate represents a collection of all migrations of a database schema.
type Xormigrate struct {
db *xorm.Engine
migrations []*Migration
initSchema InitSchemaFunc
}
// ReservedIDError is returned when a migration is using a reserved ID
type ReservedIDError struct {
ID string
}
func (e *ReservedIDError) Error() string {
return fmt.Sprintf(`xormigrate: Reserved migration ID: "%s"`, e.ID)
}
// DuplicatedIDError is returned when more than one migration have the same ID
type DuplicatedIDError struct {
ID string
}
func (e *DuplicatedIDError) Error() string {
return fmt.Sprintf(`xormigrate: Duplicated migration ID: "%s"`, e.ID)
}
var (
// ErrRollbackImpossible is returned when trying to rollback a migration
// that has no rollback function.
ErrRollbackImpossible = errors.New("xormigrate: It's impossible to rollback this migration")
// ErrNoMigrationDefined is returned when no migration is defined.
ErrNoMigrationDefined = errors.New("xormigrate: No migration defined")
// ErrMissingID is returned when the ID od migration is equal to ""
ErrMissingID = errors.New("xormigrate: Missing ID in migration")
// ErrNoRunMigration is returned when any run migration was found while
// running RollbackLast
ErrNoRunMigration = errors.New("xormigrate: Could not find last run migration")
// ErrMigrationIDDoesNotExist is returned when migrating or rolling back to a migration ID that
// does not exist in the list of migrations
ErrMigrationIDDoesNotExist = errors.New("xormigrate: Tried to migrate to an ID that doesn't exist")
)
// New returns a new Xormigrate.
func New(db *xorm.Engine, migrations []*Migration) *Xormigrate {
return &Xormigrate{
db: db,
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 migratinx. In this function you should create all tables and
// foreign key necessary to your application.
func (x *Xormigrate) InitSchema(initSchema InitSchemaFunc) {
x.initSchema = initSchema
}
// Migrate executes all migrations that did not run yet.
func (x *Xormigrate) Migrate() error {
return x.migrate("")
}
// MigrateTo executes all migrations that did not run yet up to the migration that matches `migrationID`.
func (x *Xormigrate) MigrateTo(migrationID string) error {
if err := x.checkIDExist(migrationID); err != nil {
return err
}
return x.migrate(migrationID)
}
func (x *Xormigrate) migrate(migrationID string) error {
if !x.hasMigrations() {
return ErrNoMigrationDefined
}
if err := x.checkReservedID(); err != nil {
return err
}
if err := x.checkDuplicatedID(); err != nil {
return err
}
if err := x.createMigrationTableIfNotExists(); err != nil {
return err
}
if x.initSchema != nil && x.canInitializeSchema() {
return x.runInitSchema() // return error or nil
}
for _, migration := range x.migrations {
if err := x.runMigration(migration); err != nil {
return err
}
if migrationID != "" && migration.ID == migrationID {
break
}
}
return nil
}
// There are migrations to apply if either there's a defined
// initSchema function or if the list of migrations is not empty.
func (x *Xormigrate) hasMigrations() bool {
return x.initSchema != nil || len(x.migrations) > 0
}
// Check whether any migration is using a reserved ID.
// For now there's only have one reserved ID, but there may be more in the future.
func (x *Xormigrate) checkReservedID() error {
for _, m := range x.migrations {
if m.ID == initSchemaMigrationId {
return &ReservedIDError{ID: m.ID}
}
}
return nil
}
func (x *Xormigrate) checkDuplicatedID() error {
lookup := make(map[string]struct{}, len(x.migrations))
for _, m := range x.migrations {
if _, ok := lookup[m.ID]; ok {
return &DuplicatedIDError{ID: m.ID}
}
lookup[m.ID] = struct{}{}
}
return nil
}
func (x *Xormigrate) checkIDExist(migrationID string) error {
for _, migrate := range x.migrations {
if migrate.ID == migrationID {
return nil
}
}
return ErrMigrationIDDoesNotExist
}
// RollbackLast undo the last migration
func (x *Xormigrate) RollbackLast() error {
if len(x.migrations) == 0 {
return ErrNoMigrationDefined
}
lastRunMigration, err := x.getLastRunMigration()
if err != nil {
return err
}
return x.RollbackMigration(lastRunMigration) // return error or nil
}
// RollbackTo undoes migrations up to the given migration that matches the `migrationID`.
// Migration with the matching `migrationID` is not rolled back.
func (x *Xormigrate) RollbackTo(migrationID string) error {
if len(x.migrations) == 0 {
return ErrNoMigrationDefined
}
if err := x.checkIDExist(migrationID); err != nil {
return err
}
for i := len(x.migrations) - 1; i >= 0; i-- {
migration := x.migrations[i]
if migration.ID == migrationID {
break
}
if x.migrationDidRun(migration) {
if err := x.rollbackMigration(migration); err != nil {
return err
}
}
}
return nil
}
func (x *Xormigrate) getLastRunMigration() (*Migration, error) {
for i := len(x.migrations) - 1; i >= 0; i-- {
migration := x.migrations[i]
if x.migrationDidRun(migration) {
return migration, nil
}
}
return nil, ErrNoRunMigration
}
// RollbackMigration undo a migration.
func (x *Xormigrate) RollbackMigration(m *Migration) error {
return x.rollbackMigration(m) // return error or nil
}
func (x *Xormigrate) rollbackMigration(m *Migration) error {
if m.Rollback == nil {
return ErrRollbackImpossible
}
if len(m.Description) > 0 {
logger.Errorf("Rolling back migration: %s", m.Description)
}
if err := m.Rollback(x.db); err != nil {
return err
}
if _, err := x.db.In("id", m.ID).Delete(&Migration{}); err != nil {
return err
}
return nil
}
func (x *Xormigrate) runInitSchema() error {
logger.Info("Initializing Schema")
if err := x.initSchema(x.db); err != nil {
return err
}
if err := x.insertMigration(initSchemaMigrationId); err != nil {
return err
}
for _, migration := range x.migrations {
if err := x.insertMigration(migration.ID); err != nil {
return err
}
}
return nil
}
func (x *Xormigrate) runMigration(migration *Migration) error {
if len(migration.ID) == 0 {
return ErrMissingID
}
if !x.migrationDidRun(migration) {
if len(migration.Description) > 0 {
logger.Info(migration.Description)
}
if err := migration.Migrate(x.db); err != nil {
return err
}
if err := x.insertMigration(migration.ID); err != nil {
return err
}
}
return nil
}
func (x *Xormigrate) createMigrationTableIfNotExists() error {
err := x.db.Sync2(new(Migration))
return err
}
func (x *Xormigrate) migrationDidRun(m *Migration) bool {
count, err := x.db.
In("id", m.ID).
Count(&Migration{})
if err != nil {
return false
}
return count > 0
}
// The schema can be initialised only if it hasn't been initialised yet
// and no other migration has been applied already.
func (x *Xormigrate) canInitializeSchema() bool {
if x.migrationDidRun(&Migration{ID: initSchemaMigrationId}) {
return false
}
// If the ID doesn't exist, we also want the list of migrations to be empty
count, err := x.db.
Count(&Migration{})
if err != nil {
return false
}
return count == 0
}
func (x *Xormigrate) insertMigration(id string) error {
_, err := x.db.Insert(&Migration{ID: id})
return err
}