Skip to content

Commit 1da33a4

Browse files
committed
feat(core): add migrate
feat(core): add migrate feat(core): add migrate feat(core): add migrate feat(core): add migrate
1 parent 0316100 commit 1da33a4

File tree

3 files changed

+213
-27
lines changed

3 files changed

+213
-27
lines changed

core/stores/migrate/migrate.go

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
package migrate
2+
3+
import (
4+
"context"
5+
"io"
6+
"os"
7+
"strings"
8+
9+
"github.com/eddieowens/opts"
10+
"github.com/golang-migrate/migrate/v4"
11+
_ "github.com/golang-migrate/migrate/v4/database/mysql"
12+
_ "github.com/golang-migrate/migrate/v4/database/pgx/v5"
13+
"github.com/golang-migrate/migrate/v4/source/file"
14+
"github.com/pkg/errors"
15+
"github.com/zeromicro/go-zero/core/stores/sqlx"
16+
)
17+
18+
type MigrateOpts struct {
19+
PreProcessSqlFunc func(content string) string
20+
Source string
21+
}
22+
23+
func (opts MigrateOpts) DefaultOptions() MigrateOpts {
24+
return MigrateOpts{
25+
PreProcessSqlFunc: func(content string) string {
26+
return content
27+
},
28+
Source: "file://desc/sql_migration",
29+
}
30+
}
31+
32+
func WithPreProcessSqlFunc(f func(string) string) opts.Opt[MigrateOpts] {
33+
return func(opts *MigrateOpts) {
34+
opts.PreProcessSqlFunc = f
35+
}
36+
}
37+
38+
func WithSource(source string) opts.Opt[MigrateOpts] {
39+
return func(opts *MigrateOpts) {
40+
opts.Source = source
41+
}
42+
}
43+
44+
func Migrate(ctx context.Context, c sqlx.SqlConf, op ...opts.Opt[MigrateOpts]) error {
45+
ops := opts.DefaultApply(op...)
46+
var databaseUrl string
47+
switch c.DriverName {
48+
case "mysql":
49+
databaseUrl = "mysql://" + c.DataSource
50+
case "pgx":
51+
databaseUrl = "pgx5://" + strings.TrimPrefix(c.DataSource, "postgres://")
52+
}
53+
if err := sqlMigrate(ops.Source, databaseUrl, c, ops); err != nil {
54+
return err
55+
}
56+
return nil
57+
}
58+
59+
type customFileSource struct {
60+
*file.File
61+
driverName string
62+
preProcessSqlFunc func(content string) string
63+
}
64+
65+
func (c *customFileSource) ReadUp(version uint) (r io.ReadCloser, identifier string, err error) {
66+
rc, id, err := c.File.ReadUp(version)
67+
if err != nil {
68+
return nil, "", err
69+
}
70+
71+
content, err := io.ReadAll(rc)
72+
if err != nil {
73+
return nil, "", err
74+
}
75+
76+
if err = rc.Close(); err != nil {
77+
return nil, "", err
78+
}
79+
return io.NopCloser(strings.NewReader(c.preProcessSqlFunc(string(content)))), id, nil
80+
}
81+
82+
func (c *customFileSource) ReadDown(version uint) (r io.ReadCloser, identifier string, err error) {
83+
rc, id, err := c.File.ReadDown(version)
84+
if err != nil {
85+
return nil, "", err
86+
}
87+
88+
content, err := io.ReadAll(rc)
89+
if err != nil {
90+
return nil, "", err
91+
}
92+
93+
if err = rc.Close(); err != nil {
94+
return nil, "", err
95+
}
96+
97+
modifiedContent := c.preProcessSqlFunc(string(content))
98+
return io.NopCloser(strings.NewReader(modifiedContent)), id, nil
99+
}
100+
101+
func sqlMigrate(sourceUrl, databaseUrl string, c sqlx.SqlConf, ops MigrateOpts) error {
102+
fileDriver := &file.File{}
103+
fileSource, err := fileDriver.Open(sourceUrl)
104+
if err != nil {
105+
if errors.Is(err, os.ErrNotExist) {
106+
return nil
107+
}
108+
return err
109+
}
110+
111+
customSource := &customFileSource{
112+
File: fileSource.(*file.File),
113+
driverName: c.DriverName,
114+
preProcessSqlFunc: ops.PreProcessSqlFunc,
115+
}
116+
117+
m, err := migrate.NewWithSourceInstance("file", customSource, databaseUrl)
118+
if err != nil {
119+
return err
120+
}
121+
122+
if err = m.Up(); err != nil {
123+
if errors.Is(err, migrate.ErrNoChange) {
124+
return nil
125+
}
126+
}
127+
128+
sourceErr, databaseErr := m.Close()
129+
if sourceErr != nil {
130+
return sourceErr
131+
}
132+
if databaseErr != nil {
133+
return databaseErr
134+
}
135+
return nil
136+
}

go.mod

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ require (
99
github.com/bitly/go-simplejson v0.5.1
1010
github.com/eddieowens/opts v0.1.0
1111
github.com/fsnotify/fsnotify v1.9.0
12+
github.com/golang-migrate/migrate/v4 v4.19.0
1213
github.com/gorilla/websocket v1.5.3
1314
github.com/huandu/go-sqlbuilder v1.37.0
1415
github.com/jackc/pgx/v5 v5.7.6
@@ -23,8 +24,8 @@ require (
2324
github.com/spf13/cast v1.10.0
2425
github.com/stretchr/testify v1.11.1
2526
github.com/zeromicro/go-zero v1.9.0
26-
go.opentelemetry.io/otel v1.24.0
27-
go.opentelemetry.io/otel/trace v1.24.0
27+
go.opentelemetry.io/otel v1.37.0
28+
go.opentelemetry.io/otel/trace v1.37.0
2829
golang.org/x/time v0.13.0
2930
google.golang.org/protobuf v1.36.9
3031
)
@@ -43,7 +44,7 @@ require (
4344
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
4445
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
4546
github.com/fatih/color v1.18.0 // indirect
46-
github.com/go-logr/logr v1.4.2 // indirect
47+
github.com/go-logr/logr v1.4.3 // indirect
4748
github.com/go-logr/stdr v1.2.2 // indirect
4849
github.com/go-sql-driver/mysql v1.9.0 // indirect
4950
github.com/gogo/protobuf v1.3.2 // indirect
@@ -54,8 +55,11 @@ require (
5455
github.com/grafana/pyroscope-go v1.2.4 // indirect
5556
github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // indirect
5657
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
58+
github.com/hashicorp/errwrap v1.1.0 // indirect
59+
github.com/hashicorp/go-multierror v1.1.1 // indirect
5760
github.com/huandu/go-clone v1.7.3 // indirect
5861
github.com/huandu/xstrings v1.5.0 // indirect
62+
github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa // indirect
5963
github.com/jackc/pgpassfile v1.0.0 // indirect
6064
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
6165
github.com/jackc/puddle/v2 v2.2.2 // indirect
@@ -81,14 +85,15 @@ require (
8185
go.etcd.io/etcd/api/v3 v3.5.15 // indirect
8286
go.etcd.io/etcd/client/pkg/v3 v3.5.15 // indirect
8387
go.etcd.io/etcd/client/v3 v3.5.15 // indirect
88+
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
8489
go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect
85-
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 // indirect
90+
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 // indirect
8691
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 // indirect
8792
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 // indirect
8893
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0 // indirect
8994
go.opentelemetry.io/otel/exporters/zipkin v1.24.0 // indirect
90-
go.opentelemetry.io/otel/metric v1.24.0 // indirect
91-
go.opentelemetry.io/otel/sdk v1.24.0 // indirect
95+
go.opentelemetry.io/otel/metric v1.37.0 // indirect
96+
go.opentelemetry.io/otel/sdk v1.29.0 // indirect
9297
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
9398
go.uber.org/atomic v1.10.0 // indirect
9499
go.uber.org/automaxprocs v1.6.0 // indirect
@@ -100,9 +105,9 @@ require (
100105
golang.org/x/sync v0.14.0 // indirect
101106
golang.org/x/sys v0.33.0 // indirect
102107
golang.org/x/text v0.25.0 // indirect
103-
google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d // indirect
104-
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect
105-
google.golang.org/grpc v1.65.0 // indirect
108+
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect
109+
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
110+
google.golang.org/grpc v1.67.0 // indirect
106111
gopkg.in/yaml.v2 v2.4.0 // indirect
107112
gopkg.in/yaml.v3 v3.0.1 // indirect
108113
)

0 commit comments

Comments
 (0)