Adding concurrency control in our updateMovieHandler and documenting it.
All checks were successful
Deploy Greenlight API / deploy (push) Successful in 57s
All checks were successful
Deploy Greenlight API / deploy (push) Successful in 57s
This commit is contained in:
@@ -6,8 +6,10 @@ import (
|
||||
)
|
||||
|
||||
// ErrRecordNotFound : Define a custom ErrRecordNotFound error. We'll return this from our Get() method when looking up a movie that doesn't exist in our database.
|
||||
// ErrEditConflict : This error is used when a data race occurs.
|
||||
var (
|
||||
ErrRecordNotFound = errors.New("record not found")
|
||||
ErrEditConflict = errors.New("edit conflict")
|
||||
)
|
||||
|
||||
// Models : Wraps the MovieModel. We'll add other models to this, like a UserModel and PermissionModel, as our build progresses.
|
||||
|
||||
@@ -110,10 +110,11 @@ func (m MovieModel) Get(id int64) (*Movie, error) {
|
||||
// Update : Updating a specific record in the movies table
|
||||
func (m MovieModel) Update(movie *Movie) error {
|
||||
// Declare the SQL query for updating the record and returning the new version number.
|
||||
// Add the 'AND version = $6' clause to prevent data race
|
||||
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`
|
||||
|
||||
// Create an args slice containing the values for the placeholder parameters.
|
||||
@@ -123,10 +124,21 @@ func (m MovieModel) Update(movie *Movie) error {
|
||||
movie.Runtime,
|
||||
pq.Array(movie.Genres),
|
||||
movie.ID,
|
||||
movie.Version,
|
||||
}
|
||||
|
||||
// Use the QueryRow() method to execute the query, passing in the args slice as a variadic parameter and scanning the new version value into the movie struct.
|
||||
return m.DB.QueryRow(query, args...).Scan(&movie.Version)
|
||||
// Execute the SQL query. If no matching row could be found, we know the movie version has changed (or the record has been deleted) and we return our custom ErrEditConflict error.
|
||||
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
|
||||
}
|
||||
|
||||
// Delete : Deleting a specific record from the movies table
|
||||
|
||||
Reference in New Issue
Block a user