Update storage to new object format

This commit is contained in:
Bel LaPointe
2020-07-22 20:11:52 -06:00
parent 3b174e3d60
commit 4d667e7b11
11 changed files with 232 additions and 62 deletions

View File

@@ -0,0 +1,57 @@
package operator
import (
"fmt"
"go.mongodb.org/mongo-driver/bson"
)
type FilterIn struct {
Key string
Values []interface{}
}
func NewFilterIn(key string, values interface{}) FilterIn {
fi := FilterIn{Key: key}
switch values.(type) {
case []interface{}:
fi.Values = values.([]interface{})
if len(fi.Values) == 0 {
return NewFilterIn(key, nil)
}
case []string:
value := values.([]string)
fi.Values = make([]interface{}, len(value))
for i := range value {
fi.Values[i] = value[i]
}
if len(fi.Values) == 0 {
return NewFilterIn(key, nil)
}
case []int:
value := values.([]int)
fi.Values = make([]interface{}, len(value))
for i := range value {
fi.Values[i] = value[i]
}
if len(fi.Values) == 0 {
return NewFilterIn(key, nil)
}
case nil:
fi.Key = ""
default:
panic(fmt.Sprintf("cannot convert values to filter in: %T", values))
}
return fi
}
func (fi FilterIn) MarshalBSON() ([]byte, error) {
if len(fi.Key) == 0 {
return bson.Marshal(map[string]interface{}{})
}
return bson.Marshal(map[string]map[string][]interface{}{
fi.Key: map[string][]interface{}{
"$in": fi.Values,
},
})
}

View File

@@ -0,0 +1,40 @@
package operator
import (
"fmt"
"testing"
)
func TestFilterIn(t *testing.T) {
cases := map[string]struct {
input interface{}
output interface{}
}{
"[]int{5} => []interface{5}": {
input: []int{5},
output: []interface{}{5},
},
"[]string{} => nil": {
input: []string{},
output: []interface{}{},
},
"[]interface{}{} => nil": {
input: []interface{}{},
output: []interface{}{},
},
"[]interface{}{string} => []interface{string}": {
input: []interface{}{"hi"},
output: []interface{}{"hi"},
},
}
for name, d := range cases {
c := d
t.Run(name, func(t *testing.T) {
filterIn := fmt.Sprint(NewFilterIn("key", c.input).Values)
if want := fmt.Sprint(c.output); want != filterIn {
t.Error(want, filterIn)
}
})
}
}

View File

@@ -0,0 +1,59 @@
package operator
import (
"fmt"
"go.mongodb.org/mongo-driver/bson"
)
type Unset string
func (u Unset) MarshalBSON() ([]byte, error) {
return opMarshal("$unset", string(u), "")
}
type PopIf struct {
Key string
Filter interface{}
}
func (pi PopIf) MarshalBSON() ([]byte, error) {
return opMarshal("$pull", pi.Key, pi.Filter)
}
type Set struct {
Key string
Value interface{}
}
func (s Set) MarshalBSON() ([]byte, error) {
return opMarshal("$set", s.Key, s.Value)
}
type Push struct {
Key string
Value interface{}
}
func (p Push) MarshalBSON() ([]byte, error) {
return opMarshal("$push", p.Key, p.Value)
}
func opMarshal(op, key string, value interface{}) ([]byte, error) {
marshalable := opMarshalable(op, key, value)
if len(marshalable) == 0 {
return nil, fmt.Errorf("failed marshalling op")
}
return bson.Marshal(marshalable)
}
func opMarshalable(op, key string, value interface{}) map[string]map[string]interface{} {
if len(key) == 0 {
return nil
}
return map[string]map[string]interface{}{
op: map[string]interface{}{
key: value,
},
}
}

View File

@@ -0,0 +1,65 @@
package operator
import (
"encoding/json"
"fmt"
"testing"
"go.mongodb.org/mongo-driver/bson"
)
func TestModify(t *testing.T) {
cases := map[string]struct {
marshalme interface{}
key1 string
key2 string
want interface{}
}{
"unset": {
marshalme: Unset("field"),
key1: "field",
key2: "$unset",
want: nil,
},
"popif": {
marshalme: PopIf{Key: "field", Filter: "world"},
key1: "$pull",
key2: "field",
want: "world",
},
"popif map": {
marshalme: PopIf{Key: "field", Filter: map[string]string{"world": "jk"}},
key1: "$pull",
key2: "field",
want: map[string]string{"world": "jk"},
},
"set": {
marshalme: Set{Key: "field", Value: "value"},
key1: "$set",
key2: "field",
want: "value",
},
"push": {
marshalme: Push{Key: "field", Value: "value"},
key1: "$push",
key2: "field",
want: "value",
},
}
for name, d := range cases {
c := d
t.Run(name, func(t *testing.T) {
var v map[string]map[string]interface{}
if b, err := bson.Marshal(c.marshalme); err != nil {
t.Error(err)
} else if err := bson.Unmarshal(b, &v); err != nil {
t.Error(err)
} else if got := v[c.key1][c.key2]; fmt.Sprint(got) != fmt.Sprint(c.want) {
a, _ := json.Marshal(got)
b, _ := json.Marshal(v)
t.Errorf("want [%s][%s] = %v, got %s from %s", c.key1, c.key2, c.want, string(a), string(b))
}
})
}
}