From 527c79ad1c66225677c8e25342375da0929a3263 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Garcia?= Date: Sat, 7 May 2022 22:26:27 -0300 Subject: [PATCH] Add an example repository showing how to use transactions --- examples/repo_with_transactions/models.go | 10 ++++ examples/repo_with_transactions/users.go | 63 +++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 examples/repo_with_transactions/models.go create mode 100644 examples/repo_with_transactions/users.go diff --git a/examples/repo_with_transactions/models.go b/examples/repo_with_transactions/models.go new file mode 100644 index 0000000..97a5ff5 --- /dev/null +++ b/examples/repo_with_transactions/models.go @@ -0,0 +1,10 @@ +package repo + +import "time" + +type User struct { + ID int `ksql:"id"` + Name string `ksql:"name"` + Email string `ksql:"email"` + CreatedAt time.Time `ksql:"created_at"` +} diff --git a/examples/repo_with_transactions/users.go b/examples/repo_with_transactions/users.go new file mode 100644 index 0000000..fee0e9f --- /dev/null +++ b/examples/repo_with_transactions/users.go @@ -0,0 +1,63 @@ +package repo + +import ( + "context" + "fmt" + "time" + + "github.com/vingarcia/ksql" +) + +var usersTable = ksql.NewTable("users", "id") + +// This function doesn't care if db is a transaction or not: +func GetUser(ctx context.Context, db ksql.Provider, userId int) (User, error) { + var user User + err := db.QueryOne(ctx, &user, "FROM users WHERE id = ?", userId) + return user, err +} + +// This function doesn't care if db is a transaction or not: +func GetUserByEmail(ctx context.Context, db ksql.Provider, email string) (User, error) { + var user User + err := db.QueryOne(ctx, &user, "FROM users WHERE email = ?", email) + return user, err +} + +// This function doesn't care if db is a transaction or not: +func CreateUser(ctx context.Context, db ksql.Provider, user User) error { + user.CreatedAt = time.Now() + return db.Insert(ctx, usersTable, &user) +} + +// This function doesn't care if db is a transaction or not: +func UpdateUser(ctx context.Context, db ksql.Provider, user User) error { + return db.Patch(ctx, usersTable, &user) +} + +// This function creates a transaction from the input db, if db was already a transaction +// this operation will just keep working in the same transaction instead of creating a new one. +func ChangeUserEmail(ctx context.Context, db ksql.Provider, userID int, newEmail string) error { + return db.Transaction(ctx, func(db ksql.Provider) error { + user, err := GetUser(ctx, db, userID) + if err != nil { + return err + } + + // If there is nothing to do, just return: + if user.Email == newEmail { + return nil + } + + _, err = GetUserByEmail(ctx, db, newEmail) + if err != ksql.ErrRecordNotFound { + return fmt.Errorf("can't change user email to '%s': this email is already used by other user", newEmail) + } + if err != nil { + return err + } + + user.Email = newEmail + return UpdateUser(ctx, db, user) + }) +}