diff --git a/redis_Iterator.go b/redis_Iterator.go new file mode 100644 index 0000000..2b6c8d0 --- /dev/null +++ b/redis_Iterator.go @@ -0,0 +1,26 @@ +package dorm + +type Iterator struct { + data []interface{} + index int +} + +// NewIterator 构造函数 +func NewIterator(data []interface{}) *Iterator { + return &Iterator{data: data} +} + +// HasNext 是否有下一个 +func (i *Iterator) HasNext() bool { + if i.data == nil || len(i.data) == 0 { + return false + } + return i.index < len(i.data) +} + +// Next 循环下一个 +func (i *Iterator) Next() (Ret interface{}) { + Ret = i.data[i.index] + i.index = i.index + 1 + return +} diff --git a/redis_hash_operation.go b/redis_hash_operation.go new file mode 100644 index 0000000..ca8c2a2 --- /dev/null +++ b/redis_hash_operation.go @@ -0,0 +1,26 @@ +package dorm + +import ( + "context" + "github.com/go-redis/redis/v8" +) + +type HashOperation struct { + db *redis.Client + ctx context.Context +} + +// NewHashOperation hash类型数据操作 https://www.tizi365.com/archives/296.html +func NewHashOperation(db *redis.Client, ctx context.Context) *HashOperation { + return &HashOperation{db: db, ctx: ctx} +} + +// Set 根据key和field字段设置,field字段的值 +func (cl *HashOperation) Set(key string, value interface{}) *redis.IntCmd { + return cl.db.HSet(cl.ctx, key, value) +} + +// Get 根据key和field字段设置,field字段的值 +func (cl *HashOperation) Get(key, field string) *redis.StringCmd { + return cl.db.HGet(cl.ctx, key, field) +} diff --git a/redis_list_operation.go b/redis_list_operation.go new file mode 100644 index 0000000..7cf7921 --- /dev/null +++ b/redis_list_operation.go @@ -0,0 +1,76 @@ +package dorm + +import ( + "context" + "github.com/go-redis/redis/v8" +) + +type ListOperation struct { + db *redis.Client + ctx context.Context +} + +// NewListOperation 列表(list)类型数据操作 https://www.tizi365.com/archives/299.html +func (c *RedisClient) NewListOperation() *ListOperation { + return &ListOperation{db: c.Db, ctx: context.Background()} +} + +// LPush 从列表左边插入数据 +func (cl *ListOperation) LPush(key string, value interface{}) *redis.IntCmd { + return cl.db.LPush(cl.ctx, key, value) +} + +// LPushX 跟LPush的区别是,仅当列表存在的时候才插入数据 +func (cl *ListOperation) LPushX(key string, value interface{}) *redis.IntCmd { + return cl.db.LPushX(cl.ctx, key, value) +} + +// RPop 从列表的右边删除第一个数据,并返回删除的数据 +func (cl *ListOperation) RPop(key string) *redis.StringCmd { + return cl.db.RPop(cl.ctx, key) +} + +// RPush 从列表右边插入数据 +func (cl *ListOperation) RPush(key string, value interface{}) *redis.IntCmd { + return cl.db.RPush(cl.ctx, key, value) +} + +// RPushX 跟RPush的区别是,仅当列表存在的时候才插入数据 +func (cl *ListOperation) RPushX(key string, value interface{}) *redis.IntCmd { + return cl.db.RPushX(cl.ctx, key, value) +} + +// LPop 从列表左边删除第一个数据,并返回删除的数据 +func (cl *ListOperation) LPop(key string) *redis.StringCmd { + return cl.db.LPop(cl.ctx, key) +} + +// Len 返回列表的大小 +func (cl *ListOperation) Len(key string) *redis.IntCmd { + return cl.db.LLen(cl.ctx, key) +} + +// Range 返回列表的一个范围内的数据,也可以返回全部数据 +func (cl *ListOperation) Range(key string, start, stop int64) *redis.StringSliceCmd { + return cl.db.LRange(cl.ctx, key, start, stop) +} + +// RangeAli 返回key全部数据 +func (cl *ListOperation) RangeAli(key string) *redis.StringSliceCmd { + return cl.db.LRange(cl.ctx, key, 0, -1) +} + +// Rem 删除key中的数据 +func (cl *ListOperation) Rem(key string, count int64, value interface{}) *redis.IntCmd { + return cl.db.LRem(cl.ctx, key, count, value) +} + +// Index 根据索引坐标,查询key中的数据 +func (cl *ListOperation) Index(key string, index int64) *redis.StringCmd { + return cl.db.LIndex(cl.ctx, key, index) +} + +// Insert 在指定位置插入数据 +func (cl *ListOperation) Insert(key, op string, pivot, value interface{}) *redis.IntCmd { + return cl.db.LInsert(cl.ctx, key, op, pivot, value) +} diff --git a/redis_operation_attr.go b/redis_operation_attr.go new file mode 100644 index 0000000..0aaf09f --- /dev/null +++ b/redis_operation_attr.go @@ -0,0 +1,35 @@ +package dorm + +import "time" + +type empty struct{} + +const ( + AttrExpr = "expr" // 过期时间 + AttrNx = "nx" // 设置Nx +) + +type OperationAttr struct { + Name string + Value interface{} +} + +type OperationAttrs []*OperationAttr + +func (a OperationAttrs) Find(name string) interface{} { + for _, attr := range a { + if attr.Name == name { + return attr.Value + } + } + return nil +} + +// WithExpire 过期时间 +func WithExpire(t time.Duration) *OperationAttr { + return &OperationAttr{Name: AttrExpr, Value: t} +} + +func WithNX() *OperationAttr { + return &OperationAttr{Name: AttrNx, Value: empty{}} +} diff --git a/redis_simple_cache.go b/redis_simple_cache.go new file mode 100644 index 0000000..667d26f --- /dev/null +++ b/redis_simple_cache.go @@ -0,0 +1,61 @@ +package dorm + +import ( + "encoding/json" + "time" +) + +const ( + SerializerJson = "json" + SerializerString = "string" +) + +type JsonGttFunc func() interface{} + +type DBGttFunc func() string + +// SimpleCache 缓存 +type SimpleCache struct { + Operation *StringOperation // 操作类 + Expire time.Duration // 过去时间 + DBGetter DBGttFunc // 缓存不存在的操作 DB + JsonGetter JsonGttFunc // 缓存不存在的操作 JSON + Serializer string // 序列化方式 +} + +// NewSimpleCache 构造函数 +func (c *RedisClient) NewSimpleCache(operation *StringOperation, expire time.Duration, serializer string) *SimpleCache { + return &SimpleCache{ + Operation: operation, // 操作类 + Expire: expire, // 过去时间 + Serializer: serializer, // 缓存不存在的操作 DB + } +} + +// SetCache 设置缓存 +func (c *SimpleCache) SetCache(key string, value interface{}) { + c.Operation.Set(key, value, WithExpire(c.Expire)).Unwrap() +} + +// GetCache 获取缓存 +func (c *SimpleCache) GetCache(key string) (ret interface{}) { + if c.Serializer == SerializerJson { + f := func() string { + obj := c.JsonGetter() + b, err := json.Marshal(obj) + if err != nil { + return "" + } + return string(b) + } + ret = c.Operation.Get(key).UnwrapOrElse(f) + c.SetCache(key, ret) + } else if c.Serializer == SerializerString { + f := func() string { + return c.DBGetter() + } + ret = c.Operation.Get(key).UnwrapOrElse(f) + c.SetCache(key, ret) + } + return +} diff --git a/redis_simple_interface_cache.go b/redis_simple_interface_cache.go new file mode 100644 index 0000000..3a4fba1 --- /dev/null +++ b/redis_simple_interface_cache.go @@ -0,0 +1,39 @@ +package dorm + +import ( + "log" + "time" +) + +type DBGttInterfaceFunc func() interface{} + +// SimpleInterfaceCache 缓存 +type SimpleInterfaceCache struct { + Operation *SimpleOperation // 操作类 + Expire time.Duration // 过期时间 + DBGetter DBGttInterfaceFunc // 缓存不存在的操作 DB +} + +// NewSimpleInterfaceCache 构造函数 +func (c *RedisClient) NewSimpleInterfaceCache(operation *SimpleOperation, expire time.Duration) *SimpleInterfaceCache { + return &SimpleInterfaceCache{ + Operation: operation, // 操作类 + Expire: expire, // 过期时间 + } +} + +// SetCache 设置缓存 +func (c *SimpleInterfaceCache) SetCache(key string, value interface{}) { + c.Operation.Set(key, value, WithExpire(c.Expire)).Unwrap() +} + +// GetCache 获取缓存 +func (c *SimpleInterfaceCache) GetCache(key string) (ret interface{}) { + f := func() interface{} { + return c.DBGetter() + } + ret = c.Operation.Get(key).UnwrapOrElse(f) + c.SetCache(key, ret) + log.Println(ret) + return ret +} diff --git a/redis_simple_json_cache.go b/redis_simple_json_cache.go new file mode 100644 index 0000000..ddbdf71 --- /dev/null +++ b/redis_simple_json_cache.go @@ -0,0 +1,43 @@ +package dorm + +import ( + "encoding/json" + "time" +) + +type DBGttJsonFunc func() interface{} + +// SimpleJsonCache 缓存 +type SimpleJsonCache struct { + Operation *StringOperation // 操作类 + Expire time.Duration // 过期时间 + DBGetter DBGttJsonFunc // 缓存不存在的操作 DB +} + +// NewSimpleJsonCache 构造函数 +func (c *RedisClient) NewSimpleJsonCache(operation *StringOperation, expire time.Duration) *SimpleJsonCache { + return &SimpleJsonCache{ + Operation: operation, // 操作类 + Expire: expire, // 过期时间 + } +} + +// SetCache 设置缓存 +func (c *SimpleJsonCache) SetCache(key string, value interface{}) { + c.Operation.Set(key, value, WithExpire(c.Expire)).Unwrap() +} + +// GetCache 获取缓存 +func (c *SimpleJsonCache) GetCache(key string) (ret interface{}) { + f := func() string { + obj := c.DBGetter() + b, err := json.Marshal(obj) + if err != nil { + return "" + } + return string(b) + } + ret = c.Operation.Get(key).UnwrapOrElse(f) + c.SetCache(key, ret) + return +} diff --git a/redis_simple_operation.go b/redis_simple_operation.go new file mode 100644 index 0000000..3496d84 --- /dev/null +++ b/redis_simple_operation.go @@ -0,0 +1,38 @@ +package dorm + +import ( + "context" + "github.com/go-redis/redis/v8" + "time" +) + +type SimpleOperation struct { + db *redis.Client + ctx context.Context +} + +func (c *RedisClient) NewSimpleOperation() *SimpleOperation { + return &SimpleOperation{ + db: c.Db, + ctx: context.Background(), + } +} + +// Set 设置 +func (o *SimpleOperation) Set(key string, value interface{}, attrs ...*OperationAttr) *SimpleResult { + exp := OperationAttrs(attrs).Find(AttrExpr) + if exp == nil { + exp = time.Second * 0 + } + return NewSimpleResult(o.db.Set(o.ctx, key, value, exp.(time.Duration)).Result()) +} + +// Get 获取单个 +func (o *SimpleOperation) Get(key string) *SimpleResult { + return NewSimpleResult(o.db.Get(o.ctx, key).Result()) +} + +// Del 删除key操作,支持批量删除 +func (o *SimpleOperation) Del(keys ...string) *redis.IntCmd { + return o.db.Del(o.ctx, keys...) +} diff --git a/redis_simple_result.go b/redis_simple_result.go new file mode 100644 index 0000000..f9468ff --- /dev/null +++ b/redis_simple_result.go @@ -0,0 +1,35 @@ +package dorm + +type SimpleResult struct { + Result interface{} + Err error +} + +// NewSimpleResult 构造函数 +func NewSimpleResult(result interface{}, err error) *SimpleResult { + return &SimpleResult{Result: result, Err: err} +} + +// Unwrap 空值情况下返回错误 +func (r *SimpleResult) Unwrap() interface{} { + if r.Err != nil { + panic(r.Err) + } + return r.Result +} + +// UnwrapOr 空值情况下设置返回默认值 +func (r *SimpleResult) UnwrapOr(defaults interface{}) interface{} { + if r.Err != nil { + return defaults + } + return r.Result +} + +// UnwrapOrElse 空值情况下设置返回其他 +func (r *SimpleResult) UnwrapOrElse(f func() interface{}) interface{} { + if r.Err != nil { + return f() + } + return r.Result +} diff --git a/redis_simple_sring_cache.go b/redis_simple_sring_cache.go new file mode 100644 index 0000000..2889d03 --- /dev/null +++ b/redis_simple_sring_cache.go @@ -0,0 +1,37 @@ +package dorm + +import ( + "time" +) + +type DBGttStringFunc func() string + +// SimpleStringCache 缓存 +type SimpleStringCache struct { + Operation *StringOperation // 操作类 + Expire time.Duration // 过期时间 + DBGetter DBGttStringFunc // 缓存不存在的操作 DB +} + +// NewSimpleStringCache 构造函数 +func (c *RedisClient) NewSimpleStringCache(operation *StringOperation, expire time.Duration) *SimpleStringCache { + return &SimpleStringCache{ + Operation: operation, // 操作类 + Expire: expire, // 过期时间 + } +} + +// SetCache 设置缓存 +func (c *SimpleStringCache) SetCache(key string, value string) { + c.Operation.Set(key, value, WithExpire(c.Expire)).Unwrap() +} + +// GetCache 获取缓存 +func (c *SimpleStringCache) GetCache(key string) (ret string) { + f := func() string { + return c.DBGetter() + } + ret = c.Operation.Get(key).UnwrapOrElse(f) + c.SetCache(key, ret) + return +} diff --git a/redis_slice_result.go b/redis_slice_result.go new file mode 100644 index 0000000..7afec27 --- /dev/null +++ b/redis_slice_result.go @@ -0,0 +1,31 @@ +package dorm + +type SliceResult struct { + Result []interface{} + Err error +} + +// NewSliceResult 构造函数 +func NewSliceResult(result []interface{}, err error) *SliceResult { + return &SliceResult{Result: result, Err: err} +} + +// Unwrap 空值情况下返回错误 +func (r *SliceResult) Unwrap() []interface{} { + if r.Err != nil { + panic(r.Err) + } + return r.Result +} + +// UnwrapOr 空值情况下设置返回默认值 +func (r *SliceResult) UnwrapOr(defaults []interface{}) []interface{} { + if r.Err != nil { + return defaults + } + return r.Result +} + +func (r *SliceResult) Iter() *Iterator { + return NewIterator(r.Result) +} diff --git a/redis_string_operation.go b/redis_string_operation.go new file mode 100644 index 0000000..439f5e5 --- /dev/null +++ b/redis_string_operation.go @@ -0,0 +1,43 @@ +package dorm + +import ( + "context" + "github.com/go-redis/redis/v8" + "time" +) + +type StringOperation struct { + db *redis.Client + ctx context.Context +} + +func (c *RedisClient) NewStringOperation() *StringOperation { + return &StringOperation{ + db: c.Db, + ctx: context.Background(), + } +} + +// Set 设置 +func (o *StringOperation) Set(key string, value interface{}, attrs ...*OperationAttr) *StringResult { + exp := OperationAttrs(attrs).Find(AttrExpr) + if exp == nil { + exp = time.Second * 0 + } + return NewStringResult(o.db.Set(o.ctx, key, value, exp.(time.Duration)).Result()) +} + +// Get 获取单个 +func (o *StringOperation) Get(key string) *StringResult { + return NewStringResult(o.db.Get(o.ctx, key).Result()) +} + +// MGet 获取多个 +func (o *StringOperation) MGet(keys ...string) *SliceResult { + return NewSliceResult(o.db.MGet(o.ctx, keys...).Result()) +} + +// Del 删除key操作,支持批量删除 +func (o *StringOperation) Del(keys ...string) *redis.IntCmd { + return o.db.Del(o.ctx, keys...) +} diff --git a/redis_string_result.go b/redis_string_result.go new file mode 100644 index 0000000..98c7b70 --- /dev/null +++ b/redis_string_result.go @@ -0,0 +1,38 @@ +package dorm + +type StringResult struct { + Result string // 结果 + Err error // 错误 +} + +// NewStringResult 构造函数 +func NewStringResult(result string, err error) *StringResult { + return &StringResult{ + Result: result, + Err: err, + } +} + +// Unwrap 空值情况下返回错误 +func (r *StringResult) Unwrap() string { + if r.Err != nil { + panic(r.Err) + } + return r.Result +} + +// UnwrapOr 空值情况下设置返回默认值 +func (r *StringResult) UnwrapOr(defaults string) string { + if r.Err != nil { + return defaults + } + return r.Result +} + +// UnwrapOrElse 空值情况下设置返回其他 +func (r *StringResult) UnwrapOrElse(f func() string) string { + if r.Err != nil { + return f() + } + return r.Result +}