rest/plugins/cache/cache.go

109 lines
2.1 KiB
Go

package cache
import (
"encoding/json"
"fmt"
"git.nobla.cn/golang/kos/pkg/cache"
xxhash "github.com/cespare/xxhash/v2"
"gorm.io/gorm"
"gorm.io/gorm/callbacks"
"os"
"strconv"
"time"
)
const (
DisableCache = "DISABLE_CACHE"
DurationKey = "gorm:cache_duration"
)
type Cacher struct {
rawQuery func(db *gorm.DB)
}
func (c *Cacher) Name() string {
return "gorm:cache"
}
func (c *Cacher) Initialize(db *gorm.DB) (err error) {
c.rawQuery = db.Callback().Query().Get("gorm:query")
err = db.Callback().Query().Replace("gorm:query", c.Query)
return
}
// buildCacheKey 构建一个缓存的KEY
func (c *Cacher) buildCacheKey(db *gorm.DB) string {
s := strconv.FormatUint(xxhash.Sum64String(db.Statement.SQL.String()+fmt.Sprintf("%v", db.Statement.Vars)), 10)
return s
}
// getDuration 获取缓存时长
func (c *Cacher) getDuration(db *gorm.DB) time.Duration {
var (
ok bool
v any
duration time.Duration
)
if v, ok = db.InstanceGet(DurationKey); !ok {
return 0
}
if duration, ok = v.(time.Duration); !ok {
return 0
}
return duration
}
// tryLoad 尝试从缓存读取数据
func (c *Cacher) tryLoad(key string, db *gorm.DB) (err error) {
var (
ok bool
buf []byte
)
if buf, ok = cache.Get(db.Statement.Context, key); ok {
err = json.Unmarshal(buf, db.Statement.Dest)
} else {
err = os.ErrNotExist
}
return
}
// storeCache 存储缓存数据
func (c *Cacher) storeCache(key string, db *gorm.DB, duration time.Duration) (err error) {
var (
buf []byte
)
if buf, err = json.Marshal(db.Statement.Dest); err == nil {
cache.SetEx(db.Statement.Context, key, buf, duration)
}
return
}
func (c *Cacher) Query(db *gorm.DB) {
var (
err error
cacheKey string
duration time.Duration
)
duration = c.getDuration(db)
if duration <= 0 {
c.rawQuery(db)
return
}
callbacks.BuildQuerySQL(db)
cacheKey = c.buildCacheKey(db)
if err = c.tryLoad(cacheKey, db); err == nil {
return
}
c.rawQuery(db)
if db.Error == nil {
//store cache
if err = c.storeCache(cacheKey, db, duration); err != nil {
_ = db.AddError(err)
}
}
}
func New() *Cacher {
return &Cacher{}
}