diff --git a/api/account.go b/api/account.go index 985e3f5..01b62a7 100644 --- a/api/account.go +++ b/api/account.go @@ -130,7 +130,7 @@ func (server *Server) updateAccount(ctx *gin.Context) { return } - arg := db.UpdateAccountParams{ + arg := db.UpdateAccountTxParams{ ID: req.ID, Changer: req.Changer, Passwordhash: sql.NullString{ @@ -175,7 +175,7 @@ func (server *Server) updateAccount(ctx *gin.Context) { }, } - account, err := server.store.UpdateAccount(ctx, arg) + account, err := server.store.UpdateAccountTx(ctx, arg) if err != nil { ctx.JSON(http.StatusInternalServerError, errorResponse(err)) return diff --git a/api/account_test.go b/api/account_test.go index f73515d..c3c361c 100644 --- a/api/account_test.go +++ b/api/account_test.go @@ -279,7 +279,7 @@ func TestGetAccountAPI(t *testing.T) { } } -func TestUpdateAccountAPI(t *testing.T) { +func TestUpdateAccountTxAPI(t *testing.T) { account := randomAccount() changer := util.RandomName() newPassword := util.RandomString(30) @@ -302,7 +302,7 @@ func TestUpdateAccountAPI(t *testing.T) { accountTemp := account accountTemp.Passwordhash = newPassword accountTemp.Changer = changer - arg := db.UpdateAccountParams{ + arg := db.UpdateAccountTxParams{ ID: account.ID, Passwordhash: sql.NullString{ Valid: true, @@ -312,7 +312,7 @@ func TestUpdateAccountAPI(t *testing.T) { } store.EXPECT(). - UpdateAccount(gomock.Any(), gomock.Eq(arg)). + UpdateAccountTx(gomock.Any(), gomock.Eq(arg)). Times(1). Return(accountTemp, nil) }, @@ -334,7 +334,7 @@ func TestUpdateAccountAPI(t *testing.T) { "changer": changer, }, buildStubs: func(store *mockdb.MockStore) { - arg := db.UpdateAccountParams{ + arg := db.UpdateAccountTxParams{ ID: account.ID, Email: sql.NullString{ Valid: true, @@ -344,7 +344,7 @@ func TestUpdateAccountAPI(t *testing.T) { } store.EXPECT(). - UpdateAccount(gomock.Any(), gomock.Eq(arg)). + UpdateAccountTx(gomock.Any(), gomock.Eq(arg)). Times(1). Return(account, nil) }, diff --git a/db/mock/store.go b/db/mock/store.go index b53bff0..1fcd962 100644 --- a/db/mock/store.go +++ b/db/mock/store.go @@ -586,6 +586,21 @@ func (mr *MockStoreMockRecorder) UpdateAccount(arg0, arg1 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateAccount", reflect.TypeOf((*MockStore)(nil).UpdateAccount), arg0, arg1) } +// UpdateAccountTx mocks base method. +func (m *MockStore) UpdateAccountTx(arg0 context.Context, arg1 db.UpdateAccountTxParams) (db.Account, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateAccountTx", arg0, arg1) + ret0, _ := ret[0].(db.Account) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateAccountTx indicates an expected call of UpdateAccountTx. +func (mr *MockStoreMockRecorder) UpdateAccountTx(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateAccountTx", reflect.TypeOf((*MockStore)(nil).UpdateAccountTx), arg0, arg1) +} + // UpdateDocument mocks base method. func (m *MockStore) UpdateDocument(arg0 context.Context, arg1 db.UpdateDocumentParams) (db.Document, error) { m.ctrl.T.Helper() diff --git a/db/query/account.sql b/db/query/account.sql index 370ba80..61d4042 100644 --- a/db/query/account.sql +++ b/db/query/account.sql @@ -2,6 +2,11 @@ SELECT * FROM accounts WHERE "ID" = $1 LIMIT 1; +-- name: GetAccountForUpdate :one +SELECT * FROM accounts +WHERE "ID" = $1 LIMIT 1 +FOR NO KEY UPDATE; + -- name: CreateAccount :one INSERT INTO accounts ( passwordhash, diff --git a/db/sqlc/account.sql.go b/db/sqlc/account.sql.go index 97dc368..e85213c 100644 --- a/db/sqlc/account.sql.go +++ b/db/sqlc/account.sql.go @@ -127,6 +127,40 @@ func (q *Queries) GetAccount(ctx context.Context, id int64) (Account, error) { return i, err } +const getAccountForUpdate = `-- name: GetAccountForUpdate :one +SELECT "ID", passwordhash, firstname, lastname, birthday, "privacyAccepted", "privacyAcceptedDate", email, phone, city, zip, street, country, token, "tokenValid", "tokenExpiration", creator, created, changer, changed FROM accounts +WHERE "ID" = $1 LIMIT 1 +FOR NO KEY UPDATE +` + +func (q *Queries) GetAccountForUpdate(ctx context.Context, id int64) (Account, error) { + row := q.db.QueryRowContext(ctx, getAccountForUpdate, id) + var i Account + err := row.Scan( + &i.ID, + &i.Passwordhash, + &i.Firstname, + &i.Lastname, + &i.Birthday, + &i.PrivacyAccepted, + &i.PrivacyAcceptedDate, + &i.Email, + &i.Phone, + &i.City, + &i.Zip, + &i.Street, + &i.Country, + &i.Token, + &i.TokenValid, + &i.TokenExpiration, + &i.Creator, + &i.Created, + &i.Changer, + &i.Changed, + ) + return i, err +} + const listAccounts = `-- name: ListAccounts :many SELECT "ID", passwordhash, firstname, lastname, birthday, "privacyAccepted", "privacyAcceptedDate", email, phone, city, zip, street, country, token, "tokenValid", "tokenExpiration", creator, created, changer, changed FROM accounts ORDER BY lastname, firstname diff --git a/db/sqlc/querier.go b/db/sqlc/querier.go index 61f3486..df4419c 100644 --- a/db/sqlc/querier.go +++ b/db/sqlc/querier.go @@ -20,6 +20,19 @@ type Querier interface { CreateReturnsLog(ctx context.Context, arg CreateReturnsLogParams) (ReturnsLog, error) DeleteAccount(ctx context.Context, id int64) error DeleteDocument(ctx context.Context, id int64) error + // -- name: UpdateMail :one + // UPDATE mails + // SET + // "from" = COALESCE(sqlc.narg(from), "from"), + // "to" = COALESCE(sqlc.narg(to), "to"), + // cc = COALESCE(sqlc.narg(cc), cc), + // "subject" = COALESCE(sqlc.narg(subject), "subject"), + // body = COALESCE(sqlc.narg(body), body), + // "timestamp" = COALESCE(sqlc.narg(timestamp), "timestamp"), + // changer = $2, + // changed = now() + // WHERE "ID" = $1 + // RETURNING *; DeleteMail(ctx context.Context, id int64) error DeletePayment(ctx context.Context, id int64) error DeletePerson(ctx context.Context, id int64) error @@ -27,6 +40,7 @@ type Querier interface { DeleteReturn(ctx context.Context, id int64) error DeleteReturnsLog(ctx context.Context, id int64) error GetAccount(ctx context.Context, id int64) (Account, error) + GetAccountForUpdate(ctx context.Context, id int64) (Account, error) GetDocument(ctx context.Context, id int64) (Document, error) GetMail(ctx context.Context, id int64) (Mail, error) GetPayment(ctx context.Context, id int64) (Payment, error) diff --git a/db/sqlc/store.go b/db/sqlc/store.go index 00d3bdc..6fd8b3e 100644 --- a/db/sqlc/store.go +++ b/db/sqlc/store.go @@ -9,6 +9,7 @@ import ( type Store interface { Querier CreateAccountTx(ctx context.Context, arg CreateAccountTxParams) (CreateAccountTxResult, error) + UpdateAccountTx(ctx context.Context, arg UpdateAccountTxParams) (Account, error) } // Store provides all functions to execute db queries and transactions diff --git a/db/sqlc/tx_update_account.go b/db/sqlc/tx_update_account.go new file mode 100644 index 0000000..dd6287b --- /dev/null +++ b/db/sqlc/tx_update_account.go @@ -0,0 +1,36 @@ +package db + +import ( + "context" + "database/sql" +) + +type UpdateAccountTxParams struct { + ID int64 `json:"ID"` + Changer string `json:"changer"` + Passwordhash sql.NullString `json:"passwordhash"` + Firstname sql.NullString `json:"firstname"` + Lastname sql.NullString `json:"lastname"` + Birthday sql.NullTime `json:"birthday"` + Email sql.NullString `json:"email"` + Phone sql.NullString `json:"phone"` + City sql.NullString `json:"city"` + Zip sql.NullString `json:"zip"` + Street sql.NullString `json:"street"` + Country sql.NullString `json:"country"` +} + +type UpdateAccountTxResult struct { + Account Account `json:"account"` +} + +func (store *SQLStore) UpdateAccountTx(ctx context.Context, arg UpdateAccountTxParams) (Account, error) { + var result UpdateAccountTxResult + + err := store.execTx(ctx, func(q *Queries) error { + var err error + result.Account, err = q.UpdateAccount(ctx, UpdateAccountParams(arg)) + return err + }) + return result.Account, err +}