Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[POC] Schema migration API #79

Merged
merged 52 commits into from
Sep 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
3052aa1
wip dsl
Fs02 Jul 5, 2020
3d01a42
add more functionality to dsl
Fs02 Jul 5, 2020
7823c28
simplify struct and add tests for column
Fs02 Jul 6, 2020
37cde2b
options
Fs02 Jul 7, 2020
23505ba
add index
Fs02 Jul 11, 2020
7e45fd2
add tests
Fs02 Jul 11, 2020
5d0ec7d
wip query builder
Fs02 Jul 18, 2020
77f9496
more tests
Fs02 Jul 19, 2020
1b3f76e
reafactor map column type
Fs02 Jul 19, 2020
4183f16
Merge branch 'master' into schema-migration
Fs02 Jul 19, 2020
78cf1c1
Merge branch 'master' into schema-migration
Fs02 Jul 22, 2020
931d48e
wip migration manager and use functor to define migration
Fs02 Jul 29, 2020
6e994c9
Merge branch 'master' into schema-migration
Fs02 Aug 1, 2020
b066dc8
Merge branch 'master' into schema-migration
Fs02 Aug 29, 2020
fecc194
refactor dsl to root package
Fs02 Aug 29, 2020
5491e88
implement migrator
Fs02 Aug 29, 2020
0a0e1f3
Merge branch 'master' into schema-migration
Fs02 Aug 29, 2020
5141df0
fix test
Fs02 Aug 29, 2020
043562a
Merge branch 'schema-migration' of https://github.com/Fs02/rel into s…
Fs02 Aug 29, 2020
526c058
fix coverage
Fs02 Aug 29, 2020
0d28e3d
wip adapter integration for sqlite3
Fs02 Aug 29, 2020
4fed8b0
special column type: id, wip mysql integration
Fs02 Aug 29, 2020
3fb4844
wip postgres spec
Fs02 Aug 29, 2020
905c87c
fix test
Fs02 Aug 29, 2020
24e51e3
wip migrate spec, cancel support for comment and binary
Fs02 Aug 30, 2020
1fb4e25
fix test and refactor map column
Fs02 Aug 30, 2020
76e4956
use strings.Builder
Fs02 Aug 30, 2020
80775b5
wip split index and key
Fs02 Aug 30, 2020
be06016
wip index, fix tests
Fs02 Aug 30, 2020
f3fa30b
implement create index
Fs02 Aug 30, 2020
3cd5e71
add unique option
Fs02 Aug 30, 2020
b2ff252
move config to global variable
Fs02 Aug 30, 2020
2d5a9d5
fix comment
Fs02 Aug 30, 2020
a749bb5
drop support for alter column on poc, bump sqlite3, more integration …
Fs02 Aug 31, 2020
9e47e61
go mod itdy, fix test
Fs02 Aug 31, 2020
3292054
bump sqlite3 on godep
Fs02 Aug 31, 2020
1dd9c8d
fix rename table
Fs02 Aug 31, 2020
8e1918e
add more test
Fs02 Aug 31, 2020
13a59ae
add helper for optional create and drop table
Fs02 Aug 31, 2020
2547ec2
postpone rename and rop key
Fs02 Aug 31, 2020
7c6d524
add more tests
Fs02 Sep 1, 2020
0883ee2
fix coverage
Fs02 Sep 1, 2020
3b34832
refactor NewName to Rename
Fs02 Sep 1, 2020
1f41be8
accommodate timestamp version
Fs02 Sep 1, 2020
03d75ed
unsigned version
Fs02 Sep 1, 2020
b2592e6
add schema.Exec and schema.Do
Fs02 Sep 2, 2020
c6d7b17
Merge branch 'schema-migration' of https://github.com/Fs02/rel into s…
Fs02 Sep 2, 2020
98c7df2
add feature to readme
Fs02 Sep 2, 2020
1ba1076
Update adapter_test.go
Fs02 Sep 2, 2020
877b42b
organize schema options into one file
Fs02 Sep 2, 2020
5bea861
Merge branch 'schema-migration' of https://github.com/Fs02/rel into s…
Fs02 Sep 2, 2020
e8bce29
remove unused codes
Fs02 Sep 3, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Gopkg.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,7 @@
[prune]
go-tests = true
unused-packages = true

[[constraint]]
name = "github.com/mattn/go-sqlite3"
version = "1.14.2"
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ REL is golang orm-ish database layer for layered architecture. It's testable and
- Multi adapter.
- Soft Deletion.
- Pagination.

- Schema Migration.

## Install

Expand Down
2 changes: 2 additions & 0 deletions adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,6 @@ type Adapter interface {
Begin(ctx context.Context) (Adapter, error)
Commit(ctx context.Context) error
Rollback(ctx context.Context) error

Apply(ctx context.Context, migration Migration) error
}
25 changes: 16 additions & 9 deletions adapter/mysql/mysql.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,26 @@ type Adapter struct {
*sql.Adapter
}

var _ rel.Adapter = (*Adapter)(nil)
var (
_ rel.Adapter = (*Adapter)(nil)

// New is mysql adapter constructor.
// Config for mysql adapter.
Config = sql.Config{
DropIndexOnTable: true,
Placeholder: "?",
EscapeChar: "`",
IncrementFunc: incrementFunc,
ErrorFunc: errorFunc,
MapColumnFunc: sql.MapColumn,
}
)

// New mysql adapter using existing connection.
func New(database *db.DB) *Adapter {
return &Adapter{
Adapter: &sql.Adapter{
Config: &sql.Config{
Placeholder: "?",
EscapeChar: "`",
IncrementFunc: incrementFunc,
ErrorFunc: errorFunc,
},
DB: database,
Config: Config,
DB: database,
},
}
}
Expand Down
60 changes: 8 additions & 52 deletions adapter/mysql/mysql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,58 +15,6 @@ import (

var ctx = context.TODO()

func init() {
adapter, err := Open(dsn())
paranoid.Panic(err, "failed to open database connection")

_, _, err = adapter.Exec(ctx, `DROP TABLE IF EXISTS extras;`, nil)
paranoid.Panic(err, "failed dropping extras table")
_, _, err = adapter.Exec(ctx, `DROP TABLE IF EXISTS addresses;`, nil)
paranoid.Panic(err, "failed dropping addresses table")
_, _, err = adapter.Exec(ctx, `DROP TABLE IF EXISTS users;`, nil)
paranoid.Panic(err, "failed dropping users table")
_, _, err = adapter.Exec(ctx, `DROP TABLE IF EXISTS composites;`, nil)
paranoid.Panic(err, "failed dropping composites table")

_, _, err = adapter.Exec(ctx, `CREATE TABLE users (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(30) NOT NULL DEFAULT '',
gender VARCHAR(10) NOT NULL DEFAULT '',
age INT NOT NULL DEFAULT 0,
note varchar(50),
created_at DATETIME,
updated_at DATETIME
);`, nil)
paranoid.Panic(err, "failed creating users table")

_, _, err = adapter.Exec(ctx, `CREATE TABLE addresses (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
user_id INT UNSIGNED,
name VARCHAR(60) NOT NULL DEFAULT '',
created_at DATETIME,
updated_at DATETIME,
FOREIGN KEY (user_id) REFERENCES users(id)
);`, nil)
paranoid.Panic(err, "failed creating addresses table")

_, _, err = adapter.Exec(ctx, `CREATE TABLE extras (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
slug VARCHAR(30) DEFAULT NULL UNIQUE,
user_id INT UNSIGNED,
SCORE INT,
CONSTRAINT extras_user_id_fk FOREIGN KEY (user_id) REFERENCES users(id)
);`, nil)
paranoid.Panic(err, "failed creating extras table")

_, _, err = adapter.Exec(ctx, `CREATE TABLE composites (
primary1 INT UNSIGNED,
primary2 INT UNSIGNED,
data VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (primary1, primary2)
);`, nil)
paranoid.Panic(err, "failed creating composites table")
}

func dsn() string {
if os.Getenv("MYSQL_DATABASE") != "" {
return os.Getenv("MYSQL_DATABASE") + "?charset=utf8&parseTime=True&loc=Local"
Expand All @@ -82,6 +30,14 @@ func TestAdapter_specs(t *testing.T) {

repo := rel.New(adapter)

// Prepare tables
teardown := specs.Setup(t, repo)
defer teardown()

// Migration Specs
// - Rename column is only supported by MySQL 8.0
specs.Migrate(t, repo, specs.SkipRenameColumn)

// Query Specs
specs.Query(t, repo)
specs.QueryJoin(t, repo)
Expand Down
57 changes: 47 additions & 10 deletions adapter/postgres/postgres.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ package postgres
import (
"context"
db "database/sql"
"time"

"github.com/Fs02/rel"
"github.com/Fs02/rel/adapter/sql"
Expand All @@ -25,20 +26,26 @@ type Adapter struct {
*sql.Adapter
}

var _ rel.Adapter = (*Adapter)(nil)
var (
_ rel.Adapter = (*Adapter)(nil)

// Config for postgres adapter.
Config = sql.Config{
Placeholder: "$",
EscapeChar: "\"",
Ordinal: true,
InsertDefaultValues: true,
ErrorFunc: errorFunc,
MapColumnFunc: mapColumnFunc,
}
)

// New is postgres adapter constructor.
// New postgres adapter using existing connection.
func New(database *db.DB) *Adapter {
return &Adapter{
Adapter: &sql.Adapter{
Config: &sql.Config{
Placeholder: "$",
EscapeChar: "\"",
Ordinal: true,
InsertDefaultValues: true,
ErrorFunc: errorFunc,
},
DB: database,
Config: Config,
DB: database,
},
}
}
Expand Down Expand Up @@ -144,3 +151,33 @@ func errorFunc(err error) error {
return err
}
}

func mapColumnFunc(column *rel.Column) (string, int, int) {
var (
typ string
m, n int
)

// postgres specific
column.Unsigned = false
if column.Default == "" {
column.Default = nil
}

switch column.Type {
case rel.ID:
typ = "SERIAL NOT NULL PRIMARY KEY"
case rel.DateTime:
typ = "TIMESTAMPTZ"
if t, ok := column.Default.(time.Time); ok {
column.Default = t.Format("2006-01-02 15:04:05")
}
case rel.Int, rel.BigInt, rel.Text:
column.Limit = 0
typ, m, n = sql.MapColumn(column)
default:
typ, m, n = sql.MapColumn(column)
}

return typ, m, n
}
63 changes: 9 additions & 54 deletions adapter/postgres/postgres_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,68 +16,16 @@ import (
var ctx = context.TODO()

func init() {
adapter, err := Open(dsn())
paranoid.Panic(err, "failed to open database connection")
defer adapter.Close()

_, _, err = adapter.Exec(ctx, `DROP TABLE IF EXISTS extras;`, nil)
paranoid.Panic(err, "failed dropping extras table")
_, _, err = adapter.Exec(ctx, `DROP TABLE IF EXISTS addresses;`, nil)
paranoid.Panic(err, "failed dropping addresses table")
_, _, err = adapter.Exec(ctx, `DROP TABLE IF EXISTS users;`, nil)
paranoid.Panic(err, "failed dropping users table")
_, _, err = adapter.Exec(ctx, `DROP TABLE IF EXISTS composites;`, nil)
paranoid.Panic(err, "failed dropping composites table")

_, _, err = adapter.Exec(ctx, `CREATE TABLE users (
id SERIAL NOT NULL PRIMARY KEY,
slug VARCHAR(30) DEFAULT NULL,
name VARCHAR(30) NOT NULL DEFAULT '',
gender VARCHAR(10) NOT NULL DEFAULT '',
age INT NOT NULL DEFAULT 0,
note varchar(50),
created_at TIMESTAMPTZ,
updated_at TIMESTAMPTZ,
UNIQUE(slug)
);`, nil)
paranoid.Panic(err, "failed creating users table")

_, _, err = adapter.Exec(ctx, `CREATE TABLE addresses (
id SERIAL NOT NULL PRIMARY KEY,
user_id INTEGER REFERENCES users(id),
name VARCHAR(60) NOT NULL DEFAULT '',
created_at TIMESTAMPTZ,
updated_at TIMESTAMPTZ
);`, nil)
paranoid.Panic(err, "failed creating addresses table")

_, _, err = adapter.Exec(ctx, `CREATE TABLE extras (
id SERIAL NOT NULL PRIMARY KEY,
slug VARCHAR(30) DEFAULT NULL UNIQUE,
user_id INTEGER REFERENCES users(id),
score INTEGER DEFAULT 0 CHECK (score>=0 AND score<=100)
);`, nil)
paranoid.Panic(err, "failed creating extras table")

_, _, err = adapter.Exec(ctx, `CREATE TABLE composites (
primary1 SERIAL NOT NULL,
primary2 SERIAL NOT NULL,
data VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (primary1, primary2)
);`, nil)
paranoid.Panic(err, "failed creating composites table")

// hack to make sure location it has the same location object as returned by pq driver.
time.Local, err = time.LoadLocation("Asia/Jakarta")
paranoid.Panic(err, "failed loading time location")
time.Local, _ = time.LoadLocation("Asia/Jakarta")
}

func dsn() string {
if os.Getenv("POSTGRESQL_DATABASE") != "" {
return os.Getenv("POSTGRESQL_DATABASE") + "?sslmode=disable&timezone=Asia/Jakarta"
}

return "postgres://rel@localhost:9920/rel_test?sslmode=disable&timezone=Asia/Jakarta"
return "postgres://rel@localhost:5432/rel_test?sslmode=disable&timezone=Asia/Jakarta"
}

func TestAdapter_specs(t *testing.T) {
Expand All @@ -87,6 +35,13 @@ func TestAdapter_specs(t *testing.T) {

repo := rel.New(adapter)

// Prepare tables
teardown := specs.Setup(t, repo)
defer teardown()

// Migration Specs
specs.Migrate(t, repo)

// Query Specs
specs.Query(t, repo)
specs.QueryJoin(t, repo)
Expand Down