diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 4f8ade6b..00000000 --- a/.travis.yml +++ /dev/null @@ -1,133 +0,0 @@ -dist: trusty -sudo: required -language: go - -install: - - go get -t -v ./... - - go build -v -tags sqlite -o tsoda ./soda - -before_script: - - ./tsoda create -e $SODA_DIALECT - - ./tsoda migrate -e $SODA_DIALECT - -script: - - go test -tags sqlite ./... -v - -global_env: - - MYSQL_USER="travis" - - MYSQL_PASSWORD="" - - POSTGRES_PASSWORD="" - -.mysql: &mysql - services: - - mysql - addons: - apt: - sources: - - mysql-5.7-trusty - packages: - - mysql-server - before_install: - - sudo mysql -e "use mysql; update user set authentication_string=PASSWORD('root') where User='root'; update user set plugin='mysql_native_password';FLUSH PRIVILEGES;" - - sudo mysql_upgrade -u root -proot - - sudo service mysql restart - -.postgres: &postgres - addons: - postgresql: "9.5" - -.cockroach: &cockroach - services: - - docker - before_install: - - docker pull cockroachdb/cockroach:v1.1.1 - - docker run -d -p 26257:26257 --name=cockroachdb cockroachdb/cockroach:v1.1.1 start --insecure - - sleep 4 # Wait for cockroach to be online - after_script: - - docker rm -f cockroachdb - -.crdb210ssl: &crdb210ssl - before_install: - - mkdir -p crdb/certs - - pushd crdb - - wget -qO- https://binaries.cockroachdb.com/cockroach-v2.1.0.linux-amd64.tgz | tar zxv - - mv cockroach-v2.1.0.linux-amd64/cockroach . - - ./cockroach cert create-ca --certs-dir certs --ca-key key - - ./cockroach cert create-client root --certs-dir certs --ca-key key - - ./cockroach cert create-node localhost 127.0.0.1 `hostname -s` `hostname -f` --certs-dir certs --ca-key key - - ./cockroach start --certs-dir certs --listen-addr localhost --port 26259 --http-port 8089 --background - - popd - -# TODO: MariaDB builds -.mariadb: &mariadb - addons: - mariadb: '10.0' - -matrix: - include: - - dist: trusty - go: 1.9 - env: SODA_DIALECT="postgres" - <<: *postgres - - dist: trusty - go: "1.10" - env: SODA_DIALECT="postgres" - <<: *postgres - - dist: trusty - go: "1.10" - env: SODA_DIALECT="mysql_travis" - <<: *mysql - - dist: trusty - go: "1.10" - env: SODA_DIALECT="cockroach" - <<: *cockroach - - dist: trusty - go: "1.10" - env: SODA_DIALECT="cockroach_ssl" - <<: *crdb210ssl - - dist: trusty - go: "1.10" - env: SODA_DIALECT="sqlite" - - dist: trusty - go: "1.11" - env: SODA_DIALECT="postgres" - <<: *postgres - - dist: trusty - go: "1.11" - env: SODA_DIALECT="mysql_travis" - <<: *mysql - - dist: trusty - go: "1.11" - env: SODA_DIALECT="cockroach" - <<: *cockroach - - dist: trusty - go: "1.11" - env: SODA_DIALECT="cockroach_ssl" - <<: *crdb210ssl - - dist: trusty - go: "1.11" - env: SODA_DIALECT="sqlite" - - os: windows - go: "1.11" - env: SODA_DIALECT="sqlite" - - dist: trusty - go: "tip" - env: SODA_DIALECT="postgres" - <<: *postgres - - dist: trusty - go: "tip" - env: SODA_DIALECT="mysql_travis" - <<: *mysql - - dist: trusty - go: "tip" - env: SODA_DIALECT="cockroach" - <<: *cockroach - - dist: trusty - go: "tip" - env: SODA_DIALECT="cockroach_ssl" - <<: *crdb210ssl - - dist: trusty - go: "tip" - env: SODA_DIALECT="sqlite" - allow_failures: - - go: 'tip' diff --git a/README.md b/README.md index 190e8d93..c13a3f2e 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@
# POP diff --git a/associations/has_one_association.go b/associations/has_one_association.go index 1747d343..a84cd8af 100644 --- a/associations/has_one_association.go +++ b/associations/has_one_association.go @@ -57,6 +57,9 @@ func hasOneAssociationBuilder(p associationParams) (Association, error) { } func (h *hasOneAssociation) Kind() reflect.Kind { + if h.ownedType.Kind() == reflect.Ptr { + return h.ownedType.Elem().Kind() + } return h.ownedType.Kind() } diff --git a/associations/has_one_association_test.go b/associations/has_one_association_test.go index 4bc08931..00921194 100644 --- a/associations/has_one_association_test.go +++ b/associations/has_one_association_test.go @@ -18,6 +18,12 @@ type FooHasOne struct { type barHasOne struct { Title string `db:"title"` FooHasOneID nulls.UUID `db:"foo_has_one_id"` + BazHasOneID nulls.UUID `db:"baz_id"` +} + +type bazHasOne struct { + ID uuid.UUID `db:"id"` + BarHasOne *barHasOne `has_one:"barHasOne" fk_id:"baz_id"` } func Test_Has_One_Association(t *testing.T) { @@ -44,6 +50,18 @@ func Test_Has_One_Association(t *testing.T) { for index := range after { a.Equal(nil, after[index].AfterInterface()) } + + baz := bazHasOne{ID: id} + + as, err = associations.ForStruct(&baz) + + a.NoError(err) + a.Equal(len(as), 1) + a.Equal(reflect.Struct, as[0].Kind()) + + where, args = as[0].Constraint() + a.Equal("baz_id = ?", where) + a.Equal(id, args[0].(uuid.UUID)) } func Test_Has_One_SetValue(t *testing.T) { diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 00000000..137f811c --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,72 @@ +variables: + GOBIN: "$(GOPATH)/bin" # Go binaries path + GOPATH: "$(system.defaultWorkingDirectory)/gopath" # Go workspace path + modulePath: "$(GOPATH)/src/github.com/$(build.repository.name)" # Path to the module"s code + +jobs: +- job: Windows + pool: + vmImage: "vs2017-win2016" + strategy: + matrix: + # SQLite3 + go 1.12 (off) sqlite: + go_version: "1.12" + GO111MODULE: "off" + SODA_DIALECT: "sqlite" + steps: + - template: azure-tests.yml + +- job: macOS + pool: + vmImage: "macOS-10.13" + strategy: + matrix: + # SQLite3 + go 1.12 (off) sqlite: + go_version: "1.12" + GO111MODULE: "off" + SODA_DIALECT: "sqlite" + steps: + - template: azure-tests.yml + +- job: Linux + pool: + vmImage: "ubuntu-16.04" + strategy: + matrix: + # Postgres + go 1.10 postgres: + go_version: "1.10" + SODA_DIALECT: "postgres" + go 1.11 (off) postgres: + go_version: "1.11.5" + GO111MODULE: "off" + SODA_DIALECT: "postgres" + go 1.12 (off) postgres: + go_version: "1.12" + GO111MODULE: "off" + SODA_DIALECT: "postgres" + # Cockroach + go 1.12 (off) cockroach: + go_version: "1.12" + GO111MODULE: "off" + SODA_DIALECT: "cockroach" + # Cockroach SSL + go 1.12 (off) cockroach SSL: + go_version: "1.12" + GO111MODULE: "off" + SODA_DIALECT: "cockroach_ssl" + # MySQL + go 1.12 (off) mysql: + go_version: "1.12" + GO111MODULE: "off" + SODA_DIALECT: "mysql" + MYSQL_PORT: "3307" + # SQLite3 + go 1.12 (off) sqlite: + go_version: "1.12" + GO111MODULE: "off" + SODA_DIALECT: "sqlite" + steps: + - template: azure-tests.yml \ No newline at end of file diff --git a/azure-tests.yml b/azure-tests.yml new file mode 100644 index 00000000..3490db41 --- /dev/null +++ b/azure-tests.yml @@ -0,0 +1,69 @@ +steps: + - task: GoTool@0 + inputs: + version: $(go_version) + - task: Bash@3 + inputs: + targetType: inline + script: | + mkdir -p "$(GOBIN)" + mkdir -p "$(GOPATH)/pkg" + mkdir -p "$(modulePath)" + shopt -s extglob + mv !(gopath) "$(modulePath)" + displayName: "Setup Go Workspace" + - task: Docker@1 + displayName: Run postgres image + inputs: + command: run + imageName: postgres:9.6 + ports: "5432:5432" + condition: and(succeeded(), eq(variables['SODA_DIALECT'], 'postgres')) + - task: Docker@1 + displayName: Run mysql image + inputs: + command: run + imageName: mysql:5.7 + ports: "3307:3306" + envVars: | + MYSQL_ROOT_PASSWORD=root + condition: and(succeeded(), eq(variables['SODA_DIALECT'], 'mysql')) + - task: Docker@1 + displayName: Run cockroach image + inputs: + command: run + imageName: cockroachdb/cockroach:v1.1.1 + ports: "26257:26257" + containerCommand: start --insecure + condition: and(succeeded(), eq(variables['SODA_DIALECT'], 'cockroach')) + - task: Bash@3 + displayName: Install Cockroach SSL + inputs: + targetType: inline + script: | + cd $(modulePath) + mkdir -p crdb/certs + pushd crdb + wget -qO- https://binaries.cockroachdb.com/cockroach-v2.1.0.linux-amd64.tgz | tar zxv + mv cockroach-v2.1.0.linux-amd64/cockroach . + ./cockroach cert create-ca --certs-dir certs --ca-key key + ./cockroach cert create-client root --certs-dir certs --ca-key key + ./cockroach cert create-node localhost 127.0.0.1 `hostname -s` `hostname -f` --certs-dir certs --ca-key key + ./cockroach start --certs-dir certs --listen-addr localhost --port 26259 --http-port 8089 --background + popd + condition: and(succeeded(), eq(variables['SODA_DIALECT'], 'cockroach_ssl')) + - script: | + go get -t -v ./... + go install -v -tags sqlite ./soda + workingDirectory: "$(modulePath)" + displayName: "Install soda" + - script: | + $(GOBIN)/soda drop -e $(SODA_DIALECT) + $(GOBIN)/soda create -e $(SODA_DIALECT) + $(GOBIN)/soda migrate -e $(SODA_DIALECT) + workingDirectory: "$(modulePath)" + displayName: "Create DB & run migrations" + - script: | + go test -tags sqlite ./... -v + workingDirectory: "$(modulePath)" + displayName: "Tests" \ No newline at end of file diff --git a/callbacks.go b/callbacks.go index bd094055..197bf25a 100644 --- a/callbacks.go +++ b/callbacks.go @@ -3,7 +3,6 @@ package pop import ( "reflect" - "github.com/pkg/errors" "golang.org/x/sync/errgroup" ) @@ -16,7 +15,7 @@ type AfterFindable interface { func (m *Model) afterFind(c *Connection) error { if x, ok := m.Value.(AfterFindable); ok { if err := x.AfterFind(c); err != nil { - return errors.WithStack(err) + return err } } diff --git a/config.go b/config.go index cd434753..ab4a2f29 100644 --- a/config.go +++ b/config.go @@ -40,13 +40,13 @@ func init() { func LoadConfigFile() error { path, err := findConfigPath() if err != nil { - return errors.WithStack(err) + return err } Connections = map[string]*Connection{} log(logging.Debug, "Loading config file from %s", path) f, err := os.Open(path) if err != nil { - return errors.WithStack(err) + return err } return LoadFrom(f) } @@ -104,7 +104,7 @@ func ParseConfig(r io.Reader) (map[string]*ConnectionDetails, error) { }) b, err := ioutil.ReadAll(r) if err != nil { - return nil, errors.WithStack(err) + return nil, err } t, err := tmpl.Parse(string(b)) if err != nil { diff --git a/config_test.go b/config_test.go index fd9a2533..e7c1db65 100644 --- a/config_test.go +++ b/config_test.go @@ -13,7 +13,7 @@ func Test_LoadsConnectionsFromConfig(t *testing.T) { r := require.New(t) conns := Connections - r.Equal(6, len(conns)) + r.Equal(5, len(conns)) } func Test_AddLookupPaths(t *testing.T) { @@ -28,10 +28,10 @@ func Test_ParseConfig(t *testing.T) { mysql: dialect: "mysql" database: "pop_test" - host: {{ envOr "MYSQL_HOST" "127.0.0.1" }} - port: {{ envOr "MYSQL_PORT" "3306" }} - user: {{ envOr "MYSQL_USER" "root" }} - password: {{ envOr "MYSQL_PASSWORD" "root" }} + host: "127.0.0.1" + port: "3306" + user: "root" + password: "root" options: readTimeout: 5s`) conns, err := ParseConfig(config) diff --git a/connection.go b/connection.go index 405716ff..fdf91d57 100644 --- a/connection.go +++ b/connection.go @@ -48,7 +48,7 @@ func (c *Connection) MigrationTableName() string { func NewConnection(deets *ConnectionDetails) (*Connection, error) { err := deets.Finalize() if err != nil { - return nil, errors.WithStack(err) + return nil, err } c := &Connection{ ID: randx.String(30), @@ -73,7 +73,7 @@ func Connect(e string) (*Connection, error) { if len(Connections) == 0 { err := LoadConfigFile() if err != nil { - return nil, errors.WithStack(err) + return nil, err } } e = defaults.String(e, "development") @@ -99,7 +99,9 @@ func (c *Connection) Open() error { return errors.Wrap(err, "could not open database connection") } db.SetMaxOpenConns(details.Pool) - db.SetMaxIdleConns(details.IdlePool) + if details.IdlePool != 0 { + db.SetMaxIdleConns(details.IdlePool) + } c.Store = &dB{db} if d, ok := c.Dialect.(afterOpenable); ok { @@ -133,7 +135,7 @@ func (c *Connection) Transaction(fn func(tx *Connection) error) error { dberr = cn.TX.Commit() } if err != nil { - return errors.WithStack(err) + return err } return errors.Wrap(dberr, "error committing or rolling back transaction") }) @@ -201,7 +203,7 @@ func (c *Connection) timeFunc(name string, fn func() error) error { err := fn() atomic.AddInt64(&c.Elapsed, int64(time.Since(start))) if err != nil { - return errors.WithStack(err) + return err } return nil } diff --git a/connection_details.go b/connection_details.go index 9d77d619..1e7f37a9 100644 --- a/connection_details.go +++ b/connection_details.go @@ -37,7 +37,7 @@ type ConnectionDetails struct { URL string // Defaults to 0 "unlimited". See https://golang.org/pkg/database/sql/#DB.SetMaxOpenConns Pool int - // Defaults to 0 "unlimited". See https://golang.org/pkg/database/sql/#DB.SetMaxIdleConns + // Defaults to 2. See https://golang.org/pkg/database/sql/#DB.SetMaxIdleConns IdlePool int Options map[string]string // Query string encoded options from URL. Example: "sslmode=disable" diff --git a/database.yml b/database.yml index 894d0081..d18679cc 100644 --- a/database.yml +++ b/database.yml @@ -8,16 +8,6 @@ mysql: options: readTimeout: 5s -mysql_travis: - dialect: "mysql" - database: "pop_test" - host: {{ envOr "MYSQL_HOST" "127.0.0.1" }} - port: {{ envOr "MYSQL_PORT" "3306" }} - user: {{ envOr "MYSQL_USER" "root" }} - password: {{ envOr "MYSQL_PASSWORD" "" }} - options: - readTimeout: 10s - postgres: url: "postgres://postgres:postgres@localhost:5432/pop_test?sslmode=disable" pool: 25 diff --git a/dialect_cockroach.go b/dialect_cockroach.go index e49e4d44..ea3cd9c6 100644 --- a/dialect_cockroach.go +++ b/dialect_cockroach.go @@ -76,14 +76,14 @@ func (p *cockroach) Create(s store, model *Model, cols columns.Columns) error { log(logging.SQL, query) stmt, err := s.PrepareNamed(query) if err != nil { - return errors.WithStack(err) + return err } err = stmt.Get(&id, model.Value) if err != nil { if err := stmt.Close(); err != nil { return errors.WithMessage(err, "failed to close statement") } - return errors.WithStack(err) + return err } model.setID(id.ID) return errors.WithMessage(stmt.Close(), "failed to close statement") @@ -98,7 +98,7 @@ func (p *cockroach) Update(s store, model *Model, cols columns.Columns) error { func (p *cockroach) Destroy(s store, model *Model) error { stmt := p.TranslateSQL(fmt.Sprintf("DELETE FROM %s WHERE %s", model.TableName(), model.whereID())) _, err := genericExec(s, stmt, model.ID()) - return errors.WithStack(err) + return err } func (p *cockroach) SelectOne(s store, model *Model, query Query) error { diff --git a/dialect_common.go b/dialect_common.go index d1a76392..75a6a395 100644 --- a/dialect_common.go +++ b/dialect_common.go @@ -44,14 +44,14 @@ func genericCreate(s store, model *Model, cols columns.Columns) error { log(logging.SQL, query) res, err := s.NamedExec(query, model.Value) if err != nil { - return errors.WithStack(err) + return err } id, err = res.LastInsertId() if err == nil { model.setID(id) } if err != nil { - return errors.WithStack(err) + return err } return nil case "UUID", "string": @@ -59,7 +59,7 @@ func genericCreate(s store, model *Model, cols columns.Columns) error { if model.ID() == emptyUUID { u, err := uuid.NewV4() if err != nil { - return errors.WithStack(err) + return err } model.setID(u) } @@ -72,14 +72,14 @@ func genericCreate(s store, model *Model, cols columns.Columns) error { log(logging.SQL, query) stmt, err := s.PrepareNamed(query) if err != nil { - return errors.WithStack(err) + return err } _, err = stmt.Exec(model.Value) if err != nil { if err := stmt.Close(); err != nil { return errors.WithMessage(err, "failed to close statement") } - return errors.WithStack(err) + return err } return errors.WithMessage(stmt.Close(), "failed to close statement") } @@ -91,7 +91,7 @@ func genericUpdate(s store, model *Model, cols columns.Columns) error { log(logging.SQL, stmt, model.ID()) _, err := s.NamedExec(stmt, model.Value) if err != nil { - return errors.WithStack(err) + return err } return nil } @@ -100,7 +100,7 @@ func genericDestroy(s store, model *Model) error { stmt := fmt.Sprintf("DELETE FROM %s WHERE %s", model.TableName(), model.whereID()) _, err := genericExec(s, stmt, model.ID()) if err != nil { - return errors.WithStack(err) + return err } return nil } @@ -108,7 +108,7 @@ func genericDestroy(s store, model *Model) error { func genericExec(s store, stmt string, args ...interface{}) (sql.Result, error) { log(logging.SQL, stmt, args...) res, err := s.Exec(stmt, args...) - return res, errors.WithStack(err) + return res, err } func genericSelectOne(s store, model *Model, query Query) error { @@ -116,7 +116,7 @@ func genericSelectOne(s store, model *Model, query Query) error { log(logging.SQL, sql, args...) err := s.Get(model.Value, sql, args...) if err != nil { - return errors.WithStack(err) + return err } return nil } @@ -126,7 +126,7 @@ func genericSelectMany(s store, models *Model, query Query) error { log(logging.SQL, sql, args...) err := s.Select(models.Value, sql, args...) if err != nil { - return errors.WithStack(err) + return err } return nil } diff --git a/dialect_postgresql.go b/dialect_postgresql.go index 89d02b99..a0ac85c6 100644 --- a/dialect_postgresql.go +++ b/dialect_postgresql.go @@ -65,14 +65,14 @@ func (p *postgresql) Create(s store, model *Model, cols columns.Columns) error { log(logging.SQL, query) stmt, err := s.PrepareNamed(query) if err != nil { - return errors.WithStack(err) + return err } err = stmt.Get(&id, model.Value) if err != nil { if err := stmt.Close(); err != nil { return errors.WithMessage(err, "failed to close statement") } - return errors.WithStack(err) + return err } model.setID(id.ID) return errors.WithMessage(stmt.Close(), "failed to close statement") @@ -88,7 +88,7 @@ func (p *postgresql) Destroy(s store, model *Model) error { stmt := p.TranslateSQL(fmt.Sprintf("DELETE FROM %s WHERE %s", model.TableName(), model.whereID())) _, err := genericExec(s, stmt, model.ID()) if err != nil { - return errors.WithStack(err) + return err } return nil } diff --git a/dialect_sqlite.go b/dialect_sqlite.go index b628ba13..366a9a75 100644 --- a/dialect_sqlite.go +++ b/dialect_sqlite.go @@ -70,14 +70,14 @@ func (m *sqlite) Create(s store, model *Model, cols columns.Columns) error { log(logging.SQL, query) res, err := s.NamedExec(query, model.Value) if err != nil { - return errors.WithStack(err) + return err } id, err = res.LastInsertId() if err == nil { model.setID(id) } if err != nil { - return errors.WithStack(err) + return err } return nil } diff --git a/executors.go b/executors.go index 5cf9c411..05fab9c4 100644 --- a/executors.go +++ b/executors.go @@ -47,6 +47,8 @@ func (q *Query) ExecWithCount() (int, error) { // ValidateAndSave applies validation rules on the given entry, then save it // if the validation succeed, excluding the given columns. +// +// If model is a slice, each item of the slice is validated then saved in the database. func (c *Connection) ValidateAndSave(model interface{}, excludeColumns ...string) (*validate.Errors, error) { sm := &Model{Value: model} verrs, err := sm.validateSave(c) @@ -68,6 +70,8 @@ func IsZeroOfUnderlyingType(x interface{}) bool { // Save wraps the Create and Update methods. It executes a Create if no ID is provided with the entry; // or issues an Update otherwise. +// +// If model is a slice, each item of the slice is saved in the database. func (c *Connection) Save(model interface{}, excludeColumns ...string) error { sm := &Model{Value: model} return sm.iterate(func(m *Model) error { @@ -84,6 +88,8 @@ func (c *Connection) Save(model interface{}, excludeColumns ...string) error { // ValidateAndCreate applies validation rules on the given entry, then creates it // if the validation succeed, excluding the given columns. +// +// If model is a slice, each item of the slice is validated then created in the database. func (c *Connection) ValidateAndCreate(model interface{}, excludeColumns ...string) (*validate.Errors, error) { sm := &Model{Value: model} verrs, err := sm.validateCreate(c) @@ -147,6 +153,8 @@ func (c *Connection) ValidateAndCreate(model interface{}, excludeColumns ...stri // Create add a new given entry to the database, excluding the given columns. // It updates `created_at` and `updated_at` columns automatically. // +// If model is a slice, each item of the slice is created in the database. +// // Create support two modes: // * Flat (default): Associate existing nested objects only. NO creation or update of nested objects. // * Eager: Associate existing nested objects and create non-existent objects. NO change to existing objects. @@ -300,6 +308,8 @@ func (c *Connection) Create(model interface{}, excludeColumns ...string) error { // ValidateAndUpdate applies validation rules on the given entry, then update it // if the validation succeed, excluding the given columns. +// +// If model is a slice, each item of the slice is validated then updated in the database. func (c *Connection) ValidateAndUpdate(model interface{}, excludeColumns ...string) (*validate.Errors, error) { sm := &Model{Value: model} verrs, err := sm.validateUpdate(c) @@ -314,6 +324,8 @@ func (c *Connection) ValidateAndUpdate(model interface{}, excludeColumns ...stri // Update writes changes from an entry to the database, excluding the given columns. // It updates the `updated_at` column automatically. +// +// If model is a slice, each item of the slice is updated in the database. func (c *Connection) Update(model interface{}, excludeColumns ...string) error { sm := &Model{Value: model} return sm.iterate(func(m *Model) error { @@ -349,7 +361,9 @@ func (c *Connection) Update(model interface{}, excludeColumns ...string) error { }) } -// Destroy deletes a given entry from the database +// Destroy deletes a given entry from the database. +// +// If model is a slice, each item of the slice is deleted from the database. func (c *Connection) Destroy(model interface{}) error { sm := &Model{Value: model} return sm.iterate(func(m *Model) error { diff --git a/file_migrator.go b/file_migrator.go index 0129833e..48d3d272 100644 --- a/file_migrator.go +++ b/file_migrator.go @@ -7,12 +7,9 @@ import ( "io/ioutil" "os" "path/filepath" - "strings" "text/template" "github.com/gobuffalo/fizz" - "github.com/gobuffalo/pop/fix" - "github.com/gobuffalo/pop/logging" "github.com/pkg/errors" ) @@ -33,7 +30,7 @@ func NewFileMigrator(path string, c *Connection) (FileMigrator, error) { err := fm.findMigrations() if err != nil { - return fm, errors.WithStack(err) + return fm, err } return fm, nil @@ -71,7 +68,7 @@ func (fm *FileMigrator) findMigrations() error { Runner: func(mf Migration, tx *Connection) error { f, err := os.Open(p) if err != nil { - return errors.WithStack(err) + return err } content, err := migrationContent(mf, tx, f) if err != nil { @@ -102,27 +99,13 @@ func migrationContent(mf Migration, c *Connection, r io.Reader) (string, error) return "", nil } - content := string(b) - - if mf.Type == "fizz" { - // test for && fix anko migrations - fixed, err := fix.Anko(content) - if err != nil { - return "", errors.Wrapf(err, "could not fizz the migration %s", mf.Path) - } - if strings.TrimSpace(fixed) != strings.TrimSpace(content) { - log(logging.Warn, "%s uses an old fizz syntax. please use\n%s", mf.Path, fixed) - } - content = fixed - } - - t := template.Must(template.New("sql").Parse(content)) + t := template.Must(template.New("sql").Parse(string(b))) var bb bytes.Buffer err = t.Execute(&bb, c.Dialect.Details()) if err != nil { return "", errors.Wrapf(err, "could not execute migration template %s", mf.Path) } - content = bb.String() + content := bb.String() if mf.Type == "fizz" { content, err = fizz.AString(content, c.Dialect.FizzTranslator()) diff --git a/fix/anko_test.go b/fix/anko_test.go index f724d573..c843d578 100644 --- a/fix/anko_test.go +++ b/fix/anko_test.go @@ -11,7 +11,7 @@ import ( func Test_Anko(t *testing.T) { r := require.New(t) - box := packr.New("./fixtures", "./fixtures") + box := packr.New("./fixtures/anko", "./fixtures/anko") err := box.Walk(func(path string, info packr.File) error { if strings.HasPrefix(path, "pass") { t.Run(path, testPass(path, info)) diff --git a/fix/auto_timestamps_off.go b/fix/auto_timestamps_off.go new file mode 100644 index 00000000..7beb378d --- /dev/null +++ b/fix/auto_timestamps_off.go @@ -0,0 +1,55 @@ +package fix + +import ( + "strings" + + "github.com/gobuffalo/plush/ast" + "github.com/gobuffalo/plush/parser" +) + +// AutoTimestampsOff adds a t.Timestamps() statement to fizz migrations +// when they still use the implicit auto-timestamp old fizz feature. +func AutoTimestampsOff(content string) (string, error) { + var p *ast.Program + var err error + if p, err = parser.Parse("<% " + content + "%>"); err != nil { + return "", err + } + + var pt *ast.Program + if pt, err = parser.Parse("<% t.Timestamps() %>"); err != nil { + return "", err + } + ts := pt.Statements[0].(*ast.ExpressionStatement) + + for _, s := range p.Statements { + stmt := s.(*ast.ExpressionStatement) + if function, ok := stmt.Expression.(*ast.CallExpression); ok { + if function.Function.TokenLiteral() == "create_table" { + args := function.Arguments + enableTimestamps := true + if len(args) > 1 { + if v, ok := args[1].(*ast.HashLiteral); ok { + if strings.Contains(v.String(), `"timestamps": false`) { + enableTimestamps = false + } + } + } + for _, bs := range function.Block.Statements { + bstmt := bs.(*ast.ExpressionStatement) + if f, ok := bstmt.Expression.(*ast.CallExpression); ok { + fs := f.Function.String() + if fs == "t.DisableTimestamps" || fs == "t.Timestamps" { + enableTimestamps = false + } + } + } + if enableTimestamps { + function.Block.Statements = append(function.Block.Statements, ts) + } + } + } + } + + return p.String(), nil +} diff --git a/fix/auto_timestamps_off_test.go b/fix/auto_timestamps_off_test.go new file mode 100644 index 00000000..4438e635 --- /dev/null +++ b/fix/auto_timestamps_off_test.go @@ -0,0 +1,33 @@ +package fix + +import ( + "io/ioutil" + "strings" + "testing" + + packr "github.com/gobuffalo/packr/v2" + "github.com/stretchr/testify/require" +) + +func Test_AutoTimestampsOff(t *testing.T) { + r := require.New(t) + box := packr.New("./fixtures/auto_timestamps_off/raw", "./fixtures/auto_timestamps_off/raw") + boxPatched := packr.New("./fixtures/auto_timestamps_off/patched", "./fixtures/auto_timestamps_off/patched") + + err := box.Walk(func(path string, info packr.File) error { + t.Run(path, func(tt *testing.T) { + rr := require.New(tt) + b, err := ioutil.ReadAll(info) + rr.NoError(err) + + body := string(b) + patched, err := AutoTimestampsOff(body) + rr.NoError(err) + expected, err := boxPatched.FindString(path) + rr.NoError(err) + rr.Equal(strings.Replace(expected, "\r", "", -1), patched) + }) + return nil + }) + r.NoError(err) +} diff --git a/fix/fixtures/pass/0001_with_raw_backticks.anko.fizz b/fix/fixtures/anko/pass/0001_with_raw_backticks.anko.fizz similarity index 100% rename from fix/fixtures/pass/0001_with_raw_backticks.anko.fizz rename to fix/fixtures/anko/pass/0001_with_raw_backticks.anko.fizz diff --git a/fix/fixtures/pass/0002_happy.plush.fizz b/fix/fixtures/anko/pass/0002_happy.plush.fizz similarity index 100% rename from fix/fixtures/pass/0002_happy.plush.fizz rename to fix/fixtures/anko/pass/0002_happy.plush.fizz diff --git a/fix/fixtures/auto_timestamps_off/patched/0001_nominal.fizz b/fix/fixtures/auto_timestamps_off/patched/0001_nominal.fizz new file mode 100644 index 00000000..12329f68 --- /dev/null +++ b/fix/fixtures/auto_timestamps_off/patched/0001_nominal.fizz @@ -0,0 +1,11 @@ +create_table("users") { + t.Column("id", "int", {primary: true}) + t.Column("name", "string", {}) + t.Column("user_name", "string", {"size": 100}) + t.Column("alive", "boolean", {"null": true}) + t.Column("birth_date", "timestamp", {"null": true}) + t.Column("bio", "text", {"null": true}) + t.Column("price", "numeric", {"null": true, "default": "1.00"}) + t.Column("email", "string", {"default": "foo@example.com", "size": 50}) + t.Timestamps() +} diff --git a/fix/fixtures/auto_timestamps_off/patched/0002_with_disabled_option.fizz b/fix/fixtures/auto_timestamps_off/patched/0002_with_disabled_option.fizz new file mode 100644 index 00000000..1b456174 --- /dev/null +++ b/fix/fixtures/auto_timestamps_off/patched/0002_with_disabled_option.fizz @@ -0,0 +1,10 @@ +create_table("users_2", {"timestamps": false}) { + t.Column("id", "int", {primary: true}) + t.Column("name", "string", {}) + t.Column("user_name", "string", {"size": 100}) + t.Column("alive", "boolean", {"null": true}) + t.Column("birth_date", "timestamp", {"null": true}) + t.Column("bio", "text", {"null": true}) + t.Column("price", "numeric", {"null": true, "default": "1.00"}) + t.Column("email", "string", {"default": "foo@example.com", "size": 50}) +} diff --git a/fix/fixtures/auto_timestamps_off/patched/0003_with_disable_timestamps.fizz b/fix/fixtures/auto_timestamps_off/patched/0003_with_disable_timestamps.fizz new file mode 100644 index 00000000..15602cbd --- /dev/null +++ b/fix/fixtures/auto_timestamps_off/patched/0003_with_disable_timestamps.fizz @@ -0,0 +1,11 @@ +create_table("users_3") { + t.Column("id", "int", {primary: true}) + t.Column("name", "string", {}) + t.Column("user_name", "string", {"size": 100}) + t.Column("alive", "boolean", {"null": true}) + t.Column("birth_date", "timestamp", {"null": true}) + t.Column("bio", "text", {"null": true}) + t.Column("price", "numeric", {"null": true, "default": "1.00"}) + t.Column("email", "string", {"default": "foo@example.com", "size": 50}) + t.DisableTimestamps() +} diff --git a/fix/fixtures/auto_timestamps_off/patched/0004_already_patched.fizz b/fix/fixtures/auto_timestamps_off/patched/0004_already_patched.fizz new file mode 100644 index 00000000..3eddb3d8 --- /dev/null +++ b/fix/fixtures/auto_timestamps_off/patched/0004_already_patched.fizz @@ -0,0 +1,11 @@ +create_table("users_4") { + t.Column("id", "int", {primary: true}) + t.Column("name", "string", {}) + t.Column("user_name", "string", {"size": 100}) + t.Column("alive", "boolean", {"null": true}) + t.Column("birth_date", "timestamp", {"null": true}) + t.Column("bio", "text", {"null": true}) + t.Column("price", "numeric", {"null": true, "default": "1.00"}) + t.Column("email", "string", {"default": "foo@example.com", "size": 50}) + t.Timestamps() +} diff --git a/fix/fixtures/auto_timestamps_off/raw/0001_nominal.fizz b/fix/fixtures/auto_timestamps_off/raw/0001_nominal.fizz new file mode 100644 index 00000000..d0b7b06d --- /dev/null +++ b/fix/fixtures/auto_timestamps_off/raw/0001_nominal.fizz @@ -0,0 +1,10 @@ +create_table("users") { + t.Column("id", "int", {primary: true}) + t.Column("name", "string", {}) + t.Column("user_name", "string", {"size": 100}) + t.Column("alive", "boolean", {"null": true}) + t.Column("birth_date", "timestamp", {"null": true}) + t.Column("bio", "text", {"null": true}) + t.Column("price", "numeric", {"null": true, "default": "1.00"}) + t.Column("email", "string", {"default": "foo@example.com", "size": 50}) +} diff --git a/fix/fixtures/auto_timestamps_off/raw/0002_with_disabled_option.fizz b/fix/fixtures/auto_timestamps_off/raw/0002_with_disabled_option.fizz new file mode 100644 index 00000000..1b456174 --- /dev/null +++ b/fix/fixtures/auto_timestamps_off/raw/0002_with_disabled_option.fizz @@ -0,0 +1,10 @@ +create_table("users_2", {"timestamps": false}) { + t.Column("id", "int", {primary: true}) + t.Column("name", "string", {}) + t.Column("user_name", "string", {"size": 100}) + t.Column("alive", "boolean", {"null": true}) + t.Column("birth_date", "timestamp", {"null": true}) + t.Column("bio", "text", {"null": true}) + t.Column("price", "numeric", {"null": true, "default": "1.00"}) + t.Column("email", "string", {"default": "foo@example.com", "size": 50}) +} diff --git a/fix/fixtures/auto_timestamps_off/raw/0003_with_disable_timestamps.fizz b/fix/fixtures/auto_timestamps_off/raw/0003_with_disable_timestamps.fizz new file mode 100644 index 00000000..15602cbd --- /dev/null +++ b/fix/fixtures/auto_timestamps_off/raw/0003_with_disable_timestamps.fizz @@ -0,0 +1,11 @@ +create_table("users_3") { + t.Column("id", "int", {primary: true}) + t.Column("name", "string", {}) + t.Column("user_name", "string", {"size": 100}) + t.Column("alive", "boolean", {"null": true}) + t.Column("birth_date", "timestamp", {"null": true}) + t.Column("bio", "text", {"null": true}) + t.Column("price", "numeric", {"null": true, "default": "1.00"}) + t.Column("email", "string", {"default": "foo@example.com", "size": 50}) + t.DisableTimestamps() +} diff --git a/fix/fixtures/auto_timestamps_off/raw/0004_already_patched.fizz b/fix/fixtures/auto_timestamps_off/raw/0004_already_patched.fizz new file mode 100644 index 00000000..3eddb3d8 --- /dev/null +++ b/fix/fixtures/auto_timestamps_off/raw/0004_already_patched.fizz @@ -0,0 +1,11 @@ +create_table("users_4") { + t.Column("id", "int", {primary: true}) + t.Column("name", "string", {}) + t.Column("user_name", "string", {"size": 100}) + t.Column("alive", "boolean", {"null": true}) + t.Column("birth_date", "timestamp", {"null": true}) + t.Column("bio", "text", {"null": true}) + t.Column("price", "numeric", {"null": true, "default": "1.00"}) + t.Column("email", "string", {"default": "foo@example.com", "size": 50}) + t.Timestamps() +} diff --git a/genny/config/config.go b/genny/config/config.go index 48c94928..aea15939 100644 --- a/genny/config/config.go +++ b/genny/config/config.go @@ -1,12 +1,12 @@ package config import ( + "fmt" "path/filepath" "github.com/gobuffalo/genny" "github.com/gobuffalo/gogen" "github.com/gobuffalo/packr/v2" - "github.com/pkg/errors" ) var templates = packr.New("pop:genny:config", "../config/templates") @@ -15,12 +15,12 @@ var templates = packr.New("pop:genny:config", "../config/templates") func New(opts *Options) (*genny.Generator, error) { g := genny.New() if err := opts.Validate(); err != nil { - return g, errors.WithStack(err) + return g, err } f, err := templates.Open(opts.Dialect + ".yml.tmpl") if err != nil { - return g, errors.Errorf("unable to find database.yml template for dialect %s", opts.Dialect) + return g, fmt.Errorf("unable to find database.yml template for dialect %s", opts.Dialect) } name := filepath.Join(opts.Root, opts.FileName+".tmpl") diff --git a/genny/config/options.go b/genny/config/options.go index cbab8c5a..686acc91 100644 --- a/genny/config/options.go +++ b/genny/config/options.go @@ -3,7 +3,7 @@ package config import ( "os" - "github.com/pkg/errors" + "errors" ) // Options needed for the config generator diff --git a/migration.go b/migration.go index 25486aa8..557488c2 100644 --- a/migration.go +++ b/migration.go @@ -7,7 +7,6 @@ import ( "github.com/gobuffalo/makr" "github.com/markbates/oncer" - "github.com/pkg/errors" ) // MigrationCreate writes contents for a given migration in normalized files @@ -31,7 +30,7 @@ func (c *Connection) MigrateUp(path string) error { mig, err := NewFileMigrator(path, c) if err != nil { - return errors.WithStack(err) + return err } return mig.Up() } @@ -42,7 +41,7 @@ func (c *Connection) MigrateDown(path string, step int) error { mig, err := NewFileMigrator(path, c) if err != nil { - return errors.WithStack(err) + return err } return mig.Down(step) } @@ -53,7 +52,7 @@ func (c *Connection) MigrateStatus(path string) error { mig, err := NewFileMigrator(path, c) if err != nil { - return errors.WithStack(err) + return err } return mig.Status() } @@ -64,7 +63,7 @@ func (c *Connection) MigrateReset(path string) error { mig, err := NewFileMigrator(path, c) if err != nil { - return errors.WithStack(err) + return err } return mig.Reset() } diff --git a/migration_box.go b/migration_box.go index 974166a0..75697a0f 100644 --- a/migration_box.go +++ b/migration_box.go @@ -24,7 +24,7 @@ func NewMigrationBox(box packd.Walkable, c *Connection) (MigrationBox, error) { err := fm.findMigrations() if err != nil { - return fm, errors.WithStack(err) + return fm, err } return fm, nil @@ -34,7 +34,7 @@ func (fm *MigrationBox) findMigrations() error { return fm.Box.Walk(func(p string, f packd.File) error { info, err := f.FileInfo() if err != nil { - return errors.WithStack(err) + return err } matches := mrx.FindAllStringSubmatch(info.Name(), -1) if len(matches) == 0 { diff --git a/migration_info.go b/migration_info.go index c5625142..e8361672 100644 --- a/migration_info.go +++ b/migration_info.go @@ -1,6 +1,6 @@ package pop -import "github.com/pkg/errors" +import "fmt" // Migration handles the data for a given database migration type Migration struct { @@ -24,7 +24,7 @@ type Migration struct { // no mf.Runner defined. func (mf Migration) Run(c *Connection) error { if mf.Runner == nil { - return errors.Errorf("no runner defined for %s", mf.Path) + return fmt.Errorf("no runner defined for %s", mf.Path) } return mf.Runner(mf, c) } diff --git a/migrations/20181104135255_users.up.fizz b/migrations/20181104135255_users.up.fizz index 0a64f0f4..e847e15a 100644 --- a/migrations/20181104135255_users.up.fizz +++ b/migrations/20181104135255_users.up.fizz @@ -7,4 +7,5 @@ create_table("users") { t.Column("bio", "text", {"null": true}) t.Column("price", "numeric", {"null": true, "default": "1.00"}) t.Column("email", "string", {"default": "foo@example.com", "size": 50}) + t.Timestamps() } \ No newline at end of file diff --git a/migrations/20181104135526_good_friends.up.fizz b/migrations/20181104135526_good_friends.up.fizz index 8a5b7437..61e24d3c 100644 --- a/migrations/20181104135526_good_friends.up.fizz +++ b/migrations/20181104135526_good_friends.up.fizz @@ -2,4 +2,5 @@ create_table("good_friends") { t.Column("id", "int", {primary: true}) t.Column("first_name", "string", {}) t.Column("last_name", "string", {}) + t.Timestamps() } \ No newline at end of file diff --git a/migrations/20181104135627_validatable_cars.up.fizz b/migrations/20181104135627_validatable_cars.up.fizz index fd435042..d16728fa 100644 --- a/migrations/20181104135627_validatable_cars.up.fizz +++ b/migrations/20181104135627_validatable_cars.up.fizz @@ -1,4 +1,5 @@ create_table("validatable_cars") { t.Column("id", "int", {primary: true}) t.Column("name", "string", {}) + t.Timestamps() } \ No newline at end of file diff --git a/migrations/20181104135710_not_validatable_cars.up.fizz b/migrations/20181104135710_not_validatable_cars.up.fizz index e24294e5..5d59b7ff 100644 --- a/migrations/20181104135710_not_validatable_cars.up.fizz +++ b/migrations/20181104135710_not_validatable_cars.up.fizz @@ -1,4 +1,5 @@ create_table("not_validatable_cars") { t.Column("id", "int", {primary: true}) t.Column("name", "string", {}) + t.Timestamps() } \ No newline at end of file diff --git a/migrations/20181104135800_callbacks_users.up.fizz b/migrations/20181104135800_callbacks_users.up.fizz index 18d23fe1..d37079e2 100644 --- a/migrations/20181104135800_callbacks_users.up.fizz +++ b/migrations/20181104135800_callbacks_users.up.fizz @@ -9,4 +9,5 @@ create_table("callbacks_users") { t.Column("after_u", "string", {}) t.Column("after_d", "string", {}) t.Column("after_f", "string", {}) + t.Timestamps() } \ No newline at end of file diff --git a/migrations/20181104135829_books.up.fizz b/migrations/20181104135829_books.up.fizz index 9e62cda0..d3373c2d 100644 --- a/migrations/20181104135829_books.up.fizz +++ b/migrations/20181104135829_books.up.fizz @@ -3,4 +3,5 @@ create_table("books") { t.Column("title", "string", {}) t.Column("user_id", "int", {"null": true}) t.Column("isbn", "string", {"size": 50}) + t.Timestamps() } \ No newline at end of file diff --git a/migrations/20181104135856_taxis.up.fizz b/migrations/20181104135856_taxis.up.fizz index 1a0b0c63..61c87b0b 100644 --- a/migrations/20181104135856_taxis.up.fizz +++ b/migrations/20181104135856_taxis.up.fizz @@ -2,4 +2,5 @@ create_table("taxis") { t.Column("id", "int", {primary: true}) t.Column("model", "string", {}) t.Column("user_id", "int", {"null": true}) + t.Timestamps() } \ No newline at end of file diff --git a/migrations/20181104140055_songs.up.fizz b/migrations/20181104140055_songs.up.fizz index 3ef5cdb4..408ff80b 100644 --- a/migrations/20181104140055_songs.up.fizz +++ b/migrations/20181104140055_songs.up.fizz @@ -3,4 +3,5 @@ create_table("songs") { t.Column("u_id", "int", {"null":true}) t.Column("title", "string", {}) t.Column("composed_by_id", "int", {"null":true}) + t.Timestamps() } \ No newline at end of file diff --git a/migrations/20181104140142_composers.up.fizz b/migrations/20181104140142_composers.up.fizz index 8278b023..23b9d44e 100644 --- a/migrations/20181104140142_composers.up.fizz +++ b/migrations/20181104140142_composers.up.fizz @@ -1,4 +1,5 @@ create_table("composers") { t.Column("id", "int", {primary: true}) t.Column("name", "string", {}) + t.Timestamps() } \ No newline at end of file diff --git a/migrations/20181104140221_writers.up.fizz b/migrations/20181104140221_writers.up.fizz index d3313d1a..95fde8b1 100644 --- a/migrations/20181104140221_writers.up.fizz +++ b/migrations/20181104140221_writers.up.fizz @@ -2,4 +2,5 @@ create_table("writers") { t.Column("id", "int", {primary: true}) t.Column("name", "string", {}) t.Column("book_id", "int", {}) + t.Timestamps() } \ No newline at end of file diff --git a/migrations/20181104140340_addresses.up.fizz b/migrations/20181104140340_addresses.up.fizz index c3d4e254..d57d70af 100644 --- a/migrations/20181104140340_addresses.up.fizz +++ b/migrations/20181104140340_addresses.up.fizz @@ -2,4 +2,5 @@ create_table("addresses") { t.Column("id", "int", {primary: true}) t.Column("street", "string", {}) t.Column("house_number", "int", {}) + t.Timestamps() } \ No newline at end of file diff --git a/migrations/20181104140431_users_addresses.up.fizz b/migrations/20181104140431_users_addresses.up.fizz index 506bebc4..98e18b51 100644 --- a/migrations/20181104140431_users_addresses.up.fizz +++ b/migrations/20181104140431_users_addresses.up.fizz @@ -2,4 +2,5 @@ create_table("users_addresses") { t.Column("id", "int", {primary: true}) t.Column("user_id", "int", {}) t.Column("address_id", "int", {}) + t.Timestamps() } \ No newline at end of file diff --git a/migrations/20181104140522_courses.up.fizz b/migrations/20181104140522_courses.up.fizz index 49924d08..592d6183 100644 --- a/migrations/20181104140522_courses.up.fizz +++ b/migrations/20181104140522_courses.up.fizz @@ -1,3 +1,4 @@ create_table("courses") { t.Column("id", "uuid", {"primary": true}) + t.Timestamps() } \ No newline at end of file diff --git a/migrations/20181104140606_course_codes.up.fizz b/migrations/20181104140606_course_codes.up.fizz index daa46898..f5d81165 100644 --- a/migrations/20181104140606_course_codes.up.fizz +++ b/migrations/20181104140606_course_codes.up.fizz @@ -1,4 +1,5 @@ create_table("course_codes") { t.Column("id", "uuid", {"primary": true}) t.Column("course_id", "uuid", {}) + t.Timestamps() } \ No newline at end of file diff --git a/migrations/20181104140743_cakes.up.fizz b/migrations/20181104140743_cakes.up.fizz index 814c2519..2397ab40 100644 --- a/migrations/20181104140743_cakes.up.fizz +++ b/migrations/20181104140743_cakes.up.fizz @@ -4,5 +4,6 @@ t.Column("int_slice", "int[]", {"null": true}) t.Column("float_slice", "numeric[]", {"null": true}) t.Column("string_slice", "varchar[]", {"null": true}) + t.Timestamps() } {{ end -}} \ No newline at end of file diff --git a/migrations/20190219210052_students.up.fizz b/migrations/20190219210052_students.up.fizz index 11a456db..6f84c436 100644 --- a/migrations/20190219210052_students.up.fizz +++ b/migrations/20190219210052_students.up.fizz @@ -1,3 +1,4 @@ create_table("students") { t.Column("id", "uuid", {"primary": true}) + t.Timestamps() } \ No newline at end of file diff --git a/migrations/20190219210059_parents.up.fizz b/migrations/20190219210059_parents.up.fizz index a6e86bdc..d228ab64 100644 --- a/migrations/20190219210059_parents.up.fizz +++ b/migrations/20190219210059_parents.up.fizz @@ -1,3 +1,4 @@ create_table("parents") { t.Column("id", "uuid", {"primary": true}) + t.Timestamps() } \ No newline at end of file diff --git a/migrator.go b/migrator.go index f9d87ceb..68dc78c4 100644 --- a/migrator.go +++ b/migrator.go @@ -99,7 +99,7 @@ func (m Migrator) Up() error { return errors.Wrapf(err, "problem inserting migration version %s", mi.Version) }) if err != nil { - return errors.WithStack(err) + return err } log(logging.Info, "> %s", mi.Name) applied++ @@ -158,7 +158,7 @@ func (m Migrator) Down(step int) error { func (m Migrator) Reset() error { err := m.Down(-1) if err != nil { - return errors.WithStack(err) + return err } return m.Up() } @@ -185,7 +185,7 @@ func (m Migrator) CreateSchemaMigrations() error { } err = tx.RawQuery(smSQL).Exec() if err != nil { - return errors.WithStack(errors.Wrap(err, smSQL)) + return errors.Wrap(err, smSQL) } return nil }) @@ -195,7 +195,7 @@ func (m Migrator) CreateSchemaMigrations() error { func (m Migrator) Status() error { err := m.CreateSchemaMigrations() if err != nil { - return errors.WithStack(err) + return err } w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', tabwriter.TabIndent) fmt.Fprintln(w, "Version\tName\tStatus\t") @@ -223,12 +223,12 @@ func (m Migrator) DumpMigrationSchema() error { schema := filepath.Join(m.SchemaPath, "schema.sql") f, err := os.Create(schema) if err != nil { - return errors.WithStack(err) + return err } err = c.Dialect.DumpSchema(f) if err != nil { os.RemoveAll(schema) - return errors.WithStack(err) + return err } return nil } diff --git a/model.go b/model.go index 67b61175..90c1f01b 100644 --- a/model.go +++ b/model.go @@ -9,7 +9,6 @@ import ( "github.com/gobuffalo/flect" nflect "github.com/gobuffalo/flect/name" "github.com/gofrs/uuid" - "github.com/pkg/errors" ) var tableMap = map[string]string{} @@ -117,7 +116,7 @@ func (m *Model) fieldByName(s string) (reflect.Value, error) { el := reflect.ValueOf(m.Value).Elem() fbn := el.FieldByName(s) if !fbn.IsValid() { - return fbn, errors.Errorf("Model does not have a field named %s", s) + return fbn, fmt.Errorf("Model does not have a field named %s", s) } return fbn, nil } diff --git a/slices/float.go b/slices/float.go index 316296b0..77dfb441 100644 --- a/slices/float.go +++ b/slices/float.go @@ -6,7 +6,7 @@ import ( "strconv" "strings" - "github.com/pkg/errors" + "errors" ) // Float is a slice of float64. @@ -46,7 +46,7 @@ func (f *Float) UnmarshalText(text []byte) error { for _, x := range strings.Split(string(text), ",") { f, err := strconv.ParseFloat(x, 64) if err != nil { - return errors.WithStack(err) + return err } ss = append(ss, f) } diff --git a/slices/int.go b/slices/int.go index 9c3e59dd..ee9b6e55 100644 --- a/slices/int.go +++ b/slices/int.go @@ -6,7 +6,7 @@ import ( "strconv" "strings" - "github.com/pkg/errors" + "errors" ) // Int is a slice of int. @@ -46,7 +46,7 @@ func (i *Int) UnmarshalText(text []byte) error { for _, x := range strings.Split(string(text), ",") { f, err := strconv.Atoi(x) if err != nil { - return errors.WithStack(err) + return err } ss = append(ss, f) } diff --git a/slices/map.go b/slices/map.go index 12303897..97ac24c6 100644 --- a/slices/map.go +++ b/slices/map.go @@ -4,7 +4,7 @@ import ( "database/sql/driver" "encoding/json" - "github.com/pkg/errors" + "errors" ) // Map is a map[string]interface. @@ -24,7 +24,7 @@ func (m *Map) Scan(src interface{}) error { } err := json.Unmarshal(b, m) if err != nil { - return errors.WithStack(err) + return err } return nil } @@ -34,7 +34,7 @@ func (m *Map) Scan(src interface{}) error { func (m Map) Value() (driver.Value, error) { b, err := json.Marshal(m) if err != nil { - return nil, errors.WithStack(err) + return nil, err } return string(b), nil } @@ -58,7 +58,7 @@ func (m Map) UnmarshalJSON(b []byte) error { func (m Map) UnmarshalText(text []byte) error { err := json.Unmarshal(text, &m) if err != nil { - return errors.WithStack(err) + return err } return nil } diff --git a/slices/uuid.go b/slices/uuid.go index 1657a37f..19cbfdff 100644 --- a/slices/uuid.go +++ b/slices/uuid.go @@ -6,8 +6,9 @@ import ( "fmt" "strings" + "errors" + "github.com/gofrs/uuid" - "github.com/pkg/errors" ) // For reading in arrays from postgres @@ -29,7 +30,7 @@ func (s *UUID) Scan(src interface{}) error { } us, err := strSliceToUUIDSlice(strToUUID(string(b))) if err != nil { - return errors.WithStack(err) + return err } *s = us return nil @@ -54,7 +55,7 @@ func (s *UUID) UnmarshalJSON(data []byte) error { } us, err := strSliceToUUIDSlice(ss) if err != nil { - return errors.WithStack(err) + return err } *s = us return nil @@ -69,7 +70,7 @@ func (s *UUID) UnmarshalText(text []byte) error { } us, err := strSliceToUUIDSlice(ss) if err != nil { - return errors.WithStack(err) + return err } *s = us return nil @@ -102,7 +103,7 @@ func strSliceToUUIDSlice(ss []string) (UUID, error) { } u, err := uuid.FromString(s) if err != nil { - return UUID{}, errors.WithStack(err) + return UUID{}, err } us[i] = u } diff --git a/soda/cmd/fix.go b/soda/cmd/fix.go index 1e6e20d0..75feea23 100644 --- a/soda/cmd/fix.go +++ b/soda/cmd/fix.go @@ -7,7 +7,6 @@ import ( "strings" "github.com/gobuffalo/pop/fix" - "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -20,38 +19,52 @@ var fixCmd = &cobra.Command{ if info == nil { return nil } - ext := strings.ToLower(filepath.Ext(path)) - if ext != ".fizz" { - return nil - } + return fixFizz(path) + }) + }, +} - b, err := ioutil.ReadFile(path) - if err != nil { - return errors.WithStack(err) - } +func fixFizz(path string) error { + ext := strings.ToLower(filepath.Ext(path)) + if ext != ".fizz" { + return nil + } - content := string(b) + b, err := ioutil.ReadFile(path) + if err != nil { + return err + } - fixed, err := fix.Anko(content) - if err != nil { - return errors.WithStack(err) - } - if strings.TrimSpace(fixed) != strings.TrimSpace(content) { - f, err := os.Create(path) - if err != nil { - return errors.WithStack(err) - } - if _, err := f.WriteString(fixed); err != nil { - return errors.WithStack(err) - } - if err := f.Close(); err != nil { - return errors.WithStack(err) - } - } + content := string(b) - return nil - }) - }, + // Old anko format + fixed, err := fix.Anko(content) + if err != nil { + return err + } + if strings.TrimSpace(fixed) != strings.TrimSpace(content) { + content = fixed + } + + // Rewrite migrations to use t.Timestamps() if necessary + fixed, err = fix.AutoTimestampsOff(content) + if err != nil { + return err + } + + if strings.TrimSpace(fixed) != strings.TrimSpace(content) { + f, err := os.Create(path) + if err != nil { + return err + } + if _, err := f.WriteString(fixed); err != nil { + return err + } + if err := f.Close(); err != nil { + return err + } + } + return nil } func init() { diff --git a/soda/cmd/generate/config_cmd.go b/soda/cmd/generate/config_cmd.go index 9480fd3d..af496eed 100644 --- a/soda/cmd/generate/config_cmd.go +++ b/soda/cmd/generate/config_cmd.go @@ -12,7 +12,6 @@ import ( "github.com/gobuffalo/pop/genny/config" "github.com/markbates/going/defaults" "github.com/markbates/oncer" - "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -45,7 +44,7 @@ var ConfigCmd = &cobra.Command{ Dialect: dialect, }) if err != nil { - return errors.WithStack(err) + return err } run.With(g) @@ -78,7 +77,7 @@ func Config(cfgFile string, data map[string]interface{}) error { }) if err != nil { - return errors.WithStack(err) + return err } run.With(g) diff --git a/soda/cmd/generate/fizz_cmd.go b/soda/cmd/generate/fizz_cmd.go index 44bc630e..8aa48b64 100644 --- a/soda/cmd/generate/fizz_cmd.go +++ b/soda/cmd/generate/fizz_cmd.go @@ -1,7 +1,7 @@ package generate import ( - "github.com/pkg/errors" + "errors" "github.com/gobuffalo/pop" "github.com/markbates/going/defaults" diff --git a/soda/cmd/generate/model.go b/soda/cmd/generate/model.go index 5c0a614a..990cfe32 100644 --- a/soda/cmd/generate/model.go +++ b/soda/cmd/generate/model.go @@ -87,17 +87,17 @@ func (m model) testPkgName() string { b, err := ioutil.ReadFile(p) if err != nil { - return errors.WithStack(err) + return err } f, err := parser.ParseFile(fset, p, string(b), 0) if err != nil { - return errors.WithStack(err) + return err } conf := types.Config{Importer: importer.Default()} p, err := conf.Check("cmd/hello", fset, []*ast.File{f}, nil) if err != nil { - return errors.WithStack(err) + return err } pkg = p.Name() @@ -203,6 +203,7 @@ func (m model) Fizz() string { s = append(s, "\t"+col.String()) } } + s = append(s, "\tt.Timestamps()") s = append(s, "}") return strings.Join(s, "\n") } diff --git a/soda/cmd/generate/model_cmd.go b/soda/cmd/generate/model_cmd.go index 42edc5e9..c4afc111 100644 --- a/soda/cmd/generate/model_cmd.go +++ b/soda/cmd/generate/model_cmd.go @@ -3,7 +3,8 @@ package generate import ( "strings" - "github.com/pkg/errors" + "errors" + "github.com/spf13/cobra" ) @@ -62,7 +63,7 @@ func Model(name string, opts map[string]interface{}, attributes []string) error model, err := newModel(name, mt, pp) if err != nil { - return errors.WithStack(err) + return err } for _, def := range attributes { diff --git a/soda/cmd/generate/model_test.go b/soda/cmd/generate/model_test.go index e32c0b5a..f8931c4c 100644 --- a/soda/cmd/generate/model_test.go +++ b/soda/cmd/generate/model_test.go @@ -196,6 +196,7 @@ func Test_model_Fizz(t *testing.T) { t.Column("id", "integer", {primary: true}) t.Column("brand", "string", {}) t.Column("owner", "string", {null: true}) + t.Timestamps() }` r.Equal(expected, m.Fizz()) } diff --git a/soda/cmd/generate/sql_cmd.go b/soda/cmd/generate/sql_cmd.go index 8821e3ea..70bb1e70 100644 --- a/soda/cmd/generate/sql_cmd.go +++ b/soda/cmd/generate/sql_cmd.go @@ -1,7 +1,7 @@ package generate import ( - "github.com/pkg/errors" + "errors" "github.com/gobuffalo/pop" "github.com/markbates/going/defaults" diff --git a/soda/cmd/migrate.go b/soda/cmd/migrate.go index d509a37e..b1bd2b91 100644 --- a/soda/cmd/migrate.go +++ b/soda/cmd/migrate.go @@ -3,8 +3,9 @@ package cmd import ( "os" + "errors" + "github.com/gobuffalo/pop" - "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -24,7 +25,7 @@ var migrateCmd = &cobra.Command{ } mig, err := pop.NewFileMigrator(migrationPath, getConn()) if err != nil { - return errors.WithStack(err) + return err } return mig.Up() }, diff --git a/soda/cmd/migrate_down.go b/soda/cmd/migrate_down.go index c6ad6a0b..7b968cbd 100644 --- a/soda/cmd/migrate_down.go +++ b/soda/cmd/migrate_down.go @@ -2,7 +2,6 @@ package cmd import ( "github.com/gobuffalo/pop" - "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -14,7 +13,7 @@ var migrateDownCmd = &cobra.Command{ RunE: func(cmd *cobra.Command, args []string) error { mig, err := pop.NewFileMigrator(migrationPath, getConn()) if err != nil { - return errors.WithStack(err) + return err } return mig.Down(migrationStep) }, diff --git a/soda/cmd/migrate_reset.go b/soda/cmd/migrate_reset.go index db300bf3..3ab6df78 100644 --- a/soda/cmd/migrate_reset.go +++ b/soda/cmd/migrate_reset.go @@ -3,7 +3,6 @@ package cmd import ( "github.com/gobuffalo/pop" "github.com/markbates/oncer" - "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -15,7 +14,7 @@ var migrateResetCmd = &cobra.Command{ oncer.Deprecate(0, "command `migrate reset`", "Use command `reset` instead.") mig, err := pop.NewFileMigrator(migrationPath, getConn()) if err != nil { - return errors.WithStack(err) + return err } return mig.Reset() }, diff --git a/soda/cmd/migrate_status.go b/soda/cmd/migrate_status.go index f6483088..19e87956 100644 --- a/soda/cmd/migrate_status.go +++ b/soda/cmd/migrate_status.go @@ -2,7 +2,6 @@ package cmd import ( "github.com/gobuffalo/pop" - "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -12,7 +11,7 @@ var migrateStatusCmd = &cobra.Command{ RunE: func(cmd *cobra.Command, args []string) error { mig, err := pop.NewFileMigrator(migrationPath, getConn()) if err != nil { - return errors.WithStack(err) + return err } return mig.Status() }, diff --git a/soda/cmd/migrate_up.go b/soda/cmd/migrate_up.go index a6c60dc4..00dc836b 100644 --- a/soda/cmd/migrate_up.go +++ b/soda/cmd/migrate_up.go @@ -2,7 +2,6 @@ package cmd import ( "github.com/gobuffalo/pop" - "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -12,7 +11,7 @@ var migrateUpCmd = &cobra.Command{ RunE: func(cmd *cobra.Command, args []string) error { mig, err := pop.NewFileMigrator(migrationPath, getConn()) if err != nil { - return errors.WithStack(err) + return err } return mig.Up() }, diff --git a/soda/cmd/reset.go b/soda/cmd/reset.go index 876a33ab..163518cf 100644 --- a/soda/cmd/reset.go +++ b/soda/cmd/reset.go @@ -4,7 +4,6 @@ import ( "os" "github.com/gobuffalo/pop" - "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -63,7 +62,7 @@ func doReset(c *pop.Connection, f *os.File, useMigrations bool) error { } mig, err := pop.NewFileMigrator(migrationPath, getConn()) if err != nil { - return errors.WithStack(err) + return err } if useMigrations { // Apply the migrations directly diff --git a/soda/cmd/version.go b/soda/cmd/version.go index da8bd050..c84828c2 100644 --- a/soda/cmd/version.go +++ b/soda/cmd/version.go @@ -1,4 +1,4 @@ package cmd // Version defines the current Pop version. -const Version = "v4.10.0" +const Version = "v4.11.0" diff --git a/validations.go b/validations.go index fe74dd4e..822f7605 100644 --- a/validations.go +++ b/validations.go @@ -4,7 +4,6 @@ import ( "reflect" "github.com/gobuffalo/validate" - "github.com/pkg/errors" ) type beforeValidatable interface { @@ -20,7 +19,7 @@ type modelIterableValidator func(*Model) (*validate.Errors, error) func (m *Model) validate(c *Connection) (*validate.Errors, error) { if x, ok := m.Value.(beforeValidatable); ok { if err := x.BeforeValidations(c); err != nil { - return validate.NewErrors(), errors.WithStack(err) + return validate.NewErrors(), err } } if x, ok := m.Value.(validateable); ok { @@ -37,7 +36,7 @@ func (m *Model) validateCreate(c *Connection) (*validate.Errors, error) { return m.iterateAndValidate(func(model *Model) (*validate.Errors, error) { verrs, err := model.validate(c) if err != nil { - return verrs, errors.WithStack(err) + return verrs, err } if x, ok := model.Value.(validateCreateable); ok { vs, err := x.ValidateCreate(c) @@ -45,7 +44,7 @@ func (m *Model) validateCreate(c *Connection) (*validate.Errors, error) { verrs.Append(vs) } if err != nil { - return verrs, errors.WithStack(err) + return verrs, err } } @@ -65,7 +64,7 @@ func (m *Model) validateAndOnlyCreate(c *Connection) (*validate.Errors, error) { verrs, err := model.validate(c) if err != nil { - return verrs, errors.WithStack(err) + return verrs, err } if x, ok := model.Value.(validateCreateable); ok { vs, err := x.ValidateCreate(c) @@ -73,7 +72,7 @@ func (m *Model) validateAndOnlyCreate(c *Connection) (*validate.Errors, error) { verrs.Append(vs) } if err != nil { - return verrs, errors.WithStack(err) + return verrs, err } } @@ -89,7 +88,7 @@ func (m *Model) validateSave(c *Connection) (*validate.Errors, error) { return m.iterateAndValidate(func(model *Model) (*validate.Errors, error) { verrs, err := model.validate(c) if err != nil { - return verrs, errors.WithStack(err) + return verrs, err } if x, ok := model.Value.(validateSaveable); ok { vs, err := x.ValidateSave(c) @@ -97,7 +96,7 @@ func (m *Model) validateSave(c *Connection) (*validate.Errors, error) { verrs.Append(vs) } if err != nil { - return verrs, errors.WithStack(err) + return verrs, err } } @@ -113,7 +112,7 @@ func (m *Model) validateUpdate(c *Connection) (*validate.Errors, error) { return m.iterateAndValidate(func(model *Model) (*validate.Errors, error) { verrs, err := model.validate(c) if err != nil { - return verrs, errors.WithStack(err) + return verrs, err } if x, ok := model.Value.(validateUpdateable); ok { vs, err := x.ValidateUpdate(c) @@ -121,7 +120,7 @@ func (m *Model) validateUpdate(c *Connection) (*validate.Errors, error) { verrs.Append(vs) } if err != nil { - return verrs, errors.WithStack(err) + return verrs, err } }