2024-05-22 10:54:25 +08:00

183 lines
4.1 KiB
Go

package listdemo
import (
"context"
"github.com/openimsdk/tools/db/mongoutil"
"github.com/openimsdk/tools/db/pagination"
"github.com/pkg/errors"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var (
ErrListNotFound = errors.New("list not found")
ErrElemExist = errors.New("elem exist")
ErrNotFound = mongo.ErrNoDocuments
)
type ListDoc interface {
IDName() string // 外层业务id字段名字 user_id
ElemsName() string // 外层列表名字 friends
VersionName() string // 外层版本号 version
DeleteVersion() string // 删除版本号
BuildDoc(lid any, e Elem) any // 返回一个组装的doc文档
}
type Elem interface {
IDName() string // 业务id名字 friend_user_id
IDValue() any // 业务id值 userID -> "100000000"
VersionName() string // 版本号
DeletedName() string // 删除字段名字
ToMap() map[string]any // 把结构体转换为map
}
type List[D any, E Elem] struct {
coll *mongo.Collection
lf ListDoc
}
func (l *List[D, E]) zeroE() E {
var t E
return t
}
func (l *List[D, E]) FindElem(ctx context.Context, lid any, eid any) (E, error) {
res, err := l.FindElems(ctx, lid, []any{eid})
if err != nil {
return l.zeroE(), err
}
if len(res) == 0 {
return l.zeroE(), ErrNotFound
}
return res[0], nil
}
// FindElems 查询Elems
func (l *List[D, E]) FindElems(ctx context.Context, lid any, eids []any) ([]E, error) {
//pipeline := []bson.M{
// {
// "$match": bson.M{
// l.lf.IDName(): lid,
// l.lf.IDName() + "." + l.lf.ElemsID(): bson.M{
// "$in": eids,
// },
// },
// },
// {
// "$unwind": "$" + l.lf.ElemsName(),
// },
// {
// "$match": bson.M{
// l.lf.IDName() + "." + l.lf.ElemsID(): bson.M{
// "$in": eids,
// },
// },
// },
//}
panic("todo")
}
func (l *List[D, E]) Find(ctx context.Context, filter any, opts ...*options.FindOptions) ([]E, error) {
return nil, nil
}
func (l *List[D, E]) Count(ctx context.Context, filter any, opts ...*options.CountOptions) (int64, error) {
return 0, nil
}
func (l *List[D, E]) Update(ctx context.Context, lid any, eid any) (*mongo.UpdateResult, error) {
return nil, nil
}
func (l *List[D, E]) Delete(ctx context.Context, lid any, eids any) (*mongo.UpdateResult, error) {
return nil, nil
}
func (l *List[D, E]) Page(ctx context.Context, filter any, pagination pagination.Pagination, opts ...*options.FindOptions) (int64, []E, error) {
return 0, nil, nil
}
func (l *List[D, E]) ElemIDs(ctx context.Context, filter any, opts ...*options.FindOptions) ([]E, error) {
return nil, nil
}
// InsertElem 插入一个
func (l *List[D, E]) InsertElem(ctx context.Context, lid any, e Elem) error {
if err := l.insertElem(ctx, lid, e); err == nil {
return nil
} else if !errors.Is(err, ErrListNotFound) {
return err
}
if _, err := l.coll.InsertOne(ctx, l.lf.BuildDoc(lid, e)); err == nil {
return nil
} else if mongo.IsDuplicateKeyError(err) {
return l.insertElem(ctx, lid, e)
} else {
return err
}
}
func (l *List[D, E]) insertElem(ctx context.Context, lid any, e Elem) error {
data := e.ToMap()
data[e.VersionName()] = "$max_version"
filter := bson.M{
l.lf.IDName(): lid,
}
pipeline := []bson.M{
{
"$addFields": bson.M{
"found_elem": bson.M{
"$in": bson.A{e.IDValue(), l.lf.ElemsName() + "." + e.IDName()},
},
},
},
{
"$set": bson.M{
"max_version": bson.M{
"$cond": bson.M{
"if": "$found_elem",
"then": "$max_version",
"else": bson.M{"$add": bson.A{"max_version", 1}},
},
},
},
},
{
"$set": bson.M{
l.lf.ElemsName(): bson.M{
"$cond": bson.M{
"if": "$found_elem",
"then": "$" + l.lf.ElemsName(),
"else": bson.M{
"$concatArrays": bson.A{
"$" + l.lf.ElemsName(),
bson.A{
data,
},
},
},
},
},
},
},
{
"$unset": "found_elem",
},
}
res, err := mongoutil.UpdateMany(ctx, l.coll, filter, pipeline)
if err != nil {
return err
}
if res.MatchedCount == 0 {
return ErrListNotFound
}
if res.ModifiedCount == 0 {
return ErrElemExist
}
return nil
}