Skip to content

Commit

Permalink
hacking
Browse files Browse the repository at this point in the history
  • Loading branch information
krehermann committed Jun 13, 2024
1 parent 66f1547 commit 7274c52
Show file tree
Hide file tree
Showing 7 changed files with 232 additions and 2 deletions.
33 changes: 31 additions & 2 deletions core/store/migrate/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ import (
//go:embed migrations/*.sql migrations/*.go
var embedMigrations embed.FS

// go:embed relayers/**/*.tmpl.sql
var embedRelayerMigrations embed.FS

const RELAYER_TEMPLATE_DIR string = "relayers"

const MIGRATIONS_DIR string = "migrations"

func init() {
Expand Down Expand Up @@ -99,13 +104,37 @@ func ensureMigrated(ctx context.Context, db *sql.DB) error {
})
}

func Migrate(ctx context.Context, db *sql.DB) error {
type OptionalMigration struct {
Type string
Template string
Schema string
}

func Migrate(ctx context.Context, db *sql.DB, opts ...OptionalMigration) error {
if err := ensureMigrated(ctx, db); err != nil {
return err
}
// WithAllowMissing is necessary when upgrading from 0.10.14 since it
// includes out-of-order migrations
return goose.Up(db, MIGRATIONS_DIR, goose.WithAllowMissing())
err := goose.Up(db, MIGRATIONS_DIR, goose.WithAllowMissing())
if err != nil {
return fmt.Errorf("failed to do core database migration: %w", err)
}
for _, opt := range opts {
if opt.Type != "relayer" {
return fmt.Errorf("unknown migration type: %s", opt.Type)
}
if opt.Template != "evm" {
return fmt.Errorf("unknown migration template: %s", opt.Template)
}
root := fmt.Sprintf("%s/%s", RELAYER_TEMPLATE_DIR, opt.Template)

err = goose.Up(db, fmt.Sprintf("%s/%s", RELAYER_TEMPLATE_DIR, opt.Schema), goose.WithAllowMissing())
if err != nil {
return fmt.Errorf("failed to do %s database migration: %w", opt.Type, err)
}
}
return nil
}

func Rollback(ctx context.Context, db *sql.DB, version null.Int) error {
Expand Down
5 changes: 5 additions & 0 deletions core/store/migrate/relayers/evm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
This is an illustration of managing DB migrations for the EVM chain family

# Assumptions
- All EVM instances share these migrations
- Bespoke chain-specific migrations may reference these migrations but not the other way around
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-- +goose Up
CREATE SCHEMA IF NOT EXISTS {{.Schema}};
-- +goose Down
-- we don't know if the schema was created by this migration, so we can't drop it
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-- +goose Up
CREATE TABLE {{.Schema}}.bcf_3266_01 (
name TEXT PRIMARY KEY,
);
-- +goose Down
DROP TABLE {{.Schema}}.bcf_3266_01;
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-- +goose Up
CREATE TABLE {{.Schema}}.bcf_3266_02 (
id SERIAL PRIMARY KEY,
);
-- +goose Down
DROP TABLE {{.Schema}}.bcf_3266_02;
72 changes: 72 additions & 0 deletions core/store/migrate/relayers/evm/template/resolver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package template

import (
"bytes"
"fmt"
"html/template"
"io"
"os"
"path/filepath"
"strings"
)

type RelayerDB struct {
Schema string
}

// resolve resolves the template with the given RelayerDB
func resolve(out io.Writer, in io.Reader, val RelayerDB) error {
unresolved, err := io.ReadAll(in)
if err != nil {
return err
}
tmpl, err := template.New("schema-resolver").Parse(string(unresolved))
if err != nil {
return fmt.Errorf("failed to parse template %s: %w", unresolved, err)
}
err = tmpl.Execute(out, val)
return err
}

var migrationSuffix = ".tmpl.sql"

func generateMigrations(rootDir string, tmpDir string, val RelayerDB) ([]string, error) {
err := os.MkdirAll(tmpDir, os.ModePerm)
if err != nil {
return nil, err
}
var migrations = []string{}
var resolverFunc = func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
return nil
}
if !strings.HasSuffix(path, migrationSuffix) {
return nil
}
b, err := os.ReadFile(path)
if err != nil {
return fmt.Errorf("failed to read file %s: %w", path, err)
}
outPath := filepath.Join(tmpDir, strings.Replace(filepath.Base(path), migrationSuffix, ".sql", 1))
out, err := os.Create(outPath)
if err != nil {
return fmt.Errorf("failed to create file %s: %w", outPath, err)
}
defer out.Close()
err = resolve(out, bytes.NewBuffer(b), val)
if err != nil {
return fmt.Errorf("failed to resolve template %s: %w", path, err)
}
migrations = append(migrations, outPath)
return nil
}

err = filepath.Walk(rootDir, resolverFunc)
if err != nil {
return nil, err
}
return migrations, nil
}
108 changes: 108 additions & 0 deletions core/store/migrate/relayers/evm/template/resolver_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package template

import (
"bytes"
"os"
"path/filepath"
"testing"

"github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func Test_resolve(t *testing.T) {
type args struct {
val RelayerDB
}
tests := []struct {
name string
args args
wantOut string
wantErr bool
}{

{
name: "evm template",
args: args{
val: RelayerDB{
Schema: "evm",
},
},
wantOut: `-- +goose Up
CREATE TABLE evm.bcf_3266_01 (
name TEXT PRIMARY KEY,
);
-- +goose Down
DROP TABLE evm.bcf_3266_01;`,
},

{
name: "optimism template",
args: args{
val: RelayerDB{
Schema: "optimism",
},
},
wantOut: `-- +goose Up
CREATE TABLE optimism.bcf_3266_01 (
name TEXT PRIMARY KEY,
);
-- +goose Down
DROP TABLE optimism.bcf_3266_01;`,
},
}
for _, tt := range tests {
testInput, err := os.ReadFile("./migration_0001.tmpl.sql")
require.NoError(t, err)
t.Run(tt.name, func(t *testing.T) {
out := &bytes.Buffer{}
if err := resolve(out, bytes.NewBuffer(testInput), tt.args.val); (err != nil) != tt.wantErr {
t.Errorf("resolve() error = %v, wantErr %v", err, tt.wantErr)
return
}
assert.Equal(t, tt.wantOut, out.String(), cmp.Diff(tt.wantOut, out.String()))
})
}
}

func Test_generateMigrations(t *testing.T) {
tDir := t.TempDir()
type args struct {
rootDir string
tmpDir string
val RelayerDB
}
tests := []struct {
name string
args args
want []string
wantErr bool
}{
{
name: "evm template",
args: args{
rootDir: "./",
tmpDir: filepath.Join(tDir, "evm"),
val: RelayerDB{
Schema: "evm",
},
},
want: []string{
filepath.Join(tDir, "evm/migration_0000.sql"),
filepath.Join(tDir, "evm/migration_0001.sql"),
filepath.Join(tDir, "evm/migration_0002.sql")},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := generateMigrations(tt.args.rootDir, tt.args.tmpDir, tt.args.val)
if tt.wantErr {
require.Error(t, err)
} else {
require.NoError(t, err)
assert.Equal(t, tt.want, got)
}
})
}
}

0 comments on commit 7274c52

Please sign in to comment.