Skip to content

Commit

Permalink
Merge pull request #696 from mesg-foundation/feature/object-type-support
Browse files Browse the repository at this point in the history
Object type support
  • Loading branch information
antho1404 authored Jan 14, 2019
2 parents 5cd80b0 + ad4cbe5 commit 74269f2
Show file tree
Hide file tree
Showing 11 changed files with 209 additions and 156 deletions.
1 change: 1 addition & 0 deletions interface/grpc/core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ func toProtoParameters(params []*service.Parameter) []*coreapi.Parameter {
Type: param.Type,
Repeated: param.Repeated,
Optional: param.Optional,
Object: toProtoParameters(param.Object),
}
}
return ps
Expand Down
264 changes: 136 additions & 128 deletions protobuf/coreapi/api.pb.go

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion protobuf/coreapi/api.proto
Original file line number Diff line number Diff line change
Expand Up @@ -475,9 +475,10 @@ message Parameter {
string key = 8; // Parameter's key.
string name = 1; // Parameter's name.
string description = 2; // Parameter's description.
string type = 3; // Parameter's type: `String`, `Number`, `Boolean` or `Any`.
string type = 3; // Parameter's type: `String`, `Number`, `Boolean`, `Object` or `Any`.
bool optional = 4; // Set the parameter as optional.
bool repeated = 9; // Mark a parameter as an array of the defined type
repeated Parameter object = 10; // Optional object structure definition when type is set to `Object`
}

// A dependency is a configuration of an other Docker container that runs separately from the service.
Expand Down
2 changes: 1 addition & 1 deletion service/error_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func newParameterTestCases() parameterTests {
&parameterTest{Key: "keyString", Type: "String", Value: 2323, Error: "not a string"},
&parameterTest{Key: "keyNumber", Type: "Number", Value: "string", Error: "not a number"},
&parameterTest{Key: "keyBoolean", Type: "Boolean", Value: "dwdwd", Error: "not a boolean"},
&parameterTest{Key: "keyObject", Type: "Object", Value: 2323, Error: "not an object or array"},
&parameterTest{Key: "keyObject", Type: "Object", Value: 2323, Error: "not an object"},
&parameterTest{Key: "keyUnknown", Type: "Unknown", Value: "dwdw", Error: "an invalid type"},
&parameterTest{Key: "keyRequired", Type: "String", Value: nil, Error: "required"},
}
Expand Down
4 changes: 2 additions & 2 deletions service/importer/assets/schema.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions service/importer/assets/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@
"Any"
],
"default": "String"
},
"object": {
"$ref": "#/definitions/parameters"
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions service/importer/definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,7 @@ type Parameter struct {

// Repeated is to have an array of this parameter
Repeated bool `yaml:"repeated"`

// Definition of the structure of the object when the type is object
Object map[string]*Parameter `yaml:"object"`
}
1 change: 1 addition & 0 deletions service/inject_definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ func (s *Service) defParametersToService(params map[string]*importer.Parameter)
Type: param.Type,
Optional: param.Optional,
Repeated: param.Repeated,
Object: s.defParametersToService(param.Object),
}
}
return ps
Expand Down
3 changes: 3 additions & 0 deletions service/parameter.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,7 @@ type Parameter struct {

// Repeated is to have an array of this parameter
Repeated bool `hash:"name:6"`

// Definition of the structure of the object when the type is object
Object []*Parameter `hash:"name:7"`
}
38 changes: 18 additions & 20 deletions service/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,14 @@ func (p *ParameterWarning) String() string {
// TODO(ilgooz) add this as a method to Service type when create custom types for Event, Task etc.
// TODO(ilgooz) remove pointer from *Parameter.
func validateParametersSchema(parameters []*Parameter, data map[string]interface{}) []*ParameterWarning {
warnings := make([]*ParameterWarning, 0, len(parameters))
warningResults := make([]*ParameterWarning, 0, len(parameters))

for _, param := range parameters {
warning := newParameterValidator(param).Validate(data[param.Key])
if warning != nil {
warnings = append(warnings, warning)
}
warnings := newParameterValidator(param).Validate(data[param.Key])
warningResults = append(warningResults, warnings...)
}

return warnings
return warningResults
}

// parameterValidator provides functionalities to check data against its parameter schema.
Expand All @@ -41,22 +39,22 @@ func newParameterValidator(parameter *Parameter) *parameterValidator {
}

// Validate validates value by comparing to its parameter schema.
func (v *parameterValidator) Validate(value interface{}) *ParameterWarning {
func (v *parameterValidator) Validate(value interface{}) []*ParameterWarning {
if value == nil {
if v.parameter.Optional {
return nil
}
return v.newParameterWarning("required")
return []*ParameterWarning{v.newParameterWarning("required")}
}
if v.parameter.Repeated {
// Check if the value is a slice
array, ok := value.([]interface{})
if !ok {
return v.newParameterWarning("not an array")
return []*ParameterWarning{v.newParameterWarning("not an array")}
}
for _, x := range array {
if warning := v.validateType(x); warning != nil {
return warning
if warnings := v.validateType(x); warnings != nil {
return warnings
}
}
return nil
Expand All @@ -65,36 +63,36 @@ func (v *parameterValidator) Validate(value interface{}) *ParameterWarning {
}

// validateType checks if value comforts its expected type.
func (v *parameterValidator) validateType(value interface{}) *ParameterWarning {
func (v *parameterValidator) validateType(value interface{}) []*ParameterWarning {
switch v.parameter.Type {
case "String":
if _, ok := value.(string); !ok {
return v.newParameterWarning("not a string")
return []*ParameterWarning{v.newParameterWarning("not a string")}
}

case "Number":
_, okFloat64 := value.(float64)
_, okFloat32 := value.(float32)
_, okInt := value.(int)
if !okInt && !okFloat64 && !okFloat32 {
return v.newParameterWarning("not a number")
return []*ParameterWarning{v.newParameterWarning("not a number")}
}

case "Boolean":
if _, ok := value.(bool); !ok {
return v.newParameterWarning("not a boolean")
return []*ParameterWarning{v.newParameterWarning("not a boolean")}
}

case "Object":
_, okObj := value.(map[string]interface{})
_, okArr := value.([]interface{})
if !okObj && !okArr {
return v.newParameterWarning("not an object or array")
data, okObj := value.(map[string]interface{})
if !okObj {
return []*ParameterWarning{v.newParameterWarning("not an object")}
}
return validateParametersSchema(v.parameter.Object, data)
case "Any":
return nil
default:
return v.newParameterWarning("an invalid type")
return []*ParameterWarning{v.newParameterWarning("an invalid type")}
}

return nil
Expand Down
43 changes: 39 additions & 4 deletions service/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ var eventDataSchema = []*Parameter{
Key: "object",
Type: "Object",
},
{
Key: "fullobject",
Type: "Object",
Object: []*Parameter{
{Key: "foo", Type: "String"},
{Key: "bar", Type: "String"},
},
},
{
Key: "any",
Type: "Any",
Expand All @@ -43,7 +51,7 @@ var eventDataSchema = []*Parameter{
func validateParameterData(paramKey string, data interface{}) bool {
for _, param := range eventDataSchema {
if param.Key == paramKey {
return newParameterValidator(param).Validate(data) == nil
return len(newParameterValidator(param).Validate(data)) == 0
}
}
return false
Expand Down Expand Up @@ -77,11 +85,28 @@ func TestObject(t *testing.T) {
require.True(t, validateParameterData("object", map[string]interface{}{
"foo": "bar",
}))
require.True(t, validateParameterData("object", []interface{}{
// Breaking change: now array is not supported by the type `object` but can be
// used with the parameter property `repeated: true`
require.False(t, validateParameterData("object", []interface{}{
"foo",
"bar",
}))
require.False(t, validateParameterData("object", 42))

require.True(t, validateParameterData("fullobject", map[string]interface{}{
"foo": "_",
"bar": "_",
}))

require.False(t, validateParameterData("fullobject", map[string]interface{}{
"foo": 1,
"bar": true,
}))

require.False(t, validateParameterData("fullobject", map[string]interface{}{
"x": "_",
"y": "_",
}))
}

func TestAny(t *testing.T) {
Expand Down Expand Up @@ -116,6 +141,10 @@ func TestValidateParameters(t *testing.T) {
"object": {
"foo": "bar"
},
"fullobject": {
"foo": "_",
"bar": "_"
},
"any": 0,
"array": ["foo", "bar"]
}`,
Expand All @@ -130,6 +159,10 @@ func TestValidateParameters(t *testing.T) {
"object": {
"foo": "bar"
},
"fullobject": {
"foo": "_",
"bar": "_"
},
"any": 0,
"array": ["foo", "bar"]
}`,
Expand All @@ -142,14 +175,16 @@ func TestValidateParameters(t *testing.T) {
// - invalid boolean
// - invalid object
// - invalid array
// - invalid fullobject.foo & fullobject.bar
data: `{
"number": "string",
"boolean": 42,
"object": false,
"any": 0,
"array": 42
"array": 42,
"fullobject": { "foo": 1, "bar": true }
}`,
errors: 5,
errors: 7,
},
}

Expand Down

0 comments on commit 74269f2

Please sign in to comment.