Skip to content

Commit

Permalink
Make format resolving strictly to require a valid pair of type and fo…
Browse files Browse the repository at this point in the history
…rmat.

The before implementation checks format only but it causes wrong type decisions.

e.g. {"type": "string", "format": "uint64"} had been converted to uint64.
     This behaivior is correct in case of "type" is "integer" or "number", but the "string" case is not.

This commit changes this decision algorithm. "format" is not treated as same of "type" anymore.
"format" must be available when it is specified with the valid (matched) "type". If not, the "format" will be ignored
and it just decides the type of Go code by using "type" value.

Signed-off-by: Kousuke Ebihara <[email protected]>
  • Loading branch information
co3k committed Jul 28, 2018
1 parent c4b0231 commit 5b4fae9
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 78 deletions.
115 changes: 69 additions & 46 deletions generator/formats.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,61 +92,84 @@ var stringFormatters = map[string]string{
"uint64": "swag.FormatUint64",
}

// typeMapping contains a mapping of format (or type name) to go type
// typeMapping contains a mapping of type name to go type
var typeMapping = map[string]string{
// Standard formats with native, straightforward, mapping
"binary": "io.ReadCloser",
"string": "string",
"boolean": "bool",
"char": "rune",
"double": "float64",
"float": "float32",
"int": "int64",
"int8": "int8",
"int16": "int16",
"int32": "int32",
"int64": "int64",
"integer": "int64",
"number": "float64",
"uint": "uint64",
"uint8": "uint8",
"uint16": "uint16",
"uint32": "uint32",
"uint64": "uint64",
// Extended format registry from go-openapi/strfmt.
// Currently, 23 such formats are supported (default strftm registry),
// plus the following aliases:
// - "datetime" alias for the more official "date-time"
// - "objectid" and "ObjectId" aliases for "bsonobjectid"
"byte": "strfmt.Base64",
"creditcard": "strfmt.CreditCard",
"date": "strfmt.Date",
"date-time": "strfmt.DateTime",
"datetime": "strfmt.DateTime",
"duration": "strfmt.Duration",
"email": "strfmt.Email",
"hexcolor": "strfmt.HexColor",
"hostname": "strfmt.Hostname",
"ipv4": "strfmt.IPv4",
"ipv6": "strfmt.IPv6",
"isbn": "strfmt.ISBN",
"isbn10": "strfmt.ISBN10",
"isbn13": "strfmt.ISBN13",
"mac": "strfmt.MAC",
"bsonobjectid": "strfmt.ObjectId",
"objectid": "strfmt.ObjectId",
"ObjectId": "strfmt.ObjectId", // NOTE: does it work with uppercase?
"password": "strfmt.Password",
"rgbcolor": "strfmt.RGBColor",
"ssn": "strfmt.SSN",
"uri": "strfmt.URI",
"uuid": "strfmt.UUID",
"uuid3": "strfmt.UUID3",
"uuid4": "strfmt.UUID4",
"uuid5": "strfmt.UUID5",
// For file producers
"file": "runtime.File",
}

// formatMapping contains a type-specific version of mapping of format to go type
var formatMapping = map[string]map[string]string{
"number": {
"double": "float64",
"float": "float32",
"int": "int64",
"int8": "int8",
"int16": "int16",
"int32": "int32",
"int64": "int64",
"uint": "uint64",
"uint8": "uint8",
"uint16": "uint16",
"uint32": "uint32",
"uint64": "uint64",
},
"integer": {
"int": "int64",
"int8": "int8",
"int16": "int16",
"int32": "int32",
"int64": "int64",
"uint": "uint64",
"uint8": "uint8",
"uint16": "uint16",
"uint32": "uint32",
"uint64": "uint64",
},
"string": {
"char": "rune",
// Extended format registry from go-openapi/strfmt.
// Currently, 23 such formats are supported (default strftm registry),
// plus the following aliases:
// - "datetime" alias for the more official "date-time"
// - "objectid" and "ObjectId" aliases for "bsonobjectid"
"binary": "io.ReadCloser",
"byte": "strfmt.Base64",
"creditcard": "strfmt.CreditCard",
"date": "strfmt.Date",
"date-time": "strfmt.DateTime",
"datetime": "strfmt.DateTime",
"duration": "strfmt.Duration",
"email": "strfmt.Email",
"hexcolor": "strfmt.HexColor",
"hostname": "strfmt.Hostname",
"ipv4": "strfmt.IPv4",
"ipv6": "strfmt.IPv6",
"isbn": "strfmt.ISBN",
"isbn10": "strfmt.ISBN10",
"isbn13": "strfmt.ISBN13",
"mac": "strfmt.MAC",
"bsonobjectid": "strfmt.ObjectId",
"objectid": "strfmt.ObjectId",
"ObjectId": "strfmt.ObjectId", // NOTE: does it work with uppercase?
"password": "strfmt.Password",
"rgbcolor": "strfmt.RGBColor",
"ssn": "strfmt.SSN",
"uri": "strfmt.URI",
"uuid": "strfmt.UUID",
"uuid3": "strfmt.UUID3",
"uuid4": "strfmt.UUID4",
"uuid5": "strfmt.UUID5",
// For file producers
"file": "runtime.File",
},
}

// go primitive types
var primitives = map[string]struct{}{
"bool": {},
Expand Down
8 changes: 8 additions & 0 deletions generator/typeresolver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@ var schTypeVals = []struct{ Type, Format, Expected string }{
{"string", "duration", "strfmt.Duration"},
{"string", "ObjectId", "strfmt.ObjectId"},
{"string", "password", "strfmt.Password"},
{"string", "uint8", "string"},
{"string", "uint16", "string"},
{"string", "uint32", "string"},
{"string", "uint64", "string"},
{"string", "int8", "string"},
{"string", "int16", "string"},
{"string", "int32", "string"},
{"string", "int64", "string"},
{"file", "", "io.ReadCloser"},
}

Expand Down
75 changes: 43 additions & 32 deletions generator/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,16 @@ func simpleResolvedType(tn, fmt string, items *spec.Items) (result resolvedType)

if fmt != "" {
fmtn := strings.Replace(fmt, "-", "", -1)
if tpe, ok := typeMapping[fmtn]; ok {
result.GoType = tpe
result.IsPrimitive = true
_, result.IsCustomFormatter = customFormatters[tpe]
// special case of swagger format "binary", rendered as io.ReadCloser interface
// TODO(fredbi): should set IsCustomFormatter=false when binary
result.IsStream = fmt == binary
return
if fmm, ok := formatMapping[tn]; ok {
if tpe, ok := fmm[fmtn]; ok {
result.GoType = tpe
result.IsPrimitive = true
_, result.IsCustomFormatter = customFormatters[tpe]
// special case of swagger format "binary", rendered as io.ReadCloser interface
// TODO(fredbi): should set IsCustomFormatter=false when binary
result.IsStream = fmt == binary
return
}
}
}

Expand Down Expand Up @@ -257,34 +259,43 @@ func (t *typeResolver) inferAliasing(result *resolvedType, schema *spec.Schema,
func (t *typeResolver) resolveFormat(schema *spec.Schema, isAnonymous bool, isRequired bool) (returns bool, result resolvedType, err error) {

if schema.Format != "" {
tn := schema.Type[0]

debugLog("resolving format (anon: %t, req: %t)", isAnonymous, isRequired)
schFmt := strings.Replace(schema.Format, "-", "", -1)
if tpe, ok := typeMapping[schFmt]; ok {
returns = true
result.SwaggerType = str
if len(schema.Type) > 0 {
result.SwaggerType = schema.Type[0]
if fmm, ok := formatMapping[tn]; ok {
if tpe, ok := fmm[schFmt]; ok {
returns = true
result.GoType = tpe
_, result.IsCustomFormatter = customFormatters[tpe]
}
result.SwaggerFormat = schema.Format
}
if tpe, ok := typeMapping[schFmt]; !returns && ok {
returns = true
result.GoType = tpe
t.inferAliasing(&result, schema, isAnonymous, isRequired)
// special case of swagger format "binary", rendered as io.ReadCloser interface and is therefore not a primitive type
// TODO: should set IsCustomFormatter=false in this case.
result.IsPrimitive = schFmt != binary
result.IsStream = schFmt == binary
_, result.IsCustomFormatter = customFormatters[tpe]
// propagate extensions in resolvedType
result.Extensions = schema.Extensions

switch result.SwaggerType {
case str:
result.IsNullable = nullableStrfmt(schema, isRequired)
case number, integer:
result.IsNullable = nullableNumber(schema, isRequired)
default:
result.IsNullable = t.IsNullable(schema)
}
return
}

result.SwaggerType = str
if len(schema.Type) > 0 {
result.SwaggerType = schema.Type[0]
}
result.SwaggerFormat = schema.Format
t.inferAliasing(&result, schema, isAnonymous, isRequired)
// special case of swagger format "binary", rendered as io.ReadCloser interface and is therefore not a primitive type
// TODO: should set IsCustomFormatter=false in this case.
result.IsPrimitive = schFmt != binary
result.IsStream = schFmt == binary
// propagate extensions in resolvedType
result.Extensions = schema.Extensions

switch result.SwaggerType {
case str:
result.IsNullable = nullableStrfmt(schema, isRequired)
case number, integer:
result.IsNullable = nullableNumber(schema, isRequired)
default:
result.IsNullable = t.IsNullable(schema)
}
}
return
Expand Down Expand Up @@ -625,7 +636,7 @@ func (t *typeResolver) ResolveSchema(schema *spec.Schema, isAnonymous, isRequire
result.SwaggerType = file
result.IsPrimitive = true
result.IsNullable = false
result.GoType = typeMapping[binary]
result.GoType = formatMapping[str][binary]
result.IsStream = true
return
}
Expand Down

0 comments on commit 5b4fae9

Please sign in to comment.