Skip to content

Commit

Permalink
refactor: Simplify stuff
Browse files Browse the repository at this point in the history
Squashed commit of the following:

commit b061842
Author: Rafael Espinoza <[email protected]>
Date:   Sun Apr 18 22:36:53 2021 -0700

    refactor: Rename MigrationsConf to Config, reduce usage

    This is another vestige of some overcomplicated design from when I first
    started this project. There was some unnecessary coupling between this
    type, the DSN type (removed in another commit) and the Driver type.

commit 0a01070
Author: Rafael Espinoza <[email protected]>
Date:   Sun Apr 18 20:08:11 2021 -0700

    refactor: Update Driver and remove DSN type

    Reduce the amount of work that a Driver needs to do by having the core
    library take care of the environment variable. Much easier to pass this
    in to the Driver as a regular argument. Another nice thing, you don't
    need to specify the DB_DSN anymore if all you want to do is look at the
    help menu.

    The DSN is now just one environment variable and can be handled by the
    godfish package itself. No need for this creational build pattern thing.

commit be83516
Author: Rafael Espinoza <[email protected]>
Date:   Fri Apr 2 18:06:02 2021 -0700

    refactor: Remove code, clean up stuff

    The DSN.Boot method and ConnectionParams type aren't so useful now that
    you can directly use the data source name.
  • Loading branch information
rafaelespinoza committed Apr 19, 2021
1 parent 69e9fc4 commit c0524c4
Show file tree
Hide file tree
Showing 13 changed files with 94 additions and 239 deletions.
41 changes: 1 addition & 40 deletions driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,11 @@ type Driver interface {
// internal reference to that connection for later use. This library might
// call this method multiple times, so use the internal reference if it's
// present instead of reconnecting to the database.
Connect() (*sql.DB, error)
Connect(dsn string) (*sql.DB, error)
// Close should check if there's an internal reference to a database
// connection (a *sql.DB) and if it's present, close it. Then reset the
// internal reference to that connection to nil.
Close() error
// DSN returns data source name info, ie: how do I connect?
DSN() DSN

// AppliedVersions queries the schema migrations table for migration
// versions that have been executed against the database. If the schema
Expand All @@ -39,43 +37,6 @@ type Driver interface {
UpdateSchemaMigrations(dir Direction, version string) error
}

// NewDriver initializes a Driver implementation by name and connection
// parameters.
func NewDriver(dsn DSN, migConf *MigrationsConf) (driver Driver, err error) {
return dsn.NewDriver(migConf)
}

// DSN generates a data source name or connection URL for DB connections. The
// output will be passed to the standard library's sql.Open method.
type DSN interface {
// Boot takes inputs from the host environment so it can create a Driver.
//
// Deprecated: Set the DB_DSN environment variable instead of using this.
Boot(ConnectionParams) error
// NewDriver calls the constructor of the corresponding Driver.
NewDriver(*MigrationsConf) (Driver, error)
// String uses connection parameters to form the data source name.
String() string
}

// ConnectionParams is what to use when initializing a DSN.
//
// Deprecated: Set the DB_DSN environment variable instead of using this.
type ConnectionParams struct {
Encoding string // Encoding is the client encoding for the connection.
Host string // Host is the name of the host to connect to.
Name string // Name is the database name.
Pass string // Pass is the password to use for the connection.
Port string // Port is the connection port.
User string // User is the name of the user to connect as.
}

// MigrationsConf is intended to lend customizations such as specifying the path
// to the migration files.
type MigrationsConf struct {
PathToFiles string `json:"path_to_files"`
}

// AppliedVersions represents an iterative list of migrations that have been run
// against the database and have been recorded in the schema migrations table.
// It's enough to convert a *sql.Rows struct when implementing the Driver
Expand Down
4 changes: 1 addition & 3 deletions drivers/mysql/godfish/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ import (
)

func main() {
var dsn mysql.DSN
err := commands.Run(&dsn)
if err != nil {
if err := commands.Run(mysql.NewDriver()); err != nil {
log.Println(err)
os.Exit(1)
}
Expand Down
44 changes: 4 additions & 40 deletions drivers/mysql/mysql.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,64 +3,28 @@ package mysql
import (
"database/sql"
"fmt"
"os"
"regexp"
"strings"

my "github.com/go-sql-driver/mysql"
"github.com/rafaelespinoza/godfish"
)

// DSN implements the godfish.DSN interface and defines keys, values needed to
// connect to a mysql database.
type DSN struct {
godfish.ConnectionParams
}

var _ godfish.DSN = (*DSN)(nil)

// Boot initializes the DSN from environment inputs.
func (p *DSN) Boot(params godfish.ConnectionParams) error {
p.ConnectionParams = params
return nil
}

// NewDriver creates a new mysql driver.
func (p *DSN) NewDriver(migConf *godfish.MigrationsConf) (godfish.Driver, error) {
return newMySQL(*p)
}

// String generates a data source name (or connection URL) based on the fields.
func (p *DSN) String() string {
return os.Getenv("DB_DSN")
}
func NewDriver() godfish.Driver { return &driver{} }

// driver implements the godfish.Driver interface for mysql databases.
type driver struct {
connection *sql.DB
dsn DSN
}

var _ godfish.Driver = (*driver)(nil)

func newMySQL(dsn DSN) (*driver, error) {
if dsn.Host == "" {
dsn.Host = "localhost"
}
if dsn.Port == "" {
dsn.Port = "3306"
}
return &driver{dsn: dsn}, nil
}

func (d *driver) Name() string { return "mysql" }
func (d *driver) DSN() godfish.DSN { return &d.dsn }
func (d *driver) Connect() (conn *sql.DB, err error) {
func (d *driver) Name() string { return "mysql" }
func (d *driver) Connect(dsn string) (conn *sql.DB, err error) {
if d.connection != nil {
conn = d.connection
return
}
if conn, err = sql.Open(d.Name(), d.DSN().String()); err != nil {
if conn, err = sql.Open(d.Name(), dsn); err != nil {
return
}
d.connection = conn
Expand Down
2 changes: 1 addition & 1 deletion drivers/mysql/mysql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ import (
)

func Test(t *testing.T) {
internal.RunDriverTests(t, &mysql.DSN{})
internal.RunDriverTests(t, mysql.NewDriver())
}
4 changes: 1 addition & 3 deletions drivers/postgres/godfish/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ import (
)

func main() {
var dsn postgres.DSN
err := commands.Run(&dsn)
if err != nil {
if err := commands.Run(postgres.NewDriver()); err != nil {
log.Println(err)
os.Exit(1)
}
Expand Down
44 changes: 4 additions & 40 deletions drivers/postgres/postgres.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,62 +2,26 @@ package postgres

import (
"database/sql"
"os"

"github.com/lib/pq"
"github.com/rafaelespinoza/godfish"
)

// DSN implements the godfish.DSN interface and defines keys, values needed to
// connect to a postgres database.
type DSN struct {
godfish.ConnectionParams
}

var _ godfish.DSN = (*DSN)(nil)

// Boot initializes the DSN from environment inputs.
func (p *DSN) Boot(params godfish.ConnectionParams) error {
p.ConnectionParams = params
return nil
}

// NewDriver creates a new postgres driver.
func (p *DSN) NewDriver(migConf *godfish.MigrationsConf) (godfish.Driver, error) {
return newPostgres(*p)
}

// String generates a data source name (or connection URL) based on the fields.
func (p *DSN) String() string {
return os.Getenv("DB_DSN")
}
func NewDriver() godfish.Driver { return &driver{} }

// driver implements the Driver interface for postgres databases.
type driver struct {
connection *sql.DB
dsn DSN
}

var _ godfish.Driver = (*driver)(nil)

func newPostgres(dsn DSN) (*driver, error) {
if dsn.Host == "" {
dsn.Host = "localhost"
}
if dsn.Port == "" {
dsn.Port = "5432"
}
return &driver{dsn: dsn}, nil
}

func (d *driver) Name() string { return "postgres" }
func (d *driver) DSN() godfish.DSN { return &d.dsn }
func (d *driver) Connect() (conn *sql.DB, err error) {
func (d *driver) Name() string { return "postgres" }
func (d *driver) Connect(dsn string) (conn *sql.DB, err error) {
if d.connection != nil {
conn = d.connection
return
}
if conn, err = sql.Open(d.Name(), d.DSN().String()); err != nil {
if conn, err = sql.Open(d.Name(), dsn); err != nil {
return
}
d.connection = conn
Expand Down
2 changes: 1 addition & 1 deletion drivers/postgres/postgres_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ import (
)

func Test(t *testing.T) {
internal.RunDriverTests(t, &postgres.DSN{})
internal.RunDriverTests(t, postgres.NewDriver())
}
61 changes: 49 additions & 12 deletions godfish.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,16 @@ import (

// Migrate executes all migrations at directoryPath in the specified direction.
func Migrate(driver Driver, directoryPath string, direction Direction, finishAtVersion string) (err error) {
var migrations []Migration
var (
dsn string
migrations []Migration
)
if dsn, err = getDSN(); err != nil {
return
}
if _, err = driver.Connect(dsn); err != nil {
return
}
defer driver.Close()

if finishAtVersion == "" && direction == DirForward {
Expand All @@ -23,9 +32,6 @@ func Migrate(driver Driver, directoryPath string, direction Direction, finishAtV
finishAtVersion = minVersion
}

if _, err = driver.Connect(); err != nil {
return
}
finder := migrationFinder{
direction: direction,
directoryPath: directoryPath,
Expand Down Expand Up @@ -57,17 +63,25 @@ var (
// ApplyMigration runs a migration at directoryPath with the specified version
// and direction.
func ApplyMigration(driver Driver, directoryPath string, direction Direction, version string) (err error) {
var mig Migration
var pathToFile string
var (
dsn string
pathToFile string
mig Migration
)

if dsn, err = getDSN(); err != nil {
return
}
if _, err = driver.Connect(dsn); err != nil {
return
}
defer driver.Close()

if direction == DirUnknown {
err = fmt.Errorf("unknown Direction %q", direction)
return
}
if _, err = driver.Connect(); err != nil {
return
}

if version == "" {
// attempt to find the next version to apply in the direction
var limit string
Expand Down Expand Up @@ -183,7 +197,11 @@ func runMigration(driver Driver, pathToFile string, mig Migration) (err error) {
// the database. Running any migration will create the table, so you don't
// usually need to call this function.
func CreateSchemaMigrationsTable(driver Driver) (err error) {
if _, err = driver.Connect(); err != nil {
var dsn string
if dsn, err = getDSN(); err != nil {
return
}
if _, err = driver.Connect(dsn); err != nil {
return err
}
defer driver.Close()
Expand All @@ -192,7 +210,11 @@ func CreateSchemaMigrationsTable(driver Driver) (err error) {

// Info displays the outputs of various helper functions.
func Info(driver Driver, directoryPath string, direction Direction, finishAtVersion string) (err error) {
if _, err = driver.Connect(); err != nil {
var dsn string
if dsn, err = getDSN(); err != nil {
return
}
if _, err = driver.Connect(dsn); err != nil {
return err
}
defer driver.Close()
Expand All @@ -206,6 +228,11 @@ func Info(driver Driver, directoryPath string, direction Direction, finishAtVers
return
}

// Config is for various runtime settings.
type Config struct {
PathToFiles string `json:"path_to_files"`
}

// Init creates a configuration file at pathToFile unless it already exists.
func Init(pathToFile string) (err error) {
_, err = os.Stat(pathToFile)
Expand All @@ -218,7 +245,7 @@ func Init(pathToFile string) (err error) {
}

var data []byte
if data, err = json.MarshalIndent(MigrationsConf{}, "", "\t"); err != nil {
if data, err = json.MarshalIndent(Config{}, "", "\t"); err != nil {
return err
}
return os.WriteFile(
Expand Down Expand Up @@ -454,3 +481,13 @@ func printMigrations(migrations []Migration) {
fmt.Printf("\t%-20s | %-s\n", mig.Version().String(), makeMigrationFilename(mig))
}
}

const dsnKey = "DB_DSN"

func getDSN() (dsn string, err error) {
dsn = os.Getenv(dsnKey)
if dsn == "" {
err = fmt.Errorf("missing environment variable: %s", dsnKey)
}
return
}
4 changes: 2 additions & 2 deletions godfish_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func TestInit(t *testing.T) {
if err = godfish.Init(pathToFile); err != nil {
t.Fatalf("something else is wrong with setup; %v", err)
}
var conf godfish.MigrationsConf
var conf godfish.Config
if data, err := os.ReadFile(pathToFile); err != nil {
t.Fatal(err)
} else if err = json.Unmarshal(data, &conf); err != nil {
Expand All @@ -54,7 +54,7 @@ func TestInit(t *testing.T) {
if err := godfish.Init(pathToFile); err != nil {
t.Fatal(err)
}
var conf2 godfish.MigrationsConf
var conf2 godfish.Config
if data, err := os.ReadFile(pathToFile); err != nil {
t.Fatal(err)
} else if err = json.Unmarshal(data, &conf2); err != nil {
Expand Down
Loading

0 comments on commit c0524c4

Please sign in to comment.