diff --git a/cmd/goqu-crud-gen/get_tpl.go b/cmd/goqu-crud-gen/get_tpl.go index ef0070d..bbf46c2 100644 --- a/cmd/goqu-crud-gen/get_tpl.go +++ b/cmd/goqu-crud-gen/get_tpl.go @@ -8,7 +8,7 @@ const getTpl = ` func (s *{{ .Repo.Name }}) iter( ctx context.Context, filter goqu.Expression, - f func(m {{ .Model.Name }}, stop func()), + fn func(m {{ .Model.Name }}) error, opt ...Option, ) error { @@ -56,19 +56,24 @@ func (s *{{ .Repo.Name }}) iter( return fmt.Errorf("row scan error: %w", err) } - f(m, func() { sigCtxCancel() }) + err = fn(m) + if err != nil { + sigCtxCancel() + _ = rows.Close() + return fmt.Errorf("fn call: %w", err) + } } return nil } -// iterWithOrder iterates other select with specified filter(s). +// iterWithOrder iterates other select with specified filter(s) and order. // // Can be used in your custom query methods. func (s *{{ .Repo.Name }}) iterWithOrder( ctx context.Context, filter goqu.Expression, - f func(m {{ .Model.Name }}, stop func()), + fn func(m {{ .Model.Name }}) error, order exp.OrderedExpression, opt ...Option, ) error { @@ -120,7 +125,12 @@ func (s *{{ .Repo.Name }}) iterWithOrder( return fmt.Errorf("row scan error: %w", err) } - f(m, func() { sigCtxCancel() }) + err = fn(m) + if err != nil { + sigCtxCancel() + _ = rows.Close() + return fmt.Errorf("fn call: %w", err) + } } return nil @@ -132,7 +142,7 @@ func (s *{{ .Repo.Name }}) iterWithOrder( func (s *{{ .Repo.Name }}) iterPrimaryKeys( ctx context.Context, filter goqu.Expression, - f func(pk interface{}, stop func()), + fn func(pk interface{}) error, opt ...Option, ) error { @@ -180,7 +190,12 @@ func (s *{{ .Repo.Name }}) iterPrimaryKeys( return fmt.Errorf("row scan error: %w", err) } - f(pk, func() { sigCtxCancel() }) + err = fn(pk) + if err != nil { + sigCtxCancel() + _ = rows.Close() + return fmt.Errorf("fn call: %w", err) + } } return nil @@ -191,13 +206,13 @@ func (s *{{ .Repo.Name }}) iterPrimaryKeys( // Can be used in your custom query methods, for example in All. // // See also: iter. -func (s *{{ .Repo.Name }}) each(ctx context.Context, f func(m {{ .Model.Name }})) error { +func (s *{{ .Repo.Name }}) each(ctx context.Context, fn func(m {{ .Model.Name }}) error) error { return s.iter( ctx, nil, - func(m {{ .Model.Name }}, _ func()) { - f(m) + func(m {{ .Model.Name }}) error { + return fn(m) }, ) } @@ -211,9 +226,10 @@ func (s *{{ .Repo.Name }}) {{"Get"|CRUD}}(ctx context.Context, id {{.Model.GetPr err := s.iter( ctx, s.f.PK().Eq(id), - func(m {{ .Model.Name }}, stop func()) { + func(m {{ .Model.Name }}) error { + // note: expected to be called once. r = &m - stop() + return nil }, opt..., ) @@ -230,8 +246,9 @@ func (s *{{ .Repo.Name }}) {{"GetManySlice"|CRUD}}(ctx context.Context, ids []{{ err := s.iter( ctx, s.f.PK().In(ids), - func(m {{ .Model.Name }}, _ func()) { + func(m {{ .Model.Name }}) error { items = append(items, m) + return nil }, opt..., ) diff --git a/examples/example1/cmd/main.go b/examples/example1/cmd/main.go index a6e7ceb..deb2f54 100644 --- a/examples/example1/cmd/main.go +++ b/examples/example1/cmd/main.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "log" + "os" "time" "example1/model" @@ -16,21 +17,31 @@ const ( table = "user" ) +var ( + logInfo = log.New(os.Stdout, "INF ", log.LstdFlags) + logErr = log.New(os.Stderr, "ERR ", log.LstdFlags) +) + func main() { fmt.Println("Example1") repo := model.NewUserRepo(dsn) err := repo.Connect(3 * time.Second) if err != nil { - log.Fatalf("repo connect error: %s", err) + logErr.Fatalf("repo connect error: %s", err) } // migrate err = migrateUp(dsn, table) if err != nil { - log.Fatalln(err) + logErr.Fatalln(err) } - defer migrateDown(dsn, table) + defer func() { + err = migrateDown(dsn, table) + if err != nil { + logErr.Fatalln("migrate down error:", err) + } + }() ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() @@ -48,9 +59,9 @@ func main() { return repo.Create(ctx, &u) }) if err != nil { - log.Fatalln("Create error:", err) + logErr.Fatalln("Create error:", err) } - log.Printf("user record created: %+v", u) + logInfo.Printf("user record created: %+v", u) userId = u.Id } @@ -63,13 +74,13 @@ func main() { return err }) if err != nil { - log.Fatalln("Get error:", err) + logErr.Fatalln("Get error:", err) } if u == nil { - log.Fatalln("user not exists") + logErr.Fatalln("user not exists") } - log.Printf("repo Get user result: %+v", u) + logInfo.Printf("repo Get user result: %+v", u) } fmt.Println("End.") @@ -80,7 +91,7 @@ func migrateUp(dsn, table string) error { if err != nil { return fmt.Errorf("connect error: %w", err) } - defer c.Close() + defer func() { _ = c.Close() }() _, err = c.Exec(fmt.Sprintf(` CREATE TABLE %s @@ -106,7 +117,7 @@ func migrateDown(dsn, table string) error { if err != nil { return fmt.Errorf("connect error: %w", err) } - defer c.Close() + defer func() { _ = c.Close() }() _, err = c.Exec(fmt.Sprintf(`DROP TABLE %s`, table)) if err != nil { diff --git a/examples/example1/model/user_repo.go b/examples/example1/model/user_repo.go index 6149b99..b45c6f0 100644 --- a/examples/example1/model/user_repo.go +++ b/examples/example1/model/user_repo.go @@ -215,7 +215,7 @@ func (s *UserRepo) Create(ctx context.Context, m *User) error { func (s *UserRepo) iter( ctx context.Context, filter goqu.Expression, - f func(m User, stop func()), + fn func(m User) error, opt ...Option, ) error { @@ -263,19 +263,24 @@ func (s *UserRepo) iter( return fmt.Errorf("row scan error: %w", err) } - f(m, func() { sigCtxCancel() }) + err = fn(m) + if err != nil { + sigCtxCancel() + _ = rows.Close() + return fmt.Errorf("fn call: %w", err) + } } return nil } -// iterWithOrder iterates other select with specified filter(s). +// iterWithOrder iterates other select with specified filter(s) and order. // // Can be used in your custom query methods. func (s *UserRepo) iterWithOrder( ctx context.Context, filter goqu.Expression, - f func(m User, stop func()), + fn func(m User) error, order exp.OrderedExpression, opt ...Option, ) error { @@ -327,7 +332,12 @@ func (s *UserRepo) iterWithOrder( return fmt.Errorf("row scan error: %w", err) } - f(m, func() { sigCtxCancel() }) + err = fn(m) + if err != nil { + sigCtxCancel() + _ = rows.Close() + return fmt.Errorf("fn call: %w", err) + } } return nil @@ -339,7 +349,7 @@ func (s *UserRepo) iterWithOrder( func (s *UserRepo) iterPrimaryKeys( ctx context.Context, filter goqu.Expression, - f func(pk interface{}, stop func()), + fn func(pk interface{}) error, opt ...Option, ) error { @@ -387,7 +397,12 @@ func (s *UserRepo) iterPrimaryKeys( return fmt.Errorf("row scan error: %w", err) } - f(pk, func() { sigCtxCancel() }) + err = fn(pk) + if err != nil { + sigCtxCancel() + _ = rows.Close() + return fmt.Errorf("fn call: %w", err) + } } return nil @@ -398,13 +413,13 @@ func (s *UserRepo) iterPrimaryKeys( // Can be used in your custom query methods, for example in All. // // See also: iter. -func (s *UserRepo) each(ctx context.Context, f func(m User)) error { +func (s *UserRepo) each(ctx context.Context, fn func(m User) error) error { return s.iter( ctx, nil, - func(m User, _ func()) { - f(m) + func(m User) error { + return fn(m) }, ) } @@ -418,9 +433,10 @@ func (s *UserRepo) Get(ctx context.Context, id int64, opt ...Option) (*User, err err := s.iter( ctx, s.f.PK().Eq(id), - func(m User, stop func()) { + func(m User) error { + // note: expected to be called once. r = &m - stop() + return nil }, opt..., ) @@ -437,8 +453,9 @@ func (s *UserRepo) GetManySlice(ctx context.Context, ids []int64, opt ...Option) err := s.iter( ctx, s.f.PK().In(ids), - func(m User, _ func()) { + func(m User) error { items = append(items, m) + return nil }, opt..., ) diff --git a/examples/example2/user_repo.go b/examples/example2/user_repo.go index ab66761..6c1283c 100644 --- a/examples/example2/user_repo.go +++ b/examples/example2/user_repo.go @@ -216,7 +216,7 @@ func (s *UserRepo) Create(ctx context.Context, m *User) error { func (s *UserRepo) iter( ctx context.Context, filter goqu.Expression, - f func(m User, stop func()), + fn func(m User) error, opt ...Option, ) error { @@ -264,19 +264,24 @@ func (s *UserRepo) iter( return fmt.Errorf("row scan error: %w", err) } - f(m, func() { sigCtxCancel() }) + err = fn(m) + if err != nil { + sigCtxCancel() + _ = rows.Close() + return fmt.Errorf("fn call: %w", err) + } } return nil } -// iterWithOrder iterates other select with specified filter(s). +// iterWithOrder iterates other select with specified filter(s) and order. // // Can be used in your custom query methods. func (s *UserRepo) iterWithOrder( ctx context.Context, filter goqu.Expression, - f func(m User, stop func()), + fn func(m User) error, order exp.OrderedExpression, opt ...Option, ) error { @@ -328,7 +333,12 @@ func (s *UserRepo) iterWithOrder( return fmt.Errorf("row scan error: %w", err) } - f(m, func() { sigCtxCancel() }) + err = fn(m) + if err != nil { + sigCtxCancel() + _ = rows.Close() + return fmt.Errorf("fn call: %w", err) + } } return nil @@ -340,7 +350,7 @@ func (s *UserRepo) iterWithOrder( func (s *UserRepo) iterPrimaryKeys( ctx context.Context, filter goqu.Expression, - f func(pk interface{}, stop func()), + fn func(pk interface{}) error, opt ...Option, ) error { @@ -388,7 +398,12 @@ func (s *UserRepo) iterPrimaryKeys( return fmt.Errorf("row scan error: %w", err) } - f(pk, func() { sigCtxCancel() }) + err = fn(pk) + if err != nil { + sigCtxCancel() + _ = rows.Close() + return fmt.Errorf("fn call: %w", err) + } } return nil @@ -399,13 +414,13 @@ func (s *UserRepo) iterPrimaryKeys( // Can be used in your custom query methods, for example in All. // // See also: iter. -func (s *UserRepo) each(ctx context.Context, f func(m User)) error { +func (s *UserRepo) each(ctx context.Context, fn func(m User) error) error { return s.iter( ctx, nil, - func(m User, _ func()) { - f(m) + func(m User) error { + return fn(m) }, ) } @@ -419,9 +434,10 @@ func (s *UserRepo) Get(ctx context.Context, id int64, opt ...Option) (*User, err err := s.iter( ctx, s.f.PK().Eq(id), - func(m User, stop func()) { + func(m User) error { + // note: expected to be called once. r = &m - stop() + return nil }, opt..., ) @@ -438,8 +454,9 @@ func (s *UserRepo) GetManySlice(ctx context.Context, ids []int64, opt ...Option) err := s.iter( ctx, s.f.PK().In(ids), - func(m User, _ func()) { + func(m User) error { items = append(items, m) + return nil }, opt..., ) diff --git a/examples/example3/adapters/mysql/account_repo.go b/examples/example3/adapters/mysql/account_repo.go index 0c871c0..4e756a9 100644 --- a/examples/example3/adapters/mysql/account_repo.go +++ b/examples/example3/adapters/mysql/account_repo.go @@ -211,7 +211,7 @@ func (s *AccountRepo) Create(ctx context.Context, m *Account) error { func (s *AccountRepo) iter( ctx context.Context, filter goqu.Expression, - f func(m Account, stop func()), + fn func(m Account) error, opt ...Option, ) error { @@ -259,19 +259,24 @@ func (s *AccountRepo) iter( return fmt.Errorf("row scan error: %w", err) } - f(m, func() { sigCtxCancel() }) + err = fn(m) + if err != nil { + sigCtxCancel() + _ = rows.Close() + return fmt.Errorf("fn call: %w", err) + } } return nil } -// iterWithOrder iterates other select with specified filter(s). +// iterWithOrder iterates other select with specified filter(s) and order. // // Can be used in your custom query methods. func (s *AccountRepo) iterWithOrder( ctx context.Context, filter goqu.Expression, - f func(m Account, stop func()), + fn func(m Account) error, order exp.OrderedExpression, opt ...Option, ) error { @@ -323,7 +328,12 @@ func (s *AccountRepo) iterWithOrder( return fmt.Errorf("row scan error: %w", err) } - f(m, func() { sigCtxCancel() }) + err = fn(m) + if err != nil { + sigCtxCancel() + _ = rows.Close() + return fmt.Errorf("fn call: %w", err) + } } return nil @@ -335,7 +345,7 @@ func (s *AccountRepo) iterWithOrder( func (s *AccountRepo) iterPrimaryKeys( ctx context.Context, filter goqu.Expression, - f func(pk interface{}, stop func()), + fn func(pk interface{}) error, opt ...Option, ) error { @@ -383,7 +393,12 @@ func (s *AccountRepo) iterPrimaryKeys( return fmt.Errorf("row scan error: %w", err) } - f(pk, func() { sigCtxCancel() }) + err = fn(pk) + if err != nil { + sigCtxCancel() + _ = rows.Close() + return fmt.Errorf("fn call: %w", err) + } } return nil @@ -394,13 +409,13 @@ func (s *AccountRepo) iterPrimaryKeys( // Can be used in your custom query methods, for example in All. // // See also: iter. -func (s *AccountRepo) each(ctx context.Context, f func(m Account)) error { +func (s *AccountRepo) each(ctx context.Context, fn func(m Account) error) error { return s.iter( ctx, nil, - func(m Account, _ func()) { - f(m) + func(m Account) error { + return fn(m) }, ) } @@ -414,9 +429,10 @@ func (s *AccountRepo) Get(ctx context.Context, id uuid.UUID, opt ...Option) (*Ac err := s.iter( ctx, s.f.PK().Eq(id), - func(m Account, stop func()) { + func(m Account) error { + // note: expected to be called once. r = &m - stop() + return nil }, opt..., ) @@ -433,8 +449,9 @@ func (s *AccountRepo) GetManySlice(ctx context.Context, ids []uuid.UUID, opt ... err := s.iter( ctx, s.f.PK().In(ids), - func(m Account, _ func()) { + func(m Account) error { items = append(items, m) + return nil }, opt..., ) diff --git a/examples/example3/adapters/mysql/user_public_fields_repo.go b/examples/example3/adapters/mysql/user_public_fields_repo.go index 0c4f326..490db77 100644 --- a/examples/example3/adapters/mysql/user_public_fields_repo.go +++ b/examples/example3/adapters/mysql/user_public_fields_repo.go @@ -205,7 +205,7 @@ func (s *UserPublicFieldsRepo) _Create(ctx context.Context, m *UserPublicFields) func (s *UserPublicFieldsRepo) iter( ctx context.Context, filter goqu.Expression, - f func(m UserPublicFields, stop func()), + fn func(m UserPublicFields) error, opt ...Option, ) error { @@ -253,19 +253,24 @@ func (s *UserPublicFieldsRepo) iter( return fmt.Errorf("row scan error: %w", err) } - f(m, func() { sigCtxCancel() }) + err = fn(m) + if err != nil { + sigCtxCancel() + _ = rows.Close() + return fmt.Errorf("fn call: %w", err) + } } return nil } -// iterWithOrder iterates other select with specified filter(s). +// iterWithOrder iterates other select with specified filter(s) and order. // // Can be used in your custom query methods. func (s *UserPublicFieldsRepo) iterWithOrder( ctx context.Context, filter goqu.Expression, - f func(m UserPublicFields, stop func()), + fn func(m UserPublicFields) error, order exp.OrderedExpression, opt ...Option, ) error { @@ -317,7 +322,12 @@ func (s *UserPublicFieldsRepo) iterWithOrder( return fmt.Errorf("row scan error: %w", err) } - f(m, func() { sigCtxCancel() }) + err = fn(m) + if err != nil { + sigCtxCancel() + _ = rows.Close() + return fmt.Errorf("fn call: %w", err) + } } return nil @@ -329,7 +339,7 @@ func (s *UserPublicFieldsRepo) iterWithOrder( func (s *UserPublicFieldsRepo) iterPrimaryKeys( ctx context.Context, filter goqu.Expression, - f func(pk interface{}, stop func()), + fn func(pk interface{}) error, opt ...Option, ) error { @@ -377,7 +387,12 @@ func (s *UserPublicFieldsRepo) iterPrimaryKeys( return fmt.Errorf("row scan error: %w", err) } - f(pk, func() { sigCtxCancel() }) + err = fn(pk) + if err != nil { + sigCtxCancel() + _ = rows.Close() + return fmt.Errorf("fn call: %w", err) + } } return nil @@ -388,13 +403,13 @@ func (s *UserPublicFieldsRepo) iterPrimaryKeys( // Can be used in your custom query methods, for example in All. // // See also: iter. -func (s *UserPublicFieldsRepo) each(ctx context.Context, f func(m UserPublicFields)) error { +func (s *UserPublicFieldsRepo) each(ctx context.Context, fn func(m UserPublicFields) error) error { return s.iter( ctx, nil, - func(m UserPublicFields, _ func()) { - f(m) + func(m UserPublicFields) error { + return fn(m) }, ) } @@ -408,9 +423,10 @@ func (s *UserPublicFieldsRepo) _Get(ctx context.Context, id uuid.UUID, opt ...Op err := s.iter( ctx, s.f.PK().Eq(id), - func(m UserPublicFields, stop func()) { + func(m UserPublicFields) error { + // note: expected to be called once. r = &m - stop() + return nil }, opt..., ) @@ -427,8 +443,9 @@ func (s *UserPublicFieldsRepo) _GetManySlice(ctx context.Context, ids []uuid.UUI err := s.iter( ctx, s.f.PK().In(ids), - func(m UserPublicFields, _ func()) { + func(m UserPublicFields) error { items = append(items, m) + return nil }, opt..., ) diff --git a/examples/example3/cmd/main.go b/examples/example3/cmd/main.go index 13ffee1..436fc38 100644 --- a/examples/example3/cmd/main.go +++ b/examples/example3/cmd/main.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "log" + "os" "time" "example3/adapters/mysql" @@ -17,13 +18,18 @@ const ( dsn = "test_login:test_pass@tcp(localhost:53306)/example3" ) +var ( + logInfo = log.New(os.Stdout, "INF ", log.LstdFlags) + logErr = log.New(os.Stderr, "ERR ", log.LstdFlags) +) + func main() { fmt.Println("Example3") repo := mysql.NewUserRepo(dsn) err := repo.Connect(3 * time.Second) if err != nil { - log.Fatalf("repo connect error: %s", err) + logErr.Fatalf("repo connect error: %s", err) } repo.SetMaxOpenConns(100) repo.SetConnMaxLifetime(5 * time.Minute) @@ -31,9 +37,14 @@ func main() { // migrate err = migrateUp(dsn) if err != nil { - log.Fatalln(err) + logErr.Fatalln(err) } - defer migrateDown(dsn) + defer func() { + err = migrateDown(dsn) + if err != nil { + logErr.Fatalln("migrate down error:", err) + } + }() // add record var userId uuid.UUID @@ -51,9 +62,9 @@ func main() { return repo.Create(ctx, u) }) if err != nil { - log.Fatalln("Create error:", err) + logErr.Fatalln("Create error:", err) } - log.Printf("user record created: %+v", u) + logInfo.Printf("user record created: %+v", u) userId = u.Id } @@ -66,13 +77,13 @@ func main() { return err }) if err != nil { - log.Fatalln("Get error:", err) + logErr.Fatalln("Get error:", err) } if u == nil { - log.Fatalln("user not exists") + logErr.Fatalln("user not exists") } - log.Printf("repo Get user result: %+v", u) + logInfo.Printf("repo Get user result: %+v", u) } // delete record @@ -81,10 +92,10 @@ func main() { return repo.Delete(ctx, userId) }) if err != nil { - log.Fatalln("Delete error:", err) + logErr.Fatalln("Delete error:", err) } - log.Printf("repo Delete succeed") + logInfo.Printf("repo Delete succeed") } fmt.Println("End.") @@ -95,7 +106,7 @@ func migrateUp(dsn string) error { if err != nil { return fmt.Errorf("connect error: %w", err) } - defer c.Close() + defer func() { _ = c.Close() }() queries := []string{ ` @@ -133,7 +144,7 @@ func migrateDown(dsn string) error { if err != nil { return fmt.Errorf("connect error: %w", err) } - defer c.Close() + defer func() { _ = c.Close() }() queries := []string{ `DROP TABLE user`,