mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 18:51:03 +01:00
ed45c77be5
Former-commit-id: ed635ee95de7160cde11eaabc0c1dcb0e460a620
121 lines
2.8 KiB
Go
121 lines
2.8 KiB
Go
package cache
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/url"
|
|
"strconv"
|
|
"time"
|
|
|
|
"myapp/entity"
|
|
"myapp/sql"
|
|
|
|
"github.com/mailgun/groupcache/v2"
|
|
)
|
|
|
|
// Service that cache will use to retrieve data.
|
|
type Service interface {
|
|
RecordInfo() sql.Record
|
|
GetByID(ctx context.Context, dest interface{}, id int64) error
|
|
List(ctx context.Context, dest interface{}, opts sql.ListOptions) error
|
|
}
|
|
|
|
// Cache is a simple structure which holds the groupcache and the database service, exposes
|
|
// `GetByID` and `List` which returns cached (or stores new) items.
|
|
type Cache struct {
|
|
service Service
|
|
maxAge time.Duration
|
|
group *groupcache.Group
|
|
}
|
|
|
|
// Size default size to use on groupcache, defaults to 3MB.
|
|
var Size int64 = 3 << (10 * 3)
|
|
|
|
// New returns a new cache service which exposes `GetByID` and `List` methods to work with.
|
|
// The "name" should be unique, "maxAge" for cache expiration.
|
|
func New(service Service, name string, maxAge time.Duration) *Cache {
|
|
c := new(Cache)
|
|
c.service = service
|
|
c.maxAge = maxAge
|
|
c.group = groupcache.NewGroup(name, Size, c)
|
|
return c
|
|
}
|
|
|
|
const (
|
|
prefixID = "#"
|
|
prefixList = "["
|
|
)
|
|
|
|
// Get implements the groupcache.Getter interface.
|
|
// Use `GetByID` and `List` instead.
|
|
func (c *Cache) Get(ctx context.Context, key string, dest groupcache.Sink) error {
|
|
if len(key) < 2 { // empty or missing prefix+key, should never happen.
|
|
return sql.ErrUnprocessable
|
|
}
|
|
|
|
var v interface{}
|
|
|
|
prefix := key[0:1]
|
|
key = key[1:]
|
|
switch prefix {
|
|
case prefixID:
|
|
// Get by ID.
|
|
id, err := strconv.ParseInt(key, 10, 64)
|
|
if err != nil || id <= 0 {
|
|
return err
|
|
}
|
|
|
|
switch c.service.RecordInfo().(type) {
|
|
case *entity.Category:
|
|
v = new(entity.Category)
|
|
case *entity.Product:
|
|
v = new(entity.Product)
|
|
}
|
|
|
|
err = c.service.GetByID(ctx, v, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
case prefixList:
|
|
// Get a set of records, list.
|
|
q, err := url.ParseQuery(key)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
opts := sql.ParseListOptions(q)
|
|
|
|
switch c.service.RecordInfo().(type) {
|
|
case *entity.Category:
|
|
v = new(entity.Categories)
|
|
case *entity.Product:
|
|
v = new(entity.Products)
|
|
}
|
|
|
|
err = c.service.List(ctx, v, opts)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
default:
|
|
return sql.ErrUnprocessable
|
|
}
|
|
|
|
b, err := json.Marshal(v)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return dest.SetBytes(b, time.Now().Add(c.maxAge))
|
|
}
|
|
|
|
// GetByID binds an item to "dest" an item based on its "id".
|
|
func (c *Cache) GetByID(ctx context.Context, id string, dest *[]byte) error {
|
|
return c.group.Get(ctx, prefixID+id, groupcache.AllocatingByteSliceSink(dest))
|
|
}
|
|
|
|
// List binds item to "dest" based on the "rawQuery" of `url.Values` for `ListOptions`.
|
|
func (c *Cache) List(ctx context.Context, rawQuery string, dest *[]byte) error {
|
|
return c.group.Get(ctx, prefixList+rawQuery, groupcache.AllocatingByteSliceSink(dest))
|
|
}
|