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 }