Coder Social home page Coder Social logo

pressly / goose Goto Github PK

View Code? Open in Web Editor NEW
5.7K 57.0 484.0 10.78 MB

A database migration tool. Supports SQL migrations and Go functions.

Home Page: https://pressly.github.io/goose/

License: Other

Go 98.32% Makefile 1.03% Shell 0.65%
database sql migration schema postgres mysql sqlite golang go migrations

goose's Introduction

goose

Goose CI Go Reference Go Report Card

Goose is a database migration tool. Manage your database schema by creating incremental SQL changes or Go functions.

Starting with v3.0.0 this project adds Go module support, but maintains backwards compatibility with older v2.x.y tags.

Goose supports embedding SQL migrations, which means you'll need go1.16 and up. If using go1.15 or lower, then pin v3.0.1.

Goals of this fork

github.com/pressly/goose is a fork of bitbucket.org/liamstask/goose with the following changes:

  • No config files
  • Default goose binary can migrate SQL files only
  • Go migrations:
    • We don't go build Go migrations functions on-the-fly from within the goose binary
    • Instead, we let you create your own custom goose binary, register your Go migration functions explicitly and run complex migrations with your own *sql.DB connection
    • Go migration functions let you run your code within an SQL transaction, if you use the *sql.Tx argument
  • The goose pkg is decoupled from the binary:
    • goose pkg doesn't register any SQL drivers anymore, thus no driver panic() conflict within your codebase!
    • goose pkg doesn't have any vendor dependencies anymore
  • We use timestamped migrations by default but recommend a hybrid approach of using timestamps in the development process and sequential versions in production.
  • Supports missing (out-of-order) migrations with the -allow-missing flag, or if using as a library supply the functional option goose.WithAllowMissing() to Up, UpTo or UpByOne.
  • Supports applying ad-hoc migrations without tracking them in the schema table. Useful for seeding a database after migrations have been applied. Use -no-versioning flag or the functional option goose.WithNoVersioning().

Install

go install github.com/pressly/goose/v3/cmd/goose@latest

This will install the goose binary to your $GOPATH/bin directory.

For a lite version of the binary without DB connection dependent commands, use the exclusive build tags:

go build -tags='no_postgres no_mysql no_sqlite3 no_ydb' -o goose ./cmd/goose

For macOS users goose is available as a Homebrew Formulae:

brew install goose

See the docs for more installation instructions.

Usage

Usage: goose [OPTIONS] DRIVER DBSTRING COMMAND

or

Set environment key
GOOSE_DRIVER=DRIVER
GOOSE_DBSTRING=DBSTRING
GOOSE_MIGRATION_DIR=MIGRATION_DIR

Usage: goose [OPTIONS] COMMAND

Drivers:
    postgres
    mysql
    sqlite3
    mssql
    redshift
    tidb
    clickhouse
    vertica
    ydb

Examples:
    goose sqlite3 ./foo.db status
    goose sqlite3 ./foo.db create init sql
    goose sqlite3 ./foo.db create add_some_column sql
    goose sqlite3 ./foo.db create fetch_user_data go
    goose sqlite3 ./foo.db up

    goose postgres "user=postgres dbname=postgres sslmode=disable" status
    goose mysql "user:password@/dbname?parseTime=true" status
    goose redshift "postgres://user:[email protected]: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
    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_DRIVER=sqlite3 GOOSE_DBSTRING=./foo.db goose status
    GOOSE_DRIVER=sqlite3 GOOSE_DBSTRING=./foo.db goose create init sql
    GOOSE_DRIVER=postgres GOOSE_DBSTRING="user=postgres dbname=postgres sslmode=disable" goose status
    GOOSE_DRIVER=mysql GOOSE_DBSTRING="user:password@/dbname" goose status
    GOOSE_DRIVER=redshift GOOSE_DBSTRING="postgres://user:[email protected]:5439/db" goose status

Options:

  -allow-missing
        applies missing (out-of-order) migrations
  -certfile string
        file path to root CA's certificates in pem format (only support on mysql)
  -dir string
        directory with migration files (default ".", can be set via the GOOSE_MIGRATION_DIR env variable).
  -h    print help
  -no-color
        disable color output (NO_COLOR env variable supported)
  -no-versioning
        apply migration commands with no versioning, in file order, from directory pointed to
  -s    use sequential numbering for new migrations
  -ssl-cert string
        file path to SSL certificates in pem format (only support on mysql)
  -ssl-key string
        file path to SSL key in pem format (only support on mysql)
  -table string
        migrations table name (default "goose_db_version")
  -timeout duration
        maximum allowed duration for queries to run; e.g., 1h13m
  -v    enable verbose mode
  -version
        print version

Commands:
    up                   Migrate the DB to the most recent version available
    up-by-one            Migrate the DB up by 1
    up-to VERSION        Migrate the DB to a specific VERSION
    down                 Roll back the version by 1
    down-to VERSION      Roll back to a specific VERSION
    redo                 Re-run the latest migration
    reset                Roll back all migrations
    status               Dump the migration status for the current DB
    version              Print the current version of the database
    create NAME [sql|go] Creates new migration file with the current timestamp
    fix                  Apply sequential ordering to migrations
    validate             Check migration files without running them

create

Create a new SQL migration.

$ goose create add_some_column sql
$ Created new file: 20170506082420_add_some_column.sql

Edit the newly created file to define the behavior of your migration.

You can also create a Go migration, if you then invoke it with your own goose binary:

$ goose create fetch_user_data go
$ Created new file: 20170506082421_fetch_user_data.go

up

Apply all available migrations.

$ goose up
$ OK    001_basics.sql
$ OK    002_next.sql
$ OK    003_and_again.go

up-to

Migrate up to a specific version.

$ goose up-to 20170506082420
$ OK    20170506082420_create_table.sql

up-by-one

Migrate up a single migration from the current version

$ goose up-by-one
$ OK    20170614145246_change_type.sql

down

Roll back a single migration from the current version.

$ goose down
$ OK    003_and_again.go

down-to

Roll back migrations to a specific version.

$ goose down-to 20170506082527
$ OK    20170506082527_alter_column.sql

redo

Roll back the most recently applied migration, then run it again.

$ goose redo
$ OK    003_and_again.go
$ OK    003_and_again.go

status

Print the status of all migrations:

$ goose status
$   Applied At                  Migration
$   =======================================
$   Sun Jan  6 11:25:03 2013 -- 001_basics.sql
$   Sun Jan  6 11:25:03 2013 -- 002_next.sql
$   Pending                  -- 003_and_again.go

Note: for MySQL parseTime flag must be enabled.

Note: for MySQL multiStatements must be enabled. This is required when writing multiple queries separated by ';' characters in a single sql file.

version

Print the current version of the database:

$ goose version
$ goose: version 002

Migrations

goose supports migrations written in SQL or in Go.

SQL Migrations

A sample SQL migration looks like:

-- +goose Up
CREATE TABLE post (
    id int NOT NULL,
    title text,
    body text,
    PRIMARY KEY(id)
);

-- +goose Down
DROP TABLE post;

Each migration file must have exactly one -- +goose Up annotation. The -- +goose Down annotation is optional. If the file has both annotations, then the -- +goose Up annotation must come first.

Notice the annotations in the comments. Any statements following -- +goose Up will be executed as part of a forward migration, and any statements following -- +goose Down will be executed as part of a rollback.

By default, all migrations are run within a transaction. Some statements like CREATE DATABASE, however, cannot be run within a transaction. You may optionally add -- +goose NO TRANSACTION to the top of your migration file in order to skip transactions within that specific migration file. Both Up and Down migrations within this file will be run without transactions.

By default, SQL statements are delimited by semicolons - in fact, query statements must end with a semicolon to be properly recognized by goose.

More complex statements (PL/pgSQL) that have semicolons within them must be annotated with -- +goose StatementBegin and -- +goose StatementEnd to be properly recognized. For example:

-- +goose Up
-- +goose StatementBegin
CREATE OR REPLACE FUNCTION histories_partition_creation( DATE, DATE )
returns void AS $$
DECLARE
  create_query text;
BEGIN
  FOR create_query IN SELECT
      'CREATE TABLE IF NOT EXISTS histories_'
      || TO_CHAR( d, 'YYYY_MM' )
      || ' ( CHECK( created_at >= timestamp '''
      || TO_CHAR( d, 'YYYY-MM-DD 00:00:00' )
      || ''' AND created_at < timestamp '''
      || TO_CHAR( d + INTERVAL '1 month', 'YYYY-MM-DD 00:00:00' )
      || ''' ) ) inherits ( histories );'
    FROM generate_series( $1, $2, '1 month' ) AS d
  LOOP
    EXECUTE create_query;
  END LOOP;  -- LOOP END
END;         -- FUNCTION END
$$
language plpgsql;
-- +goose StatementEnd

Goose supports environment variable substitution in SQL migrations through annotations. To enable this feature, use the -- +goose ENVSUB ON annotation before the queries where you want substitution applied. It stays active until the -- +goose ENVSUB OFF annotation is encountered. You can use these annotations multiple times within a file.

This feature is disabled by default for backward compatibility with existing scripts.

For PL/pgSQL functions or other statements where substitution is not desired, wrap the annotations explicitly around the relevant parts. For example, to exclude escaping the ** characters:

-- +goose StatementBegin
CREATE OR REPLACE FUNCTION test_func()
RETURNS void AS $$
-- +goose ENVSUB ON
BEGIN
	RAISE NOTICE '${SOME_ENV_VAR}';
END;
-- +goose ENVSUB OFF
$$ LANGUAGE plpgsql;
-- +goose StatementEnd
Supported expansions (click here to expand):
  • ${VAR} or $VAR - expands to the value of the environment variable VAR
  • ${VAR:-default} - expands to the value of the environment variable VAR, or default if VAR is unset or null
  • ${VAR-default} - expands to the value of the environment variable VAR, or default if VAR is unset
  • ${VAR?err_msg} - expands to the value of the environment variable VAR, or prints err_msg and error if VAR unset
  • ${VAR:?err_msg} - expands to the value of the environment variable VAR, or prints err_msg and error if VAR unset or null. THIS IS NOT SUPPORTED

See mfridman/interpolate for more details on supported expansions.

Embedded sql migrations

Go 1.16 introduced new feature: compile-time embedding files into binary and corresponding filesystem abstraction.

This feature can be used only for applying existing migrations. Modifying operations such as fix and create will continue to operate on OS filesystem even if using embedded files. This is expected behaviour because io/fs interfaces allows read-only access.

Make sure to configure the correct SQL dialect, see dialect.go for supported SQL dialects.

Example usage, assuming that SQL migrations are placed in the migrations directory:

package main

import (
    "database/sql"
    "embed"

    "github.com/pressly/goose/v3"
)

//go:embed migrations/*.sql
var embedMigrations embed.FS

func main() {
    var db *sql.DB
    // setup database

    goose.SetBaseFS(embedMigrations)

    if err := goose.SetDialect("postgres"); err != nil {
        panic(err)
    }

    if err := goose.Up(db, "migrations"); err != nil {
        panic(err)
    }

    // run app
}

Note that we pass "migrations" as directory argument in Up because embedding saves directory structure.

Go Migrations

  1. Create your own goose binary, see example
  2. Import github.com/pressly/goose
  3. Register your migration functions
  4. Run goose command, ie. goose.Up(db *sql.DB, dir string)

A sample Go migration 00002_users_add_email.go file looks like:

package migrations

import (
	"database/sql"

	"github.com/pressly/goose/v3"
)

func init() {
	goose.AddMigration(Up, Down)
}

func Up(tx *sql.Tx) error {
	_, err := tx.Exec("UPDATE users SET username='admin' WHERE username='root';")
	if err != nil {
		return err
	}
	return nil
}

func Down(tx *sql.Tx) error {
	_, err := tx.Exec("UPDATE users SET username='root' WHERE username='admin';")
	if err != nil {
		return err
	}
	return nil
}

Note that Go migration files must begin with a numeric value, followed by an underscore, and must not end with *_test.go.

Development

This can be used to build local goose binaries without having the latest Go version installed locally.

DOCKER_BUILDKIT=1  docker build -f Dockerfile.local --output bin .

Hybrid Versioning

Please, read the versioning problem first.

By default, if you attempt to apply missing (out-of-order) migrations goose will raise an error. However, If you want to apply these missing migrations pass goose the -allow-missing flag, or if using as a library supply the functional option goose.WithAllowMissing() to Up, UpTo or UpByOne.

However, we strongly recommend adopting a hybrid versioning approach, using both timestamps and sequential numbers. Migrations created during the development process are timestamped and sequential versions are ran on production. We believe this method will prevent the problem of conflicting versions when writing software in a team environment.

To help you adopt this approach, create will use the current timestamp as the migration version. When you're ready to deploy your migrations in a production environment, we also provide a helpful fix command to convert your migrations into sequential order, while preserving the timestamp ordering. We recommend running fix in the CI pipeline, and only when the migrations are ready for production.

Credit

The gopher mascot was designed by Renée French / CC 3.0. For more info check out the Go Blog. Adapted by Ellen.

License

Licensed under MIT License

goose's People

Contributors

1vn avatar adampie avatar chapsuk avatar craigpangea avatar danielheath avatar dependabot[bot] avatar duffn avatar gyepisam avatar huynguyenh avatar jkl1337 avatar josharian avatar keiichihirobe avatar liamstask avatar lukehutton avatar mfridman avatar mkozjak avatar mmatczuk avatar msdinit avatar ntindall avatar ori-shalom avatar parkr avatar sashamelentyev avatar sblackstone avatar shuhaowu avatar smacker avatar songmu avatar stephenafamo avatar tbaud0n avatar vojtechvitek avatar yoshiya0503 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

goose's Issues

Add support for sequential numbering of migrations

When two or more developers decide to create a new migration at the same revision in a project, the order of migration is non-deterministic (according to the moment when they create migration template).
This problem can be resolved by extending goose with an option to create sequential migrations (i.e create-next) which always determine the next sequence number as the most recent existing migration version plus one. With this procedure, a possible race in migrations versioning will be resolved by CI or repository because a migration with the target version may already exist.

Integration with testing

Hi Programmers,

I want to integrate goose migration to my Go testing code, my scenario is to up all migrations before test and then reset all database once testing is done.

my problem is I can't find any documentation/sample code to do it.

my question is it possible to trigger migration (up/down/reset) from inside Go Code (in this case is testing code) ?

I also have tried to execute the goose command using exec.Command() but it always returns exit code 1

this is my code to trigger the migration up:

func pretest() {
      var args = []string{
          os.Getenv("DB_SERVER"),
          "\"user=" + os.Getenv("DB_USERNAME") + " dbname=" + os.Getenv("DB_TEST_NAME") + " sslmode=disable\"",
          "up",
      }   
  
      exe := exec.Command("goose", args...)
      exe.Dir = os.Getenv("DB_MIGRATION")
      /* result, err := exe.Output()*/
      //fmt.Println(string(result))
      /*fmt.Println(err)*/
  
      output := exe.Run()
      fmt.Println(output)
  }

My testing output:

image

Thanks a lot

Create command

Hi,

Just found this package after looking how to run goose via API. I like what I see, but I notice within the Readme creating migrations is still listed. However the binary usage no longer reports this functionality, and looking through the code appears to confirm this, should we expect to write the SQL migrations by hand?

Thanks

Migrating error on create function

-- +goose Up
CREATE FUNCTION update_updated_at_column()
  RETURNS TRIGGER AS $$
BEGIN
  NEW.updated_at = now();
  RETURN NEW;
END;
$$ LANGUAGE 'plpgsql';

-- +goose Down
DROP FUNCTION update_updated_at_column();

I'm run goose util in terminal for up migration and see next error

onea$ goose postgres "postgres://smaling:smaling@localhost:5432/smaling?sslmode=disable" up
2017/12/26 00:08:08 goose run: FAIL pq: unterminated dollar-quoted string at or near "$$
BEGIN
  NEW.updated_at = now();
", quitting migration

How fix this error?

Gopkg.lock missing from repo

In Homebrew/homebrew-core#28759 I moved all formulae using dep ensure to use dep ensure -vendor-only. goose was the only one for which that was not possible yet:

==> dep ensure -vendor-only
no Gopkg.lock exists from which to populate vendor/

It seems Gopkg.lock has not been checked into source control.

Note that as of Homebrew/brew#4305 this is now a hard requirement so it would be great if Gopkg.lock could be added so that goose isn't failing audit. Thanks!

Timestamp migration ID

Hi, what do you think about having possibility to make migration number depending of timestamp?
It is useful when several people work on the same project

If ok, I can make the PR for doing this leaving the default behavoir like it works now?

go build for linux error

warbook:goose pendolf$ make dist
GOOS=darwin GOARCH=amd64 go build -o ./bin/goose-darwin64 ./cmd/goose
GOOS=linux GOARCH=amd64 go build -o ./bin/goose-linux64 ./cmd/goose
# github.com/mattn/go-sqlite3
../../mattn/go-sqlite3/sqlite3_go18.go:18: undefined: SQLiteConn
../../mattn/go-sqlite3/sqlite3_go18.go:26: undefined: SQLiteConn
../../mattn/go-sqlite3/sqlite3_go18.go:27: undefined: namedValue
../../mattn/go-sqlite3/sqlite3_go18.go:29: undefined: namedValue
../../mattn/go-sqlite3/sqlite3_go18.go:35: undefined: SQLiteConn
../../mattn/go-sqlite3/sqlite3_go18.go:36: undefined: namedValue
../../mattn/go-sqlite3/sqlite3_go18.go:44: undefined: SQLiteConn
../../mattn/go-sqlite3/sqlite3_go18.go:49: undefined: SQLiteConn
../../mattn/go-sqlite3/sqlite3_go18.go:54: undefined: SQLiteStmt
../../mattn/go-sqlite3/sqlite3_go18.go:63: undefined: SQLiteStmt
../../mattn/go-sqlite3/sqlite3_go18.go:36: too many errors
make: *** [dist] Error 2

Custom connections

Thanks for your work on this fork.

I had a couple questions regarding how you are setting connections.

I'm currently using stock goose but my major issue is using TLS/SSL. I use TLS/SSL in my go app by registering TLS setups then referencing it in the connection string "?tls=custom". But goose doesn't have a way to run arbitrary code to run this setup routine. Is there a way in this fork to handle TLS/SSL connections? I looked into just wrapping it in custom binary but didnt seem too simple to pull off.

Is command line the only way to pass in the connection password? Seems like bad practice as it gets left in the bash_history, no?

Thanks!

Edit: To clarify, I have been using goose successfully for a year, but we are just now implementing SSL for MySQL as we are moving our DB server.

Use of log.Fatal/f prevents use as a library

There are quite a few places in the code where log.Fatal or its variants are used when an error condition is encountered. This may be an easy way to handle such conditions for a CLI app, but if this code is used as a library in another application, that causes the application to exit and the programmer has no control over it. It would be better to log as an error and return immediately, and have the caller deal with the error.

Include SQL files

Isn't it possible to include external SQL files (with function definitions etc)?

Importing requires too much duplicate code

I am working on a project with go migrations. As per the instructions, the entire example/main.go file needs to be copied. This can lead to outdated versions of the methods being called, even after upgrading the package itself. There are already 2 slightly different versions of the main.go file in the repo.

Question about redo command

I am very new to Go and I was trying to understand how this library works.

My understanding is that the redo command should roll the last migration back and roll it up again.
If all your migrations are 'up' and you try to run redo, you get the following error - no next version found.

I noticed that the code for this is as follows -

previous, err := migrations.Next(currentVersion)
if err != nil {
	return err
}

if err := previous.Up(db); err != nil {
	return err
}

if err := current.Up(db); err != nil {
	return err
}

I think it should call Down and then Up method on the current migration.

if err := current.Down(db); err != nil {
	return err
}

if err := current.Up(db); err != nil {
	return err
}

If you think this is correct, let me know. I'll send a PR.

Add Redshift support

Though Redshift is partially compatible with PostgreSQL, it does not support the serial data type. Minor updates should make goose work with Redshift.

% goose postgres "postgres://user:**********@db.qwerty.us-east-1.redshift.amazonaws.com:5439/test" up
2017/05/03 10:11:10 goose run: pq: Column "goose_db_version.id" has unsupported type "serial".

goose fails with Killed: 9 on macOS

Hi,

Thanks for making this available! :-)

I'm eager to use it, but the following happens:

bash> go get -u github.com/pressly/goose/cmd/goose
Killed: 9

goose crashes like this every time, I cannot get goose to work.

I'm on macOS 10.12.3 with Xcode Version 8.3.2 (8E2002). go version go1.8 darwin/amd64

I think this may be related to this issue: runtime: some Go executables broken with macOS 10.12.4 / Xcode 8.3 but fine with Xcode 8.2

Any chance you could take a look? :-)

In the meantime, I'll try building my own goose binary by copying and pasting your main.go and adjusting it as needed, but I just wanted to log this since it's confusing and unfortunate for a new goose user to see goose crash on first use.

goose create edge cases

goose create doesn't see Go migrations, unless the binary is rebuilt every each time

See discussion at #50 (comment)

Possible solution: We might try reading directly from FS (current directory) rather than relying on CollectMigrations()

fizz support

Hi.

Would you be interested in a PR which would add support for fizz migrations ? https://github.com/markbates/pop/tree/master/fizz

My bigger picture is that I would like to combine this with a system for embedding the migrations in binary. I have read trough source code of markbates/pop and it uses an array of migrations with a common interface. what this means is that, when implemented, one of the implementations would be the files and directories whereas the other one would be a bridge towards resource embedding libraries: https://github.com/avelino/awesome-go#resource-embedding

pop itself enforces the migrations to be in a separate files, which I don't like. By implementing this, it would allow goose to be database-agnostic.

I can add some pseudocode if you're interested.

cheers and thank you for maintaining this project :)

Useless error messages

2017/06/23 15:46:58 FAIL 20170615160950_Base.sql (pq: syntax error at or near "CREATE"), quitting migration.

Is there any way of getting more useful error messages? I just switched to using psql directly on a testing db for debugging...

create migration command not working

The documentation lists

goose create AddSomeColumns

But the cli expects driver first:

https://github.com/pressly/goose/blob/master/cmd/goose/main.go#L38-L41

Ex:

goose create AddSomeColumns sql
2016/10/21 09:23:27 "create" driver not supported

This works

goose postgres "user=postgres dbname=postgres sslmode=disable" create blahblah
Created go migration at 20161021092603_blahblah.go

However, the driver and dbstring aren't necessary to creating a migration file, so I think the cli should match the readme example

Dollar quoting supprt

Trying to run this create trigger

CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = now();
    RETURN NEW;
END;
$$ language 'plpgsql';

CREATE TRIGGER update_properties_updated_at BEFORE UPDATE ON properties FOR EACH ROW EXECUTE PROCEDURE  update_updated_at_column();

And I keep getting pq: unterminated dollar-quoted string at or near "$$. Am I doing something wrong or goose doesn't support dollar quoting?

Release with binaries

Hello guys,

Is it possible to add at least one tagged release with builds?
That's supper convenient to fetch and use with automation and avoid fetching and building it each time !

Thank you for making it available on Github!
Cheers!

Could not update tables: Error 1054: Unknown column '$1' in 'field list'

Hello,

I'm trying to use the goose.Up function in my project, but I'm running into the error Could not update tables: Error 1054: Unknown column '$1' in 'field list'. I'm probably doing something wrong, but some help with this would be greatly appreciated.

Failing code

func UpdateTables() error {
	log.Println("Updating the tables.")
	config, err := config.New()

	if err != nil {
		log.Println("Could not access the config struct")
		return err
	}

	conn, err := connections.New()

	if err != nil {
		log.Println("Could not access the database")
		return err
	}

	// conn is a sqlx.DB, so get the sql.DB pointer from that
	// config.MigrationsPath points to the db directory with the migrations file.
	if err := goose.Up(conn.DB, config.MigrationsPath); err != nil {
		log.Println("Could not update database")
		return err
	}

	return nil
}

func CreateDefaults() error {
	log.Println("Creating default entries.")
	if err := CreateDefaultStatuses(); err != nil {
		return err
	}
	return nil
}

Migrations file

-- +goose Up
-- SQL in section 'Up' is executed when this migration is applied

-- Enums
CREATE TABLE StatusEnum(
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  name VARCHAR(50) NOT NULL,
  PRIMARY KEY(id),
  UNIQUE(name)
);
CREATE TABLE ClassEnum(
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  name VARCHAR(50) NOT NULL,
  PRIMARY KEY(id),
  UNIQUE(name)
);
CREATE TABLE GenderEnum(
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  name VARCHAR(50) NOT NULL,
  other VARCHAR(150) NOT NULL,
  PRIMARY KEY(id),
  UNIQUE(name)
);

-- Roles and permissions
CREATE TABLE Role(
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  status_id INT UNSIGNED NOT NULL,
  name VARCHAR(100) NOT NULL,
  isAdmin BOOLEAN NOT NULL,
  PRIMARY KEY(id),
  UNIQUE(name),
  CONSTRAINT statusRole_fkConstraint
    FOREIGN KEY (status_id) REFERENCES StatusEnum (id)
);
CREATE TABLE Permission(
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  name VARCHAR(100) NOT NULL,
  PRIMARY KEY(id),
  UNIQUE(name)
);
CREATE TABLE RolePermission(
  role_id INT UNSIGNED NOT NULL,
  permission_id INT UNSIGNED NOT NULL,
  CONSTRAINT roleRolePermission_fkConstraint
    FOREIGN KEY (role_id) REFERENCES Role (id)
    ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT permissionRolePermission_fkConstraint
    FOREIGN KEY (permission_id) REFERENCES Permission (id)
    ON DELETE CASCADE ON UPDATE CASCADE
);

-- Hero/Party classes
CREATE TABLE Hero(
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  firstName VARCHAR(50) NOT NULL,
  lastName VARCHAR(50) NOT NULL,
  email VARCHAR(200) NOT NULL,
  gender_id INT UNSIGNED NOT NULL,
  class_id INT UNSIGNED NOT NULL,
  status_id INT UNSIGNED NOT NULL,
  role_id INT UNSIGNED NOT NULL,
  UNIQUE(email),
  PRIMARY KEY(id),
  CONSTRAINT statusHero_fkConstraint
    FOREIGN KEY (status_id) REFERENCES StatusEnum (id),
  CONSTRAINT genderHero_fkConstraint
    FOREIGN KEY (gender_id) REFERENCES GenderEnum (id),
  CONSTRAINT roleHero_fkConstraint
    FOREIGN KEY (role_id) REFERENCES Role (id)
);
CREATE TABLE Party(
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  name VARCHAR(200) NOT NULL,
  partyLeader_id INT UNSIGNED NOT NULL,
  PRIMARY KEY(id),
  CONSTRAINT heroParty_fkConstraint
    FOREIGN KEY (id) REFERENCES Hero (id)
);
CREATE TABLE HeroParty(
  hero_id INT UNSIGNED NOT NULL,
  party_id INT UNSIGNED NOT NULL,
  CONSTRAINT heroHeroParty_fkConstraint
    FOREIGN KEY (hero_id) REFERENCES Hero (id)
    ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT partyHeroParty_fkConstraint
    FOREIGN KEY (party_id) REFERENCES Party (id)
    ON DELETE CASCADE ON UPDATE CASCADE
);

-- Authentication
CREATE TABLE Auth(
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  seed CHAR(128) NOT NULL,
  iterations INT UNSIGNED NOT NULL,
  hashedPassword CHAR(128) NOT NULL,
  hero_id INT UNSIGNED NOT NULL,
  PRIMARY KEY(id),
  CONSTRAINT heroAuth_fkConstraint
    FOREIGN KEY (hero_id) REFERENCES Hero (id)
);

-- Invitation
CREATE TABLE Invitation(
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  slug CHAR(128) NOT NULL,
  status_id INT UNSIGNED NOT NULL,
  party_id INT UNSIGNED NOT NULL,
  PRIMARY KEY(id),
  UNIQUE(slug),
  CONSTRAINT statusInvitation_fkConstraint
    FOREIGN KEY (status_id) REFERENCES StatusEnum (id),
  CONSTRAINT partyInvitation_fkConstraint
    FOREIGN KEY (party_id) REFERENCES Party (id)
    ON DELETE CASCADE ON UPDATE CASCADE
);

-- Blog
CREATE TABLE BlogPost(
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  slug VARCHAR(200) NOT NULL,
  title VARCHAR(200) NOT NULL,
  body TEXT NOT NULL,
  submitDate DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  displayDate DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  hero_id INT UNSIGNED NOT NULL,
  PRIMARY KEY(id),
  UNIQUE(slug),
  CONSTRAINT heroBlogPost_fkConstraint
    FOREIGN KEY (hero_id) REFERENCES Hero (id)
);

-- Survey
CREATE TABLE Survey(
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  description TEXT NOT NULL,
  startDate DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  endDate DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY(id)
);
CREATE TABLE Question(
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  survey_id INT UNSIGNED NOT NULL,
  question JSON,
  PRIMARY KEY(id),
  CONSTRAINT surveyQuestion_fkConstraint
    FOREIGN KEY (survey_id) REFERENCES Survey (id)
);
CREATE TABLE Response(
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  question_id INT UNSIGNED NOT NULL,
  hero_id INT UNSIGNED NOT NULL,
  response JSON,
  PRIMARY KEY(id),
  CONSTRAINT questionResponse_fkConstraint
    FOREIGN KEY (question_id) REFERENCES Question (id),
  CONSTRAINT heroResponse_fkConstraint
    FOREIGN KEY (hero_id) REFERENCES Hero (id)
);


-- +goose Down
-- SQL section 'Down' is executed when this migration is rolled back
DROP TABLE Response;
DROP TABLE Question;
DROP TABLE Survey;
DROP TABLE Invitation;
DROP TABLE BlogPost;
DROP TABLE Auth;
DROP TABLE HeroParty;
DROP TABLE Party;
DROP TABLE Hero;
DROP TABLE RolePermission;
DROP TABLE Permission;
DROP TABLE Role;
DROP TABLE StatusEnum;
DROP TABLE GenderEnum;
DROP TABLE ClassEnum;

Allow to run migration without transaction

We have migration with CREATE INDEX CONCURRENTLY. It can't be done in transaction.
Will you be welcome for pull request similar to this commit? smacker@a56fc24

Migration example:

-- +goose DisableTransaction

-- +goose Up
-- SQL in section 'Up' is executed when this migration is applied

-- IF NOT EXISTS allows to run queries manually
-- CONCURRENTLY doesn't lock table, so it's safe to run on production without downtime
CREATE INDEX CONCURRENTLY
IF NOT EXISTS journey_last_miles_tracking_number_index
ON journey_last_miles (tracking_number);

-- +goose Down
-- SQL section 'Down' is executed when this migration is rolled back

DROP INDEX journey_last_miles_tracking_number_index;

sequential numbering with postgres or redshift schemas

I'm just started using this fork because it has support for Redshift. However, I use schemas to organize tables with databases like redshift and postgres but the new sequential numbering of files, instead of timestamps, means that I have to put all my migration files in the same directory, otherwise the counter will start again at 00001 for each directory.

Say I have a single database in redshift or postgres, and it has multiple schemas CREATE SCHEMA foo; and CREATE SCHEMA bar;. If I wanted to organize my goose migrations by folders, I might have:

foo/
bar/

If i then ran cd foo && goose create add_cars sql then cd ../bar && goose_create add_trains sql, goose will create foo/00001_add_cars.sql and bar/00001_add_trains.sql. So running:

$ cd foo
$ goose postgres "user=rkulla dbname=postgres sslmode=disable" up
goose: no migrations to run. current version: 1
$ cd ../bar
$ goose postgres "user=rkulla dbname=postgres sslmode=disable" up
goose: no migrations to run. current version: 1

would only apply the migration under foo/ but not the one under bar/, because both migrations start with 00001_ and postgres or redshift only get ONE goose_db_version table to share amongst the different schema names. This makes them harder to organize unless I do goose create add_cars_foo sql' and goose create add_trains_bar sql, then run commands like ls *_foo.sqlandls *_bar.sql`.

It's not that big of a deal right now I guess, but I'm wondering if there's a better way and if it's really worth not using timestamps. IIRC, Ruby on Rails's migration feature used to use sequential numbers but developers complained because it caused a lot of conflicts when 2 different developers working on the same project made separate changes but both generated a migration with the same number. So Rails switched to UTC timestamps.

Support repetable migration

In some cases would be convient to migrate not by creating new migration, but by updating an existing one (for example, for update stored procedure / triggers). Flyway, from-JVM-world migration tool, has this feature (https://flywaydb.org/getstarted/repeatable). Are there plans to add this feature to goose, or a workaround for such case?

Precompiled 2.1.0 binaries

I noticed that only version 1.0 have compiled binaries in the list of releases. I would be nice to have the latest precompiled binary so we can use it in our dockerfile :)

Feature Request: Custom migration templates

Hi,

If I'm willing to create a PR, would you be open to adding an option to allow us to specify custom templates?

The reason I ask is that the current sql template produces:


-- +goose Up
-- SQL in section 'Up' is executed when this migration is applied


-- +goose Down
-- SQL section 'Down' is executed when this migration is rolled back


but I would like it to produce:


-- +goose Up
-- +goose StatementBegin
-- +goose StatementEnd


-- +goose Down
-- +goose StatementBegin
-- +goose StatementEnd


I want to always use the begin and end statements since we will be doing some complex migrations including plpgsql functions and I'd rather just always use the same format.

Allowing me to specify a custom template would avoid me having to replace the default template in the newly-created file after creating a new migration.

If you're open to this, please give me a suggestion as to how you'd like the template specified and I'd be happy to follow that. I guess I'd see these templates specified in code, but I suppose a command like arg would work as well.

Thoughts?

Thanks!

Update README and usage

The README and usage need some updates. I think they should contain a list of drivers, all commands (I didn't even know up-to and down-to existed until reading the source) and examples. I'm thinking along the lines of the below. I'll do this, but wanted to discuss first.

Usage: goose [OPTIONS] DRIVER DBSTRING COMMAND

Drivers:
    postgres PostgreSQL driver
    MySQL MySQL drivers
    ....

Commands:
    up         Migrate the DB to the most recent version available
    up-to     .....
    down       Roll back the version by 1
    down-to .....
    redo       Re-run the latest migration
    status     Dump the migration status for the current DB
    dbversion  Print the current version of the database
    create     Creates a blank migration template

Options:
  -dir string
    	directory with migration files (default ".")

Examples:
    goose postgres "user=postgres dbname=postgres sslmode=disable" up
    goose mysql "user:password@/dbname" down
    goose sqlite3 ./foo.db status
    goose redshift "postgres://user:[email protected]:5439/db" create init sql
    .....

Cannot connect to remote host/postgres

both commands below just hungs with no errors or any output:

goose postgres "postgresql://user:pass@remotehost:5432/dbname?sslmode=disable" status
goose postgres "host=remotehost password=user:pass user=user dbname=dbname sslmode=disable" status

k8s setup, postgres is in the same cluster and accesible via ip

Add support for precompiled go migrations

In some environments it may be impossible to deploy a working go compiler due to security reasons. In that case, one approach to support migrations in go, is to provide them as precompiled shared libraries (*.so). Golang 1.8/stable has support for plugins and these can be loaded from goose in the same way as sql migrations or go migrations are loaded.
This improvement will not break existing API:

  • migrations path will contain *.sql, *.go and *.so files
  • collect migrations will also load shared libraries and look for migrations there
  • precompiled migrations can be stored in one or more libraries - depending on requirements from deployment procedure
  • compilation of migration libraries can be done offline so the runtime migration will be faster (no need for 'go run')

Goose returns error :(

After running [ $GOPATH/bin/goose CreateUsersTable ] command, I'm getting this error [ [1] 1035 killed $GOPATH/bin/goose CreateUsersTable ]

@trevrosen

`status` fails with mysql if the dsn does not have `parseTime=true`

To reproduce: run ./bin/goose mysql $DSN status where DSN is a DSN with no parameters.

This produces the following output:

    Applied At                  Migration
    =======================================
2018/03/29 22:07:13 sql: Scan error on column index 0: unsupported Scan, storing driver.Value type []uint8 into type *time.Time

I modified by DSN to have the parseTime=true parameter, and the problem subsides. Should goose really be so opinionated about how the DSN is formatted in order to work?

We could consider appending / inserting the &parseTime=true option into the dsn param sequence, if it is not present. Alternatively, we changing the struct holder to take a string and then parse it as needed (but maybe we need to strip parseTime in that case?).

Use a logger and support log configuration

Instead of using fmt.Printf for all output consider supporting using a logger and allowing configuring log level and format. This would support clean output when embedding goose in a service with a logger.

goose run: no separator found

I've installed the binary using go get -u github.com/pressly/goose/cmd/goose. I can generate the migration files in anywhere, but not in my project directory. When i type something like goose postgres <connection_string> status, i got error goose run: no separator found. Is there something i might misconfigure ? or misunderstand the usage ? thanks

I'm using

  • golang:1.9.2 darwin/amd64
  • macOS High Sierra 10.13

Support large lines

Trying to use goose migrations to dump the contents of one table.

However, due to the length of the dump, I'm getting this error scanning migration: bufio.Scanner: token too long

I believe that replacing bufio.Scanner with bufio.Reader could solve this issue.

Bug: Scan error on column index 0

I have that error after command:

goose mysql "dev:dev@/table" status

    Applied At                  Migration
    =======================================
2017/10/26 20:15:43 sql: Scan error on column index 0: unsupported Scan, storing driver.Value type []uint8 into type *time.Time

Cant go get

$ go get -v -u github.com/pressly/goose/cmd/goose
github.com/pressly/goose (download)
github.com/go-sql-driver/mysql (download)
github.com/lib/pq (download)
github.com/mattn/go-sqlite3 (download)
Fetching https://golang.org/x/net/context?go-get=1
Parsing meta tags from https://golang.org/x/net/context?go-get=1 (status code 200)
get "golang.org/x/net/context": found meta tag main.metaImport{Prefix:"golang.org/x/net", VCS:"git", RepoRoot:"https://go.googlesource.com/net"} at https://golang.org/x/net/context?go-get=1
get "golang.org/x/net/context": verifying non-authoritative meta tag
Fetching https://golang.org/x/net?go-get=1
Parsing meta tags from https://golang.org/x/net?go-get=1 (status code 200)
golang.org/x/net (download)
github.com/ziutek/mymysql (download)
github.com/mattn/go-sqlite3
# github.com/mattn/go-sqlite3
../../../github.com/mattn/go-sqlite3/backup.go:14:20: fatal error: stdlib.h: No such file or directory
compilation terminated.

Linux Mint 18.2
go version go1.8.3 linux/amd64

Have TravisCI report status to repository

There are Travis tests, but they do not report status back to the repository, making it more difficult to see if Travis tests pass or not.

Travis should report status back to the repository.

Releases

For v1, in release section you have a compiled download available.
Is it possible for v2 as well?

Error value returned when no migrations found for goose.Up

At the moment you're returning a vanilla error type when goose.Up and goose.Down finds no migrations to use ("goose: no migrations to run. current version: 0"), this presents a problem because in my code if there are no migrations present then I want it to gracefully continue, but if there is an error related to the syntax of my migration file (such as an error thrown by the database), then it should explode. As it stands there's no clear way to differentiate these errors. It would be good to use something other than text (like a custom error type) to be able to differentiate between these errors. Is this something you could add? If you have no interest in adding it, if I was to PR it, is this something you would merge? Thank you.

Edit: Seems I was wrong, what it does is actually more of a problem than what I've described above. Apparently it just prints that message and returns nil as the error. This means that I have no way of knowing whether migrations executed or not, which means that I have to call goose.Down() every time (even if the migrations didn't execute), and if there was no migrations goose.Down will throw the error: no migration 0

So you've got an inconsistency there, and you've also got no way to skip a call to goose.Down if no migrations were found by goose because you don't actually know when that "no migrations" message has been thrown, which subsequently causes an unpreventable goose.Down error to be thrown. You've also got an error message that cannot be silenced due to the library print output.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.