mirror of
				https://github.com/openimsdk/open-im-server.git
				synced 2025-11-04 11:22:10 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			183 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			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
 | 
						|
}
 |