forked from deepmap/oapi-codegen
/
merge_schemas_v1.go
111 lines (100 loc) · 3.47 KB
/
merge_schemas_v1.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package codegen
import (
"errors"
"fmt"
"strings"
"github.com/getkin/kin-openapi/openapi3"
)
func mergeSchemasV1(allOf []*openapi3.SchemaRef, path []string) (Schema, error) {
var outSchema Schema
for _, schemaOrRef := range allOf {
ref := schemaOrRef.Ref
var refType string
var err error
if IsGoTypeReference(ref) {
refType, err = RefPathToGoType(ref)
if err != nil {
return Schema{}, fmt.Errorf("error converting reference path to a go type: %w", err)
}
}
schema, err := GenerateGoSchema(schemaOrRef, path)
if err != nil {
return Schema{}, fmt.Errorf("error generating Go schema in allOf: %w", err)
}
schema.RefType = refType
for _, p := range schema.Properties {
err = outSchema.AddProperty(p)
if err != nil {
return Schema{}, fmt.Errorf("error merging properties: %w", err)
}
}
if schema.HasAdditionalProperties {
if outSchema.HasAdditionalProperties {
// Both this schema, and the aggregate schema have additional
// properties, they must match.
if schema.AdditionalPropertiesType.TypeDecl() != outSchema.AdditionalPropertiesType.TypeDecl() {
return Schema{}, errors.New("additional properties in allOf have incompatible types")
}
} else {
// We're switching from having no additional properties to having
// them
outSchema.HasAdditionalProperties = true
outSchema.AdditionalPropertiesType = schema.AdditionalPropertiesType
}
}
}
// Now, we generate the struct which merges together all the fields.
var err error
outSchema.GoType, err = GenStructFromAllOf(allOf, path)
if err != nil {
return Schema{}, fmt.Errorf("unable to generate aggregate type for AllOf: %w", err)
}
return outSchema, nil
}
// GenStructFromAllOf generates an object that is the union of the objects in the
// input array. In the case of Ref objects, we use an embedded struct, otherwise,
// we inline the fields.
func GenStructFromAllOf(allOf []*openapi3.SchemaRef, path []string) (string, error) {
// Start out with struct {
objectParts := []string{"struct {"}
for _, schemaOrRef := range allOf {
ref := schemaOrRef.Ref
if IsGoTypeReference(ref) {
// We have a referenced type, we will generate an inlined struct
// member.
// struct {
// InlinedMember
// ...
// }
goType, err := RefPathToGoType(ref)
if err != nil {
return "", err
}
objectParts = append(objectParts,
fmt.Sprintf(" // Embedded struct due to allOf(%s)", ref))
objectParts = append(objectParts,
fmt.Sprintf(" %s `yaml:\",inline\"`", goType))
} else {
// Inline all the fields from the schema into the output struct,
// just like in the simple case of generating an object.
goSchema, err := GenerateGoSchema(schemaOrRef, path)
if err != nil {
return "", err
}
objectParts = append(objectParts, " // Embedded fields due to inline allOf schema")
objectParts = append(objectParts, GenFieldsFromProperties(goSchema.Properties)...)
if goSchema.HasAdditionalProperties {
addPropsType := goSchema.AdditionalPropertiesType.GoType
if goSchema.AdditionalPropertiesType.RefType != "" {
addPropsType = goSchema.AdditionalPropertiesType.RefType
}
additionalPropertiesPart := fmt.Sprintf("AdditionalProperties map[string]%s `json:\"-\"`", addPropsType)
if !StringInArray(additionalPropertiesPart, objectParts) {
objectParts = append(objectParts, additionalPropertiesPart)
}
}
}
}
objectParts = append(objectParts, "}")
return strings.Join(objectParts, "\n"), nil
}