mirror of
https://github.com/kataras/iris.git
synced 2025-12-20 03:17:04 +00:00
reorganization of _examples and add some new examples such as iris+groupcache+mysql+docker
Former-commit-id: ed635ee95de7160cde11eaabc0c1dcb0e460a620
This commit is contained in:
74
_examples/database/mysql/service/category_service.go
Normal file
74
_examples/database/mysql/service/category_service.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"myapp/entity"
|
||||
"myapp/sql"
|
||||
)
|
||||
|
||||
// CategoryService represents the category entity service.
|
||||
// Note that the given entity (request) should be already validated
|
||||
// before service's calls.
|
||||
type CategoryService struct {
|
||||
*sql.Service
|
||||
}
|
||||
|
||||
// NewCategoryService returns a new category service to communicate with the database.
|
||||
func NewCategoryService(db sql.Database) *CategoryService {
|
||||
return &CategoryService{Service: sql.NewService(db, new(entity.Category))}
|
||||
}
|
||||
|
||||
// Insert stores a category to the database and returns its ID.
|
||||
func (s *CategoryService) Insert(ctx context.Context, e entity.Category) (int64, error) {
|
||||
if e.Title == "" || e.ImageURL == "" {
|
||||
return 0, sql.ErrUnprocessable
|
||||
}
|
||||
|
||||
q := fmt.Sprintf(`INSERT INTO %s (title, position, image_url)
|
||||
VALUES (?,?,?);`, e.TableName())
|
||||
|
||||
res, err := s.DB().Exec(ctx, q, e.Title, e.Position, e.ImageURL)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return res.LastInsertId()
|
||||
}
|
||||
|
||||
// Update updates a category based on its `ID`.
|
||||
func (s *CategoryService) Update(ctx context.Context, e entity.Category) (int, error) {
|
||||
if e.ID == 0 || e.Title == "" || e.ImageURL == "" {
|
||||
return 0, sql.ErrUnprocessable
|
||||
}
|
||||
|
||||
q := fmt.Sprintf(`UPDATE %s
|
||||
SET
|
||||
title = ?,
|
||||
position = ?,
|
||||
image_url = ?
|
||||
WHERE %s = ?;`, e.TableName(), e.PrimaryKey())
|
||||
|
||||
res, err := s.DB().Exec(ctx, q, e.Title, e.Position, e.ImageURL, e.ID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
n := sql.GetAffectedRows(res)
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// The updatable fields, separately from that we create for any possible future necessities.
|
||||
var categoryUpdateSchema = map[string]reflect.Kind{
|
||||
"title": reflect.String,
|
||||
"image_url": reflect.String,
|
||||
"position": reflect.Int,
|
||||
}
|
||||
|
||||
// PartialUpdate accepts a key-value map to
|
||||
// update the record based on the given "id".
|
||||
func (s *CategoryService) PartialUpdate(ctx context.Context, id int64, attrs map[string]interface{}) (int, error) {
|
||||
return s.Service.PartialUpdate(ctx, id, categoryUpdateSchema, attrs)
|
||||
}
|
||||
42
_examples/database/mysql/service/category_service_test.go
Normal file
42
_examples/database/mysql/service/category_service_test.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"myapp/entity"
|
||||
"myapp/sql"
|
||||
|
||||
"github.com/DATA-DOG/go-sqlmock"
|
||||
)
|
||||
|
||||
func TestCategoryServiceInsert(t *testing.T) {
|
||||
conn, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
db := &sql.MySQL{Conn: conn}
|
||||
service := NewCategoryService(db)
|
||||
newCategory := entity.Category{
|
||||
Title: "computer-internet",
|
||||
Position: 2,
|
||||
ImageURL: "https://animage",
|
||||
}
|
||||
mock.ExpectExec("INSERT INTO categories (title, position, image_url) VALUES (?,?,?);").
|
||||
WithArgs(newCategory.Title, newCategory.Position, newCategory.ImageURL).WillReturnResult(sqlmock.NewResult(1, 1))
|
||||
|
||||
id, err := service.Insert(context.TODO(), newCategory)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if id != 1 {
|
||||
t.Fatalf("expected ID to be 1 as this is the first entry")
|
||||
}
|
||||
|
||||
if err = mock.ExpectationsWereMet(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
110
_examples/database/mysql/service/product_service.go
Normal file
110
_examples/database/mysql/service/product_service.go
Normal file
@@ -0,0 +1,110 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user