| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239 | 
							- package svc
 
- import (
 
- 	"context"
 
- 	"errors"
 
- 	"fmt"
 
- 	"golib/features/mo"
 
- 	"golib/infra/ii"
 
- 	"golib/log/logs"
 
- )
 
- var (
 
- 	ErrItemNotfound = func(name string) error {
 
- 		return fmt.Errorf("item notfound: %s", name)
 
- 	}
 
- 	ErrInternalError = errors.New("internal error")
 
- 	ErrDataError     = errors.New("data error")
 
- )
 
- type Permission interface {
 
- 	Have() bool
 
- 	User() ii.User
 
- }
 
- type Service struct {
 
- 	Items  ii.Items
 
- 	Client *mo.Client
 
- 	Logs   *logs.Logs
 
- }
 
- func (s *Service) Find(name string, filter any) ([]mo.M, error) {
 
- 	itemInfo, ok := s.Items.Has(name)
 
- 	if !ok {
 
- 		s.Logs.Println("svc.Find: item notfound", name)
 
- 		return nil, ErrItemNotfound(name)
 
- 	}
 
- 	cursor, err := itemInfo.Open(s.Client).Find(filter)
 
- 	if err != nil {
 
- 		s.Logs.Println("svc.Find: %s -> itemName[%s], filter[%v]", err, name)
 
- 		return nil, ErrInternalError
 
- 	}
 
- 	var data []mo.M
 
- 	if err = cursor.All(context.Background(), &data); err != nil {
 
- 		s.Logs.Println("svc.Find: cursor.All: %s -> itemName[%s]", err, name)
 
- 		return nil, ErrInternalError
 
- 	}
 
- 	if err = itemInfo.Validate(data); err != nil {
 
- 		s.Logs.Println("svc.Find: Validate: %s -> itemName[%s]", err, name)
 
- 		return nil, ErrDataError
 
- 	}
 
- 	return data, nil
 
- }
 
- // FindOne 查询一个文档, 当查询成功但没有符合条件的结果时会返回 mo.ErrNoDocuments
 
- func (s *Service) FindOne(name string, filter any) (mo.M, error) {
 
- 	itemInfo, ok := s.Items.Has(name)
 
- 	if !ok {
 
- 		s.Logs.Println("svc.FindOne: item notfound", name)
 
- 		return nil, ErrItemNotfound(name)
 
- 	}
 
- 	result := itemInfo.Open(s.Client).FindOne(filter)
 
- 	if err := result.Err(); err != nil {
 
- 		s.Logs.Println("svc.FindOne: %s -> itemName[%s]", err, name)
 
- 		return nil, err
 
- 	}
 
- 	var data mo.M
 
- 	if err := result.Decode(&data); err != nil {
 
- 		s.Logs.Println("svc.FindOne: Decode: %s -> itemName[%s]", err, name)
 
- 		return nil, ErrInternalError
 
- 	}
 
- 	return data, nil
 
- }
 
- // FindOneAndDelete 查找并删除文档
 
- // TODO 待定真删除还是假删除
 
- func (s *Service) FindOneAndDelete() {}
 
- // FindOneAndUpdate 查找并更新文档, 详情见 mo.SingleResult
 
- func (s *Service) FindOneAndUpdate(name string, filter, update any) error {
 
- 	itemInfo, ok := s.Items.Has(name)
 
- 	if !ok {
 
- 		s.Logs.Println("svc.FindOneAndUpdate: item notfound", name)
 
- 		return ErrItemNotfound(name)
 
- 	}
 
- 	if err := itemInfo.Validate(update); err != nil {
 
- 		s.Logs.Println("svc.FindOneAndUpdate: Validate: %s -> itemName[%s]", err, name)
 
- 		return ErrDataError
 
- 	}
 
- 	result := itemInfo.Open(s.Client).FindOneAndUpdate(filter, update)
 
- 	if err := result.Err(); err != nil {
 
- 		s.Logs.Println("svc.FindOneAndUpdate: %s -> itemName[%s]", err, name)
 
- 		return err
 
- 	}
 
- 	return result.Err()
 
- }
 
- // EstimatedDocumentCount 合计合集中的文档数量
 
- func (s *Service) EstimatedDocumentCount(name string) (int64, error) {
 
- 	itemInfo, ok := s.Items.Has(name)
 
- 	if !ok {
 
- 		s.Logs.Println("svc.EstimatedDocumentCount: item notfound", name)
 
- 		return 0, ErrItemNotfound(name)
 
- 	}
 
- 	result, err := itemInfo.Open(s.Client).EstimatedDocumentCount()
 
- 	if err != nil {
 
- 		s.Logs.Println("svc.EstimatedDocumentCount: %s -> itemName[%s]", err, name)
 
- 		return 0, ErrInternalError
 
- 	}
 
- 	return result, nil
 
- }
 
- // InsertOne 插入一条文档
 
- // MongoDB 在插入文档时对于 _id 的做法: 即 doc 中不存在 _id 字段时会在数据编码时补充 _id 字段并且值使用 mo.ObjectID 而不修改源文档.
 
- // 当 _id 字段存在时不会修改其数据类型. 但为了保持数据类型的统一性, 此处当 _id 存在时其必须为 mo.ObjectID 类型
 
- func (s *Service) InsertOne(name string, doc mo.M) (mo.ObjectID, error) {
 
- 	itemInfo, ok := s.Items.Has(name)
 
- 	if !ok {
 
- 		s.Logs.Println("svc.InsertOne: item notfound", name)
 
- 		return mo.NilObjectID, ErrItemNotfound(name)
 
- 	}
 
- 	if err := itemInfo.PrepareInsert(doc); err != nil {
 
- 		s.Logs.Println("svc.InsertOne: PrepareInsert: %s -> itemName[%s]", err, name)
 
- 		return mo.NilObjectID, ErrDataError
 
- 	}
 
- 	result, err := itemInfo.Open(s.Client).InsertOne(doc)
 
- 	if err != nil {
 
- 		s.Logs.Println("svc.InsertOne: %s -> itemName[%s]", err, name)
 
- 		return mo.NilObjectID, ErrInternalError
 
- 	}
 
- 	return result.InsertedID.(mo.ObjectID), nil
 
- }
 
- // InsertMany 插入多条文档
 
- // 对于 _id 的处理参见 InsertOne
 
- // MongoDB 插入多条文档时并不要求列表内所有元素的数据类型一致, 但为了保持数据类型的统一性, docs 内的所有元素数据类型必须为 map[string]interface{}
 
- func (s *Service) InsertMany(name string, docs []any) ([]mo.ObjectID, error) {
 
- 	itemInfo, ok := s.Items.Has(name)
 
- 	if !ok {
 
- 		s.Logs.Println("svc.InsertMany: item notfound", name)
 
- 		return nil, ErrItemNotfound(name)
 
- 	}
 
- 	for i, doc := range docs {
 
- 		var val map[string]interface{}
 
- 		val, ok = doc.(map[string]interface{})
 
- 		if !ok {
 
- 			s.Logs.Println("svc.InsertMany: all elements in the slice must be map[string]interface{}: idx[%d] %s", name, i, ValueType(doc))
 
- 			return nil, ErrDataError
 
- 		}
 
- 		if err := itemInfo.PrepareInsert(val); err != nil {
 
- 			s.Logs.Println("svc.InsertMany: PrepareInsert: %s -> itemName[%s]", err, name)
 
- 			return nil, ErrDataError
 
- 		}
 
- 		docs[i] = val
 
- 	}
 
- 	result, err := itemInfo.Open(s.Client).InsertMany(docs)
 
- 	if err != nil {
 
- 		s.Logs.Println("svc.InsertMany: %s -> itemName[%s]", err, name)
 
- 		return nil, ErrInternalError
 
- 	}
 
- 	ids := make([]mo.ObjectID, len(result.InsertedIDs))
 
- 	for i, id := range result.InsertedIDs {
 
- 		ids[i] = id.(mo.ObjectID)
 
- 	}
 
- 	return ids, nil
 
- }
 
- func (s *Service) UpdateOne(name string, filter any, update mo.M) error {
 
- 	itemInfo, ok := s.Items.Has(name)
 
- 	if !ok {
 
- 		s.Logs.Println("svc.UpdateOne: item notfound", name)
 
- 		return ErrItemNotfound(name)
 
- 	}
 
- 	if err := itemInfo.PrepareUpdate(update); err != nil {
 
- 		s.Logs.Println("svc.UpdateOne: PrepareUpdate: %s -> itemName[%s]", err, name)
 
- 		return ErrDataError
 
- 	}
 
- 	_, err := itemInfo.Open(s.Client).UpdateOne(filter, update)
 
- 	if err != nil {
 
- 		s.Logs.Println("svc.UpdateOne: %s -> itemName[%s]", err, name)
 
- 		return ErrInternalError
 
- 	}
 
- 	return nil
 
- }
 
- func (s *Service) UpdateByID(name string, id mo.ObjectID, update mo.M) error {
 
- 	itemInfo, ok := s.Items.Has(name)
 
- 	if !ok {
 
- 		s.Logs.Println("svc.UpdateByID: item notfound", name)
 
- 		return ErrItemNotfound(name)
 
- 	}
 
- 	if id.IsZero() {
 
- 		s.Logs.Println("svc.UpdateByID: id are zero", name)
 
- 		return ErrDataError
 
- 	}
 
- 	if err := itemInfo.PrepareUpdate(update); err != nil {
 
- 		s.Logs.Println("svc.UpdateByID: PrepareUpdate: %s -> itemName[%s]", err, name)
 
- 		return ErrDataError
 
- 	}
 
- 	_, err := itemInfo.Open(s.Client).UpdateByID(id, update)
 
- 	if err != nil {
 
- 		s.Logs.Println("svc.UpdateByID: %s -> itemName[%s]", err, name)
 
- 		return ErrInternalError
 
- 	}
 
- 	return nil
 
- }
 
- func (s *Service) UpdateMany(name string, filter any, update mo.M) error {
 
- 	itemInfo, ok := s.Items.Has(name)
 
- 	if !ok {
 
- 		s.Logs.Println("svc.UpdateMany: item notfound", name)
 
- 		return ErrItemNotfound(name)
 
- 	}
 
- 	if err := itemInfo.PrepareUpdate(update); err != nil {
 
- 		s.Logs.Println("svc.UpdateMany: PrepareUpdate: %s -> itemName[%s]", err, name)
 
- 		return ErrDataError
 
- 	}
 
- 	_, err := itemInfo.Open(s.Client).UpdateMany(filter, update)
 
- 	if err != nil {
 
- 		s.Logs.Println("svc.UpdateMany: %s -> itemName[%s]", err, name)
 
- 		return ErrInternalError
 
- 	}
 
- 	return nil
 
- }
 
 
  |