New API tested
This commit is contained in:
@@ -316,7 +316,29 @@ func applySet(doc, operator bson.M) (bson.M, error) {
|
||||
if k == entity.Name {
|
||||
return nil, errModifiedReserved
|
||||
}
|
||||
doc[k] = v
|
||||
nesting := strings.Split(k, ".")
|
||||
if len(nesting) > 1 {
|
||||
mInterface, ok := doc[nesting[0]]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("path does not exist: %s (%s): %+v", k, nesting[0], doc)
|
||||
}
|
||||
m, ok := mInterface.(map[string]interface{})
|
||||
if !ok {
|
||||
pm, pmok := mInterface.(primitive.M)
|
||||
m = map[string]interface{}(pm)
|
||||
ok = pmok
|
||||
}
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("subpath cannot be followed for non object: %s (%s): %+v (%T)", k, nesting[0], mInterface, mInterface)
|
||||
}
|
||||
subdoc, err := applySet(bson.M(m), bson.M{strings.Join(nesting[1:], "."): v})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
doc[nesting[0]] = subdoc
|
||||
} else {
|
||||
doc[k] = v
|
||||
}
|
||||
}
|
||||
return doc, nil
|
||||
}
|
||||
|
||||
@@ -396,3 +396,50 @@ func fillBoltDB(t *testing.T, bdb *BoltDB) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplySet(t *testing.T) {
|
||||
cases := map[string]struct {
|
||||
doc bson.M
|
||||
operator bson.M
|
||||
want bson.M
|
||||
}{
|
||||
"noop on empty": {},
|
||||
"noop on full": {
|
||||
doc: bson.M{"hello": "world"},
|
||||
want: bson.M{"hello": "world"},
|
||||
},
|
||||
"add new field on full": {
|
||||
operator: bson.M{"hi": "mom"},
|
||||
doc: bson.M{"hello": "world"},
|
||||
want: bson.M{"hello": "world", "hi": "mom"},
|
||||
},
|
||||
"change only field on full": {
|
||||
operator: bson.M{"hello": "lol jk not world"},
|
||||
doc: bson.M{"hello": "world"},
|
||||
want: bson.M{"hello": "lol jk not world"},
|
||||
},
|
||||
"set existing, nested field": {
|
||||
operator: bson.M{"hello.world": "hi"},
|
||||
doc: bson.M{"hello": bson.M{"world": "not hi"}},
|
||||
want: bson.M{"hello": bson.M{"world": "hi"}},
|
||||
},
|
||||
"add to existing, nested field": {
|
||||
operator: bson.M{"hello.notworld": "hi"},
|
||||
doc: bson.M{"hello": bson.M{"world": "not hi"}},
|
||||
want: bson.M{"hello": bson.M{"world": "not hi", "notworld": "hi"}},
|
||||
},
|
||||
}
|
||||
|
||||
for name, d := range cases {
|
||||
c := d
|
||||
t.Run(name, func(t *testing.T) {
|
||||
out, err := applySet(c.doc, c.operator)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if fmt.Sprint(out) != fmt.Sprint(c.want) {
|
||||
t.Fatalf("(%+v, %+v) => want \n%+v\n, got \n%+v", c.doc, c.operator, c.want, out)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,14 @@ func (pi PopIf) MarshalBSON() ([]byte, error) {
|
||||
return opMarshal("$pull", pi.Key, pi.Filter)
|
||||
}
|
||||
|
||||
type SetMany struct {
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
func (s SetMany) MarshalBSON() ([]byte, error) {
|
||||
return opMarshal("$set", "", s.Value)
|
||||
}
|
||||
|
||||
type Set struct {
|
||||
Key string
|
||||
Value interface{}
|
||||
@@ -49,20 +57,28 @@ func opMarshal(op, key string, value interface{}) ([]byte, error) {
|
||||
return bson.Marshal(marshalable)
|
||||
}
|
||||
|
||||
func opMarshalable(op, key string, value interface{}) map[string]map[string]interface{} {
|
||||
if len(key) == 0 {
|
||||
func opMarshalable(op, key string, value interface{}) map[string]interface{} {
|
||||
if len(key) == 0 && value == nil {
|
||||
return nil
|
||||
}
|
||||
m := map[string]map[string]interface{}{
|
||||
m := map[string]interface{}{
|
||||
op: map[string]interface{}{
|
||||
key: value,
|
||||
},
|
||||
}
|
||||
if len(key) == 0 {
|
||||
m[op] = value
|
||||
}
|
||||
if _, ok := m["$set"]; !ok {
|
||||
m["$set"] = map[string]interface{}{}
|
||||
}
|
||||
if _, ok := m["$set"][entity.Modified]; !ok {
|
||||
m["$set"][entity.Modified] = time.Now().UnixNano()
|
||||
switch m["$set"].(type) {
|
||||
case map[string]interface{}:
|
||||
m["$set"].(map[string]interface{})[entity.Modified] = time.Now().UnixNano()
|
||||
case bson.M:
|
||||
m["$set"].(bson.M)[entity.Modified] = time.Now().UnixNano()
|
||||
//case primitive.M:
|
||||
//m["$set"].(primitive.M)[entity.Modified] = time.Now().UnixNano()
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user