iris/_examples/database/mysql/service/product_service.go

111 lines
2.9 KiB
Go
Raw Permalink Normal View History

package service
import (
"context"
"fmt"
"reflect"
"strings"
"myapp/entity"
"myapp/sql"
)
// ProductService represents the product entity service.
// Note that the given entity (request) should be already validated
// before service's calls.
type ProductService struct {
*sql.Service
rec sql.Record
}
// NewProductService returns a new product service to communicate with the database.
func NewProductService(db sql.Database) *ProductService {
return &ProductService{Service: sql.NewService(db, new(entity.Product))}
}
// Insert stores a product to the database and returns its ID.
func (s *ProductService) Insert(ctx context.Context, e entity.Product) (int64, error) {
if !e.ValidateInsert() {
return 0, sql.ErrUnprocessable
}
q := fmt.Sprintf(`INSERT INTO %s (category_id, title, image_url, price, description)
VALUES (?,?,?,?,?);`, e.TableName())
res, err := s.DB().Exec(ctx, q, e.CategoryID, e.Title, e.ImageURL, e.Price, e.Description)
if err != nil {
return 0, err
}
return res.LastInsertId()
}
// BatchInsert inserts one or more products at once and returns the total length created.
func (s *ProductService) BatchInsert(ctx context.Context, products []entity.Product) (int, error) {
if len(products) == 0 {
return 0, nil
}
var (
valuesLines []string
args []interface{}
)
for _, p := range products {
if !p.ValidateInsert() {
// all products should be "valid", we don't skip, we cancel.
return 0, sql.ErrUnprocessable
}
valuesLines = append(valuesLines, "(?,?,?,?,?)")
args = append(args, []interface{}{p.CategoryID, p.Title, p.ImageURL, p.Price, p.Description}...)
}
q := fmt.Sprintf("INSERT INTO %s (category_id, title, image_url, price, description) VALUES %s;",
s.RecordInfo().TableName(),
strings.Join(valuesLines, ", "))
res, err := s.DB().Exec(ctx, q, args...)
if err != nil {
return 0, err
}
n := sql.GetAffectedRows(res)
return n, nil
}
// Update updates a product based on its `ID` from the database
// and returns the affected numbrer (0 when nothing changed otherwise 1).
func (s *ProductService) Update(ctx context.Context, e entity.Product) (int, error) {
q := fmt.Sprintf(`UPDATE %s
SET
category_id = ?,
title = ?,
image_url = ?,
price = ?,
description = ?
WHERE %s = ?;`, e.TableName(), e.PrimaryKey())
res, err := s.DB().Exec(ctx, q, e.CategoryID, e.Title, e.ImageURL, e.Price, e.Description, e.ID)
if err != nil {
return 0, err
}
n := sql.GetAffectedRows(res)
return n, nil
}
var productUpdateSchema = map[string]reflect.Kind{
"category_id": reflect.Int,
"title": reflect.String,
"image_url": reflect.String,
"price": reflect.Float32,
"description": reflect.String,
}
// PartialUpdate accepts a key-value map to
// update the record based on the given "id".
func (s *ProductService) PartialUpdate(ctx context.Context, id int64, attrs map[string]interface{}) (int, error) {
return s.Service.PartialUpdate(ctx, id, productUpdateSchema, attrs)
}