Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions pkg/mongoproxy/plugins/schema/example.json
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,24 @@
},
"enforceSchema": true
},
"requireonlyarray": {
"denyUnknownFields": false,
"fields": {
"a": {
"required": true,
"type": "string"
},
"b": {
"required": false,
"type": "[]object"
},
"c": {
"required": false,
"type": "object"
}
},
"enforceSchema": true
},
"requireonlysuba": {
"denyUnknownFields": true,
"fields": {
Expand All @@ -240,6 +258,64 @@
},
"enforceSchema": true
},
"requireonlysubddnosub": {
"denyUnknownFields": false,
"fields": {
"doc": {
"required": true,
"type": "object"
}
},
"enforceSchema": true
},
"requireonlysubddwithsub": {
"denyUnknownFields": false,
"fields": {
"doc": {
"required": true,
"subfields": {
"a": {
"required": true,
"type": "object"
}
},
"type": "object"
}
},
"enforceSchema": true
},
"requireonlysubddwithsubdeny": {
"denyUnknownFields": true,
"fields": {
"doc": {
"required": true,
"subfields": {
"a": {
"required": true,
"type": "object"
}
},
"type": "object"
}
},
"enforceSchema": true
},
"requireonlysubddwithsubarr": {
"denyUnknownFields": false,
"fields": {
"doc": {
"required": true,
"subfields": {
"a": {
"required": true,
"type": "[]string"
}
},
"type": "object"
}
},
"enforceSchema": true
},
"requireonlysub": {
"denyUnknownFields": true,
"fields": {
Expand Down
20 changes: 20 additions & 0 deletions pkg/mongoproxy/plugins/schema/type_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ var (
{DB: "testdb", Collection: "testcollection", In: bson.D{{"$addToSet", bson.D{{"name", 1}}}}, Err: true},
// addToSet unknown field
{DB: "testdb", Collection: "testcollection", In: bson.D{{"$addToSet", bson.D{{"unknown", 1}}}}},
{DB: "testdb", Collection: "requireonlyarray", In: bson.D{{"$addToSet", bson.D{{"a", "dsdes"}}}}},
// addToSet correct type
{DB: "testdb", Collection: "testcollection", In: bson.D{{"$addToSet", bson.D{{"name", "name"}}}}},

Expand Down Expand Up @@ -401,6 +402,21 @@ var (
{"$setOnInsert", bson.D{{"a", "a"}}},
}, Upsert: true},

{DB: "testdb", Collection: "requireonlysubddnosub", In: bson.D{
{"$set", bson.D{{"doc.a.123", 1}}},
}, Upsert: true},
{DB: "testdb", Collection: "requireonlysubddwithsub", In: bson.D{
{"$set", bson.D{{"doc.a.123", 1}}},
}, Upsert: true},
{DB: "testdb", Collection: "requireonlysubddwithsub", In: bson.D{
{"$set", bson.D{{"doc.a.123", 1}}},
}, Upsert: false},
{DB: "testdb", Collection: "requireonlysubddwithsubdeny", In: bson.D{
{"$set", bson.D{{"doc.a.123", 1}}},
}, Upsert: true, Err: true},
{DB: "testdb", Collection: "requireonlysubddwithsubarr", In: bson.D{
{"$set", bson.D{{"doc.a.123", "test"}}},
}, Upsert: true},
// incorrect type
{DB: "testdb", Collection: "requireonlya", In: bson.D{
{"$set", bson.D{{"a", 1}}},
Expand Down Expand Up @@ -472,6 +488,10 @@ var (

// set correct type for array
{DB: "testdb", Collection: "testcollection", In: bson.D{{"$set", bson.D{{"friends.$", "linda"}}}}},
// test operator without $ sign
{DB: "testdb", Collection: "requireonlyarray", In: bson.D{{"a", bson.D{{"$eq", "a"}}}}},
{DB: "testdb", Collection: "requireonlyarray", In: bson.D{{"b", bson.D{{"$in", bson.A{bson.D{{"a", "b"}}}}}}}},
{DB: "testdb", Collection: "requireonlyarray", In: bson.D{{"c", bson.D{{"$nin", bson.D{{"a", "b"}}}}}}},
{DB: "testdb", Collection: "testcollection", In: bson.D{{"$set", bson.D{{"friends.0", "linda"}}}}},
{DB: "testdb", Collection: "testcollection", In: bson.D{{"$set", bson.D{{"friends", bson.A{"linda", "test"}}}}}},
{DB: "testdb", Collection: "testcollection", In: bson.D{{"$set", bson.D{{"friends.$[]", "linda"}}}}},
Expand Down
86 changes: 75 additions & 11 deletions pkg/mongoproxy/plugins/schema/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"reflect"
"strconv"
"strings"

"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -206,6 +207,11 @@ func (c *Collection) GetField(names ...string) *CollectionField {
if !ok {
return nil
}
vType := fmt.Sprint(v.Type)
if vType == "object" && v.SubFields == nil {
field = &v
break
}
field = &v
} else {
var (
Expand All @@ -216,6 +222,10 @@ func (c *Collection) GetField(names ...string) *CollectionField {
v, ok = field.remoteCollection.Fields[name]
} else {
v, ok = field.SubFields[name]
if _, err := strconv.ParseInt(name, 10, 64); err == nil {
ok = true
}
print("okokokok ,", ok)
}
if !ok {
logrus.Debugf("can not find field in collection: %s", name)
Expand Down Expand Up @@ -248,6 +258,7 @@ func (c *Collection) ValidateUpdate(ctx context.Context, obj bson.D, upsert bool
insertFields bson.M // Insert fields (if we have them) -- only for upserts
unsetFields bson.M // fields being unset
renameFields bson.M // fields being renamed
flag bool
)

if !c.EnforceSchema && !c.EnforceSchemaByCollectionLogOnly {
Expand All @@ -262,12 +273,32 @@ func (c *Collection) ValidateUpdate(ctx context.Context, obj bson.D, upsert bool
*/
if !strings.HasPrefix(obj[0].Key, "$") || !SetContain(OpMap, obj[0].Key) {
m := make(bson.M, len(obj))
if upsert {
insertFields = handleObj(obj, m)
logrus.Debugf("insertFields: %s", insertFields)
var findOp = []string{"$in", "$nin", "$eq", "$gt", "$gte", "$lt", "$lte", "$ne"}
interfaceType := fmt.Sprint(reflect.TypeOf(obj[0].Value))
if string(interfaceType) == "primitive.D" {
curObj := obj[0].Value.(primitive.D)
curMap := curObj.Map()
for _, s := range findOp {
if _, ok := curMap[s]; ok {
newObj := bson.D{{obj[0].Key, curMap[s]}}
if upsert {
insertFields = handleObj(newObj, m)
logrus.Debugf("insertFields: %s", insertFields)
} else {
setFields = handleObj(newObj, m)
logrus.Debugf("setFields: %s", setFields)
}
}
}
} else {
setFields = handleObj(obj, m)
logrus.Debugf("setFields: %s", setFields)
if upsert {
insertFields = handleObj(obj, m)
logrus.Debugf("insertFields: %s", insertFields)
} else {
setFields = handleObj(obj, m)
fmt.Println(obj)
logrus.Debugf("setFields: %s", setFields)
}
}
} else {
for _, e := range obj {
Expand Down Expand Up @@ -359,8 +390,39 @@ func (c *Collection) ValidateUpdate(ctx context.Context, obj bson.D, upsert bool
return fmt.Errorf("cannot set a required field with nil value: %f", v)
}
if f != nil && v != nil {
if err := f.Validate(ctx, v, c.DenyUnknownFields, true); err != nil {
return err
fString := fmt.Sprint(c.GetField(strings.Split(k, ".")[0]).Type)
if fString == "object" {
if c.GetField(strings.Split(k, ".")[0]).SubFields == nil {
flag = true
continue
} else {
for _, e := range obj {
newObj := e.Value.(bson.D)
for _, i := range newObj {
newKey := i.Key
newVal := i.Value
fObj := c.GetField(strings.Split(newKey, ".")...)
fObjStr := strings.Trim(fmt.Sprint(fObj), "&{")
fObjStr = strings.TrimSpace(fObjStr)
if fObj == nil || strings.HasPrefix(fObjStr, "<nil>") {
if !c.DenyUnknownFields {
flag = true
continue
} else {
logrus.Errorf("Can't set value for unknonw field %s", newKey)
break
}
}
if err := fObj.Validate(ctx, newVal, c.DenyUnknownFields, true); err != nil {
return err
}
}
}
}
} else {
if err := f.Validate(ctx, v, c.DenyUnknownFields, true); err != nil {
return err
}
}
}
}
Expand All @@ -369,12 +431,14 @@ func (c *Collection) ValidateUpdate(ctx context.Context, obj bson.D, upsert bool
if upsert {
doc := make(bson.M, len(setFields)+len(insertFields))
logrus.Debugf("upsert doc built")
for k, v := range setFields {
if err := SetValue(doc, strings.Split(k, "."), v); err != nil {
return err
if !flag {
for k, v := range setFields {
if err := SetValue(doc, strings.Split(k, "."), v); err != nil {
return err
}
}
logrus.Debugf("finished setField setValue")
}
logrus.Debugf("finished setField setValue")

for k, v := range insertFields {
if err := SetValue(doc, strings.Split(k, "."), v); err != nil {
Expand Down