diff --git a/cache/abstract.go b/cache/abstract.go index bea1910..16db547 100644 --- a/cache/abstract.go +++ b/cache/abstract.go @@ -10,6 +10,14 @@ import ( "github.com/vmihailenco/msgpack/v5" ) +const ( + TAG_ENTITY = "ENTITY" + TAG_COUNT = "COUNT" + TAG_SEARCH = "SEARCH" + TAG_EXISTS = "CHECK" + TAG_SESSION = "SESSION" +) + // 向Redis缓存中保存一个数据 // ! 如果需要长期保存一个数据,那么需要向expires传入0。 func Cache[T interface{}](key string, value *T, expires time.Duration) error { diff --git a/cache/count.go b/cache/count.go new file mode 100644 index 0000000..488b892 --- /dev/null +++ b/cache/count.go @@ -0,0 +1,52 @@ +package cache + +import ( + "electricity_bill_calc/global" + "fmt" + "strconv" + "strings" +) + +func assembleCountKey(entityName string) string { + var keys = make([]string, 0) + keys = append(keys, strings.ToUpper(entityName)) + return CacheKey(TAG_COUNT, keys...) +} + +func assembleCountIdentification(additional ...string) string { + var b strings.Builder + for _, s := range additional { + fmt.Fprintf(&b, ":%s", s) + } + return b.String() +} + +// 向缓存中缓存模型名称明确的包含指定条件的实体记录数量 +func CacheCount(entityName string, count int64, conditions ...string) error { + countKey := assembleCountKey(entityName) + identification := assembleCountIdentification(conditions...) + result := global.RedisConn.HSet(global.Ctx, countKey, map[string]interface{}{identification: count}) + return result.Err() +} + +// 从缓存中获取模型名称明确的,包含指定条件的实体记录数量 +func RetreiveCount(entityName string, condtions ...string) (int64, error) { + countKey := assembleCountKey(entityName) + identification := assembleCountIdentification(condtions...) + result := global.RedisConn.HGet(global.Ctx, countKey, identification) + if result.Err() != nil { + return -1, result.Err() + } + count, err := strconv.ParseInt(result.Val(), 10, 64) + if err != nil { + return -1, err + } + return count, nil +} + +// 删除指定模型名称的数量缓存 +func AbolishCountEntity(entityName string) error { + countKey := assembleCountKey(entityName) + result := global.RedisConn.Del(global.Ctx, countKey) + return result.Err() +} diff --git a/cache/entity.go b/cache/entity.go new file mode 100644 index 0000000..7f945f5 --- /dev/null +++ b/cache/entity.go @@ -0,0 +1,61 @@ +package cache + +import ( + "electricity_bill_calc/global" + "fmt" + "strings" +) + +func assembleEntityKey(entityName, id string) string { + var keys = make([]string, 0) + keys = append(keys, TAG_ENTITY) + keys = append(keys, strings.ToUpper(entityName), id) + var b strings.Builder + for _, s := range keys { + fmt.Fprintf(&b, ":%s", s) + } + return b.String() +} + +// 缓存模型名称明确的,使用ID进行检索的实体内容。 +func CacheEntity[T any](instance T, entityName, id string) error { + entityKey := assembleEntityKey(entityName, id) + err := Cache(entityKey, &instance, 0) + return err +} + +// 从缓存中取出模型名称明确的,使用ID进行检索的实体内容。 +func RetreiveEntity[T any](entityName, id string) (T, error) { + entityKey := assembleEntityKey(entityName, id) + instance, err := Retreive[T](entityKey) + return *instance, err +} + +// 精确的从缓存中删除指定模型名称、指定ID的实体内容。 +func AbolishSpecificEntity(entityName, id string) (bool, error) { + entityKey := assembleEntityKey(entityName, id) + return Delete(entityKey) +} + +// 从缓存中删除指定模型名称的所有内容。 +func AbolishEntity(entityName string) error { + var ( + cursor uint64 + keys = make([]string, 0) + ) + pattern := fmt.Sprintf("%s:%s:*", TAG_ENTITY, strings.ToUpper(entityName)) + for { + k, cursor, err := global.RedisConn.Scan(global.Ctx, cursor, pattern, 20).Result() + if err != nil { + return err + } + keys = append(keys, k...) + if cursor == 0 { + break + } + } + pipeline := global.RedisConn.Pipeline() + pipeline.Del(global.Ctx, keys...) + _, err := pipeline.Exec(global.Ctx) + return err +} diff --git a/cache/exists.go b/cache/exists.go new file mode 100644 index 0000000..4a7449a --- /dev/null +++ b/cache/exists.go @@ -0,0 +1,70 @@ +package cache + +import ( + "electricity_bill_calc/global" + "electricity_bill_calc/tools" + "fmt" + "strings" +) + +func assembleExistsKey(entityName string) string { + var keys = make([]string, 0) + keys = append(keys, strings.ToUpper(entityName)) + return CacheKey(TAG_EXISTS, keys...) +} + +func assembleExistsIdentification(id string, additional ...string) string { + var b strings.Builder + b.WriteString(id) + for _, s := range additional { + fmt.Fprintf(&b, ":%s", s) + } + return b.String() +} + +// 缓存模型名称明确的、包含指定ID以及一些附加条件的记录 +func CacheExists(entityName, id string, conditions ...string) error { + existskey := assembleExistsKey(entityName) + identification := assembleExistsIdentification(id, conditions...) + result := global.RedisConn.SAdd(global.Ctx, existskey, identification) + return result.Err() +} + +// 从缓存中获取模型名称明确、包含指定ID以及一些附加条件的实体是否存在的标记,函数在返回false时不保证数据库中相关记录也不存在 +func CheckExists(entityName, id string, condtions ...string) (bool, error) { + existsKey := assembleExistsKey(entityName) + identification := assembleExistsIdentification(id, condtions...) + result := global.RedisConn.SIsMember(global.Ctx, existsKey, identification) + return result.Val(), result.Err() +} + +// 从缓存中删除模型名称明确、包含指定ID的全部实体存在标记 +func AbolishExists(entityName, id string) error { + existsKey := assembleExistsKey(entityName) + pattern := fmt.Sprintf("%s*", id) + var ( + cursor uint64 + elems = make([]string, 0) + ) + for { + k, cursor, err := global.RedisConn.SScan(global.Ctx, existsKey, cursor, pattern, 20).Result() + if err != nil { + return err + } + elems = append(elems, k...) + if cursor == 0 { + break + } + } + pipeline := global.RedisConn.Pipeline() + pipeline.SRem(global.Ctx, existsKey, tools.ConvertSliceToInterfaceSlice(elems)...) + _, err := pipeline.Exec(global.Ctx) + return err +} + +// 从缓存中删除指定模型名称的全部存在标记 +func AbolishExistsEntity(entityName string) error { + existskey := assembleExistsKey(entityName) + result := global.RedisConn.Del(global.Ctx, existskey) + return result.Err() +} diff --git a/cache/search.go b/cache/search.go new file mode 100644 index 0000000..3312b52 --- /dev/null +++ b/cache/search.go @@ -0,0 +1,56 @@ +package cache + +import ( + "electricity_bill_calc/global" + "fmt" + "strings" +) + +func assembleSearchKey(entityName string, additional ...string) string { + var keys = make([]string, 0) + keys = append(keys, TAG_SEARCH) + keys = append(keys, strings.ToUpper(entityName)) + keys = append(keys, additional...) + var b strings.Builder + for _, s := range keys { + fmt.Fprintf(&b, ":%s", s) + } + return b.String() +} + +// 缓存模型名称明确的,使用或者包含非ID检索条件的实体内容。 +func CacheSearch[T any](instance T, entityName string, conditions ...string) error { + searchKey := assembleSearchKey(entityName, conditions...) + err := Cache(searchKey, &instance, 0) + return err +} + +// 从缓存中取得模型名称明确的,使用或者包含非ID检索条件的实体内容。 +func RetreiveSearch[T any](entityName string, conditions ...string) (T, error) { + searchKey := assembleSearchKey(entityName, conditions...) + instance, err := Retreive[T](searchKey) + return *instance, err +} + +// 从缓存中删除全部指定模型名称的实体内容。 +func AbolishSearch(entityName string) error { + var ( + cursor uint64 + keys = make([]string, 0) + ) + pattern := fmt.Sprintf("%s:%s:*", TAG_SEARCH, strings.ToUpper(entityName)) + for { + k, cursor, err := global.RedisConn.Scan(global.Ctx, cursor, pattern, 20).Result() + if err != nil { + return err + } + keys = append(keys, k...) + if cursor == 0 { + break + } + } + pipeline := global.RedisConn.Pipeline() + pipeline.Del(global.Ctx, keys...) + _, err := pipeline.Exec(global.Ctx) + return err +} diff --git a/cache/session.go b/cache/session.go index 501d5b5..30000d7 100644 --- a/cache/session.go +++ b/cache/session.go @@ -9,7 +9,7 @@ import ( func SessionKey(keys ...string) string { var b strings.Builder - b.WriteString("session") + b.WriteString(TAG_SESSION) for _, s := range keys { fmt.Fprintf(&b, ":%s", s) } diff --git a/tools/utils.go b/tools/utils.go index 0f3d6c7..1c4ab06 100644 --- a/tools/utils.go +++ b/tools/utils.go @@ -30,3 +30,11 @@ func ConvertStructToMap[T any](origin T) map[string]interface{} { json.Unmarshal(incr, &dest) return dest } + +func ConvertSliceToInterfaceSlice[T any](origin []T) []interface{} { + dest := make([]interface{}, len(origin)) + for i, e := range origin { + dest[i] = e + } + return dest +}