Skip to content
This repository has been archived by the owner on Apr 17, 2024. It is now read-only.

refactor(db): move mysql to postgres #119

Merged
merged 6 commits into from
May 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,18 @@ jobs:
MYSQL_DATABASE: old_test_db
ports:
- 3306:3306

postgres:
image: postgres:12
env:
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- name: Install Go
uses: actions/setup-go@v2
Expand All @@ -56,6 +68,13 @@ jobs:
DBUSER: root
DBPASSWORD: cardinal_passw0rd
DBNAME: old_test_db # For old database test

PGPORT: 5432
PGHOST: localhost
PGUSER: postgres
PGPASSWORD: postgres
PGSSLMODE: disable

CARDINAL_TEST: true
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v1
Expand Down
29 changes: 17 additions & 12 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
module github.com/vidar-team/Cardinal

go 1.13
go 1.16

require (
github.com/BurntSushi/toml v0.3.1
github.com/Microsoft/go-winio v0.4.14 // indirect
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 // indirect
github.com/andybalholm/cascadia v1.1.0 // indirect
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496 // indirect
github.com/aws/aws-sdk-go v1.30.20 // indirect
github.com/containerd/containerd v1.3.6 // indirect
github.com/containerd/containerd v1.4.1 // indirect
github.com/denisenkom/go-mssqldb v0.0.0-20200620013148-b91950f658ec // indirect
github.com/disintegration/imaging v1.6.2 // indirect
github.com/docker/distribution v2.7.1+incompatible // indirect
github.com/docker/docker v17.12.0-ce-rc1.0.20200728121027-0f41a77c6993+incompatible
Expand All @@ -21,14 +21,16 @@ require (
github.com/gin-contrib/cors v1.3.0
github.com/gin-contrib/static v0.0.0-20191128031702-f81c604d8ac2
github.com/gin-gonic/gin v1.5.0
github.com/go-sql-driver/mysql v1.6.0 // indirect
github.com/gogo/protobuf v1.3.1 // indirect
github.com/gorilla/context v1.1.1 // indirect
github.com/golang/protobuf v1.4.3 // indirect
github.com/google/go-cmp v0.5.1 // indirect
github.com/gorilla/mux v1.7.4 // indirect
github.com/gorilla/sessions v1.2.0 // indirect
github.com/gorilla/websocket v1.4.2
github.com/gosimple/slug v1.9.0 // indirect
github.com/jinzhu/configor v1.2.0 // indirect
github.com/jinzhu/gorm v1.9.12
github.com/lib/pq v1.8.0 // indirect
github.com/moby/term v0.0.0-20200611042045-63b9a826fb74 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
Expand All @@ -50,7 +52,7 @@ require (
github.com/qor/session v0.0.0-20170907035918-8206b0adab70 // indirect
github.com/qor/validations v0.0.0-20171228122639-f364bca61b46 // indirect
github.com/satori/go.uuid v1.2.0
github.com/sirupsen/logrus v1.6.0 // indirect
github.com/sirupsen/logrus v1.7.0 // indirect
github.com/stretchr/testify v1.5.1
github.com/thanhpk/randstr v1.0.4
github.com/theplant/cldr v0.0.0-20190423050709-9f76f7ce4ee8 // indirect
Expand All @@ -59,14 +61,17 @@ require (
github.com/vidar-team/Cardinal_frontend v0.7.3
github.com/vidar-team/Cardinal_manager_frontend v0.7.3
github.com/yosssi/gohtml v0.0.0-20200424144038-a48de20dd9dd // indirect
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd
golang.org/x/text v0.3.0
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2
golang.org/x/text v0.3.3
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect
google.golang.org/grpc v1.30.0 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/genproto v0.0.0-20201030142918-24207fddd1c3 // indirect
google.golang.org/grpc v1.33.1 // indirect
google.golang.org/protobuf v1.25.0 // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
gorm.io/driver/mysql v1.1.0
gopkg.in/yaml.v2 v2.2.8 // indirect
gorm.io/driver/postgres v1.1.0
gorm.io/gorm v1.21.9
gotest.tools v2.2.0+incompatible // indirect
moul.io/http2curl v1.0.0 // indirect
unknwon.dev/clog/v2 v2.1.2
)
445 changes: 407 additions & 38 deletions go.sum

Large diffs are not rendered by default.

2 changes: 0 additions & 2 deletions internal/db/bulletins_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ func TestBulletins(t *testing.T) {
t.Parallel()

db, cleanup := newTestDB(t)
err := db.AutoMigrate(&Bulletin{})
assert.Nil(t, err)
store := NewBulletinsStore(db)

for _, tc := range []struct {
Expand Down
2 changes: 0 additions & 2 deletions internal/db/challenges_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ func TestChallenges(t *testing.T) {
t.Parallel()

db, cleanup := newTestDB(t)
err := db.AutoMigrate(&Challenge{})
assert.Nil(t, err)
store := NewChallengesStore(db)

for _, tc := range []struct {
Expand Down
31 changes: 19 additions & 12 deletions internal/db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,43 @@ package db

import (
"fmt"
"time"

"github.com/pkg/errors"
"gorm.io/driver/mysql"
"gorm.io/driver/postgres"
"gorm.io/gorm"

"github.com/vidar-team/Cardinal/internal/dbold"
"github.com/vidar-team/Cardinal/internal/dbutil"
)

var ErrBadCharset = errors.New("bad charset")

var allTables = []interface{}{
&Bulletin{},
&Challenge{},
&Manager{},
&Team{},
}

// Init initializes the database.
func Init(username, password, host, name string) error {
dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?parseTime=true&loc=Local&charset=utf8mb4,utf8", username, password, host, name)
db, err := gorm.Open(mysql.Open(dsn))
func Init(username, password, host, port, name, sslMode string) error {
dsn := fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=%s", username, password, host, port, name, sslMode)
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
NowFunc: func() time.Time {
return dbutil.Now()
},
})
if err != nil {
return errors.Wrap(err, "open connection")
}

// Migrate databases.
if db.AutoMigrate(
&Bulletin{},
&Challenge{},
&Manager{},
&Team{},
) != nil {
if db.AutoMigrate(allTables...) != nil {
return errors.Wrap(err, "auto migrate")
}

// Test database charset, we should support Chinese input.
if dbold.MySQL.Exec("SELECT * FROM `logs` WHERE `Content` = '中文测试';").Error != nil {
if db.Exec("SELECT * FROM `logs` WHERE `Content` = '中文测试';").Error != nil {
return ErrBadCharset
}

Expand Down
4 changes: 2 additions & 2 deletions internal/db/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import (

"gorm.io/gorm"

"github.com/vidar-team/Cardinal/internal/test"
"github.com/vidar-team/Cardinal/internal/dbutil"
)

func newTestDB(t *testing.T) (*gorm.DB, func(...string) error) {
return test.NewTestDB(t)
return dbutil.NewTestDB(t, allTables...)
}
2 changes: 0 additions & 2 deletions internal/db/managers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ func TestManagers(t *testing.T) {
t.Parallel()

db, cleanup := newTestDB(t)
err := db.AutoMigrate(&Manager{})
assert.Nil(t, err)
store := NewManagersStore(db)

for _, tc := range []struct {
Expand Down
2 changes: 0 additions & 2 deletions internal/db/teams_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ func TestTeams(t *testing.T) {
t.Parallel()

db, cleanup := newTestDB(t)
err := db.AutoMigrate(&Team{})
assert.Nil(t, err)
store := NewTeamsStore(db)

for _, tc := range []struct {
Expand Down
13 changes: 13 additions & 0 deletions internal/dbutil/clock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2021 E99p1ant. All rights reserved.
// Use of this source code is governed by Apache-2.0
// license that can be found in the LICENSE file.

package dbutil

import (
"time"
)

func Now() time.Time {
return time.Now().Truncate(time.Microsecond)
}
61 changes: 46 additions & 15 deletions internal/test/testing.go → internal/dbutil/testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,33 @@
// Use of this source code is governed by Apache-2.0
// license that can be found in the LICENSE file.

package test
package dbutil

import (
"context"
"flag"
"math/rand"
"net/url"
"os"
"strconv"
"strings"
"sync"
"testing"
"time"

"gorm.io/driver/mysql"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)

func NewTestDB(t *testing.T) (testDB *gorm.DB, cleanup func(...string) error) {
dsn := os.ExpandEnv("$DBUSER:$DBPASSWORD@tcp($DBHOST:$DBPORT)/?parseTime=true&loc=Local&charset=utf8mb4,utf8")
db, err := gorm.Open(mysql.Open(dsn))
var flagParseOnce sync.Once

func NewTestDB(t *testing.T, migrationTables ...interface{}) (testDB *gorm.DB, cleanup func(...string) error) {
dsn := os.ExpandEnv("postgres://$PGUSER:$PGPASSWORD@$PGHOST:$PGPORT/$PGDATABASE?sslmode=$PGSSLMODE")
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
NowFunc: func() time.Time {
return Now()
},
})
if err != nil {
t.Fatalf("Failed to open connection: %v", err)
}
Expand All @@ -33,12 +42,28 @@ func NewTestDB(t *testing.T) (testDB *gorm.DB, cleanup func(...string) error) {
t.Fatalf("Failed to create test database: %v", err)
}

dsn = os.ExpandEnv("$DBUSER:$DBPASSWORD@tcp($DBHOST:$DBPORT)/" + dbname + "?parseTime=true&loc=Local&charset=utf8mb4,utf8")
testDB, err = gorm.Open(mysql.Open(dsn))
cfg, err := url.Parse(dsn)
if err != nil {
t.Fatalf("Failed to parse DSN: %v", err)
}
cfg.Path = "/" + dbname

flagParseOnce.Do(flag.Parse)

testDB, err = gorm.Open(postgres.Open(cfg.String()), &gorm.Config{
NowFunc: func() time.Time {
return Now()
},
})
if err != nil {
t.Fatalf("Failed to open test connection: %v", err)
}

err = testDB.AutoMigrate(migrationTables...)
if err != nil {
t.Fatalf("Failed to auto migrate tables: %v", err)
}

t.Cleanup(func() {
defer func() {
if database, err := db.DB(); err == nil {
Expand All @@ -51,7 +76,17 @@ func NewTestDB(t *testing.T) (testDB *gorm.DB, cleanup func(...string) error) {
return
}

err := testDB.WithContext(ctx).Exec(`DROP DATABASE ` + QuoteIdentifier(dbname)).Error
database, err := testDB.DB()
if err != nil {
t.Fatalf("Failed to get currently open database: %v", err)
}

err = database.Close()
if err != nil {
t.Fatalf("Failed to close currently open database: %v", err)
}

err = db.WithContext(ctx).Exec(`DROP DATABASE ` + QuoteIdentifier(dbname)).Error
if err != nil {
t.Fatalf("Failed to drop test database: %v", err)
}
Expand All @@ -63,7 +98,7 @@ func NewTestDB(t *testing.T) (testDB *gorm.DB, cleanup func(...string) error) {
}

for _, table := range tables {
err := testDB.WithContext(ctx).Exec(`TRUNCATE TABLE ` + QuoteIdentifier(table)).Error
err := testDB.WithContext(ctx).Exec(`TRUNCATE TABLE ` + QuoteIdentifier(table) + ` RESTART IDENTITY CASCADE`).Error
if err != nil {
return err
}
Expand All @@ -74,10 +109,6 @@ func NewTestDB(t *testing.T) (testDB *gorm.DB, cleanup func(...string) error) {

// QuoteIdentifier quotes an "identifier" (e.g. a table or a column name) to be
// used as part of an SQL statement.
func QuoteIdentifier(name string) string {
end := strings.IndexRune(name, 0)
if end > -1 {
name = name[:end]
}
return "`" + strings.Replace(name, "`", "``", -1) + "`"
func QuoteIdentifier(s string) string {
return `"` + strings.ReplaceAll(s, `"`, `""`) + `"`
}