Skip to content

Commit

Permalink
Merge pull request #67 from stripe/brandur-param-coercer-any-of
Browse files Browse the repository at this point in the history
Support primitives in an `anyOf` from the parameters coercer
  • Loading branch information
brandur-stripe committed Apr 26, 2018
2 parents 4362e10 + 50ceb42 commit e16881a
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 2 deletions.
47 changes: 45 additions & 2 deletions param/coercer/coercer.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func CoerceParams(schema *spec.Schema, data map[string]interface{}) error {
CoerceParams(subSchema.Items, itemValMap)
} else if subSchema.Items.Type != "" {
// Handles the case of an array of primitive types
itemValCoerced, ok := coercePrimitiveType(itemVal, subSchema.Items.Type)
itemValCoerced, ok := coerceSchema(itemVal, subSchema.Items)
if ok {
valArr[i] = itemValCoerced
}
Expand All @@ -61,7 +61,7 @@ func CoerceParams(schema *spec.Schema, data map[string]interface{}) error {
continue
}

valCoerced, ok := coercePrimitiveType(val, subSchema.Type)
valCoerced, ok := coerceSchema(val, subSchema)
if ok {
data[key] = valCoerced
}
Expand Down Expand Up @@ -127,6 +127,49 @@ func coercePrimitiveType(val interface{}, primitiveType string) (interface{}, bo
return nil, false
}

// coerceSchema tries to coerce a schema containing a primitive type from the
// given generic interface{} value.
//
// It's similar to coercePrimitiveType above (and indeed calls into it), but
// also handles the case of an anyOf schema that supports a number of different
// primitve types.
func coerceSchema(val interface{}, schema *spec.Schema) (interface{}, bool) {
if isSchemaPrimitiveType(schema) {
return coercePrimitiveType(val, schema.Type)
} else if schema.AnyOf != nil {
for _, subSchema := range schema.AnyOf {
val, ok := coerceSchema(val, subSchema)
if ok {
return val, ok
}
}
}

return nil, false
}

// isSchemaPrimitiveType checks whether the given schema is a coercable
// primitive type (as opposed to an object or array).
//
// The conditional ladder in this function should be *identical* to the one in
// coercePrimitiveType (i.e., if support is added for a new type, it needs to
// be added in both places).
func isSchemaPrimitiveType(schema *spec.Schema) bool {
if schema.Type == booleanType {
return true
}

if schema.Type == integerType {
return true
}

if schema.Type == numberType {
return true
}

return false
}

// parseIntegerIndexedMap tries to parse a map that has all integer-indexed
// keys (e.g. { "0": ..., "1": "...", "2": "..." }) as a slice. We only try to
// do this when we know that the target schema requires an array.
Expand Down
18 changes: 18 additions & 0 deletions param/coercer/coercer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,24 @@ import (
"github.com/stripe/stripe-mock/spec"
)

func TestCoerceParams_AnyOfCoercion(t *testing.T) {
schema := &spec.Schema{Properties: map[string]*spec.Schema{
"objectorintkey": {
AnyOf: []*spec.Schema{
{Type: objectType},
{Type: integerType},
},
},
}}
data := map[string]interface{}{
"objectorintkey": "123",
}

err := CoerceParams(schema, data)
assert.NoError(t, err)
assert.Equal(t, 123, data["objectorintkey"])
}

func TestCoerceParams_ArrayCoercion(t *testing.T) {
// Array of primitive values
{
Expand Down

0 comments on commit e16881a

Please sign in to comment.