Returning pagination metadata.
All checks were successful
Deploy Greenlight API / deploy (push) Successful in 2m48s

This commit is contained in:
Maxime Delporte
2025-11-15 16:51:13 +01:00
parent 28b25fed6e
commit e93375d441
3 changed files with 39 additions and 8 deletions

View File

@@ -194,15 +194,16 @@ func (m MovieModel) Delete(id int64) error {
}
// GetAll : Returns a slice of movies. Although we're not using them right now, we've set this up to accept the various filter parameters as arguments
func (m MovieModel) GetAll(title string, genres []string, filters Filters) ([]*Movie, error) {
func (m MovieModel) GetAll(title string, genres []string, filters Filters) ([]*Movie, Metadata, error) {
// Construct the SQL query to retrieve all movie records.
// to_tsvector('simple', title) transforms 'The Breakfast Club' into 'breakfast' 'club' 'the'. The 'simple' parameter's value is the configuration.
// plainto_tsquery('simple', $1) takes a search value and turns it into a formatted query term that PostgreSQL full-text search can understand. As an example : "The Club" would result in the query term 'the' & 'club'
// The @@ operator is the matches' operator. To continue the example, the query term 'the' & 'club' will match rows which contain both lexemes 'the' and 'club'.
// Add an ORDER BY clause and interpolate the sort column and direction. Importantly, notice that we also include a secondary sort on the movie ID to ensure a consistent ordering.
// Update the SQL query to include the LIMIT and OFFSET clauses with placeholder parameter values
// Update the SQL query to include the window function which counts the total (filtered) records
query := fmt.Sprintf(`
SELECT id, created_at, title, year, runtime, genres, version
SELECT count(*) OVER(), id, created_at, title, year, runtime, genres, version
FROM movies
WHERE (to_tsvector('simple', title) @@ plainto_tsquery('simple', $1) OR $1 = '')
AND (genres @> $2 OR $2 = '{}')
@@ -220,12 +221,13 @@ func (m MovieModel) GetAll(title string, genres []string, filters Filters) ([]*M
// And then pass the args slice to QueryContext() as a variadic parameter
rows, err := m.DB.QueryContext(ctx, query, args...)
if err != nil {
return nil, err
return nil, Metadata{}, err
}
// Importantly, defer a call to rows.Close() to ensure the resultset is closed before GetAll() returns
defer rows.Close()
totalRecords := 0
// Initialize an empty slice to hold the movie data.
movies := []*Movie{}
@@ -236,6 +238,7 @@ func (m MovieModel) GetAll(title string, genres []string, filters Filters) ([]*M
// Scan the values from the row into the Movie struct. Again, note that we're using the pq.Array() adapter on the genres field here.
err := rows.Scan(
&totalRecords,
&movie.ID,
&movie.CreatedAt,
&movie.Title,
@@ -245,7 +248,7 @@ func (m MovieModel) GetAll(title string, genres []string, filters Filters) ([]*M
&movie.Version,
)
if err != nil {
return nil, err
return nil, Metadata{}, err
}
// Add the Movie struct to the slice.
@@ -254,10 +257,14 @@ func (m MovieModel) GetAll(title string, genres []string, filters Filters) ([]*M
// When the rows.Next() loop has finished, call rows.Err() to retrieve any error that was encountered during the iteration.
if err = rows.Err(); err != nil {
return nil, err
return nil, Metadata{}, err
}
// Generate a Metadata struct, passing in the total record count and pagination parameters from the client
metadata := calculateMetadata(totalRecords, filters.Page, filters.PageSize)
// If everything went OK, then return the slice of movies
return movies, nil
// Include the metadata struct when returning
return movies, metadata, nil
}