Adding filter and refactoring functions for new import graph

main
Drew Bednar 3 days ago
parent ae8fa143a7
commit faca55f866

@ -45,7 +45,7 @@ func (app *application) createMovieHandler(w http.ResponseWriter, r *http.Reques
v := validator.New()
if validator.ValidateMovie(v, m); !v.Valid() {
if data.ValidateMovie(v, m); !v.Valid() {
app.failedValidationResponse(w, r, v.Errors)
}
@ -177,7 +177,7 @@ func (app *application) updateMovieHandler(w http.ResponseWriter, r *http.Reques
v := validator.New()
if validator.ValidateMovie(v, movie); !v.Valid() {
if data.ValidateMovie(v, movie); !v.Valid() {
app.failedValidationResponse(w, r, v.Errors)
return
}
@ -248,6 +248,28 @@ func (app *application) listMoviesHandler(w http.ResponseWriter, r *http.Request
app.logger.Debug("query params", "qp", qparams)
}
//holds values from input string
var input struct {
Title string
Genres []string
data.Filters
}
v := validator.New()
input.Title = app.readString(qparams, "title", "")
input.Genres = app.readCSV(qparams, "genres", []string{})
input.Page = app.readInt(qparams, "page", 1, v)
input.PageSize = app.readInt(qparams, "page_size", 20, v)
input.Sort = app.readString(qparams, "sort", "id")
input.Filters.SortSafelist = []string{"id", "title", "year", "runtime", "-id", "-title", "-year", "-runtime"}
data.ValidateFilters(v, input.Filters)
if !v.Valid() {
app.failedValidationResponse(w, r, v.Errors)
return
}
movies, err := app.models.Movies.List(r.Context())
if err != nil {
app.serverErrorResponse(w, r, err)

@ -10,9 +10,11 @@ import (
"fmt"
"io"
"net/http"
"net/url"
"strconv"
"strings"
"git.runcible.io/learning/pulley/internal/validator"
"github.com/julienschmidt/httprouter"
)
@ -156,3 +158,35 @@ func (a *application) readIDParam(r *http.Request) (int64, error) {
return id, err
}
func (a *application) readString(qs url.Values, key string, defaultValue string) string {
s := qs.Get(key)
if s == "" {
return defaultValue
}
return s
}
func (a *application) readInt(qs url.Values, key string, defaultInt int, v *validator.Validator) int {
s := qs.Get(key)
if s == "" {
return defaultInt
}
i, err := strconv.Atoi(s)
if err != nil {
v.AddError(key, "must be an integer value")
return defaultInt
}
return i
}
func (a *application) readCSV(qs url.Values, key string, defaultValue []string) []string {
s := qs.Get(key)
if s == "" {
return defaultValue
}
return strings.Split(s, ",")
}

@ -0,0 +1,18 @@
package data
import "git.runcible.io/learning/pulley/internal/validator"
type Filters struct {
Page int
PageSize int
Sort string
SortSafelist []string
}
func ValidateFilters(v *validator.Validator, f Filters) {
v.Check(f.Page > 0, "page", "must be greater than zero")
v.Check(f.Page < 10_000_000, "page", "must be a maximum of 10 million")
v.Check(f.PageSize > 0, "page_size", "must be greater than zero")
v.Check(f.PageSize <= 100, "page_size", "must be a maximum of 100")
v.Check(validator.PermittedValue(f.Sort, f.SortSafelist...), "sort", "invalid sort value")
}

@ -5,6 +5,7 @@ import (
"errors"
"time"
"git.runcible.io/learning/pulley/internal/validator"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgconn"
"github.com/jackc/pgx/v5/pgxpool"
@ -52,8 +53,6 @@ func (m MovieModel) Get(ctx context.Context, id int64) (*Movie, error) {
return nil, ErrRecordNotFound
}
panic("OMG!")
query := `
SELECT id, created_at, title, year, runtime, genres, version
FROM movies
@ -207,3 +206,18 @@ func (m MovieModel) List(ctx context.Context) ([]*Movie, error) {
return movies, nil
}
func ValidateMovie(v *validator.Validator, m *Movie) {
v.Check(m.Title != "", "title", "must be provided")
v.Check(len(m.Title) <= 500, "title", "must not be more than 500 bytes long")
v.Check(m.Year != 0, "year", "must be provided")
v.Check(m.Year >= 1888, "year", "must be greater than 1888")
v.Check(m.Year <= int32(time.Now().Year()), "year", "must not be in the future")
v.Check(m.Runtime != 0, "runtime", "must be provided")
v.Check(m.Runtime > 0, "runtime", "must be a positive integer")
v.Check(m.Genres != nil, "genres", "must be provided")
v.Check(len(m.Genres) >= 1, "genres", "must contain one genre")
v.Check(len(m.Genres) <= 5, "genres", "must not contain more than 5 genres")
v.Check(validator.Unique(m.Genres), "genres", "must not contain duplicate values")
}

@ -1,10 +1,8 @@
package validator
import (
"git.runcible.io/learning/pulley/internal/data"
"regexp"
"slices"
"time"
)
// Declare a regular expression for sanity checking the format of email addresses (we'll
@ -63,18 +61,3 @@ func Unique[T comparable](values []T) bool {
return len(values) == len(uniqueValues)
}
func ValidateMovie(v *Validator, m *data.Movie) {
v.Check(m.Title != "", "title", "must be provided")
v.Check(len(m.Title) <= 500, "title", "must not be more than 500 bytes long")
v.Check(m.Year != 0, "year", "must be provided")
v.Check(m.Year >= 1888, "year", "must be greater than 1888")
v.Check(m.Year <= int32(time.Now().Year()), "year", "must not be in the future")
v.Check(m.Runtime != 0, "runtime", "must be provided")
v.Check(m.Runtime > 0, "runtime", "must be a positive integer")
v.Check(m.Genres != nil, "genres", "must be provided")
v.Check(len(m.Genres) >= 1, "genres", "must contain one genre")
v.Check(len(m.Genres) <= 5, "genres", "must not contain more than 5 genres")
v.Check(Unique(m.Genres), "genres", "must not contain duplicate values")
}

Loading…
Cancel
Save