diff --git a/Makefile b/Makefile index cfa7968ac..47709cfd8 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,7 @@ DB_MYSQL_PORT ?= 3307 DB_CLICKHOUSE_PORT ?= 9001 DB_YDB_PORT ?= 2136 DB_TURSO_PORT ?= 8080 +DB_STARROCKS_PORT ?= 9030 list-build-tags: @echo "Available build tags:" @@ -86,6 +87,9 @@ test-vertica: add-gowork test-ydb: add-gowork go test $(GO_TEST_FLAGS) ./internal/testing/integration -run='TestYDB' +test-starrocks: add-gowork + go test $(GO_TEST_FLAGS) ./internal/testing/integration -run='TestStarrocks' + test-integration: add-gowork go test $(GO_TEST_FLAGS) ./internal/testing/integration/... diff --git a/README.md b/README.md index 86b4302cb..533c257ea 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,7 @@ Drivers: clickhouse vertica ydb + starrocks Examples: goose sqlite3 ./foo.db status @@ -95,6 +96,7 @@ Examples: goose clickhouse "tcp://127.0.0.1:9000" status goose vertica "vertica://user:password@localhost:5433/dbname?connection_load_balance=1" status goose ydb "grpcs://localhost:2135/local?go_query_mode=scripting&go_fake_tx=scripting&go_query_bind=declare,numeric" status + goose starrocks "user:password@/dbname?parseTime=true&interpolateParams=true" status GOOSE_DRIVER=sqlite3 GOOSE_DBSTRING=./foo.db goose status GOOSE_DRIVER=sqlite3 GOOSE_DBSTRING=./foo.db goose create init sql diff --git a/database/dialect.go b/database/dialect.go index 2ac197d10..ba2da5cab 100644 --- a/database/dialect.go +++ b/database/dialect.go @@ -23,6 +23,7 @@ const ( DialectTurso Dialect = "turso" DialectVertica Dialect = "vertica" DialectYdB Dialect = "ydb" + DialectStarrocks Dialect = "starrocks" ) // NewStore returns a new [Store] implementation for the given dialect. @@ -44,6 +45,7 @@ func NewStore(dialect Dialect, tablename string) (Store, error) { DialectVertica: &dialectquery.Vertica{}, DialectYdB: &dialectquery.Ydb{}, DialectTurso: &dialectquery.Turso{}, + DialectStarrocks: &dialectquery.Starrocks{}, } querier, ok := lookup[dialect] if !ok { diff --git a/db.go b/db.go index 10311236e..7dfb7615a 100644 --- a/db.go +++ b/db.go @@ -33,10 +33,12 @@ func OpenDBWithDriver(driver string, dbstring string) (*sql.DB, error) { driver = "sqlite" case "postgres", "redshift": driver = "pgx" + case "starrocks": + driver = "mysql" } switch driver { - case "postgres", "pgx", "sqlite3", "sqlite", "mysql", "sqlserver", "clickhouse", "vertica", "azuresql", "ydb", "libsql": + case "postgres", "pgx", "sqlite3", "sqlite", "mysql", "sqlserver", "clickhouse", "vertica", "azuresql", "ydb", "libsql", "starrocks": return sql.Open(driver, dbstring) default: return nil, fmt.Errorf("unsupported driver %s", driver) diff --git a/dialect.go b/dialect.go index 3454c5f6d..ecebd144f 100644 --- a/dialect.go +++ b/dialect.go @@ -20,6 +20,7 @@ const ( DialectTiDB Dialect = database.DialectTiDB DialectVertica Dialect = database.DialectVertica DialectYdB Dialect = database.DialectYdB + DialectStarrocks Dialect = database.DialectStarrocks ) func init() { @@ -52,6 +53,8 @@ func SetDialect(s string) error { d = dialect.Ydb case "turso": d = dialect.Turso + case "starrocks": + d = dialect.Starrocks default: return fmt.Errorf("%q: unknown dialect", s) } diff --git a/internal/dialect/dialectquery/starrocks.go b/internal/dialect/dialectquery/starrocks.go new file mode 100644 index 000000000..7b35be4d5 --- /dev/null +++ b/internal/dialect/dialectquery/starrocks.go @@ -0,0 +1,45 @@ +package dialectquery + +import "fmt" + +type Starrocks struct{} + +var _ Querier = (*Starrocks)(nil) + +func (m *Starrocks) CreateTable(tableName string) string { + q := `CREATE TABLE IF NOT EXISTS %s ( + id bigint NOT NULL AUTO_INCREMENT, + version_id bigint NOT NULL, + is_applied boolean NOT NULL, + tstamp datetime NULL default CURRENT_TIMESTAMP + ) + PRIMARY KEY (id) + DISTRIBUTED BY HASH (id) + ORDER BY (id,version_id)` + return fmt.Sprintf(q, tableName) +} + +func (m *Starrocks) InsertVersion(tableName string) string { + q := `INSERT INTO %s (version_id, is_applied) VALUES (?, ?)` + return fmt.Sprintf(q, tableName) +} + +func (m *Starrocks) DeleteVersion(tableName string) string { + q := `DELETE FROM %s WHERE version_id=?` + return fmt.Sprintf(q, tableName) +} + +func (m *Starrocks) GetMigrationByVersion(tableName string) string { + q := `SELECT tstamp, is_applied FROM %s WHERE version_id=? ORDER BY tstamp DESC LIMIT 1` + return fmt.Sprintf(q, tableName) +} + +func (m *Starrocks) ListMigrations(tableName string) string { + q := `SELECT version_id, is_applied from %s ORDER BY id DESC` + return fmt.Sprintf(q, tableName) +} + +func (m *Starrocks) GetLatestVersion(tableName string) string { + q := `SELECT MAX(version_id) FROM %s` + return fmt.Sprintf(q, tableName) +} diff --git a/internal/dialect/dialects.go b/internal/dialect/dialects.go index 6ab06e5df..acf064258 100644 --- a/internal/dialect/dialects.go +++ b/internal/dialect/dialects.go @@ -14,4 +14,5 @@ const ( Vertica Dialect = "vertica" Ydb Dialect = "ydb" Turso Dialect = "turso" + Starrocks Dialect = "starrocks" ) diff --git a/internal/dialect/store.go b/internal/dialect/store.go index f698fd3bd..5179cabaf 100644 --- a/internal/dialect/store.go +++ b/internal/dialect/store.go @@ -69,6 +69,8 @@ func NewStore(d Dialect) (Store, error) { querier = &dialectquery.Ydb{} case Turso: querier = &dialectquery.Turso{} + case Starrocks: + querier = &dialectquery.Starrocks{} default: return nil, fmt.Errorf("unknown querier dialect: %v", d) } diff --git a/internal/testing/go.mod b/internal/testing/go.mod index 954c7d2d5..63bd8737a 100644 --- a/internal/testing/go.mod +++ b/internal/testing/go.mod @@ -3,20 +3,26 @@ module github.com/pressly/goose/v3/internal/testing go 1.22.1 require ( + github.com/ClickHouse/clickhouse-go/v2 v2.28.3 github.com/ClickHouse/clickhouse-go/v2 v2.28.3 github.com/go-sql-driver/mysql v1.8.1 github.com/jackc/pgx/v5 v5.7.1 + github.com/jackc/pgx/v5 v5.7.1 github.com/ory/dockertest/v3 v3.11.0 github.com/pressly/goose/v3 v3.22.0 + github.com/pressly/goose/v3 v3.22.0 github.com/sethvargo/go-retry v0.3.0 github.com/stretchr/testify v1.9.0 github.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d + github.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d github.com/vertica/vertica-sql-go v1.3.3 github.com/ydb-platform/ydb-go-sdk/v3 v3.80.2 + github.com/ydb-platform/ydb-go-sdk/v3 v3.80.2 golang.org/x/sync v0.8.0 ) require ( + dario.cat/mergo v1.0.1 // indirect dario.cat/mergo v1.0.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect @@ -31,6 +37,8 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/docker/cli v27.2.1+incompatible // indirect github.com/docker/docker v27.2.1+incompatible // indirect + github.com/docker/cli v27.2.1+incompatible // indirect + github.com/docker/docker v27.2.1+incompatible // indirect github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/elastic/go-sysinfo v1.14.1 // indirect @@ -45,6 +53,7 @@ require ( github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/jonboulle/clockwork v0.4.0 // indirect github.com/klauspost/compress v1.17.9 // indirect github.com/kr/text v0.2.0 // indirect @@ -54,6 +63,7 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect github.com/opencontainers/runc v1.1.14 // indirect + github.com/opencontainers/runc v1.1.14 // indirect github.com/paulmach/orb v0.11.1 // indirect github.com/pierrec/lz4/v4 v4.1.21 // indirect github.com/pkg/errors v0.9.1 // indirect @@ -68,6 +78,9 @@ require ( github.com/ydb-platform/ydb-go-genproto v0.0.0-20240821162910-6cb364b2ccc8 // indirect go.opentelemetry.io/otel v1.30.0 // indirect go.opentelemetry.io/otel/trace v1.30.0 // indirect + github.com/ydb-platform/ydb-go-genproto v0.0.0-20240821162910-6cb364b2ccc8 // indirect + go.opentelemetry.io/otel v1.30.0 // indirect + go.opentelemetry.io/otel/trace v1.30.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.27.0 // indirect golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect @@ -76,6 +89,13 @@ require ( golang.org/x/text v0.18.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect google.golang.org/grpc v1.66.2 // indirect + golang.org/x/crypto v0.27.0 // indirect + golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect + golang.org/x/net v0.29.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/text v0.18.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect + google.golang.org/grpc v1.66.2 // indirect google.golang.org/protobuf v1.34.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/internal/testing/go.sum b/internal/testing/go.sum index a5e022038..04986048a 100644 --- a/internal/testing/go.sum +++ b/internal/testing/go.sum @@ -2,6 +2,8 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= +dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= @@ -11,6 +13,8 @@ github.com/ClickHouse/ch-go v0.62.0 h1:eXH0hytXeCEEZHgMvOX9IiW7wqBb4w1MJMp9rArbk github.com/ClickHouse/ch-go v0.62.0/go.mod h1:uzso52/PD9+gZj7tL6XAo8/EYDrx7CIwNF4c6PnO6S0= github.com/ClickHouse/clickhouse-go/v2 v2.28.3 h1:SkFzPULX6nzgfNZd1YD1XTECivjTMrCtD09ZPKcVLFQ= github.com/ClickHouse/clickhouse-go/v2 v2.28.3/go.mod h1:vzn73hp+3JwxtFU4RjPCQ7r6fP2pMKVwdi8E1/Tkua8= +github.com/ClickHouse/clickhouse-go/v2 v2.28.3 h1:SkFzPULX6nzgfNZd1YD1XTECivjTMrCtD09ZPKcVLFQ= +github.com/ClickHouse/clickhouse-go/v2 v2.28.3/go.mod h1:vzn73hp+3JwxtFU4RjPCQ7r6fP2pMKVwdi8E1/Tkua8= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= @@ -45,6 +49,10 @@ github.com/docker/cli v27.2.1+incompatible h1:U5BPtiD0viUzjGAjV1p0MGB8eVA3L3cbIr github.com/docker/cli v27.2.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/docker v27.2.1+incompatible h1:fQdiLfW7VLscyoeYEBz7/J8soYFDZV1u6VW6gJEjNMI= github.com/docker/docker v27.2.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/cli v27.2.1+incompatible h1:U5BPtiD0viUzjGAjV1p0MGB8eVA3L3cbIrnyWmSJI70= +github.com/docker/cli v27.2.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/docker v27.2.1+incompatible h1:fQdiLfW7VLscyoeYEBz7/J8soYFDZV1u6VW6gJEjNMI= +github.com/docker/docker v27.2.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -118,6 +126,10 @@ github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs= github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA= github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs= +github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= @@ -153,6 +165,8 @@ github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQ github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/opencontainers/runc v1.1.14 h1:rgSuzbmgz5DUJjeSnw337TxDbRuqjs6iqQck/2weR6w= github.com/opencontainers/runc v1.1.14/go.mod h1:E4C2z+7BxR7GHXp0hAY53mek+x49X1LjPNeMTfRGvOA= +github.com/opencontainers/runc v1.1.14 h1:rgSuzbmgz5DUJjeSnw337TxDbRuqjs6iqQck/2weR6w= +github.com/opencontainers/runc v1.1.14/go.mod h1:E4C2z+7BxR7GHXp0hAY53mek+x49X1LjPNeMTfRGvOA= github.com/ory/dockertest/v3 v3.11.0 h1:OiHcxKAvSDUwsEVh2BjxQQc/5EHz9n0va9awCtNGuyA= github.com/ory/dockertest/v3 v3.11.0/go.mod h1:VIPxS1gwT9NpPOrfD3rACs8Y9Z7yhzO4SB194iUDnUI= github.com/paulmach/orb v0.11.1 h1:3koVegMC4X/WeiXYz9iswopaTwMem53NzTJuTF20JzU= @@ -167,6 +181,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pressly/goose/v3 v3.22.0 h1:wd/7kNiPTuNAztWun7iaB98DrhulbWPrzMAaw2DEZNw= github.com/pressly/goose/v3 v3.22.0/go.mod h1:yJM3qwSj2pp7aAaCvso096sguezamNb2OBgxCnh/EYg= +github.com/pressly/goose/v3 v3.22.0 h1:wd/7kNiPTuNAztWun7iaB98DrhulbWPrzMAaw2DEZNw= +github.com/pressly/goose/v3 v3.22.0/go.mod h1:yJM3qwSj2pp7aAaCvso096sguezamNb2OBgxCnh/EYg= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= @@ -196,6 +212,8 @@ github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8 github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d h1:dOMI4+zEbDI37KGb0TI44GUAwxHF9cMsIoDTJ7UmgfU= github.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d/go.mod h1:l8xTsYB90uaVdMHXMCxKKLSgw5wLYBwBKKefNIUnm9s= +github.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d h1:dOMI4+zEbDI37KGb0TI44GUAwxHF9cMsIoDTJ7UmgfU= +github.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d/go.mod h1:l8xTsYB90uaVdMHXMCxKKLSgw5wLYBwBKKefNIUnm9s= github.com/vertica/vertica-sql-go v1.3.3 h1:fL+FKEAEy5ONmsvya2WH5T8bhkvY27y/Ik3ReR2T+Qw= github.com/vertica/vertica-sql-go v1.3.3/go.mod h1:jnn2GFuv+O2Jcjktb7zyc4Utlbu9YVqpHH/lx63+1M4= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= @@ -212,6 +230,10 @@ github.com/ydb-platform/ydb-go-genproto v0.0.0-20240821162910-6cb364b2ccc8 h1:ZW github.com/ydb-platform/ydb-go-genproto v0.0.0-20240821162910-6cb364b2ccc8/go.mod h1:Er+FePu1dNUieD+XTMDduGpQuCPssK5Q4BjF+IIXJ3I= github.com/ydb-platform/ydb-go-sdk/v3 v3.80.2 h1:qmZGJQCNx09/r0HDIT2cDDogiOvWikELy13ubM2CFS8= github.com/ydb-platform/ydb-go-sdk/v3 v3.80.2/go.mod h1:IHwuXyolaAmGK2Dp7+dlhsnXphG1pwCoaP/OITT3+tU= +github.com/ydb-platform/ydb-go-genproto v0.0.0-20240821162910-6cb364b2ccc8 h1:ZWxYw6L51aNAMLbTpC/VbXP0rcnvsCAJqx7EI/CjWmc= +github.com/ydb-platform/ydb-go-genproto v0.0.0-20240821162910-6cb364b2ccc8/go.mod h1:Er+FePu1dNUieD+XTMDduGpQuCPssK5Q4BjF+IIXJ3I= +github.com/ydb-platform/ydb-go-sdk/v3 v3.80.2 h1:qmZGJQCNx09/r0HDIT2cDDogiOvWikELy13ubM2CFS8= +github.com/ydb-platform/ydb-go-sdk/v3 v3.80.2/go.mod h1:IHwuXyolaAmGK2Dp7+dlhsnXphG1pwCoaP/OITT3+tU= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -220,6 +242,10 @@ go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts= go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc= go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc= go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o= +go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts= +go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc= +go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc= +go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= @@ -231,9 +257,13 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -252,6 +282,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -277,6 +309,8 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -284,6 +318,8 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -304,6 +340,8 @@ google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= @@ -313,6 +351,8 @@ google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo= google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= +google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo= +google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -352,12 +392,18 @@ modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQX modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U= modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w= +modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U= +modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w= modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= modernc.org/sqlite v1.32.0 h1:6BM4uGza7bWypsw4fdLRsLxut6bHe4c58VeqjRgST8s= modernc.org/sqlite v1.32.0/go.mod h1:UqoylwmTb9F+IqXERT8bW9zzOWN8qwAIcLdzeBZs4hA= +modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= +modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= +modernc.org/sqlite v1.32.0 h1:6BM4uGza7bWypsw4fdLRsLxut6bHe4c58VeqjRgST8s= +modernc.org/sqlite v1.32.0/go.mod h1:UqoylwmTb9F+IqXERT8bW9zzOWN8qwAIcLdzeBZs4hA= modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= diff --git a/internal/testing/integration/database_test.go b/internal/testing/integration/database_test.go index ebaba6067..649020255 100644 --- a/internal/testing/integration/database_test.go +++ b/internal/testing/integration/database_test.go @@ -193,3 +193,14 @@ func TestYDB(t *testing.T) { testDatabase(t, database.DialectYdB, db, "testdata/migrations/ydb") } + +func TestStarrocks(t *testing.T) { + t.Parallel() + + db, cleanup, err := testdb.NewStarrocks() + require.NoError(t, err) + t.Cleanup(cleanup) + require.NoError(t, db.Ping()) + + testDatabase(t, database.DialectStarrocks, db, "testdata/migrations/starrocks") +} diff --git a/internal/testing/integration/testdata/migrations/starrocks/00001_a.sql b/internal/testing/integration/testdata/migrations/starrocks/00001_a.sql new file mode 100644 index 000000000..02fbc20b7 --- /dev/null +++ b/internal/testing/integration/testdata/migrations/starrocks/00001_a.sql @@ -0,0 +1,9 @@ +-- +goose Up +-- +goose StatementBegin +CREATE SCHEMA IF NOT EXISTS testing; +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DROP SCHEMA IF EXISTS testing; +-- +goose StatementEnd diff --git a/internal/testing/integration/testdata/migrations/starrocks/00002_b.sql b/internal/testing/integration/testdata/migrations/starrocks/00002_b.sql new file mode 100644 index 000000000..26f9b67bd --- /dev/null +++ b/internal/testing/integration/testdata/migrations/starrocks/00002_b.sql @@ -0,0 +1,31 @@ +-- +goose Up +-- +goose StatementBegin +CREATE TABLE testing.test_migrations_1 ( + version_id bigint NOT NULL, + id bigint NOT NULL AUTO_INCREMENT, + is_applied boolean NOT NULL, + tstamp datetime NULL default CURRENT_TIMESTAMP + ) + PRIMARY KEY (version_id,id) + DISTRIBUTED BY HASH (id) + ORDER BY (version_id); +-- +goose StatementEnd +-- +goose StatementBegin +CREATE TABLE testing.test_migrations_2 ( + version_id bigint NOT NULL, + id bigint NOT NULL AUTO_INCREMENT, + is_applied boolean NOT NULL, + tstamp datetime NULL default CURRENT_TIMESTAMP + ) + PRIMARY KEY (version_id,id) + DISTRIBUTED BY HASH (id) + ORDER BY (version_id); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DROP TABLE IF EXISTS testing.test_migrations_1; +-- +goose StatementEnd +-- +goose StatementBegin +DROP TABLE IF EXISTS testing.test_migrations_2; +-- +goose StatementEnd diff --git a/internal/testing/integration/testdata/migrations/starrocks/00003_c.sql b/internal/testing/integration/testdata/migrations/starrocks/00003_c.sql new file mode 100644 index 000000000..c7dfd1f0a --- /dev/null +++ b/internal/testing/integration/testdata/migrations/starrocks/00003_c.sql @@ -0,0 +1,15 @@ +-- +goose Up +-- +goose StatementBegin +INSERT INTO testing.test_migrations_1 (version_id, is_applied) VALUES (1, true); +-- +goose StatementEnd +-- +goose StatementBegin +INSERT INTO testing.test_migrations_1 (version_id, is_applied) VALUES (2, true); +-- +goose StatementEnd +-- +goose StatementBegin +INSERT INTO testing.test_migrations_1 (version_id, is_applied) VALUES (3, true); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DELETE FROM testing.test_migrations_1 WHERE version_id < 10; +-- +goose StatementEnd diff --git a/internal/testing/testdb/starrocks.go b/internal/testing/testdb/starrocks.go new file mode 100644 index 000000000..9ab823904 --- /dev/null +++ b/internal/testing/testdb/starrocks.go @@ -0,0 +1,103 @@ +package testdb + +import ( + "database/sql" + "fmt" + "log" + "strconv" + "time" + + _ "github.com/go-sql-driver/mysql" + "github.com/ory/dockertest/v3" + "github.com/ory/dockertest/v3/docker" +) + +const ( + // https://hub.docker.com/r/starrocks/allin1-ubuntu + STARROCKS_IMAGE = "starrocks/allin1-ubuntu" + STARROCKS_VERSION = "3.2-latest" + + STARROCKS_USER = "root" + STARROCKS_INIT_DB = "migrations" +) + +func newStarrocks(opts ...OptionsFunc) (*sql.DB, func(), error) { + option := &options{} + for _, f := range opts { + f(option) + } + // Uses a sensible default on windows (tcp/http) and linux/osx (socket). + pool, err := dockertest.NewPool("") + if err != nil { + return nil, nil, fmt.Errorf("failed to connect to docker: %v", err) + } + + options := &dockertest.RunOptions{ + Repository: STARROCKS_IMAGE, + Tag: STARROCKS_VERSION, + Labels: map[string]string{"goose_test": "1"}, + PortBindings: make(map[docker.Port][]docker.PortBinding), + ExposedPorts: []string{"9030/tcp"}, + } + if option.bindPort > 0 { + options.PortBindings[docker.Port("9030/tcp")] = []docker.PortBinding{ + {HostPort: strconv.Itoa(option.bindPort)}, + } + } + container, err := pool.RunWithOptions( + options, + func(config *docker.HostConfig) { + // Set AutoRemove to true so that stopped container goes away by itself. + config.AutoRemove = true + config.RestartPolicy = docker.RestartPolicy{Name: "no"} + }, + ) + if err != nil { + return nil, nil, fmt.Errorf("failed to create docker container: %v", err) + } + cleanup := func() { + if option.debug { + // User must manually delete the Docker container. + return + } + if err := pool.Purge(container); err != nil { + log.Printf("failed to purge resource: %v", err) + } + } + dsn := fmt.Sprintf("%s:%s@(%s:%s)/%s?parseTime=true&interpolateParams=true", + STARROCKS_USER, + "", + "localhost", + container.GetPort("9030/tcp"), // Fetch port dynamically assigned to container, + "", + ) + var db *sql.DB + + // Exponential backoff-retry, because the application in the container + // might not be ready to accept connections yet. Add an extra sleep + // because container take much longer to startup. + pool.MaxWait = time.Minute * 2 + if err := pool.Retry(func() error { + var err error + db, err = sql.Open("mysql", dsn) + if err != nil { + return err + } + + _, err = db.Exec("CREATE DATABASE IF NOT EXISTS " + STARROCKS_INIT_DB) + if err != nil { + return fmt.Errorf("could not create initial database: %v", err) + } + _, err = db.Exec("USE " + STARROCKS_INIT_DB) + if err != nil { + return fmt.Errorf("could not set default initial database: %v", err) + } + + return db.Ping() + }, + ); err != nil { + return nil, cleanup, fmt.Errorf("could not connect to docker database: %v", err) + } + + return db, cleanup, nil +} diff --git a/internal/testing/testdb/testdb.go b/internal/testing/testdb/testdb.go index 733df911a..72a2b19d5 100644 --- a/internal/testing/testdb/testdb.go +++ b/internal/testing/testdb/testdb.go @@ -26,3 +26,8 @@ func NewVertica(options ...OptionsFunc) (db *sql.DB, cleanup func(), err error) func NewYdb(options ...OptionsFunc) (db *sql.DB, cleanup func(), err error) { return newYdb(options...) } + +// NewStarrocks starts a Starrocks docker container. Returns db connection and a docker cleanup function. +func NewStarrocks(options ...OptionsFunc) (db *sql.DB, cleanup func(), err error) { + return newStarrocks(options...) +}