gf/net/goai/goai_shema_ref.go

184 lines
4.9 KiB
Go
Raw Normal View History

2021-10-02 18:54:06 +08:00
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
2021-10-02 14:52:28 +08:00
package goai
import (
2023-04-20 16:30:42 +08:00
"fmt"
2021-11-13 23:34:16 +08:00
"reflect"
2021-10-11 21:41:56 +08:00
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
2023-04-20 16:30:42 +08:00
"github.com/gogf/gf/v2/util/gtag"
2021-10-02 14:52:28 +08:00
)
type SchemaRefs []SchemaRef
type SchemaRef struct {
Ref string
Value *Schema
}
// isEmbeddedStructDefinition checks and returns whether given golang type is embedded struct definition, like:
//
// struct A struct{
// B struct{
// // ...
// }
// }
//
// The `B` in `A` is called `embedded struct definition`.
func (oai *OpenApiV3) isEmbeddedStructDefinition(golangType reflect.Type) bool {
s := golangType.String()
return gstr.Contains(s, `struct {`)
}
// newSchemaRefWithGolangType creates a new Schema and returns its SchemaRef.
2021-10-02 18:54:06 +08:00
func (oai *OpenApiV3) newSchemaRefWithGolangType(golangType reflect.Type, tagMap map[string]string) (*SchemaRef, error) {
2021-10-02 14:52:28 +08:00
var (
err error
2021-10-02 14:52:28 +08:00
oaiType = oai.golangTypeToOAIType(golangType)
2021-10-02 15:07:47 +08:00
oaiFormat = oai.golangTypeToOAIFormat(golangType)
2023-04-20 16:30:42 +08:00
typeName = golangType.Name()
pkgPath = golangType.PkgPath()
2021-10-02 18:54:06 +08:00
schemaRef = &SchemaRef{}
2021-10-02 14:52:28 +08:00
schema = &Schema{
Type: oaiType,
Format: oaiFormat,
XExtensions: make(XExtensions),
2021-10-02 14:52:28 +08:00
}
)
2023-04-20 16:30:42 +08:00
if pkgPath == "" {
switch golangType.Kind() {
case reflect.Ptr, reflect.Array, reflect.Slice:
pkgPath = golangType.Elem().PkgPath()
typeName = golangType.Elem().Name()
}
}
// Type enums.
var typeId = fmt.Sprintf(`%s.%s`, pkgPath, typeName)
if enums := gtag.GetEnumsByType(typeId); enums != "" {
schema.Enum = make([]interface{}, 0)
if err = json.Unmarshal([]byte(enums), &schema.Enum); err != nil {
return nil, err
}
}
2021-10-02 14:52:28 +08:00
if len(tagMap) > 0 {
2022-03-02 20:00:40 +08:00
if err := oai.tagMapToSchema(tagMap, schema); err != nil {
return nil, err
2022-03-01 11:43:42 +08:00
}
2021-10-02 14:52:28 +08:00
}
schemaRef.Value = schema
switch oaiType {
case TypeString, TypeFile:
// Nothing to do.
case TypeInteger:
if schemaRef.Value.Default != nil {
schemaRef.Value.Default = gconv.Int64(schemaRef.Value.Default)
}
// keep the default value as nil.
// example value needs to be converted just like default value
if schemaRef.Value.Example != nil {
schemaRef.Value.Example = gconv.Int64(schemaRef.Value.Example)
}
// keep the example value as nil.
case TypeNumber:
if schemaRef.Value.Default != nil {
schemaRef.Value.Default = gconv.Float64(schemaRef.Value.Default)
}
// keep the default value as nil.
// example value needs to be converted just like default value
if schemaRef.Value.Example != nil {
schemaRef.Value.Example = gconv.Float64(schemaRef.Value.Example)
}
// keep the example value as nil.
case TypeBoolean:
if schemaRef.Value.Default != nil {
schemaRef.Value.Default = gconv.Bool(schemaRef.Value.Default)
}
// keep the default value as nil.
// example value needs to be converted just like default value
if schemaRef.Value.Example != nil {
schemaRef.Value.Example = gconv.Bool(schemaRef.Value.Example)
}
// keep the example value as nil.
2021-10-02 14:52:28 +08:00
case
TypeArray:
2021-10-02 18:54:06 +08:00
subSchemaRef, err := oai.newSchemaRefWithGolangType(golangType.Elem(), nil)
if err != nil {
return nil, err
}
schema.Items = subSchemaRef
if len(schema.Enum) > 0 {
schema.Items.Value.Enum = schema.Enum
schema.Enum = nil
}
2021-10-02 14:52:28 +08:00
case
TypeObject:
2021-10-14 15:03:39 +08:00
for golangType.Kind() == reflect.Ptr {
golangType = golangType.Elem()
}
switch golangType.Kind() {
case reflect.Map:
// Specially for map type.
2021-10-02 18:54:06 +08:00
subSchemaRef, err := oai.newSchemaRefWithGolangType(golangType.Elem(), nil)
if err != nil {
return nil, err
}
schema.AdditionalProperties = subSchemaRef
return schemaRef, nil
2021-10-14 15:03:39 +08:00
case reflect.Interface:
// Specially for interface type.
var (
structTypeName = oai.golangTypeToSchemaName(golangType)
)
if oai.Components.Schemas.Get(structTypeName) == nil {
2021-10-14 15:03:39 +08:00
if err := oai.addSchema(reflect.New(golangType).Interface()); err != nil {
return nil, err
}
}
schemaRef.Ref = structTypeName
schemaRef.Value = nil
default:
golangTypeInstance := reflect.New(golangType).Elem().Interface()
if oai.isEmbeddedStructDefinition(golangType) {
schema, err = oai.structToSchema(golangTypeInstance)
if err != nil {
2021-10-14 15:03:39 +08:00
return nil, err
}
schemaRef.Ref = ""
schemaRef.Value = schema
} else {
var structTypeName = oai.golangTypeToSchemaName(golangType)
if oai.Components.Schemas.Get(structTypeName) == nil {
if err := oai.addSchema(golangTypeInstance); err != nil {
return nil, err
}
}
schemaRef.Ref = structTypeName
schemaRef.Value = nil
2021-10-02 18:54:06 +08:00
}
2021-10-02 14:52:28 +08:00
}
}
2021-10-02 18:54:06 +08:00
return schemaRef, nil
2021-10-02 14:52:28 +08:00
}
func (r SchemaRef) MarshalJSON() ([]byte, error) {
if r.Ref != "" {
2021-10-02 18:54:06 +08:00
return formatRefToBytes(r.Ref), nil
2021-10-02 14:52:28 +08:00
}
return json.Marshal(r.Value)
}