go-transaction-manager
130 строк · 2.7 Кб
1package sql_test2
3import (4"context"5"database/sql"6"fmt"7
8_ "github.com/mattn/go-sqlite3"9
10trmsql "github.com/avito-tech/go-transaction-manager/drivers/sql/v2"11
12trmcontext "github.com/avito-tech/go-transaction-manager/trm/v2/context"13
14"github.com/avito-tech/go-transaction-manager/trm/v2/manager"15)
16
17// Example demonstrates the implementation of the Repository pattern by trm.Manager.
18func Example() {19db, err := sql.Open("sqlite3", "file:test?mode=memory")20checkErr(err)21
22defer db.Close() //nolint:errcheck23
24sqlStmt := `CREATE TABLE IF NOT EXISTS user (user_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, username TEXT);`25_, err = db.Exec(sqlStmt)26checkErr(err, sqlStmt)27
28r := newRepo(db, trmsql.DefaultCtxGetter)29
30u := &user{31Username: "username",32}33
34ctx := context.Background()35trManager := manager.Must(36trmsql.NewDefaultFactory(db),37manager.WithCtxManager(trmcontext.DefaultManager),38)39
40err = trManager.Do(ctx, func(ctx context.Context) error {41if err := r.Save(ctx, u); err != nil {42return err43}44
45return trManager.Do(ctx, func(ctx context.Context) error {46u.Username = "new_username"47
48return r.Save(ctx, u)49})50})51checkErr(err)52
53userFromDB, err := r.GetByID(ctx, u.ID)54checkErr(err)55
56fmt.Println(userFromDB)57
58// Output: &{1 new_username}59}
60
61type repo struct {62db *sql.DB63getter *trmsql.CtxGetter64}
65
66func newRepo(db *sql.DB, c *trmsql.CtxGetter) *repo {67return &repo{68db: db,69getter: c,70}71}
72
73type user struct {74ID int6475Username string76}
77
78func (r *repo) GetByID(ctx context.Context, id int64) (*user, error) {79query := "SELECT * FROM user WHERE user_id = ?;"80
81u := &user{}82
83err := r.getter.DefaultTrOrDB(ctx, r.db).QueryRowContext(ctx, query, id).Scan(&u.ID, &u.Username)84if err != nil {85return nil, err86}87
88return u, nil89}
90
91func (r *repo) Save(ctx context.Context, u *user) error {92isNew := u.ID == 093
94args := []interface{}{95sql.Named("username", u.Username),96}97query := `INSERT INTO user (username) VALUES (:username);`98
99if !isNew {100query = `UPDATE user SET username = :username WHERE user_id = :user_id;`101
102args = append(args, sql.Named("user_id", u.ID))103}104
105res, err := r.getter.DefaultTrOrDB(ctx, r.db).ExecContext(ctx, query, args...)106if err != nil {107return err108} else if !isNew {109return nil110} else if u.ID, err = res.LastInsertId(); err != nil {111return err112}113
114// For PostgreSql need to use NamedQueryContext with RETURNING115// DO UPDATE SET username = EXCLUDED.username RETURNING id;116// defer res.Next()117// if u.ID == 0 && res.Next() {118// if err = res.Scan(&u.ID); err != nil {119// return err120// }121// }122
123return nil124}
125
126func checkErr(err error, args ...interface{}) {127if err != nil {128panic(fmt.Sprint(append([]interface{}{err}, args...)...))129}130}
131