Skip to content

Commit

Permalink
fix: Generic Fields does not handle Arrays in the .swaggo file
Browse files Browse the repository at this point in the history
- Detect array type and transform schema into spec.ArrayProperty if needed

fixes #1318, #1320
  • Loading branch information
FabianMartin committed Sep 12, 2022
1 parent bc895ed commit d215316
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 15 deletions.
5 changes: 3 additions & 2 deletions generics_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ func TestParseGenericsBasic(t *testing.T) {

p := New()
p.Overrides = map[string]string{
"types.Field[string]": "string",
"types.DoubleField[string,string]": "string",
"types.Field[string]": "string",
"types.DoubleField[string,string]": "[]string",
"types.TrippleField[string,string]": "[][]string",
}

err = p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)
Expand Down
38 changes: 30 additions & 8 deletions parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -871,21 +871,22 @@ func convertFromSpecificToPrimitive(typeName string) (string, error) {
}

func (parser *Parser) getTypeSchema(typeName string, file *ast.File, ref bool) (*spec.Schema, error) {
var arrayDepth = 0
if override, ok := parser.Overrides[typeName]; ok {
parser.debug.Printf("Override detected for %s: using %s instead", typeName, override)
typeName = override
arrayDepth, typeName = getArrayDepth(override)
}

if IsInterfaceLike(typeName) {
return &spec.Schema{}, nil
return transformToArray(&spec.Schema{}, arrayDepth), nil
}
if IsGolangPrimitiveType(typeName) {
return PrimitiveSchema(TransToValidSchemeType(typeName)), nil
return transformToArray(PrimitiveSchema(TransToValidSchemeType(typeName)), arrayDepth), nil
}

schemaType, err := convertFromSpecificToPrimitive(typeName)
if err == nil {
return PrimitiveSchema(schemaType), nil
return transformToArray(PrimitiveSchema(schemaType), arrayDepth), nil
}

typeSpecDef := parser.packages.FindTypeSpec(typeName, file, parser.ParseDependency)
Expand All @@ -901,13 +902,18 @@ func (parser *Parser) getTypeSchema(typeName string, file *ast.File, ref bool) (
}

parser.debug.Printf("Override detected for %s: using %s instead", typeSpecDef.FullPath(), override)
arrayDepth, override = getArrayDepth(override)

separator := strings.LastIndex(override, ".")
if separator == -1 {
// treat as a swaggertype tag
parts := strings.Split(override, ",")

return BuildCustomSchema(parts)
s, err := BuildCustomSchema(parts)
if err != nil {
return nil, err
}
return transformToArray(s, arrayDepth), nil
}

typeSpecDef = parser.packages.findTypeSpec(override[0:separator], override[separator+1:])
Expand All @@ -920,18 +926,18 @@ func (parser *Parser) getTypeSchema(typeName string, file *ast.File, ref bool) (
schema, err = parser.ParseDefinition(typeSpecDef)
if err != nil {
if err == ErrRecursiveParseStruct && ref {
return parser.getRefTypeSchema(typeSpecDef, schema), nil
return transformToArray(parser.getRefTypeSchema(typeSpecDef, schema), arrayDepth), nil
}

return nil, err
}
}

if ref && len(schema.Schema.Type) > 0 && schema.Schema.Type[0] == OBJECT {
return parser.getRefTypeSchema(typeSpecDef, schema), nil
return transformToArray(parser.getRefTypeSchema(typeSpecDef, schema), arrayDepth), nil
}

return schema.Schema, nil
return transformToArray(schema.Schema, arrayDepth), nil
}

func (parser *Parser) renameRefSchemas() {
Expand Down Expand Up @@ -1607,3 +1613,19 @@ func (parser *Parser) addTestType(typename string) {
Schema: PrimitiveSchema(OBJECT),
}
}

func getArrayDepth(typename string) (int, string) {
var d = 0
for strings.HasPrefix(typename, "[]") {
typename = typename[2:]
d++
}
return d, typename
}

func transformToArray(s *spec.Schema, arrayDepth int) *spec.Schema {
for i := 0; i < arrayDepth; i++ {
s = spec.ArrayProperty(s)
}
return s
}
3 changes: 2 additions & 1 deletion testdata/generics_basic/.swaggo
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
replace types.Field[string] string
replace types.DoubleField[string,string] string
replace types.DoubleField[string,string] []string
replace types.TrippleField[string,string] [][]string
14 changes: 13 additions & 1 deletion testdata/generics_basic/expected.json
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,20 @@
"types.Hello": {
"type": "object",
"properties": {
"myNewArrayField": {
"type": "array",
"items": {
"type": "array",
"items": {
"type": "string"
}
}
},
"myNewField": {
"type": "string"
"type": "array",
"items": {
"type": "string"
}
},
"myStringField1": {
"type": "string"
Expand Down
12 changes: 9 additions & 3 deletions testdata/generics_basic/types/string.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,14 @@ type DoubleField[T1 any, T2 any] struct {
Value2 T2
}

type TrippleField[T1 any, T2 any] struct {
Value1 T1
Value2 T2
}

type Hello struct {
MyStringField1 Field[*string] `json:"myStringField1"`
MyStringField2 Field[string] `json:"myStringField2"`
MyArrayField DoubleField[*string, string] `json:"myNewField"`
MyStringField1 Field[*string] `json:"myStringField1"`
MyStringField2 Field[string] `json:"myStringField2"`
MyArrayField DoubleField[*string, string] `json:"myNewField"`
MyArrayDepthField TrippleField[*string, string] `json:"myNewArrayField"`
}

0 comments on commit d215316

Please sign in to comment.