From 5a442f5b206cbc42ceb0dcb39997f39ea5e02a44 Mon Sep 17 00:00:00 2001 From: Stanislas Michalak Date: Sun, 5 May 2019 14:39:08 +0200 Subject: [PATCH] v4.11.0 (#379) * Back to development * Add Timestamps() macro when generating fizz migrations (#365) * Azure pipelines (#367) * WIP Azure pipelines * Fix typo * Fix soda install script * Fix binary name * Fix tsoda call * Build soda without modules * Use Bash to install soda * Fix pipeline * Fix soda build * Remove go module builds * Fix soda install * Install soda with go install * Fix config parse test * Do not create Docker default DBs * Remove Travis * Update badge in Readme * Remove legacy Anko format fixer (#366) It can still be called using soda fix command. * removes errors.WithStack as its noisy and makes it harder to understand (#372) * removes errors.WithStack as its noisy and makes it harder to understand * fix packr file * Add a fix for old fizz without Timestamps() (#373) * WIP fix old auto-timestamp * Use plush AST to rewrite fizz files * Fix case when files are already using t.Timestamps() * Fix Windows line breaks issue * Add a mention in godocs about the behavior on slices for executors (#375) Fixes #363. * Fix "has_one" pointer association (#378) * hasOneAssociation did not work with pointers * Bump version * Fix IdlePool option (#380) The zero value was not the same as in the stdlib and could cause perfs issues. This will now not call SetMaxIdleConns when IdlePool is set to the zero value. Fixes #376 --- .travis.yml | 133 ------------------ README.md | 2 +- associations/has_one_association.go | 3 + associations/has_one_association_test.go | 18 +++ azure-pipelines.yml | 72 ++++++++++ azure-tests.yml | 69 +++++++++ callbacks.go | 3 +- config.go | 6 +- config_test.go | 10 +- connection.go | 12 +- connection_details.go | 2 +- database.yml | 10 -- dialect_cockroach.go | 6 +- dialect_common.go | 20 +-- dialect_postgresql.go | 6 +- dialect_sqlite.go | 4 +- executors.go | 16 ++- file_migrator.go | 25 +--- fix/anko_test.go | 2 +- fix/auto_timestamps_off.go | 55 ++++++++ fix/auto_timestamps_off_test.go | 33 +++++ .../pass/0001_with_raw_backticks.anko.fizz | 0 .../{ => anko}/pass/0002_happy.plush.fizz | 0 .../patched/0001_nominal.fizz | 11 ++ .../patched/0002_with_disabled_option.fizz | 10 ++ .../patched/0003_with_disable_timestamps.fizz | 11 ++ .../patched/0004_already_patched.fizz | 11 ++ .../auto_timestamps_off/raw/0001_nominal.fizz | 10 ++ .../raw/0002_with_disabled_option.fizz | 10 ++ .../raw/0003_with_disable_timestamps.fizz | 11 ++ .../raw/0004_already_patched.fizz | 11 ++ genny/config/config.go | 6 +- genny/config/options.go | 2 +- migration.go | 9 +- migration_box.go | 4 +- migration_info.go | 4 +- migrations/20181104135255_users.up.fizz | 1 + .../20181104135526_good_friends.up.fizz | 1 + .../20181104135627_validatable_cars.up.fizz | 1 + ...0181104135710_not_validatable_cars.up.fizz | 1 + .../20181104135800_callbacks_users.up.fizz | 1 + migrations/20181104135829_books.up.fizz | 1 + migrations/20181104135856_taxis.up.fizz | 1 + migrations/20181104140055_songs.up.fizz | 1 + migrations/20181104140142_composers.up.fizz | 1 + migrations/20181104140221_writers.up.fizz | 1 + migrations/20181104140340_addresses.up.fizz | 1 + .../20181104140431_users_addresses.up.fizz | 1 + migrations/20181104140522_courses.up.fizz | 1 + .../20181104140606_course_codes.up.fizz | 1 + migrations/20181104140743_cakes.up.fizz | 1 + migrations/20190219210052_students.up.fizz | 1 + migrations/20190219210059_parents.up.fizz | 1 + migrator.go | 12 +- model.go | 3 +- slices/float.go | 4 +- slices/int.go | 4 +- slices/map.go | 8 +- slices/uuid.go | 11 +- soda/cmd/fix.go | 71 ++++++---- soda/cmd/generate/config_cmd.go | 5 +- soda/cmd/generate/fizz_cmd.go | 2 +- soda/cmd/generate/model.go | 7 +- soda/cmd/generate/model_cmd.go | 5 +- soda/cmd/generate/model_test.go | 1 + soda/cmd/generate/sql_cmd.go | 2 +- soda/cmd/migrate.go | 5 +- soda/cmd/migrate_down.go | 3 +- soda/cmd/migrate_reset.go | 3 +- soda/cmd/migrate_status.go | 3 +- soda/cmd/migrate_up.go | 3 +- soda/cmd/reset.go | 3 +- soda/cmd/version.go | 2 +- validations.go | 19 ++- 74 files changed, 513 insertions(+), 297 deletions(-) delete mode 100644 .travis.yml create mode 100644 azure-pipelines.yml create mode 100644 azure-tests.yml create mode 100644 fix/auto_timestamps_off.go create mode 100644 fix/auto_timestamps_off_test.go rename fix/fixtures/{ => anko}/pass/0001_with_raw_backticks.anko.fizz (100%) rename fix/fixtures/{ => anko}/pass/0002_happy.plush.fizz (100%) create mode 100644 fix/fixtures/auto_timestamps_off/patched/0001_nominal.fizz create mode 100644 fix/fixtures/auto_timestamps_off/patched/0002_with_disabled_option.fizz create mode 100644 fix/fixtures/auto_timestamps_off/patched/0003_with_disable_timestamps.fizz create mode 100644 fix/fixtures/auto_timestamps_off/patched/0004_already_patched.fizz create mode 100644 fix/fixtures/auto_timestamps_off/raw/0001_nominal.fizz create mode 100644 fix/fixtures/auto_timestamps_off/raw/0002_with_disabled_option.fizz create mode 100644 fix/fixtures/auto_timestamps_off/raw/0003_with_disable_timestamps.fizz create mode 100644 fix/fixtures/auto_timestamps_off/raw/0004_already_patched.fizz 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 @@

GoDoc - Build Status + Build Status

# 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 } }