Created
September 19, 2020 00:06
-
-
Save dapperAuteur/8cb13c61389e0f1448eebb78ba679895 to your computer and use it in GitHub Desktop.
This gist contains the model, service, handler, and route to filter products
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// model | |
// FilterProduct defines what information may be provided to make a request to get Products and filter the results. | |
// All fields are optional so clients can send just the fields they want changed. | |
// It uses pointer fields so we can differentiate between a field that was not provided and a field that was provided as explicitly blank. | |
// Normally we do not want to use pointers to basic types but we make exceptions around marshalling/unmarshalling. | |
type FilterProduct struct { | |
Name *string `json:"name"` | |
Cost *int `json:"cost" validate:"omitempty,gte=0"` | |
Quantity *int `json:"quantity" validate:"omitempty,gte=1"` | |
} | |
// service | |
// FilterProducts gets all the Products from the database that meet the filter criteria. | |
// Then encodes them in a response client. | |
// It returns an empty array if none of the Products fit the criteria. | |
func FilterProducts(ctx context.Context, db *sqlx.DB, fp FilterProduct) ([]Product, error) { | |
list := []Product{} | |
var ( | |
name string | |
cost, | |
quantity int | |
) | |
if fp.Name != nil { | |
name = *fp.Name | |
} | |
if fp.Cost != nil { | |
cost = *fp.Cost | |
} | |
if fp.Quantity != nil { | |
quantity = *fp.Quantity | |
} | |
const q = `SELECT | |
p.product_id, p.name, p.cost, p.quantity, | |
FROM products AS p | |
WHERE p.Name = $1 OR | |
WHERE p.cost = $2 OR | |
WHERE p.quantity = $3 | |
GROUP BY p.Name` | |
if err := db.GetContext(ctx, &list, q, name, cost, quantity); err != nil { | |
if err == sql.ErrNoRows { | |
return nil, ErrNotFound | |
} | |
return nil, err | |
} | |
return list, nil | |
} | |
// handler | |
// FilterProducts gets all filtered products from the service layer. | |
func (p *Product) FilterProducts(ctx context.Context, w http.ResponseWriter, r *http.Request) error { | |
ctx, span := trace.StartSpan(ctx, "handlers.Product.FilterProducts") | |
defer span.End() | |
filterProduct := product.FilterProduct{} | |
if err := web.Decode(r, &filterProduct); err != nil { | |
return err | |
} | |
list, err := product.FilterProducts(ctx, p.DB, filterProduct) | |
if err != nil { | |
return errors.Wrapf(err, "filtering products %q", filterProduct) | |
} | |
return web.Respond(ctx, w, list, http.StatusOK) | |
} | |
// route | |
app.Handle(http.MethodPost, "/v1/products/filter", p.FilterProducts) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment