123 lines
3.1 KiB
Go
123 lines
3.1 KiB
Go
package cache_common
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
|
|
"gitea.ddegame.cn/open/servicebase/pkg/cache"
|
|
"github.com/redis/go-redis/v9"
|
|
)
|
|
|
|
type DBCacheFetcher[T any] func(fieldKey string) (*T, error)
|
|
type DBCacheFetcherMany[T any] func(fieldKeys []string) (map[string]*T, error)
|
|
|
|
func GetOrCacheOne[T any](cli *redis.Client, hashKey string, fieldKey string, dbFetcher DBCacheFetcher[T]) (*T, error) {
|
|
if len(fieldKey) == 0 {
|
|
return nil, nil
|
|
}
|
|
var cachedStr string
|
|
var err error
|
|
if cachedStr, err = cli.HGet(cache.Ctx(), hashKey, fieldKey).Result(); err != nil && !errors.Is(err, redis.Nil) {
|
|
return nil, err
|
|
}
|
|
var model *T
|
|
if len(cachedStr) > 0 {
|
|
model = new(T)
|
|
if err = json.Unmarshal([]byte(cachedStr), model); err == nil {
|
|
return model, nil
|
|
}
|
|
}
|
|
if model, err = dbFetcher(fieldKey); err != nil {
|
|
return nil, err
|
|
}
|
|
if model == nil {
|
|
return nil, nil
|
|
}
|
|
bytes, marshalErr := json.Marshal(model)
|
|
if marshalErr != nil {
|
|
return model, nil
|
|
}
|
|
_, _ = cli.HSet(cache.Ctx(), hashKey, fieldKey, string(bytes)).Result()
|
|
return model, nil
|
|
}
|
|
|
|
func GetOrCacheMany[T any](cli *redis.Client, hashKey string, fieldKeyList []string, dbFetcherMany DBCacheFetcherMany[T]) ([]*T, error) {
|
|
if len(fieldKeyList) == 0 {
|
|
return make([]*T, 0), nil
|
|
}
|
|
finalResults := make([]*T, len(fieldKeyList))
|
|
missingKeysMap := make(map[string]int)
|
|
missingKeysList := make([]string, 0)
|
|
values, err := cli.HMGet(cache.Ctx(), hashKey, fieldKeyList...).Result()
|
|
if err != nil && !errors.Is(err, redis.Nil) {
|
|
return nil, err
|
|
}
|
|
for i, fieldKey := range fieldKeyList {
|
|
value := values[i]
|
|
if value == nil {
|
|
missingKeysMap[fieldKey] = i
|
|
missingKeysList = append(missingKeysList, fieldKey)
|
|
continue
|
|
}
|
|
cachedStr, ok := value.(string)
|
|
if !ok {
|
|
missingKeysMap[fieldKey] = i
|
|
missingKeysList = append(missingKeysList, fieldKey)
|
|
continue
|
|
}
|
|
model := new(T)
|
|
if jsonErr := json.Unmarshal([]byte(cachedStr), model); jsonErr == nil {
|
|
finalResults[i] = model
|
|
} else {
|
|
missingKeysMap[fieldKey] = i
|
|
missingKeysList = append(missingKeysList, fieldKey)
|
|
}
|
|
}
|
|
if len(missingKeysList) == 0 {
|
|
return finalResults, nil
|
|
}
|
|
dbModelsMap, err := dbFetcherMany(missingKeysList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
cacheMap := make(map[string]any)
|
|
for fieldKey, model := range dbModelsMap {
|
|
originalIndex, found := missingKeysMap[fieldKey]
|
|
if !found {
|
|
continue
|
|
}
|
|
finalResults[originalIndex] = model
|
|
if model != nil {
|
|
if bytes, marshalErr := json.Marshal(model); marshalErr == nil {
|
|
cacheMap[fieldKey] = string(bytes)
|
|
}
|
|
}
|
|
}
|
|
if len(cacheMap) > 0 {
|
|
_, _ = cli.HSet(cache.Ctx(), hashKey, cacheMap).Result()
|
|
}
|
|
return finalResults, nil
|
|
}
|
|
|
|
func DelCacheFields(cli *redis.Client, hashKey string, fieldKeyList ...string) error {
|
|
if len(fieldKeyList) == 0 {
|
|
return nil
|
|
}
|
|
_, err := cli.HDel(cache.Ctx(), hashKey, fieldKeyList...).Result()
|
|
if err != nil && !errors.Is(err, redis.Nil) {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func DelCacheHash(cli *redis.Client, hashKey string) error {
|
|
if len(hashKey) == 0 {
|
|
return nil
|
|
}
|
|
_, err := cli.Del(cache.Ctx(), hashKey).Result()
|
|
if err != nil && !errors.Is(err, redis.Nil) {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|