package driver import ( "context" "errors" "local/dndex/storage/entity" "sync" "go.mongodb.org/mongo-driver/bson" ) type Map struct { db map[string]map[string][]byte lock sync.RWMutex } func NewMap() *Map { return &Map{ db: make(map[string]map[string][]byte), lock: sync.RWMutex{}, } } func (mp *Map) Count(ctx context.Context, namespace string, filter interface{}) (int, error) { ch, err := mp.Find(ctx, namespace, filter) if err != nil { return 0, err } n := 0 for _ = range ch { n++ } return n, nil } func (mp *Map) Find(_ context.Context, namespace string, filter interface{}) (chan bson.Raw, error) { mp.lock.RLock() defer mp.lock.RUnlock() b, err := bson.Marshal(filter) if err != nil { return nil, err } m := bson.M{} if err := bson.Unmarshal(b, &m); err != nil { return nil, err } results := make([]bson.Raw, 0) for _, v := range mp.db[namespace] { n := bson.M{} if err := bson.Unmarshal(v, &n); err != nil { return nil, err } if matches(n, m) { results = append(results, bson.Raw(v)) } } ch := make(chan bson.Raw) go func() { defer close(ch) for i := range results { ch <- results[i] } }() return ch, err } func (mp *Map) Update(_ context.Context, namespace string, filter, operator interface{}) error { mp.lock.Lock() defer mp.lock.Unlock() b, err := bson.Marshal(filter) if err != nil { return err } m := bson.M{} if err := bson.Unmarshal(b, &m); err != nil { return err } for k, v := range mp.db[namespace] { n := bson.M{} if err := bson.Unmarshal(v, &n); err != nil { return err } if matches(n, m) { n, err := apply(n, operator) if err != nil { return err } v, err := bson.Marshal(n) if err != nil { return err } mp.db[namespace][k] = v } } return nil } func (mp *Map) Insert(_ context.Context, namespace string, doc interface{}) error { mp.lock.Lock() defer mp.lock.Unlock() b, err := bson.Marshal(doc) if err != nil { return err } m := bson.M{} if err := bson.Unmarshal(b, &m); err != nil { return err } if _, ok := m[entity.ID]; !ok { return errors.New("primary key required to insert: did not find " + entity.ID) } else if _, ok := m[entity.ID].(string); !ok { return errors.New("primary key must be a string") } if _, ok := mp.db[namespace][m[entity.ID].(string)]; ok { return errors.New("cannot insert: collision on primary key") } if _, ok := mp.db[namespace]; !ok { mp.db[namespace] = make(map[string][]byte) } mp.db[namespace][m[entity.ID].(string)] = b return nil } func (mp *Map) Delete(_ context.Context, namespace string, filter interface{}) error { mp.lock.Lock() defer mp.lock.Unlock() b, err := bson.Marshal(filter) if err != nil { return err } m := bson.M{} if err := bson.Unmarshal(b, &m); err != nil { return err } for k, v := range mp.db[namespace] { n := bson.M{} if err := bson.Unmarshal(v, &n); err != nil { return err } if matches(n, m) { delete(mp.db[namespace], k) } } return nil }