diff --git a/cmd/api/errors.go b/cmd/api/errors.go index ed507d6..ecd9c30 100644 --- a/cmd/api/errors.go +++ b/cmd/api/errors.go @@ -43,3 +43,8 @@ func (app *application) badRequestResponse(w http.ResponseWriter, r *http.Reques func (app *application) failedValidationResponse(w http.ResponseWriter, r *http.Request, errors map[string]string) { app.errorResponse(w, r, http.StatusUnprocessableEntity, errors) } + +func (app *application) editConflictResponse(w http.ResponseWriter, r *http.Request) { + message := "unable to update the record due to an edit conflict, please try again" + app.errorResponse(w, r, http.StatusConflict, message) +} diff --git a/cmd/api/movies.go b/cmd/api/movies.go index 81a171b..662bc79 100644 --- a/cmd/api/movies.go +++ b/cmd/api/movies.go @@ -127,7 +127,12 @@ func (app *application) updateMovieHandler(w http.ResponseWriter, r *http.Reques err = app.models.Movies.Update(movie) if err != nil { - app.serverErrorResponse(w, r, err) + switch { + case errors.Is(err, data.ErrEditConflict): + app.editConflictResponse(w, r) + default: + app.serverErrorResponse(w, r, err) + } return } diff --git a/internal/data/models.go b/internal/data/models.go index b549650..6106037 100644 --- a/internal/data/models.go +++ b/internal/data/models.go @@ -7,6 +7,7 @@ import ( var ( ErrRecordNotFound = errors.New("record not found") + ErrEditConflict = errors.New("edit conflict") ) type Models struct { diff --git a/internal/data/movies.go b/internal/data/movies.go index 8129ded..d55559c 100644 --- a/internal/data/movies.go +++ b/internal/data/movies.go @@ -70,7 +70,7 @@ func (m MovieModel) Update(movie *Movie) error { query := ` UPDATE movies SET title=$1, year=$2, runtime=$3, genres=$4, version = version + 1 - WHERE id = $5 + WHERE id = $5 AND version = $6 RETURNING version` args := []any{ @@ -79,9 +79,20 @@ func (m MovieModel) Update(movie *Movie) error { movie.Runtime, pq.Array(movie.Genres), movie.ID, + movie.Version, } - return m.DB.QueryRow(query, args...).Scan(&movie.Version) + err := m.DB.QueryRow(query, args...).Scan(&movie.Version) + if err != nil { + switch { + case errors.Is(err, sql.ErrNoRows): + return ErrEditConflict + default: + return err + } + } + + return nil } func (m MovieModel) Delete(id int64) error {