diff --git a/cmd/goose/driver_clickhouse.go b/cmd/goose/driver_clickhouse.go new file mode 100644 index 0000000..c7c21ec --- /dev/null +++ b/cmd/goose/driver_clickhouse.go @@ -0,0 +1,7 @@ +// +build !no_sqlite3 + +package main + +import ( + _ "github.com/ClickHouse/clickhouse-go" +) diff --git a/cmd/goose/main.go b/cmd/goose/main.go index 44572f3..0f45edf 100644 --- a/cmd/goose/main.go +++ b/cmd/goose/main.go @@ -85,6 +85,7 @@ Drivers: sqlite3 mssql redshift + clickhouse Examples: goose sqlite3 ./foo.db status @@ -98,6 +99,7 @@ Examples: goose redshift "postgres://user:password@qwerty.us-east-1.redshift.amazonaws.com:5439/db" status goose tidb "user:password@/dbname?parseTime=true" status goose mssql "sqlserver://user:password@dbname:1433?database=master" status + goose clickhouse "tcp://127.0.0.1:9000" status Options: ` diff --git a/db.go b/db.go index 1eb1464..428e777 100644 --- a/db.go +++ b/db.go @@ -22,7 +22,7 @@ func OpenDBWithDriver(driver string, dbstring string) (*sql.DB, error) { } switch driver { - case "postgres", "sqlite3", "mysql", "sqlserver": + case "postgres", "sqlite3", "mysql", "sqlserver", "clickhouse": return sql.Open(driver, dbstring) default: return nil, fmt.Errorf("unsupported driver %s", driver) diff --git a/dialect.go b/dialect.go index 1ce7856..fca863f 100644 --- a/dialect.go +++ b/dialect.go @@ -37,6 +37,8 @@ func SetDialect(d string) error { dialect = &RedshiftDialect{} case "tidb": dialect = &TiDBDialect{} + case "clickhouse": + dialect = &ClickHouseDialect{} default: return fmt.Errorf("%q: unknown dialect", d) } @@ -155,11 +157,11 @@ WITH Migrations AS ( SELECT tstamp, is_applied, ROW_NUMBER() OVER (ORDER BY tstamp) AS 'RowNumber' - FROM %s + FROM %s WHERE version_id=@p1 -) -SELECT tstamp, is_applied -FROM Migrations +) +SELECT tstamp, is_applied +FROM Migrations WHERE RowNumber BETWEEN 1 AND 2 ORDER BY tstamp DESC ` @@ -282,3 +284,41 @@ func (m TiDBDialect) migrationSQL() string { func (m TiDBDialect) deleteVersionSQL() string { return fmt.Sprintf("DELETE FROM %s WHERE version_id=?;", TableName()) } + +//////////////////////////// +// ClickHouse +//////////////////////////// + +// ClickHouseDialect struct. +type ClickHouseDialect struct{} + +func (m ClickHouseDialect) createVersionTableSQL() string { + return ` + CREATE TABLE goose_db_version ( + version_id Int64, + is_applied UInt8, + date Date default now(), + tstamp DateTime default now() + ) Engine = MergeTree(date, (date), 8192) + ` +} + +func (m ClickHouseDialect) dbVersionQuery(db *sql.DB) (*sql.Rows, error) { + rows, err := db.Query(fmt.Sprintf("SELECT version_id, is_applied FROM %s ORDER BY tstamp DESC LIMIT 1", TableName())) + if err != nil { + return nil, err + } + return rows, err +} + +func (m ClickHouseDialect) insertVersionSQL() string { + return fmt.Sprintf("INSERT INTO %s (version_id, is_applied) VALUES (?, ?)", TableName()) +} + +func (m ClickHouseDialect) migrationSQL() string { + return fmt.Sprintf("SELECT tstamp, is_applied FROM %s WHERE version_id = ? ORDER BY tstamp DESC LIMIT 1", TableName()) +} + +func (m ClickHouseDialect) deleteVersionSQL() string { + return fmt.Sprintf("ALTER TABLE %s DELETE WHERE version_id = ?", TableName()) +}