From f04c597c11faa26c5e558dbb41de963ff199aba4 Mon Sep 17 00:00:00 2001 From: kolaente Date: Mon, 25 Mar 2019 08:05:06 +0100 Subject: [PATCH 1/3] Added bare migrations --- pkg/migration/20190324205606.go | 20 ++++++ pkg/migration/migration.go | 121 +++++++++++++++++--------------- 2 files changed, 84 insertions(+), 57 deletions(-) diff --git a/pkg/migration/20190324205606.go b/pkg/migration/20190324205606.go index a138d474c..18956f890 100644 --- a/pkg/migration/20190324205606.go +++ b/pkg/migration/20190324205606.go @@ -15,3 +15,23 @@ // along with this program. If not, see . package migration + +import ( + "github.com/go-xorm/xorm" + "src.techknowlogick.com/xormigrate" +) + +func init() { + migrations = append(migrations, &xormigrate.Migration{ + ID: "20190324205606", + Description: "Lorem Ipsum", + Migrate: func(tx *xorm.Engine) error { + + return nil + }, + Rollback: func(tx *xorm.Engine) error { + + return nil + }, + }) +} diff --git a/pkg/migration/migration.go b/pkg/migration/migration.go index 2e4d0f631..bcf325d55 100644 --- a/pkg/migration/migration.go +++ b/pkg/migration/migration.go @@ -16,7 +16,10 @@ package migration -import "src.techknowlogick.com/xormigrate" +import ( + "sort" + "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. @@ -25,64 +28,68 @@ 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 + sort.Slice(migrations, func(i, j int) bool { + return migrations[i].ID < migrations[j].ID + }) /* - XORM logs from try.vikunja.io: + XORM logs from try.vikunja.io: - Table users Column email db default is 'NULL', struct default is - Table users Column is_active db default is NULL, struct default is - Table users Column password_reset_token db default is 'NULL', struct default is - Table users Column email_confirm_token db default is 'NULL', struct default is - Table users Column created db default is NULL, struct default is - Table users Column updated db default is NULL, struct default is - Table list Column title db default is 'NULL', struct default is - Table list Column description db default is 'NULL', struct default is - Table list Column owner_id db default is NULL, struct default is - Table list Column namespace_id db default is NULL, struct default is - Table list Column created db default is NULL, struct default is - Table list Column updated db default is NULL, struct default is - Table tasks Column text db default is 'NULL', struct default is - Table tasks Column description db default is 'NULL', struct default is - Table tasks Column done db default is NULL, struct default is - Table tasks Column due_date_unix db default is NULL, struct default is - Table tasks Column reminders_unix db default is 'NULL', struct default is - Table tasks Column created_by_id db default is NULL, struct default is - Table tasks Column list_id db default is NULL, struct default is - Table tasks Column repeat_after db default is NULL, struct default is - Table tasks Column parent_task_id db default is NULL, struct default is - Table tasks Column priority db default is NULL, struct default is - Table tasks Column start_date_unix db default is NULL, struct default is - Table tasks Column end_date_unix db default is NULL, struct default is - Table tasks Column created db default is NULL, struct default is - Table tasks Column updated db default is NULL, struct default is - Table teams Column description db default is 'NULL', struct default is - Table teams Column created db default is NULL, struct default is - Table teams Column updated db default is NULL, struct default is - Table team_members Column admin db default is NULL, struct default is - Table team_members Column created db default is NULL, struct default is - Table team_list Column right db default is NULL, struct default is - Table team_list Column created db default is NULL, struct default is - Table team_list Column updated db default is NULL, struct default is - Table team_namespaces Column right db default is NULL, struct default is - Table team_namespaces Column created db default is NULL, struct default is - Table team_namespaces Column updated db default is NULL, struct default is - Table namespaces Column name db default is 'NULL', struct default is - Table namespaces Column description db default is 'NULL', struct default is - Table namespaces Column created db default is NULL, struct default is - Table namespaces Column updated db default is NULL, struct default is - Table users_list Column right db default is NULL, struct default is - Table users_list Column created db default is NULL, struct default is - Table users_list Column updated db default is NULL, struct default is - Table users_namespace Column right db default is NULL, struct default is - Table users_namespace Column created db default is NULL, struct default is - Table users_namespace Column updated db default is NULL, struct default is - Table task_assignees Column created db default is NULL, struct default is - Table labels Column description db default is 'NULL', struct default is - Table labels Column hex_color db default is 'NULL', struct default is - Table labels Column created db default is NULL, struct default is - Table labels Column updated db default is NULL, struct default is - Table label_task Column created db default is NULL, struct default is - Table tasks has column reminder_unix but struct has not related field - Table team_members has column updated but struct has not related field + Table users Column email db default is 'NULL', struct default is + Table users Column is_active db default is NULL, struct default is + Table users Column password_reset_token db default is 'NULL', struct default is + Table users Column email_confirm_token db default is 'NULL', struct default is + Table users Column created db default is NULL, struct default is + Table users Column updated db default is NULL, struct default is + Table list Column title db default is 'NULL', struct default is + Table list Column description db default is 'NULL', struct default is + Table list Column owner_id db default is NULL, struct default is + Table list Column namespace_id db default is NULL, struct default is + Table list Column created db default is NULL, struct default is + Table list Column updated db default is NULL, struct default is + Table tasks Column text db default is 'NULL', struct default is + Table tasks Column description db default is 'NULL', struct default is + Table tasks Column done db default is NULL, struct default is + Table tasks Column due_date_unix db default is NULL, struct default is + Table tasks Column reminders_unix db default is 'NULL', struct default is + Table tasks Column created_by_id db default is NULL, struct default is + Table tasks Column list_id db default is NULL, struct default is + Table tasks Column repeat_after db default is NULL, struct default is + Table tasks Column parent_task_id db default is NULL, struct default is + Table tasks Column priority db default is NULL, struct default is + Table tasks Column start_date_unix db default is NULL, struct default is + Table tasks Column end_date_unix db default is NULL, struct default is + Table tasks Column created db default is NULL, struct default is + Table tasks Column updated db default is NULL, struct default is + Table teams Column description db default is 'NULL', struct default is + Table teams Column created db default is NULL, struct default is + Table teams Column updated db default is NULL, struct default is + Table team_members Column admin db default is NULL, struct default is + Table team_members Column created db default is NULL, struct default is + Table team_list Column right db default is NULL, struct default is + Table team_list Column created db default is NULL, struct default is + Table team_list Column updated db default is NULL, struct default is + Table team_namespaces Column right db default is NULL, struct default is + Table team_namespaces Column created db default is NULL, struct default is + Table team_namespaces Column updated db default is NULL, struct default is + Table namespaces Column name db default is 'NULL', struct default is + Table namespaces Column description db default is 'NULL', struct default is + Table namespaces Column created db default is NULL, struct default is + Table namespaces Column updated db default is NULL, struct default is + Table users_list Column right db default is NULL, struct default is + Table users_list Column created db default is NULL, struct default is + Table users_list Column updated db default is NULL, struct default is + Table users_namespace Column right db default is NULL, struct default is + Table users_namespace Column created db default is NULL, struct default is + Table users_namespace Column updated db default is NULL, struct default is + Table task_assignees Column created db default is NULL, struct default is + Table labels Column description db default is 'NULL', struct default isdfdfsd + Table labels Column hex_color db default is 'NULL', struct default is + Table labels Column created db default is NULL, struct default is + Table labels Column updated db default is NULL, struct default is + Table label_task Column created db default is NULL, struct default is + + Table tasks has column reminder_unix but struct has not related field + Table team_members has column updated but struct has not related field */ } From e4c5bfc42ba8999037cf7251da321b972975e2c8 Mon Sep 17 00:00:00 2001 From: kolaente Date: Mon, 25 Mar 2019 08:23:56 +0100 Subject: [PATCH 2/3] Moved db handling to own package --- pkg/db/db.go | 81 ++++++++++++++++++++++++++++++++++++++ pkg/migration/migration.go | 23 ++++++++++- pkg/models/models.go | 59 +++------------------------ 3 files changed, 109 insertions(+), 54 deletions(-) create mode 100644 pkg/db/db.go diff --git a/pkg/db/db.go b/pkg/db/db.go new file mode 100644 index 000000000..73b0c135e --- /dev/null +++ b/pkg/db/db.go @@ -0,0 +1,81 @@ +// 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 . + +package db + +import ( + "code.vikunja.io/api/pkg/log" + "encoding/gob" + "fmt" + "github.com/go-xorm/core" + "github.com/go-xorm/xorm" + xrc "github.com/go-xorm/xorm-redis-cache" + "github.com/spf13/viper" + + _ "github.com/go-sql-driver/mysql" // Because. + _ "github.com/mattn/go-sqlite3" // Because. +) + +// CreateDBEngine initializes a db engine from the config +func CreateDBEngine() (engine *xorm.Engine, err error) { + // Use Mysql if set + if viper.GetString("database.type") == "mysql" { + connStr := fmt.Sprintf( + "%s:%s@tcp(%s)/%s?charset=utf8&parseTime=true", + viper.GetString("database.user"), + viper.GetString("database.password"), + viper.GetString("database.host"), + viper.GetString("database.database")) + e, err := xorm.NewEngine("mysql", connStr) + e.SetMaxOpenConns(viper.GetInt("database.openconnections")) + return e, err + } + + // Otherwise use sqlite + path := viper.GetString("database.path") + if path == "" { + path = "./db.db" + } + + engine, err = xorm.NewEngine("sqlite3", path) + if err != nil { + return nil, err + } + + // Cache + if viper.GetBool("cache.enabled") { + switch viper.GetString("cache.type") { + case "memory": + cacher := xorm.NewLRUCacher(xorm.NewMemoryStore(), viper.GetInt("cache.maxelementsize")) + engine.SetDefaultCacher(cacher) + case "redis": + cacher := xrc.NewRedisCacher(viper.GetString("redis.host"), viper.GetString("redis.password"), xrc.DEFAULT_EXPIRATION, x.Logger()) + engine.SetDefaultCacher(cacher) + // Get the tables from migration + gob.Register(tables) + gob.Register(tablesWithPointer) // Need to register tables with pointer as well... + default: + log.Log.Info("Did not find a valid cache type. Caching disabled. Please refer to the docs for poosible cache types.") + } + } + + engine.SetMapper(core.GonicMapper{}) + + engine.ShowSQL(viper.GetString("log.database") != "off") + engine.SetLogger(xorm.NewSimpleLogger(log.GetLogWriter("database"))) + + return +} diff --git a/pkg/migration/migration.go b/pkg/migration/migration.go index bcf325d55..1920b0058 100644 --- a/pkg/migration/migration.go +++ b/pkg/migration/migration.go @@ -17,6 +17,9 @@ package migration import ( + "code.vikunja.io/api/pkg/db" + "code.vikunja.io/api/pkg/log" + "github.com/go-xorm/xorm" "sort" "src.techknowlogick.com/xormigrate" ) @@ -25,13 +28,31 @@ import ( var migrations []*xormigrate.Migration -func Migrate() { +func Migrate(x *xorm.Engine) { + // Get our own xorm engine if we don't have one + if x == nil { + var err error + x, err = db.CreateDBEngine() + if err != nil { + log.Log.Criticalf("Could not connect to db: %v", err.Error()) + return + } + } + // 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 sort.Slice(migrations, func(i, j int) bool { return migrations[i].ID < migrations[j].ID }) + m := xormigrate.New(nil, migrations) + + m.NewLogger(log.GetLogWriter("database")) + + m.InitSchema() + + // TODO: Init schema + /* XORM logs from try.vikunja.io: diff --git a/pkg/models/models.go b/pkg/models/models.go index 03c47afe9..b96b69b1f 100644 --- a/pkg/models/models.go +++ b/pkg/models/models.go @@ -17,13 +17,11 @@ package models import ( + "code.vikunja.io/api/pkg/db" "code.vikunja.io/api/pkg/log" - "encoding/gob" - "fmt" + "code.vikunja.io/api/pkg/migration" _ "github.com/go-sql-driver/mysql" // Because. - "github.com/go-xorm/core" "github.com/go-xorm/xorm" - xrc "github.com/go-xorm/xorm-redis-cache" _ "github.com/mattn/go-sqlite3" // Because. "github.com/spf13/viper" ) @@ -35,28 +33,6 @@ var ( tablesWithPointer []interface{} ) -func getEngine() (*xorm.Engine, error) { - // Use Mysql if set - if viper.GetString("database.type") == "mysql" { - connStr := fmt.Sprintf( - "%s:%s@tcp(%s)/%s?charset=utf8&parseTime=true", - viper.GetString("database.user"), - viper.GetString("database.password"), - viper.GetString("database.host"), - viper.GetString("database.database")) - e, err := xorm.NewEngine("mysql", connStr) - e.SetMaxOpenConns(viper.GetInt("database.openconnections")) - return e, err - } - - // Otherwise use sqlite - path := viper.GetString("database.path") - if path == "" { - path = "./db.db" - } - return xorm.NewEngine("sqlite3", path) -} - func init() { tables = append(tables, new(User), @@ -93,36 +69,13 @@ func init() { // SetEngine sets the xorm.Engine func SetEngine() (err error) { - x, err = getEngine() + x, err = db.CreateDBEngine() if err != nil { - return fmt.Errorf("failed to connect to database: %v", err) + log.Log.Criticalf("Could not connect to db: %v", err.Error()) + return } - // Cache - if viper.GetBool("cache.enabled") { - switch viper.GetString("cache.type") { - case "memory": - cacher := xorm.NewLRUCacher(xorm.NewMemoryStore(), viper.GetInt("cache.maxelementsize")) - x.SetDefaultCacher(cacher) - case "redis": - cacher := xrc.NewRedisCacher(viper.GetString("redis.host"), viper.GetString("redis.password"), xrc.DEFAULT_EXPIRATION, x.Logger()) - x.SetDefaultCacher(cacher) - gob.Register(tables) - gob.Register(tablesWithPointer) // Need to register tables with pointer as well... - default: - log.Log.Info("Did not find a valid cache type. Caching disabled. Please refer to the docs for poosible cache types.") - } - } - - x.SetMapper(core.GonicMapper{}) - - // Sync dat shit - if err = x.StoreEngine("InnoDB").Sync2(tables...); err != nil { - return fmt.Errorf("sync database struct error: %v", err) - } - - x.ShowSQL(viper.GetString("log.database") != "off") - x.SetLogger(xorm.NewSimpleLogger(log.GetLogWriter("database"))) + migration.Migrate(x) return nil } From 154170e4d0bd033ce419f9ef3d6d3c5a5cf754b5 Mon Sep 17 00:00:00 2001 From: kolaente Date: Mon, 25 Mar 2019 08:24:11 +0100 Subject: [PATCH 3/3] Added libs --- vendor/github.com/go-xorm/builder/.drone.yml | 37 ++ .../go-xorm/builder/builder_limit.go | 100 ++++++ .../go-xorm/builder/builder_union.go | 47 +++ vendor/github.com/go-xorm/builder/go.mod | 1 + vendor/github.com/go-xorm/builder/sql.go | 156 +++++++++ .../go-xorm/builder/string_builder.go | 119 +++++++ vendor/github.com/go-xorm/xorm/.drone.yml | 125 +++++++ vendor/github.com/go-xorm/xorm/context.go | 26 ++ .../github.com/go-xorm/xorm/context_cache.go | 30 ++ .../github.com/go-xorm/xorm/engine_group.go | 204 +++++++++++ .../go-xorm/xorm/engine_group_policy.go | 116 +++++++ .../github.com/go-xorm/xorm/engine_table.go | 113 ++++++ vendor/github.com/go-xorm/xorm/go.mod | 24 ++ vendor/github.com/go-xorm/xorm/go.sum | 43 +++ vendor/github.com/go-xorm/xorm/interface.go | 116 +++++++ vendor/github.com/go-xorm/xorm/transaction.go | 26 ++ .../xormigrate/.drone.yml | 38 +++ vendor/src.techknowlogick.com/xormigrate/.env | 4 + .../src.techknowlogick.com/xormigrate/LICENSE | 19 ++ .../xormigrate/README.md | 162 +++++++++ .../src.techknowlogick.com/xormigrate/go.mod | 9 + .../src.techknowlogick.com/xormigrate/go.sum | 34 ++ .../xormigrate/logger.go | 92 +++++ .../xormigrate/renovate.json | 5 + .../xormigrate/xormigrate.go | 322 ++++++++++++++++++ 25 files changed, 1968 insertions(+) create mode 100644 vendor/github.com/go-xorm/builder/.drone.yml create mode 100644 vendor/github.com/go-xorm/builder/builder_limit.go create mode 100644 vendor/github.com/go-xorm/builder/builder_union.go create mode 100644 vendor/github.com/go-xorm/builder/go.mod create mode 100644 vendor/github.com/go-xorm/builder/sql.go create mode 100644 vendor/github.com/go-xorm/builder/string_builder.go create mode 100644 vendor/github.com/go-xorm/xorm/.drone.yml create mode 100644 vendor/github.com/go-xorm/xorm/context.go create mode 100644 vendor/github.com/go-xorm/xorm/context_cache.go create mode 100644 vendor/github.com/go-xorm/xorm/engine_group.go create mode 100644 vendor/github.com/go-xorm/xorm/engine_group_policy.go create mode 100644 vendor/github.com/go-xorm/xorm/engine_table.go create mode 100644 vendor/github.com/go-xorm/xorm/go.mod create mode 100644 vendor/github.com/go-xorm/xorm/go.sum create mode 100644 vendor/github.com/go-xorm/xorm/interface.go create mode 100644 vendor/github.com/go-xorm/xorm/transaction.go create mode 100644 vendor/src.techknowlogick.com/xormigrate/.drone.yml create mode 100644 vendor/src.techknowlogick.com/xormigrate/.env create mode 100644 vendor/src.techknowlogick.com/xormigrate/LICENSE create mode 100644 vendor/src.techknowlogick.com/xormigrate/README.md create mode 100644 vendor/src.techknowlogick.com/xormigrate/go.mod create mode 100644 vendor/src.techknowlogick.com/xormigrate/go.sum create mode 100644 vendor/src.techknowlogick.com/xormigrate/logger.go create mode 100644 vendor/src.techknowlogick.com/xormigrate/renovate.json create mode 100644 vendor/src.techknowlogick.com/xormigrate/xormigrate.go diff --git a/vendor/github.com/go-xorm/builder/.drone.yml b/vendor/github.com/go-xorm/builder/.drone.yml new file mode 100644 index 000000000..ca4037772 --- /dev/null +++ b/vendor/github.com/go-xorm/builder/.drone.yml @@ -0,0 +1,37 @@ +workspace: + base: /go + path: src/github.com/go-xorm/builder + +clone: + git: + image: plugins/git:next + depth: 50 + tags: true + +matrix: + GO_VERSION: + - 1.8 + - 1.9 + - 1.10 + - 1.11 + +pipeline: + test: + image: golang:${GO_VERSION} + commands: + - go get -u github.com/golang/lint/golint + - go get -u github.com/stretchr/testify/assert + - go get -u github.com/go-xorm/sqlfiddle + - golint ./... + - go test -v -race -coverprofile=coverage.txt -covermode=atomic + when: + event: [ push, tag, pull_request ] + +codecov: + image: robertstettner/drone-codecov + group: build + secrets: [ codecov_token ] + files: + - coverage.txt + when: + event: [ push, pull_request ] \ No newline at end of file diff --git a/vendor/github.com/go-xorm/builder/builder_limit.go b/vendor/github.com/go-xorm/builder/builder_limit.go new file mode 100644 index 000000000..82435dacb --- /dev/null +++ b/vendor/github.com/go-xorm/builder/builder_limit.go @@ -0,0 +1,100 @@ +// Copyright 2018 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package builder + +import ( + "fmt" + "strings" +) + +func (b *Builder) limitWriteTo(w Writer) error { + if strings.TrimSpace(b.dialect) == "" { + return ErrDialectNotSetUp + } + + if b.limitation != nil { + limit := b.limitation + if limit.offset < 0 || limit.limitN <= 0 { + return ErrInvalidLimitation + } + // erase limit condition + b.limitation = nil + ow := w.(*BytesWriter) + + switch strings.ToLower(strings.TrimSpace(b.dialect)) { + case ORACLE: + if len(b.selects) == 0 { + b.selects = append(b.selects, "*") + } + + var final *Builder + selects := b.selects + b.selects = append(selects, "ROWNUM RN") + + var wb *Builder + if b.optype == unionType { + wb = Dialect(b.dialect).Select("at.*", "ROWNUM RN"). + From(b, "at") + } else { + wb = b + } + + if limit.offset == 0 { + final = Dialect(b.dialect).Select(selects...).From(wb, "at"). + Where(Lte{"at.RN": limit.limitN}) + } else { + sub := Dialect(b.dialect).Select("*"). + From(b, "at").Where(Lte{"at.RN": limit.offset + limit.limitN}) + + final = Dialect(b.dialect).Select(selects...).From(sub, "att"). + Where(Gt{"att.RN": limit.offset}) + } + + return final.WriteTo(ow) + case SQLITE, MYSQL, POSTGRES: + // if type UNION, we need to write previous content back to current writer + if b.optype == unionType { + if err := b.WriteTo(ow); err != nil { + return err + } + } + + if limit.offset == 0 { + fmt.Fprint(ow, " LIMIT ", limit.limitN) + } else { + fmt.Fprintf(ow, " LIMIT %v OFFSET %v", limit.limitN, limit.offset) + } + case MSSQL: + if len(b.selects) == 0 { + b.selects = append(b.selects, "*") + } + + var final *Builder + selects := b.selects + b.selects = append(append([]string{fmt.Sprintf("TOP %d %v", limit.limitN+limit.offset, b.selects[0])}, + b.selects[1:]...), "ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS RN") + + var wb *Builder + if b.optype == unionType { + wb = Dialect(b.dialect).Select("*", "ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS RN"). + From(b, "at") + } else { + wb = b + } + + if limit.offset == 0 { + final = Dialect(b.dialect).Select(selects...).From(wb, "at") + } else { + final = Dialect(b.dialect).Select(selects...).From(wb, "at").Where(Gt{"at.RN": limit.offset}) + } + + return final.WriteTo(ow) + default: + return ErrNotSupportType + } + } + + return nil +} diff --git a/vendor/github.com/go-xorm/builder/builder_union.go b/vendor/github.com/go-xorm/builder/builder_union.go new file mode 100644 index 000000000..4ba921617 --- /dev/null +++ b/vendor/github.com/go-xorm/builder/builder_union.go @@ -0,0 +1,47 @@ +// Copyright 2018 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package builder + +import ( + "fmt" + "strings" +) + +func (b *Builder) unionWriteTo(w Writer) error { + if b.limitation != nil || b.cond.IsValid() || + b.orderBy != "" || b.having != "" || b.groupBy != "" { + return ErrNotUnexpectedUnionConditions + } + + for idx, u := range b.unions { + current := u.builder + if current.optype != selectType { + return ErrUnsupportedUnionMembers + } + + if len(b.unions) == 1 { + if err := current.selectWriteTo(w); err != nil { + return err + } + } else { + if b.dialect != "" && b.dialect != current.dialect { + return ErrInconsistentDialect + } + + if idx != 0 { + fmt.Fprint(w, fmt.Sprintf(" UNION %v ", strings.ToUpper(u.unionType))) + } + fmt.Fprint(w, "(") + + if err := current.selectWriteTo(w); err != nil { + return err + } + + fmt.Fprint(w, ")") + } + } + + return nil +} diff --git a/vendor/github.com/go-xorm/builder/go.mod b/vendor/github.com/go-xorm/builder/go.mod new file mode 100644 index 000000000..ef1a659ad --- /dev/null +++ b/vendor/github.com/go-xorm/builder/go.mod @@ -0,0 +1 @@ +module "github.com/go-xorm/builder" diff --git a/vendor/github.com/go-xorm/builder/sql.go b/vendor/github.com/go-xorm/builder/sql.go new file mode 100644 index 000000000..083424276 --- /dev/null +++ b/vendor/github.com/go-xorm/builder/sql.go @@ -0,0 +1,156 @@ +// Copyright 2018 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package builder + +import ( + sql2 "database/sql" + "fmt" + "reflect" + "time" +) + +func condToSQL(cond Cond) (string, []interface{}, error) { + if cond == nil || !cond.IsValid() { + return "", nil, nil + } + + w := NewWriter() + if err := cond.WriteTo(w); err != nil { + return "", nil, err + } + return w.writer.String(), w.args, nil +} + +func condToBoundSQL(cond Cond) (string, error) { + if cond == nil || !cond.IsValid() { + return "", nil + } + + w := NewWriter() + if err := cond.WriteTo(w); err != nil { + return "", err + } + return ConvertToBoundSQL(w.writer.String(), w.args) +} + +// ToSQL convert a builder or conditions to SQL and args +func ToSQL(cond interface{}) (string, []interface{}, error) { + switch cond.(type) { + case Cond: + return condToSQL(cond.(Cond)) + case *Builder: + return cond.(*Builder).ToSQL() + } + return "", nil, ErrNotSupportType +} + +// ToBoundSQL convert a builder or conditions to parameters bound SQL +func ToBoundSQL(cond interface{}) (string, error) { + switch cond.(type) { + case Cond: + return condToBoundSQL(cond.(Cond)) + case *Builder: + return cond.(*Builder).ToBoundSQL() + } + return "", ErrNotSupportType +} + +func noSQLQuoteNeeded(a interface{}) bool { + switch a.(type) { + case int, int8, int16, int32, int64: + return true + case uint, uint8, uint16, uint32, uint64: + return true + case float32, float64: + return true + case bool: + return true + case string: + return false + case time.Time, *time.Time: + return false + } + + t := reflect.TypeOf(a) + switch t.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return true + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return true + case reflect.Float32, reflect.Float64: + return true + case reflect.Bool: + return true + case reflect.String: + return false + } + + return false +} + +// ConvertToBoundSQL will convert SQL and args to a bound SQL +func ConvertToBoundSQL(sql string, args []interface{}) (string, error) { + buf := StringBuilder{} + var i, j, start int + for ; i < len(sql); i++ { + if sql[i] == '?' { + _, err := buf.WriteString(sql[start:i]) + if err != nil { + return "", err + } + start = i + 1 + + if len(args) == j { + return "", ErrNeedMoreArguments + } + + arg := args[j] + if namedArg, ok := arg.(sql2.NamedArg); ok { + arg = namedArg.Value + } + + if noSQLQuoteNeeded(arg) { + _, err = fmt.Fprint(&buf, arg) + } else { + _, err = fmt.Fprintf(&buf, "'%v'", arg) + } + if err != nil { + return "", err + } + j = j + 1 + } + } + _, err := buf.WriteString(sql[start:]) + if err != nil { + return "", err + } + return buf.String(), nil +} + +// ConvertPlaceholder replaces ? to $1, $2 ... or :1, :2 ... according prefix +func ConvertPlaceholder(sql, prefix string) (string, error) { + buf := StringBuilder{} + var i, j, start int + for ; i < len(sql); i++ { + if sql[i] == '?' { + if _, err := buf.WriteString(sql[start:i]); err != nil { + return "", err + } + + start = i + 1 + j = j + 1 + + if _, err := buf.WriteString(fmt.Sprintf("%v%d", prefix, j)); err != nil { + return "", err + } + } + } + + if _, err := buf.WriteString(sql[start:]); err != nil { + return "", err + } + + return buf.String(), nil +} diff --git a/vendor/github.com/go-xorm/builder/string_builder.go b/vendor/github.com/go-xorm/builder/string_builder.go new file mode 100644 index 000000000..d4de8717e --- /dev/null +++ b/vendor/github.com/go-xorm/builder/string_builder.go @@ -0,0 +1,119 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package builder + +import ( + "unicode/utf8" + "unsafe" +) + +// A StringBuilder is used to efficiently build a string using Write methods. +// It minimizes memory copying. The zero value is ready to use. +// Do not copy a non-zero Builder. +type StringBuilder struct { + addr *StringBuilder // of receiver, to detect copies by value + buf []byte +} + +// noescape hides a pointer from escape analysis. noescape is +// the identity function but escape analysis doesn't think the +// output depends on the input. noescape is inlined and currently +// compiles down to zero instructions. +// USE CAREFULLY! +// This was copied from the runtime; see issues 23382 and 7921. +//go:nosplit +func noescape(p unsafe.Pointer) unsafe.Pointer { + x := uintptr(p) + return unsafe.Pointer(x ^ 0) +} + +func (b *StringBuilder) copyCheck() { + if b.addr == nil { + // This hack works around a failing of Go's escape analysis + // that was causing b to escape and be heap allocated. + // See issue 23382. + // TODO: once issue 7921 is fixed, this should be reverted to + // just "b.addr = b". + b.addr = (*StringBuilder)(noescape(unsafe.Pointer(b))) + } else if b.addr != b { + panic("strings: illegal use of non-zero Builder copied by value") + } +} + +// String returns the accumulated string. +func (b *StringBuilder) String() string { + return *(*string)(unsafe.Pointer(&b.buf)) +} + +// Len returns the number of accumulated bytes; b.Len() == len(b.String()). +func (b *StringBuilder) Len() int { return len(b.buf) } + +// Reset resets the Builder to be empty. +func (b *StringBuilder) Reset() { + b.addr = nil + b.buf = nil +} + +// grow copies the buffer to a new, larger buffer so that there are at least n +// bytes of capacity beyond len(b.buf). +func (b *StringBuilder) grow(n int) { + buf := make([]byte, len(b.buf), 2*cap(b.buf)+n) + copy(buf, b.buf) + b.buf = buf +} + +// Grow grows b's capacity, if necessary, to guarantee space for +// another n bytes. After Grow(n), at least n bytes can be written to b +// without another allocation. If n is negative, Grow panics. +func (b *StringBuilder) Grow(n int) { + b.copyCheck() + if n < 0 { + panic("strings.Builder.Grow: negative count") + } + if cap(b.buf)-len(b.buf) < n { + b.grow(n) + } +} + +// Write appends the contents of p to b's buffer. +// Write always returns len(p), nil. +func (b *StringBuilder) Write(p []byte) (int, error) { + b.copyCheck() + b.buf = append(b.buf, p...) + return len(p), nil +} + +// WriteByte appends the byte c to b's buffer. +// The returned error is always nil. +func (b *StringBuilder) WriteByte(c byte) error { + b.copyCheck() + b.buf = append(b.buf, c) + return nil +} + +// WriteRune appends the UTF-8 encoding of Unicode code point r to b's buffer. +// It returns the length of r and a nil error. +func (b *StringBuilder) WriteRune(r rune) (int, error) { + b.copyCheck() + if r < utf8.RuneSelf { + b.buf = append(b.buf, byte(r)) + return 1, nil + } + l := len(b.buf) + if cap(b.buf)-l < utf8.UTFMax { + b.grow(utf8.UTFMax) + } + n := utf8.EncodeRune(b.buf[l:l+utf8.UTFMax], r) + b.buf = b.buf[:l+n] + return n, nil +} + +// WriteString appends the contents of s to b's buffer. +// It returns the length of s and a nil error. +func (b *StringBuilder) WriteString(s string) (int, error) { + b.copyCheck() + b.buf = append(b.buf, s...) + return len(s), nil +} diff --git a/vendor/github.com/go-xorm/xorm/.drone.yml b/vendor/github.com/go-xorm/xorm/.drone.yml new file mode 100644 index 000000000..0a79ed021 --- /dev/null +++ b/vendor/github.com/go-xorm/xorm/.drone.yml @@ -0,0 +1,125 @@ +workspace: + base: /go + path: src/github.com/go-xorm/xorm + +clone: + git: + image: plugins/git:next + depth: 50 + tags: true + +services: + mysql: + image: mysql:5.7 + environment: + - MYSQL_DATABASE=xorm_test + - MYSQL_ALLOW_EMPTY_PASSWORD=yes + when: + event: [ push, tag, pull_request ] + + pgsql: + image: postgres:9.5 + environment: + - POSTGRES_USER=postgres + - POSTGRES_DB=xorm_test + when: + event: [ push, tag, pull_request ] + + #mssql: + # image: microsoft/mssql-server-linux:2017-CU11 + # environment: + # - ACCEPT_EULA=Y + # - SA_PASSWORD=yourStrong(!)Password + # - MSSQL_PID=Developer + # commands: + # - echo 'CREATE DATABASE xorm_test' > create.sql + # - /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P yourStrong(!)Password -i "create.sql" + +matrix: + GO_VERSION: + - 1.8 + - 1.9 + - 1.10 + - 1.11 + +pipeline: + init_postgres: + image: postgres:9.5 + commands: + # wait for postgres service to become available + - | + until psql -U postgres -d xorm_test -h pgsql \ + -c "SELECT 1;" >/dev/null 2>&1; do sleep 1; done + # query the database + - | + psql -U postgres -d xorm_test -h pgsql \ + -c "create schema xorm;" + + build: + image: golang:${GO_VERSION} + commands: + - go get -t -d -v ./... + - go get -u github.com/go-xorm/core + - go get -u github.com/go-xorm/builder + - go build -v + when: + event: [ push, pull_request ] + + test-sqlite: + image: golang:${GO_VERSION} + commands: + - go get -u github.com/wadey/gocovmerge + - go test -v -race -db="sqlite3" -conn_str="./test.db" -coverprofile=coverage1-1.txt -covermode=atomic + - go test -v -race -db="sqlite3" -conn_str="./test.db" -cache=true -coverprofile=coverage1-2.txt -covermode=atomic + when: + event: [ push, pull_request ] + + test-mysql: + image: golang:${GO_VERSION} + commands: + - go test -v -race -db="mysql" -conn_str="root:@tcp(mysql)/xorm_test" -coverprofile=coverage2-1.txt -covermode=atomic + - go test -v -race -db="mysql" -conn_str="root:@tcp(mysql)/xorm_test" -cache=true -coverprofile=coverage2-2.txt -covermode=atomic + when: + event: [ push, pull_request ] + + test-mysql-utf8mb4: + image: golang:${GO_VERSION} + commands: + - go test -v -race -db="mysql" -conn_str="root:@tcp(mysql)/xorm_test?charset=utf8mb4" -coverprofile=coverage2.1-1.txt -covermode=atomic + - go test -v -race -db="mysql" -conn_str="root:@tcp(mysql)/xorm_test?charset=utf8mb4" -cache=true -coverprofile=coverage2.1-2.txt -covermode=atomic + when: + event: [ push, pull_request ] + + test-mymysql: + image: golang:${GO_VERSION} + commands: + - go test -v -race -db="mymysql" -conn_str="tcp:mysql:3306*xorm_test/root/" -coverprofile=coverage3-1.txt -covermode=atomic + - go test -v -race -db="mymysql" -conn_str="tcp:mysql:3306*xorm_test/root/" -cache=true -coverprofile=coverage3-2.txt -covermode=atomic + when: + event: [ push, pull_request ] + + test-postgres: + image: golang:${GO_VERSION} + commands: + - go test -v -race -db="postgres" -conn_str="postgres://postgres:@pgsql/xorm_test?sslmode=disable" -coverprofile=coverage4-1.txt -covermode=atomic + - go test -v -race -db="postgres" -conn_str="postgres://postgres:@pgsql/xorm_test?sslmode=disable" -cache=true -coverprofile=coverage4-2.txt -covermode=atomic + when: + event: [ push, pull_request ] + + test-postgres-schema: + image: golang:${GO_VERSION} + commands: + - go test -v -race -db="postgres" -conn_str="postgres://postgres:@pgsql/xorm_test?sslmode=disable" -schema=xorm -coverprofile=coverage5-1.txt -covermode=atomic + - go test -v -race -db="postgres" -conn_str="postgres://postgres:@pgsql/xorm_test?sslmode=disable" -schema=xorm -cache=true -coverprofile=coverage5-2.txt -covermode=atomic + - gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt > coverage.txt + when: + event: [ push, pull_request ] + + #coverage: + # image: robertstettner/drone-codecov + # secrets: [ codecov_token ] + # files: + # - coverage.txt + # when: + # event: [ push, pull_request ] + # branch: [ master ] \ No newline at end of file diff --git a/vendor/github.com/go-xorm/xorm/context.go b/vendor/github.com/go-xorm/xorm/context.go new file mode 100644 index 000000000..074ba35a8 --- /dev/null +++ b/vendor/github.com/go-xorm/xorm/context.go @@ -0,0 +1,26 @@ +// Copyright 2017 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build go1.8 + +package xorm + +import "context" + +// PingContext tests if database is alive +func (engine *Engine) PingContext(ctx context.Context) error { + session := engine.NewSession() + defer session.Close() + return session.PingContext(ctx) +} + +// PingContext test if database is ok +func (session *Session) PingContext(ctx context.Context) error { + if session.isAutoClose { + defer session.Close() + } + + session.engine.logger.Infof("PING DATABASE %v", session.engine.DriverName()) + return session.DB().PingContext(ctx) +} diff --git a/vendor/github.com/go-xorm/xorm/context_cache.go b/vendor/github.com/go-xorm/xorm/context_cache.go new file mode 100644 index 000000000..1bc228849 --- /dev/null +++ b/vendor/github.com/go-xorm/xorm/context_cache.go @@ -0,0 +1,30 @@ +// Copyright 2018 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xorm + +// ContextCache is the interface that operates the cache data. +type ContextCache interface { + // Put puts value into cache with key. + Put(key string, val interface{}) + // Get gets cached value by given key. + Get(key string) interface{} +} + +type memoryContextCache map[string]interface{} + +// NewMemoryContextCache return memoryContextCache +func NewMemoryContextCache() memoryContextCache { + return make(map[string]interface{}) +} + +// Put puts value into cache with key. +func (m memoryContextCache) Put(key string, val interface{}) { + m[key] = val +} + +// Get gets cached value by given key. +func (m memoryContextCache) Get(key string) interface{} { + return m[key] +} diff --git a/vendor/github.com/go-xorm/xorm/engine_group.go b/vendor/github.com/go-xorm/xorm/engine_group.go new file mode 100644 index 000000000..5eee3e618 --- /dev/null +++ b/vendor/github.com/go-xorm/xorm/engine_group.go @@ -0,0 +1,204 @@ +// Copyright 2017 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xorm + +import ( + "time" + + "github.com/go-xorm/core" +) + +// EngineGroup defines an engine group +type EngineGroup struct { + *Engine + slaves []*Engine + policy GroupPolicy +} + +// NewEngineGroup creates a new engine group +func NewEngineGroup(args1 interface{}, args2 interface{}, policies ...GroupPolicy) (*EngineGroup, error) { + var eg EngineGroup + if len(policies) > 0 { + eg.policy = policies[0] + } else { + eg.policy = RoundRobinPolicy() + } + + driverName, ok1 := args1.(string) + conns, ok2 := args2.([]string) + if ok1 && ok2 { + engines := make([]*Engine, len(conns)) + for i, conn := range conns { + engine, err := NewEngine(driverName, conn) + if err != nil { + return nil, err + } + engine.engineGroup = &eg + engines[i] = engine + } + + eg.Engine = engines[0] + eg.slaves = engines[1:] + return &eg, nil + } + + master, ok3 := args1.(*Engine) + slaves, ok4 := args2.([]*Engine) + if ok3 && ok4 { + master.engineGroup = &eg + for i := 0; i < len(slaves); i++ { + slaves[i].engineGroup = &eg + } + eg.Engine = master + eg.slaves = slaves + return &eg, nil + } + return nil, ErrParamsType +} + +// Close the engine +func (eg *EngineGroup) Close() error { + err := eg.Engine.Close() + if err != nil { + return err + } + + for i := 0; i < len(eg.slaves); i++ { + err := eg.slaves[i].Close() + if err != nil { + return err + } + } + return nil +} + +// Master returns the master engine +func (eg *EngineGroup) Master() *Engine { + return eg.Engine +} + +// Ping tests if database is alive +func (eg *EngineGroup) Ping() error { + if err := eg.Engine.Ping(); err != nil { + return err + } + + for _, slave := range eg.slaves { + if err := slave.Ping(); err != nil { + return err + } + } + return nil +} + +// SetColumnMapper set the column name mapping rule +func (eg *EngineGroup) SetColumnMapper(mapper core.IMapper) { + eg.Engine.ColumnMapper = mapper + for i := 0; i < len(eg.slaves); i++ { + eg.slaves[i].ColumnMapper = mapper + } +} + +// SetConnMaxLifetime sets the maximum amount of time a connection may be reused. +func (eg *EngineGroup) SetConnMaxLifetime(d time.Duration) { + eg.Engine.SetConnMaxLifetime(d) + for i := 0; i < len(eg.slaves); i++ { + eg.slaves[i].SetConnMaxLifetime(d) + } +} + +// SetDefaultCacher set the default cacher +func (eg *EngineGroup) SetDefaultCacher(cacher core.Cacher) { + eg.Engine.SetDefaultCacher(cacher) + for i := 0; i < len(eg.slaves); i++ { + eg.slaves[i].SetDefaultCacher(cacher) + } +} + +// SetLogger set the new logger +func (eg *EngineGroup) SetLogger(logger core.ILogger) { + eg.Engine.SetLogger(logger) + for i := 0; i < len(eg.slaves); i++ { + eg.slaves[i].SetLogger(logger) + } +} + +// SetLogLevel sets the logger level +func (eg *EngineGroup) SetLogLevel(level core.LogLevel) { + eg.Engine.SetLogLevel(level) + for i := 0; i < len(eg.slaves); i++ { + eg.slaves[i].SetLogLevel(level) + } +} + +// SetMapper set the name mapping rules +func (eg *EngineGroup) SetMapper(mapper core.IMapper) { + eg.Engine.SetMapper(mapper) + for i := 0; i < len(eg.slaves); i++ { + eg.slaves[i].SetMapper(mapper) + } +} + +// SetMaxIdleConns set the max idle connections on pool, default is 2 +func (eg *EngineGroup) SetMaxIdleConns(conns int) { + eg.Engine.db.SetMaxIdleConns(conns) + for i := 0; i < len(eg.slaves); i++ { + eg.slaves[i].db.SetMaxIdleConns(conns) + } +} + +// SetMaxOpenConns is only available for go 1.2+ +func (eg *EngineGroup) SetMaxOpenConns(conns int) { + eg.Engine.db.SetMaxOpenConns(conns) + for i := 0; i < len(eg.slaves); i++ { + eg.slaves[i].db.SetMaxOpenConns(conns) + } +} + +// SetPolicy set the group policy +func (eg *EngineGroup) SetPolicy(policy GroupPolicy) *EngineGroup { + eg.policy = policy + return eg +} + +// SetTableMapper set the table name mapping rule +func (eg *EngineGroup) SetTableMapper(mapper core.IMapper) { + eg.Engine.TableMapper = mapper + for i := 0; i < len(eg.slaves); i++ { + eg.slaves[i].TableMapper = mapper + } +} + +// ShowExecTime show SQL statement and execute time or not on logger if log level is great than INFO +func (eg *EngineGroup) ShowExecTime(show ...bool) { + eg.Engine.ShowExecTime(show...) + for i := 0; i < len(eg.slaves); i++ { + eg.slaves[i].ShowExecTime(show...) + } +} + +// ShowSQL show SQL statement or not on logger if log level is great than INFO +func (eg *EngineGroup) ShowSQL(show ...bool) { + eg.Engine.ShowSQL(show...) + for i := 0; i < len(eg.slaves); i++ { + eg.slaves[i].ShowSQL(show...) + } +} + +// Slave returns one of the physical databases which is a slave according the policy +func (eg *EngineGroup) Slave() *Engine { + switch len(eg.slaves) { + case 0: + return eg.Engine + case 1: + return eg.slaves[0] + } + return eg.policy.Slave(eg) +} + +// Slaves returns all the slaves +func (eg *EngineGroup) Slaves() []*Engine { + return eg.slaves +} diff --git a/vendor/github.com/go-xorm/xorm/engine_group_policy.go b/vendor/github.com/go-xorm/xorm/engine_group_policy.go new file mode 100644 index 000000000..5b56e8995 --- /dev/null +++ b/vendor/github.com/go-xorm/xorm/engine_group_policy.go @@ -0,0 +1,116 @@ +// Copyright 2017 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xorm + +import ( + "math/rand" + "sync" + "time" +) + +// GroupPolicy is be used by chosing the current slave from slaves +type GroupPolicy interface { + Slave(*EngineGroup) *Engine +} + +// GroupPolicyHandler should be used when a function is a GroupPolicy +type GroupPolicyHandler func(*EngineGroup) *Engine + +// Slave implements the chosen of slaves +func (h GroupPolicyHandler) Slave(eg *EngineGroup) *Engine { + return h(eg) +} + +// RandomPolicy implmentes randomly chose the slave of slaves +func RandomPolicy() GroupPolicyHandler { + var r = rand.New(rand.NewSource(time.Now().UnixNano())) + return func(g *EngineGroup) *Engine { + return g.Slaves()[r.Intn(len(g.Slaves()))] + } +} + +// WeightRandomPolicy implmentes randomly chose the slave of slaves +func WeightRandomPolicy(weights []int) GroupPolicyHandler { + var rands = make([]int, 0, len(weights)) + for i := 0; i < len(weights); i++ { + for n := 0; n < weights[i]; n++ { + rands = append(rands, i) + } + } + var r = rand.New(rand.NewSource(time.Now().UnixNano())) + + return func(g *EngineGroup) *Engine { + var slaves = g.Slaves() + idx := rands[r.Intn(len(rands))] + if idx >= len(slaves) { + idx = len(slaves) - 1 + } + return slaves[idx] + } +} + +func RoundRobinPolicy() GroupPolicyHandler { + var pos = -1 + var lock sync.Mutex + return func(g *EngineGroup) *Engine { + var slaves = g.Slaves() + + lock.Lock() + defer lock.Unlock() + pos++ + if pos >= len(slaves) { + pos = 0 + } + + return slaves[pos] + } +} + +func WeightRoundRobinPolicy(weights []int) GroupPolicyHandler { + var rands = make([]int, 0, len(weights)) + for i := 0; i < len(weights); i++ { + for n := 0; n < weights[i]; n++ { + rands = append(rands, i) + } + } + var pos = -1 + var lock sync.Mutex + + return func(g *EngineGroup) *Engine { + var slaves = g.Slaves() + lock.Lock() + defer lock.Unlock() + pos++ + if pos >= len(rands) { + pos = 0 + } + + idx := rands[pos] + if idx >= len(slaves) { + idx = len(slaves) - 1 + } + return slaves[idx] + } +} + +// LeastConnPolicy implements GroupPolicy, every time will get the least connections slave +func LeastConnPolicy() GroupPolicyHandler { + return func(g *EngineGroup) *Engine { + var slaves = g.Slaves() + connections := 0 + idx := 0 + for i := 0; i < len(slaves); i++ { + openConnections := slaves[i].DB().Stats().OpenConnections + if i == 0 { + connections = openConnections + idx = i + } else if openConnections <= connections { + connections = openConnections + idx = i + } + } + return slaves[idx] + } +} diff --git a/vendor/github.com/go-xorm/xorm/engine_table.go b/vendor/github.com/go-xorm/xorm/engine_table.go new file mode 100644 index 000000000..94871a4bc --- /dev/null +++ b/vendor/github.com/go-xorm/xorm/engine_table.go @@ -0,0 +1,113 @@ +// Copyright 2018 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xorm + +import ( + "fmt" + "reflect" + "strings" + + "github.com/go-xorm/core" +) + +// TableNameWithSchema will automatically add schema prefix on table name +func (engine *Engine) tbNameWithSchema(v string) string { + // Add schema name as prefix of table name. + // Only for postgres database. + if engine.dialect.DBType() == core.POSTGRES && + engine.dialect.URI().Schema != "" && + engine.dialect.URI().Schema != postgresPublicSchema && + strings.Index(v, ".") == -1 { + return engine.dialect.URI().Schema + "." + v + } + return v +} + +// TableName returns table name with schema prefix if has +func (engine *Engine) TableName(bean interface{}, includeSchema ...bool) string { + tbName := engine.tbNameNoSchema(bean) + if len(includeSchema) > 0 && includeSchema[0] { + tbName = engine.tbNameWithSchema(tbName) + } + + return tbName +} + +// tbName get some table's table name +func (session *Session) tbNameNoSchema(table *core.Table) string { + if len(session.statement.AltTableName) > 0 { + return session.statement.AltTableName + } + + return table.Name +} + +func (engine *Engine) tbNameForMap(v reflect.Value) string { + if v.Type().Implements(tpTableName) { + return v.Interface().(TableName).TableName() + } + if v.Kind() == reflect.Ptr { + v = v.Elem() + if v.Type().Implements(tpTableName) { + return v.Interface().(TableName).TableName() + } + } + + return engine.TableMapper.Obj2Table(v.Type().Name()) +} + +func (engine *Engine) tbNameNoSchema(tablename interface{}) string { + switch tablename.(type) { + case []string: + t := tablename.([]string) + if len(t) > 1 { + return fmt.Sprintf("%v AS %v", engine.Quote(t[0]), engine.Quote(t[1])) + } else if len(t) == 1 { + return engine.Quote(t[0]) + } + case []interface{}: + t := tablename.([]interface{}) + l := len(t) + var table string + if l > 0 { + f := t[0] + switch f.(type) { + case string: + table = f.(string) + case TableName: + table = f.(TableName).TableName() + default: + v := rValue(f) + t := v.Type() + if t.Kind() == reflect.Struct { + table = engine.tbNameForMap(v) + } else { + table = engine.Quote(fmt.Sprintf("%v", f)) + } + } + } + if l > 1 { + return fmt.Sprintf("%v AS %v", engine.Quote(table), + engine.Quote(fmt.Sprintf("%v", t[1]))) + } else if l == 1 { + return engine.Quote(table) + } + case TableName: + return tablename.(TableName).TableName() + case string: + return tablename.(string) + case reflect.Value: + v := tablename.(reflect.Value) + return engine.tbNameForMap(v) + default: + v := rValue(tablename) + t := v.Type() + if t.Kind() == reflect.Struct { + return engine.tbNameForMap(v) + } + return engine.Quote(fmt.Sprintf("%v", tablename)) + } + return "" +} diff --git a/vendor/github.com/go-xorm/xorm/go.mod b/vendor/github.com/go-xorm/xorm/go.mod new file mode 100644 index 000000000..185616955 --- /dev/null +++ b/vendor/github.com/go-xorm/xorm/go.mod @@ -0,0 +1,24 @@ +module github.com/go-xorm/xorm + +require ( + github.com/cockroachdb/apd v1.1.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/denisenkom/go-mssqldb v0.0.0-20181014144952-4e0d7dc8888f + github.com/go-sql-driver/mysql v1.4.0 + github.com/go-xorm/builder v0.3.2 + github.com/go-xorm/core v0.6.0 + github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a // indirect + github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect + github.com/jackc/pgx v3.2.0+incompatible + github.com/kr/pretty v0.1.0 // indirect + github.com/lib/pq v1.0.0 + github.com/mattn/go-sqlite3 v1.9.0 + github.com/pkg/errors v0.8.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/satori/go.uuid v1.2.0 // indirect + github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 // indirect + github.com/stretchr/testify v1.2.2 + github.com/ziutek/mymysql v1.5.4 + gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect + gopkg.in/stretchr/testify.v1 v1.2.2 +) diff --git a/vendor/github.com/go-xorm/xorm/go.sum b/vendor/github.com/go-xorm/xorm/go.sum new file mode 100644 index 000000000..dbf757d1d --- /dev/null +++ b/vendor/github.com/go-xorm/xorm/go.sum @@ -0,0 +1,43 @@ +github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= +github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= +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 h1:WH0w/R4Yoey+04HhFxqZ6VX6I0d7RMyw5aXQ9UTvQPs= +github.com/denisenkom/go-mssqldb v0.0.0-20181014144952-4e0d7dc8888f/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc= +github.com/go-sql-driver/mysql v1.4.0 h1:7LxgVwFb2hIQtMm87NdgAVfXjnt4OePseqT1tKx+opk= +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 h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y= +github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM= +github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc= +github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= +github.com/jackc/pgx v3.2.0+incompatible h1:0Vihzu20St42/UDsvZGdNE6jak7oi/UOeMzwMPHkgFY= +github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +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 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4= +github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= +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 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE= +github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= +github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= +github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/stretchr/testify.v1 v1.2.2 h1:yhQC6Uy5CqibAIlk1wlusa/MJ3iAN49/BsR/dCCKz3M= +gopkg.in/stretchr/testify.v1 v1.2.2/go.mod h1:QI5V/q6UbPmuhtm10CaFZxED9NreB8PnFYN9JcR6TxU= diff --git a/vendor/github.com/go-xorm/xorm/interface.go b/vendor/github.com/go-xorm/xorm/interface.go new file mode 100644 index 000000000..33d2078e4 --- /dev/null +++ b/vendor/github.com/go-xorm/xorm/interface.go @@ -0,0 +1,116 @@ +// Copyright 2017 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xorm + +import ( + "database/sql" + "reflect" + "time" + + "github.com/go-xorm/core" +) + +// Interface defines the interface which Engine, EngineGroup and Session will implementate. +type Interface interface { + AllCols() *Session + Alias(alias string) *Session + Asc(colNames ...string) *Session + BufferSize(size int) *Session + Cols(columns ...string) *Session + Count(...interface{}) (int64, error) + CreateIndexes(bean interface{}) error + CreateUniques(bean interface{}) error + Decr(column string, arg ...interface{}) *Session + Desc(...string) *Session + Delete(interface{}) (int64, error) + Distinct(columns ...string) *Session + DropIndexes(bean interface{}) error + Exec(sqlOrAgrs ...interface{}) (sql.Result, error) + Exist(bean ...interface{}) (bool, error) + Find(interface{}, ...interface{}) error + FindAndCount(interface{}, ...interface{}) (int64, error) + Get(interface{}) (bool, error) + GroupBy(keys string) *Session + ID(interface{}) *Session + In(string, ...interface{}) *Session + Incr(column string, arg ...interface{}) *Session + Insert(...interface{}) (int64, error) + InsertOne(interface{}) (int64, error) + IsTableEmpty(bean interface{}) (bool, error) + IsTableExist(beanOrTableName interface{}) (bool, error) + Iterate(interface{}, IterFunc) error + Limit(int, ...int) *Session + MustCols(columns ...string) *Session + NoAutoCondition(...bool) *Session + NotIn(string, ...interface{}) *Session + Join(joinOperator string, tablename interface{}, condition string, args ...interface{}) *Session + Omit(columns ...string) *Session + OrderBy(order string) *Session + Ping() error + Query(sqlOrAgrs ...interface{}) (resultsSlice []map[string][]byte, err error) + QueryInterface(sqlorArgs ...interface{}) ([]map[string]interface{}, error) + QueryString(sqlorArgs ...interface{}) ([]map[string]string, error) + Rows(bean interface{}) (*Rows, error) + SetExpr(string, string) *Session + SQL(interface{}, ...interface{}) *Session + Sum(bean interface{}, colName string) (float64, error) + SumInt(bean interface{}, colName string) (int64, error) + Sums(bean interface{}, colNames ...string) ([]float64, error) + SumsInt(bean interface{}, colNames ...string) ([]int64, error) + Table(tableNameOrBean interface{}) *Session + Unscoped() *Session + Update(bean interface{}, condiBeans ...interface{}) (int64, error) + UseBool(...string) *Session + Where(interface{}, ...interface{}) *Session +} + +// EngineInterface defines the interface which Engine, EngineGroup will implementate. +type EngineInterface interface { + Interface + + Before(func(interface{})) *Session + Charset(charset string) *Session + ClearCache(...interface{}) error + CreateTables(...interface{}) error + DBMetas() ([]*core.Table, error) + Dialect() core.Dialect + DropTables(...interface{}) error + DumpAllToFile(fp string, tp ...core.DbType) error + GetCacher(string) core.Cacher + GetColumnMapper() core.IMapper + GetDefaultCacher() core.Cacher + GetTableMapper() core.IMapper + GetTZDatabase() *time.Location + GetTZLocation() *time.Location + MapCacher(interface{}, core.Cacher) error + NewSession() *Session + NoAutoTime() *Session + Quote(string) string + SetCacher(string, core.Cacher) + SetConnMaxLifetime(time.Duration) + SetDefaultCacher(core.Cacher) + SetLogger(logger core.ILogger) + SetLogLevel(core.LogLevel) + SetMapper(core.IMapper) + SetMaxOpenConns(int) + SetMaxIdleConns(int) + SetSchema(string) + SetTZDatabase(tz *time.Location) + SetTZLocation(tz *time.Location) + ShowExecTime(...bool) + ShowSQL(show ...bool) + Sync(...interface{}) error + Sync2(...interface{}) error + StoreEngine(storeEngine string) *Session + TableInfo(bean interface{}) *Table + TableName(interface{}, ...bool) string + UnMapType(reflect.Type) +} + +var ( + _ Interface = &Session{} + _ EngineInterface = &Engine{} + _ EngineInterface = &EngineGroup{} +) diff --git a/vendor/github.com/go-xorm/xorm/transaction.go b/vendor/github.com/go-xorm/xorm/transaction.go new file mode 100644 index 000000000..4104103fd --- /dev/null +++ b/vendor/github.com/go-xorm/xorm/transaction.go @@ -0,0 +1,26 @@ +// Copyright 2018 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xorm + +// Transaction Execute sql wrapped in a transaction(abbr as tx), tx will automatic commit if no errors occurred +func (engine *Engine) Transaction(f func(*Session) (interface{}, error)) (interface{}, error) { + session := engine.NewSession() + defer session.Close() + + if err := session.Begin(); err != nil { + return nil, err + } + + result, err := f(session) + if err != nil { + return nil, err + } + + if err := session.Commit(); err != nil { + return nil, err + } + + return result, nil +} diff --git a/vendor/src.techknowlogick.com/xormigrate/.drone.yml b/vendor/src.techknowlogick.com/xormigrate/.drone.yml new file mode 100644 index 000000000..f222772a5 --- /dev/null +++ b/vendor/src.techknowlogick.com/xormigrate/.drone.yml @@ -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 diff --git a/vendor/src.techknowlogick.com/xormigrate/.env b/vendor/src.techknowlogick.com/xormigrate/.env new file mode 100644 index 000000000..d190de508 --- /dev/null +++ b/vendor/src.techknowlogick.com/xormigrate/.env @@ -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" diff --git a/vendor/src.techknowlogick.com/xormigrate/LICENSE b/vendor/src.techknowlogick.com/xormigrate/LICENSE new file mode 100644 index 000000000..f4dbc70e0 --- /dev/null +++ b/vendor/src.techknowlogick.com/xormigrate/LICENSE @@ -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. diff --git a/vendor/src.techknowlogick.com/xormigrate/README.md b/vendor/src.techknowlogick.com/xormigrate/README.md new file mode 100644 index 000000000..5c64fe834 --- /dev/null +++ b/vendor/src.techknowlogick.com/xormigrate/README.md @@ -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 diff --git a/vendor/src.techknowlogick.com/xormigrate/go.mod b/vendor/src.techknowlogick.com/xormigrate/go.mod new file mode 100644 index 000000000..d578f6bcd --- /dev/null +++ b/vendor/src.techknowlogick.com/xormigrate/go.mod @@ -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 +) diff --git a/vendor/src.techknowlogick.com/xormigrate/go.sum b/vendor/src.techknowlogick.com/xormigrate/go.sum new file mode 100644 index 000000000..2b926358b --- /dev/null +++ b/vendor/src.techknowlogick.com/xormigrate/go.sum @@ -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= diff --git a/vendor/src.techknowlogick.com/xormigrate/logger.go b/vendor/src.techknowlogick.com/xormigrate/logger.go new file mode 100644 index 000000000..cd4c5e756 --- /dev/null +++ b/vendor/src.techknowlogick.com/xormigrate/logger.go @@ -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...) +} diff --git a/vendor/src.techknowlogick.com/xormigrate/renovate.json b/vendor/src.techknowlogick.com/xormigrate/renovate.json new file mode 100644 index 000000000..f45d8f110 --- /dev/null +++ b/vendor/src.techknowlogick.com/xormigrate/renovate.json @@ -0,0 +1,5 @@ +{ + "extends": [ + "config:base" + ] +} diff --git a/vendor/src.techknowlogick.com/xormigrate/xormigrate.go b/vendor/src.techknowlogick.com/xormigrate/xormigrate.go new file mode 100644 index 000000000..709ea603d --- /dev/null +++ b/vendor/src.techknowlogick.com/xormigrate/xormigrate.go @@ -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 +}