3
0

add(all): database migrations prod

This commit is contained in:
Tit Petric
2018-10-08 16:04:20 +02:00
parent 5606f0b957
commit 102a162108
17 changed files with 246 additions and 32 deletions
+108
View File
@@ -0,0 +1,108 @@
package db
import (
"fmt"
"log"
"os"
"path/filepath"
"regexp"
"sort"
"strings"
_ "github.com/crusttech/crust/auth/db/mysql"
"github.com/pkg/errors"
"github.com/rakyll/statik/fs"
"github.com/titpetric/factory"
)
//go:generate statik -p mysql -Z -f -src=schema/mysql
func statements(contents []byte, err error) ([]string, error) {
if err != nil {
return []string{}, err
}
return regexp.MustCompilePOSIX(";$").Split(string(contents), -1), nil
}
func Migrate(db *factory.DB) error {
statikFS, err := fs.New()
if err != nil {
return errors.Wrap(err, "Error creating statik filesystem")
}
var files []string
if err := fs.Walk(statikFS, "/", func(filename string, info os.FileInfo, err error) error {
matched, err := filepath.Match("/*.up.sql", filename)
if matched {
files = append(files, filename)
}
return err
}); err != nil {
return errors.Wrap(err, "Error when listing files for migrations")
}
sort.Strings(files)
if len(files) == 0 {
return errors.New("No files encoded for migration, need at least one SQL file")
}
migrate := func(filename string, useLog bool) error {
status := migration{
Project: "auth",
Filename: filename,
}
if useLog {
if err := db.Get(&status, "select * from migrations where project=? and filename=?", status.Project, status.Filename); err != nil {
return err
}
if status.Status == "ok" {
return nil
}
}
up := func() error {
stmts, err := statements(fs.ReadFile(statikFS, filename))
if err != nil {
return errors.Wrap(err, fmt.Sprintf("Error reading migration %s", filename))
}
log.Println("Running migration for", filename)
for idx, query := range stmts {
if strings.TrimSpace(query) != "" && idx >= status.StatementIndex {
status.StatementIndex = idx
if _, err := db.Exec(query); err != nil {
return err
}
}
}
log.Println("Migration done OK")
status.Status = "ok"
return nil
}
err := db.Transaction(up)
if err != nil {
status.Status = err.Error()
}
if useLog {
if err := db.Replace("migrations", status); err != nil {
log.Println("replace failed", err)
}
}
return err
}
if err := migrate("/migrations.sql", false); err != nil {
return err
}
for _, filename := range files {
if err := migrate(filename, true); err != nil {
return err
}
}
return nil
}
+42
View File
@@ -0,0 +1,42 @@
package db
import (
"context"
"log"
"testing"
"time"
"github.com/titpetric/dockertest"
"github.com/titpetric/factory"
)
func TestMigrations(t *testing.T) {
args := []string{
// "--rm",
"-e", "MYSQL_ROOT_PASSWORD=root",
"-e", "MYSQL_DATABASE=test",
}
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(30*time.Second))
defer cancel()
count := 0
mysql, err := dockertest.RunContainerContext(ctx, "titpetric/percona-xtrabackup", "3306", func(addr string) error {
factory.Database.Add("default", "root:root@tcp("+addr+")/test?collation=utf8mb4_general_ci")
log.Println(addr)
_, err := factory.Database.Get()
count++
time.Sleep(time.Second)
return err
}, args...)
defer mysql.Terminate() // Shutdown()
if err != nil {
t.Fatalf("Error starting mysql: %#v", err)
}
db := factory.Database.MustGet()
if err := Migrate(db); err != nil {
t.Fatalf("Unexpected error: %#v", err)
}
}
+13
View File
@@ -0,0 +1,13 @@
// Code generated by statik. DO NOT EDIT.
// Package statik contains static assets.
package mysql
import (
"github.com/rakyll/statik/fs"
)
func init() {
data := "PK\x03\x04\x14\x00\x08\x00\x00\x00WBAM\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1a\x00 \x0020180704080000.base.up.sqlUT\x05\x00\x01g\xd8\xb1[CREATE TABLE settings (\n name VARCHAR(200) NOT NULL COMMENT 'Unique set of setting keys',\n value TEXT COMMENT 'Setting value',\n\n PRIMARY KEY (name)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\n-- Keeps all known users, home and external organisation\n-- changes are stored in audit log\nCREATE TABLE users (\n id BIGINT UNSIGNED NOT NULL,\n email TEXT NOT NULL,\n username TEXT NOT NULL,\n password TEXT NOT NULL,\n name TEXT NOT NULL,\n handle TEXT NOT NULL,\n meta JSON NOT NULL,\n satosa_id CHAR(36) NULL,\n\n rel_organisation BIGINT UNSIGNED NOT NULL,\n\n created_at DATETIME NOT NULL DEFAULT NOW(),\n updated_at DATETIME NULL,\n suspended_at DATETIME NULL,\n deleted_at DATETIME NULL, -- user soft delete\n\n PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nCREATE UNIQUE INDEX uid_satosa ON users (satosa_id);\nPK\x07\x08>\xa7\xd7\x12$\x04\x00\x00$\x04\x00\x00PK\x03\x04\x14\x00\x08\x00\x00\x00\xc0kHM\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00 \x00migrations.sqlUT\x05\x00\x01\xd9[\xbb[CREATE TABLE IF NOT EXISTS `migrations` (\n `project` varchar(16) NOT NULL COMMENT 'sam, crm, ...',\n `filename` varchar(255) NOT NULL COMMENT 'yyyymmddHHMMSS.sql',\n `statement_index` int(11) NOT NULL COMMENT 'Statement number from SQL file',\n `status` varchar(16) NOT NULL COMMENT 'ok or full error message',\n PRIMARY KEY (`project`,`filename`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nPK\x07\x08%l\xb2\x16\x7f\x01\x00\x00\x7f\x01\x00\x00PK\x01\x02\x14\x03\x14\x00\x08\x00\x00\x00WBAM>\xa7\xd7\x12$\x04\x00\x00$\x04\x00\x00\x1a\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00\x00\x00\x0020180704080000.base.up.sqlUT\x05\x00\x01g\xd8\xb1[PK\x01\x02\x14\x03\x14\x00\x08\x00\x00\x00\xc0kHM%l\xb2\x16\x7f\x01\x00\x00\x7f\x01\x00\x00\x0e\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81u\x04\x00\x00migrations.sqlUT\x05\x00\x01\xd9[\xbb[PK\x05\x06\x00\x00\x00\x00\x02\x00\x02\x00\x96\x00\x00\x009\x06\x00\x00\x00\x00"
fs.Register(data)
}
+8
View File
@@ -0,0 +1,8 @@
CREATE TABLE IF NOT EXISTS `migrations` (
`project` varchar(16) NOT NULL COMMENT 'sam, crm, ...',
`filename` varchar(255) NOT NULL COMMENT 'yyyymmddHHMMSS.sql',
`statement_index` int(11) NOT NULL COMMENT 'Statement number from SQL file',
`status` varchar(16) NOT NULL COMMENT 'ok or full error message',
PRIMARY KEY (`project`,`filename`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+8
View File
@@ -0,0 +1,8 @@
package db
type migration struct {
Project string `db:"project"`
Filename string `db:"filename"`
StatementIndex int `db:"statement_index"`
Status string `db:"status"`
}
+9 -2
View File
@@ -7,14 +7,15 @@ import (
"net/http"
"github.com/SentimensRG/ctx/sigctx"
"github.com/crusttech/crust/auth/rest"
"github.com/crusttech/crust/auth/service"
"github.com/go-chi/chi"
"github.com/go-chi/cors"
"github.com/pkg/errors"
"github.com/titpetric/factory"
"github.com/titpetric/factory/resputil"
migrate "github.com/crusttech/crust/auth/db"
"github.com/crusttech/crust/auth/rest"
"github.com/crusttech/crust/auth/service"
"github.com/crusttech/crust/internal/auth"
)
@@ -30,6 +31,7 @@ func Init() error {
if err != nil {
return err
}
// @todo: profiling as an external service?
switch flags.db.Profiler {
case "stdout":
@@ -38,6 +40,11 @@ func Init() error {
fmt.Println("No database query profiler selected")
}
// migrate database schema
if err := migrate.Migrate(db); err != nil {
return err
}
// configure resputil options
resputil.SetConfig(resputil.Options{
Pretty: flags.http.Pretty,
+6
View File
@@ -12,6 +12,11 @@ function gofmt {
done
}
echo "=== go generate ==="
cd auth/db && go generate && cd ../..
cd crm/db && go generate && cd ../..
cd sam/db && go generate && cd ../..
_PWD=$PWD
SPECS=$(find $PWD -name 'spec.json' | xargs -n1 dirname)
for SPEC in $SPECS; do
@@ -33,4 +38,5 @@ go run sam/types/permissions/main.go -package types -function "func (c *Organisa
go run sam/types/permissions/main.go -package types -function "func (c *Team) Permissions() []rbac.OperationGroup" -input sam/types/permissions/2-team.json -output sam/types/team_perms.go
go run sam/types/permissions/main.go -package types -function "func (c *Channel) Permissions() []rbac.OperationGroup" -input sam/types/permissions/3-channel.json -output sam/types/channel_perms.go
gofmt
+8 -13
View File
@@ -24,13 +24,6 @@ func statements(contents []byte, err error) ([]string, error) {
return regexp.MustCompilePOSIX(";$").Split(string(contents), -1), nil
}
type migration struct {
Project string
Filename string
StatementIndex int `db:"statement_index"`
Status string
}
func Migrate(db *factory.DB) error {
statikFS, err := fs.New()
if err != nil {
@@ -89,14 +82,16 @@ func Migrate(db *factory.DB) error {
return nil
}
if err := db.Transaction(up); err != nil {
err := db.Transaction(up)
if err != nil {
status.Status = err.Error()
if useLog {
db.Replace("migrations", status)
}
return err
}
return nil
if useLog {
if err := db.Replace("migrations", status); err != nil {
log.Println("replace failed", err)
}
}
return err
}
if err := migrate("/migrations.sql", false); err != nil {
+1 -1
View File
@@ -8,6 +8,6 @@ import (
)
func init() {
data := "PK\x03\x04\x14\x00\x08\x00\x00\x00\xdaeHM\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1a\x00 \x0020180704080000.base.up.sqlUT\x05\x00\x01\xbcQ\xbb[CREATE TABLE `crm_content` (\n `id` bigint(20) unsigned NOT NULL,\n `module_id` bigint(20) unsigned NOT NULL,\n `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,\n `updated_at` datetime DEFAULT NULL,\n `archived_at` datetime DEFAULT NULL,\n `deleted_at` datetime DEFAULT NULL,\n PRIMARY KEY (`id`,`module_id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nCREATE TABLE `crm_content_columns` (\n `content_id` bigint(20) NOT NULL,\n `column_name` varchar(255) NOT NULL,\n `column_value` text NOT NULL,\n PRIMARY KEY (`content_id`,`column_name`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nCREATE TABLE `crm_fields` (\n `field_type` varchar(16) NOT NULL COMMENT 'Short field type (string, boolean,...)',\n `field_name` varchar(255) NOT NULL COMMENT 'Description of field contents',\n `field_template` varchar(255) NOT NULL COMMENT 'HTML template file for field',\n PRIMARY KEY (`field_type`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nCREATE TABLE `crm_module` (\n `id` bigint(20) unsigned NOT NULL,\n `name` varchar(64) NOT NULL COMMENT 'The name of the module',\n `json` json NOT NULL COMMENT 'List of field definitions for the module',\n PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nCREATE TABLE `crm_module_form` (\n `module_id` bigint(20) unsigned NOT NULL,\n `place` tinyint(3) unsigned NOT NULL,\n `type` varchar(64) NOT NULL COMMENT 'The type of the form input field',\n `name` varchar(64) NOT NULL COMMENT 'The name of the field in the form',\n `title` varchar(255) NOT NULL COMMENT 'The label of the form input',\n `placeholder` varchar(255) NOT NULL COMMENT 'Placeholder text (if supported by input)',\n PRIMARY KEY (`module_id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nPK\x07\x08\xe9\xe8\x9a\xeex\x06\x00\x00x\x06\x00\x00PK\x03\x04\x14\x00\x08\x00\x00\x00\xdaeHM\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%\x00 \x0020180704080001.crm_fields-data.up.sqlUT\x05\x00\x01\xbcQ\xbb[INSERT INTO `crm_fields` VALUES ('bool','Boolean value (yes / no)','');\nINSERT INTO `crm_fields` VALUES ('email','E-mail input','');\nINSERT INTO `crm_fields` VALUES ('enum','Single option picker','');\nINSERT INTO `crm_fields` VALUES ('hidden','Hidden value','');\nINSERT INTO `crm_fields` VALUES ('stamp','Date/time input','');\nINSERT INTO `crm_fields` VALUES ('text','Text input','');\nINSERT INTO `crm_fields` VALUES ('textarea','Text input (multi-line)','');\nPK\x07\x08\xf8u|\xb9\xcc\x01\x00\x00\xcc\x01\x00\x00PK\x03\x04\x14\x00\x08\x00\x00\x00\xdaeHM\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00 \x00migrations.sqlUT\x05\x00\x01\xbcQ\xbb[CREATE TABLE IF NOT EXISTS `migrations` (\n `project` varchar(16) NOT NULL COMMENT 'sam, crm, ...',\n `filename` varchar(255) NOT NULL COMMENT 'yyyymmddHHMMSS.sql',\n `statement_index` int(11) NOT NULL COMMENT 'Statement number from SQL file',\n `status` varchar(16) NOT NULL COMMENT 'ok or full error message'\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nPK\x07\x08~ 9=Z\x01\x00\x00Z\x01\x00\x00PK\x01\x02\x14\x03\x14\x00\x08\x00\x00\x00\xdaeHM\xe9\xe8\x9a\xeex\x06\x00\x00x\x06\x00\x00\x1a\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00\x00\x00\x0020180704080000.base.up.sqlUT\x05\x00\x01\xbcQ\xbb[PK\x01\x02\x14\x03\x14\x00\x08\x00\x00\x00\xdaeHM\xf8u|\xb9\xcc\x01\x00\x00\xcc\x01\x00\x00%\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\xc9\x06\x00\x0020180704080001.crm_fields-data.up.sqlUT\x05\x00\x01\xbcQ\xbb[PK\x01\x02\x14\x03\x14\x00\x08\x00\x00\x00\xdaeHM~ 9=Z\x01\x00\x00Z\x01\x00\x00\x0e\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\xf1\x08\x00\x00migrations.sqlUT\x05\x00\x01\xbcQ\xbb[PK\x05\x06\x00\x00\x00\x00\x03\x00\x03\x00\xf2\x00\x00\x00\x90\n\x00\x00\x00\x00"
data := "PK\x03\x04\x14\x00\x08\x00\x00\x00\xdaeHM\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1a\x00 \x0020180704080000.base.up.sqlUT\x05\x00\x01\xbcQ\xbb[CREATE TABLE `crm_content` (\n `id` bigint(20) unsigned NOT NULL,\n `module_id` bigint(20) unsigned NOT NULL,\n `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,\n `updated_at` datetime DEFAULT NULL,\n `archived_at` datetime DEFAULT NULL,\n `deleted_at` datetime DEFAULT NULL,\n PRIMARY KEY (`id`,`module_id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nCREATE TABLE `crm_content_columns` (\n `content_id` bigint(20) NOT NULL,\n `column_name` varchar(255) NOT NULL,\n `column_value` text NOT NULL,\n PRIMARY KEY (`content_id`,`column_name`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nCREATE TABLE `crm_fields` (\n `field_type` varchar(16) NOT NULL COMMENT 'Short field type (string, boolean,...)',\n `field_name` varchar(255) NOT NULL COMMENT 'Description of field contents',\n `field_template` varchar(255) NOT NULL COMMENT 'HTML template file for field',\n PRIMARY KEY (`field_type`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nCREATE TABLE `crm_module` (\n `id` bigint(20) unsigned NOT NULL,\n `name` varchar(64) NOT NULL COMMENT 'The name of the module',\n `json` json NOT NULL COMMENT 'List of field definitions for the module',\n PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nCREATE TABLE `crm_module_form` (\n `module_id` bigint(20) unsigned NOT NULL,\n `place` tinyint(3) unsigned NOT NULL,\n `type` varchar(64) NOT NULL COMMENT 'The type of the form input field',\n `name` varchar(64) NOT NULL COMMENT 'The name of the field in the form',\n `title` varchar(255) NOT NULL COMMENT 'The label of the form input',\n `placeholder` varchar(255) NOT NULL COMMENT 'Placeholder text (if supported by input)',\n PRIMARY KEY (`module_id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nPK\x07\x08\xe9\xe8\x9a\xeex\x06\x00\x00x\x06\x00\x00PK\x03\x04\x14\x00\x08\x00\x00\x00\xdaeHM\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%\x00 \x0020180704080001.crm_fields-data.up.sqlUT\x05\x00\x01\xbcQ\xbb[INSERT INTO `crm_fields` VALUES ('bool','Boolean value (yes / no)','');\nINSERT INTO `crm_fields` VALUES ('email','E-mail input','');\nINSERT INTO `crm_fields` VALUES ('enum','Single option picker','');\nINSERT INTO `crm_fields` VALUES ('hidden','Hidden value','');\nINSERT INTO `crm_fields` VALUES ('stamp','Date/time input','');\nINSERT INTO `crm_fields` VALUES ('text','Text input','');\nINSERT INTO `crm_fields` VALUES ('textarea','Text input (multi-line)','');\nPK\x07\x08\xf8u|\xb9\xcc\x01\x00\x00\xcc\x01\x00\x00PK\x03\x04\x14\x00\x08\x00\x00\x00\xc0kHM\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00 \x00migrations.sqlUT\x05\x00\x01\xd9[\xbb[CREATE TABLE IF NOT EXISTS `migrations` (\n `project` varchar(16) NOT NULL COMMENT 'sam, crm, ...',\n `filename` varchar(255) NOT NULL COMMENT 'yyyymmddHHMMSS.sql',\n `statement_index` int(11) NOT NULL COMMENT 'Statement number from SQL file',\n `status` varchar(16) NOT NULL COMMENT 'ok or full error message',\n PRIMARY KEY (`project`,`filename`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nPK\x07\x08%l\xb2\x16\x7f\x01\x00\x00\x7f\x01\x00\x00PK\x01\x02\x14\x03\x14\x00\x08\x00\x00\x00\xdaeHM\xe9\xe8\x9a\xeex\x06\x00\x00x\x06\x00\x00\x1a\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00\x00\x00\x0020180704080000.base.up.sqlUT\x05\x00\x01\xbcQ\xbb[PK\x01\x02\x14\x03\x14\x00\x08\x00\x00\x00\xdaeHM\xf8u|\xb9\xcc\x01\x00\x00\xcc\x01\x00\x00%\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\xc9\x06\x00\x0020180704080001.crm_fields-data.up.sqlUT\x05\x00\x01\xbcQ\xbb[PK\x01\x02\x14\x03\x14\x00\x08\x00\x00\x00\xc0kHM%l\xb2\x16\x7f\x01\x00\x00\x7f\x01\x00\x00\x0e\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\xf1\x08\x00\x00migrations.sqlUT\x05\x00\x01\xd9[\xbb[PK\x05\x06\x00\x00\x00\x00\x03\x00\x03\x00\xf2\x00\x00\x00\xb5\n\x00\x00\x00\x00"
fs.Register(data)
}
+2 -1
View File
@@ -2,6 +2,7 @@ CREATE TABLE IF NOT EXISTS `migrations` (
`project` varchar(16) NOT NULL COMMENT 'sam, crm, ...',
`filename` varchar(255) NOT NULL COMMENT 'yyyymmddHHMMSS.sql',
`statement_index` int(11) NOT NULL COMMENT 'Statement number from SQL file',
`status` varchar(16) NOT NULL COMMENT 'ok or full error message'
`status` varchar(16) NOT NULL COMMENT 'ok or full error message',
PRIMARY KEY (`project`,`filename`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+8
View File
@@ -0,0 +1,8 @@
package db
type migration struct {
Project string `db:"project"`
Filename string `db:"filename"`
StatementIndex int `db:"statement_index"`
Status string `db:"status"`
}
+7
View File
@@ -13,6 +13,7 @@ import (
"github.com/titpetric/factory"
"github.com/titpetric/factory/resputil"
migrate "github.com/crusttech/crust/crm/db"
"github.com/crusttech/crust/crm/rest"
"github.com/crusttech/crust/internal/auth"
)
@@ -29,6 +30,7 @@ func Init() error {
if err != nil {
return err
}
// @todo: profiling as an external service?
switch flags.db.Profiler {
case "stdout":
@@ -37,6 +39,11 @@ func Init() error {
fmt.Println("No database query profiler selected")
}
// migrate database schema
if err := migrate.Migrate(db); err != nil {
return err
}
// configure resputil options
resputil.SetConfig(resputil.Options{
Pretty: flags.http.Pretty,
+8 -13
View File
@@ -24,13 +24,6 @@ func statements(contents []byte, err error) ([]string, error) {
return regexp.MustCompilePOSIX(";$").Split(string(contents), -1), nil
}
type migration struct {
Project string
Filename string
StatementIndex int `db:"statement_index"`
Status string
}
func Migrate(db *factory.DB) error {
statikFS, err := fs.New()
if err != nil {
@@ -89,14 +82,16 @@ func Migrate(db *factory.DB) error {
return nil
}
if err := db.Transaction(up); err != nil {
err := db.Transaction(up)
if err != nil {
status.Status = err.Error()
if useLog {
db.Replace("migrations", status)
}
return err
}
return nil
if useLog {
if err := db.Replace("migrations", status); err != nil {
log.Println("replace failed", err)
}
}
return err
}
if err := migrate("/migrations.sql", false); err != nil {
File diff suppressed because one or more lines are too long
+2 -1
View File
@@ -2,6 +2,7 @@ CREATE TABLE IF NOT EXISTS `migrations` (
`project` varchar(16) NOT NULL COMMENT 'sam, crm, ...',
`filename` varchar(255) NOT NULL COMMENT 'yyyymmddHHMMSS.sql',
`statement_index` int(11) NOT NULL COMMENT 'Statement number from SQL file',
`status` varchar(16) NOT NULL COMMENT 'ok or full error message'
`status` varchar(16) NOT NULL COMMENT 'ok or full error message',
PRIMARY KEY (`project`,`filename`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+8
View File
@@ -0,0 +1,8 @@
package db
type migration struct {
Project string `db:"project"`
Filename string `db:"filename"`
StatementIndex int `db:"statement_index"`
Status string `db:"status"`
}
+7
View File
@@ -16,6 +16,7 @@ import (
authService "github.com/crusttech/crust/auth/service"
"github.com/crusttech/crust/internal/auth"
migrate "github.com/crusttech/crust/sam/db"
"github.com/crusttech/crust/sam/rest"
samService "github.com/crusttech/crust/sam/service"
"github.com/crusttech/crust/sam/websocket"
@@ -33,6 +34,7 @@ func Init() error {
if err != nil {
return err
}
// @todo: profiling as an external service?
switch flags.db.Profiler {
case "stdout":
@@ -41,6 +43,11 @@ func Init() error {
fmt.Println("No database query profiler selected")
}
// migrate database schema
if err := migrate.Migrate(db); err != nil {
return err
}
// configure resputil options
resputil.SetConfig(resputil.Options{
Pretty: flags.http.Pretty,