Files
servicebase/pkg/cache/common/common.go
2025-12-02 14:41:30 +08:00

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
}