go_dreamfactory/modules/comp_model.go
2022-06-28 15:43:02 +08:00

380 lines
11 KiB
Go

package modules
import (
"context"
"fmt"
"go_dreamfactory/comm"
"go_dreamfactory/lego/core"
"go_dreamfactory/lego/core/cbase"
"go_dreamfactory/lego/sys/log"
"go_dreamfactory/lego/sys/mgo"
"go_dreamfactory/lego/sys/redis"
"go_dreamfactory/sys/cache"
"go_dreamfactory/sys/db"
"reflect"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
)
/*
基础组件 缓存组件 读写缓存数据
DB组件也封装进来
*/
type MCompModel struct {
cbase.ModuleCompBase
Redis redis.ISys
DB mgo.ISys
TableName string //redis key前缀
}
const (
DB_ModelTable core.SqlTable = "model_log"
)
//组件初始化接口
func (this *MCompModel) Init(service core.IService, module core.IModule, comp core.IModuleComp, options core.IModuleOptions) (err error) {
this.ModuleCompBase.Init(service, module, comp, options)
this.Redis = cache.Redis()
this.DB = db.Mgo()
return
}
func (this *MCompModel) Start() (err error) {
err = this.ModuleCompBase.Start()
return
}
func (this *MCompModel) ukey(uid string) string {
return fmt.Sprintf("%s:%s", this.TableName, uid)
}
func (this *MCompModel) ukeylist(uid string, id string) string {
return fmt.Sprintf("%s:%s-%s", this.TableName, uid, id)
}
func (this *MCompModel) InsertModelLogs(table string, uID string, target interface{}) (err error) {
data := &comm.Autogenerated{
ID: primitive.NewObjectID().Hex(),
UID: uID,
Act: string(comm.LogHandleType_Insert),
}
data.D = append(data.D, table) // D[0]
data.D = append(data.D, target) // D[1]
_, err = this.DB.InsertOne(DB_ModelTable, data)
if err != nil {
log.Errorf("insert model db err %v", err)
}
return err
}
func (this *MCompModel) DeleteModelLogs(table string, uID string, where interface{}) (err error) {
data := &comm.Autogenerated{
ID: primitive.NewObjectID().Hex(),
UID: uID,
Act: string(comm.LogHandleType_Delete),
}
data.D = append(data.D, table) // D[0]
data.D = append(data.D, where) // D[1]
_, err = this.DB.InsertOne(DB_ModelTable, data)
if err != nil {
log.Errorf("insert model db err %v", err)
}
return err
}
func (this *MCompModel) UpdateModelLogs(table string, uID string, where bson.M, target interface{}) (err error) {
data := &comm.Autogenerated{
ID: primitive.NewObjectID().Hex(),
UID: uID,
Act: string(comm.LogHandleType_Update),
}
data.D = append(data.D, table) // D[0]
data.D = append(data.D, where) // D[1]
data.D = append(data.D, target) // D[2]
_, err = this.DB.InsertOne(DB_ModelTable, data)
if err != nil {
log.Errorf("insert model db err %v", err)
}
return err
}
//添加新的数据
func (this *MCompModel) Add(uid string, data interface{}, attrs ...*cache.OperationAttr) (err error) {
if err = this.Redis.HMSet(this.ukey(uid), data); err != nil {
return
}
if ret := cache.OperationAttrs(attrs).Find(cache.ATTR_EXPIRE).Unwrap_Or(nil); ret != nil {
this.Redis.Expire(this.ukey(uid), ret.(time.Duration))
}
if ret := cache.OperationAttrs(attrs).Find(cache.ATTR_MGOLOG).Unwrap_Or(nil); ret == nil {
err = this.InsertModelLogs(this.TableName, uid, data)
}
return
}
//添加新的数据到列表
func (this *MCompModel) AddList(uid string, id string, data interface{}, attrs ...*cache.OperationAttr) (err error) {
key := this.ukeylist(uid, id)
if err = this.Redis.HMSet(key, data); err != nil {
return
}
if err = this.Redis.HSet(this.ukey(uid), id, key); err != nil {
return
}
if ret := cache.OperationAttrs(attrs).Find(cache.ATTR_EXPIRE).Unwrap_Or(nil); ret != nil {
this.Redis.Expire(this.ukey(uid), ret.(time.Duration))
}
if ret := cache.OperationAttrs(attrs).Find(cache.ATTR_MGOLOG).Unwrap_Or(nil); ret == nil {
err = this.InsertModelLogs(this.TableName, uid, []interface{}{data})
}
return
}
//添加新的多个数据到列表 data map[string]type
func (this *MCompModel) AddLists(uid string, data interface{}, attrs ...*cache.OperationAttr) (err error) {
vof := reflect.ValueOf(data)
if !vof.IsValid() {
return fmt.Errorf("Model_Comp: AddLists(nil)")
}
if vof.Kind() != reflect.Map {
return fmt.Errorf("Model_Comp: AddLists(non-pointer %T)", data)
}
listskeys := make(map[string]string)
keys := vof.MapKeys()
lists := make([]interface{}, len(keys))
for i, k := range keys {
value := vof.MapIndex(k)
keydata := k.Interface().(string)
valuedata := value.Interface()
key := this.ukeylist(uid, keydata)
if err = this.Redis.HMSet(key, valuedata); err != nil {
return
}
listskeys[keydata] = key
lists[i] = valuedata
}
if err = this.Redis.HMSet(this.ukey(uid), listskeys); err != nil {
return
}
if ret := cache.OperationAttrs(attrs).Find(cache.ATTR_EXPIRE).Unwrap_Or(nil); ret != nil {
this.Redis.Expire(this.ukey(uid), ret.(time.Duration))
for _, v := range listskeys {
this.Redis.Expire(v, ret.(time.Duration))
}
}
if ret := cache.OperationAttrs(attrs).Find(cache.ATTR_MGOLOG).Unwrap_Or(nil); ret == nil {
err = this.InsertModelLogs(this.TableName, uid, lists)
}
return
}
//修改数据多个字段 uid 作为主键
func (this *MCompModel) Change(uid string, data map[string]interface{}, attrs ...*cache.OperationAttr) (err error) {
if err = this.Redis.HMSet(this.ukey(uid), data); err != nil {
return
}
if ret := cache.OperationAttrs(attrs).Find(cache.ATTR_EXPIRE).Unwrap_Or(nil); ret != nil {
this.Redis.Expire(this.ukey(uid), ret.(time.Duration))
}
if ret := cache.OperationAttrs(attrs).Find(cache.ATTR_MGOLOG).Unwrap_Or(nil); ret == nil {
err = this.UpdateModelLogs(this.TableName, uid, bson.M{"uid": uid}, data)
}
return nil
}
//修改数据多个字段 uid 作为主键
func (this *MCompModel) ChangeList(uid string, _id string, data map[string]interface{}, attrs ...*cache.OperationAttr) (err error) {
if err = this.Redis.HMSet(this.ukeylist(uid, _id), data); err != nil {
return
}
if ret := cache.OperationAttrs(attrs).Find(cache.ATTR_EXPIRE).Unwrap_Or(nil); ret != nil {
this.Redis.Expire(this.ukey(uid), ret.(time.Duration))
}
if ret := cache.OperationAttrs(attrs).Find(cache.ATTR_MGOLOG).Unwrap_Or(nil); ret == nil {
err = this.UpdateModelLogs(this.TableName, uid, bson.M{"_id": _id, "uid": uid}, data)
}
return nil
}
//读取全部数据
func (this *MCompModel) Get(uid string, data interface{}) (err error) {
if err = this.Redis.HGetAll(this.ukey(uid), data); err != nil {
return
}
if err == redis.RedisNil {
//query from mgo
if err = this.DB.FindOne(core.SqlTable(this.TableName), bson.M{"uid": uid}).Decode(data); err != nil {
return
}
err = this.Redis.HMSet(this.ukey(uid), data)
}
return
}
//获取列表数据 注意 data 必须啊转 切片的指针 *[]type
func (this *MCompModel) GetList(uid string, data interface{}) (err error) {
var keys map[string]string = make(map[string]string)
var c *mongo.Cursor
t := reflect.TypeOf(data)
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
if t.Kind() == reflect.Slice {
t = t.Elem()
} else {
err = fmt.Errorf("Input param is not a slice")
}
sl := reflect.ValueOf(data)
if t.Kind() == reflect.Ptr {
sl = sl.Elem()
}
st := sl.Type()
sliceType := st.Elem()
if sliceType.Kind() == reflect.Ptr {
sliceType = sliceType.Elem()
}
err = this.Redis.HGetAll(this.ukey(uid), keys)
if err == nil {
for _, v := range keys {
if sl.Len() < sl.Cap() {
sl.Set(sl.Slice(0, sl.Len()+1))
elem := sl.Index(sl.Len() - 1)
if elem.IsNil() {
elem.Set(reflect.New(sliceType))
}
if err = this.Redis.HGetAll(v, elem.Elem().Addr().Interface()); err != nil {
return
}
continue
}
elem := reflect.New(sliceType)
sl.Set(reflect.Append(sl, elem))
if err = this.Redis.HGetAll(v, elem.Elem().Addr().Interface()); err != nil {
return
}
}
}
if err == redis.RedisNil {
//query from mgo
if c, err = this.DB.Find(core.SqlTable(this.TableName), bson.M{"uid": uid}); err != nil {
return err
} else {
var temp map[string]interface{} = make(map[string]interface{})
var keys map[string]string = make(map[string]string)
for c.Next(context.Background()) {
_id := c.Current.Lookup("_id").StringValue()
if sl.Len() < sl.Cap() {
sl.Set(sl.Slice(0, sl.Len()+1))
elem := sl.Index(sl.Len() - 1)
if elem.IsNil() {
elem.Set(reflect.New(sliceType))
}
if err = c.Decode(elem.Elem().Addr().Interface()); err != nil {
return
}
temp[_id] = elem.Elem().Addr().Interface()
continue
}
elem := reflect.New(sliceType)
sl.Set(reflect.Append(sl, elem))
if err = c.Decode(elem.Elem().Addr().Interface()); err != nil {
return
}
temp[_id] = elem.Elem().Addr().Interface()
}
if len(temp) == 0 { //没有数据自己返回
return
}
for k, v := range temp {
key := this.ukeylist(uid, k)
if err = this.Redis.HMSet(key, v); err != nil {
return
}
keys[k] = key
}
if err = this.Redis.HMSet(this.ukey(uid), keys); err != nil {
return
}
}
}
return err
}
//读取单个数据中 多个字段数据
func (this *MCompModel) GetFields(uid string, data interface{}, fields ...string) (err error) {
this.Redis.HMGet(this.ukey(uid), data, fields...)
return
}
//读取List列表中单个数据中 多个字段数据
func (this *MCompModel) GetListFields(uid string, id string, data interface{}, fields ...string) (err error) {
this.Redis.HMGet(this.ukeylist(uid, id), data, fields...)
return
}
//读取列表数据中单个数据
func (this *MCompModel) GetListObj(uid string, id string, data interface{}) (err error) {
err = this.Redis.HGetAll(this.ukeylist(uid, id), data)
return
}
//删除用户数据
func (this *MCompModel) Del(uid string) (err error) {
err = this.Redis.Delete(this.ukey(uid))
if err != nil {
return err
}
err = this.DeleteModelLogs(this.TableName, uid, bson.M{"uid": uid})
return nil
}
//删除多条数据
func (this *MCompModel) DelListlds(uid string, ids ...string) (err error) {
listkey := this.ukey(uid)
for _, v := range ids {
key := this.ukeylist(uid, v)
if err = this.Redis.Delete(key); err != nil {
return
}
}
if err = this.Redis.HDel(listkey, ids...); err == nil {
err = this.DeleteModelLogs(this.TableName, uid, bson.M{"_id": bson.M{"$in": ids}})
}
return
}
//日志操作可选项
func (this *MCompModel) logOpt(uid string, data interface{}, attrs ...*cache.OperationAttr) error {
ret := cache.OperationAttrs(attrs).Find(cache.ATTR_MGOLOG).Unwrap_Or(nil)
if ret == nil { //启用mgolog
ir := cache.OperationAttrs(attrs).Find(cache.ATTR_INSERT).Unwrap_Or(nil)
if ir == nil { //updte opt
where := bson.M{"uid": uid}
if reflect.ValueOf(data).Kind() == reflect.Map {
if m, ok := data.(map[string]interface{}); ok {
where["_id"] = m["_id"]
} else {
return fmt.Errorf("have %v,but want map[string]interface{}", data)
}
}
return this.UpdateModelLogs(this.TableName, uid, where, data)
} else { //insert opt
return this.InsertModelLogs(this.TableName, uid, data)
}
}
return nil
}