package db import ( "context" "database/sql" "fmt" "os" _ "github.com/go-sql-driver/mysql" ) func Open(ctx context.Context, url string) (*sql.DB, error) { d, err := sql.Open("mysql", url) if err != nil { return nil, err } if err := d.PingContext(ctx); err != nil { return nil, err } return d, nil } func Migrate(ctx context.Context, d *sql.DB) error { d.ExecContext(ctx, `SELECT GET_LOCK('trading_tool_migrate', 30)`) defer d.ExecContext(ctx, `SELECT RELEASE_LOCK('trading_tool_migrate')`) if _, err := d.ExecContext(ctx, `CREATE TABLE IF NOT EXISTS schema_migrations(version VARCHAR(255) PRIMARY KEY, applied_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP)`); err != nil { return err } files := []string{"migrations/001_init.sql", "migrations/002_admin.sql"} for _, f := range files { var exists bool if err := d.QueryRowContext(ctx, `SELECT EXISTS(SELECT 1 FROM schema_migrations WHERE version=?)`, f).Scan(&exists); err != nil { return err } if exists { continue } b, err := os.ReadFile(f) if err != nil { return err } if _, err := d.ExecContext(ctx, string(b)); err != nil { return fmt.Errorf("%s: %w", f, err) } if _, err := d.ExecContext(ctx, `INSERT INTO schema_migrations(version) VALUES(?)`, f); err != nil { return err } } return nil }