github.com/wangyougui/gf/v2@v2.6.5/net/goai/goai_shema_ref.go (about)

     1  // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/wangyougui/gf.
     6  
     7  package goai
     8  
     9  import (
    10  	"fmt"
    11  	"reflect"
    12  
    13  	"github.com/wangyougui/gf/v2/internal/json"
    14  	"github.com/wangyougui/gf/v2/text/gstr"
    15  	"github.com/wangyougui/gf/v2/util/gconv"
    16  	"github.com/wangyougui/gf/v2/util/gtag"
    17  )
    18  
    19  type SchemaRefs []SchemaRef
    20  
    21  type SchemaRef struct {
    22  	Ref   string
    23  	Value *Schema
    24  }
    25  
    26  // isEmbeddedStructDefinition checks and returns whether given golang type is embedded struct definition, like:
    27  //
    28  //	struct A struct{
    29  //	    B struct{
    30  //	        // ...
    31  //	    }
    32  //	}
    33  //
    34  // The `B` in `A` is called `embedded struct definition`.
    35  func (oai *OpenApiV3) isEmbeddedStructDefinition(golangType reflect.Type) bool {
    36  	s := golangType.String()
    37  	return gstr.Contains(s, `struct {`)
    38  }
    39  
    40  // newSchemaRefWithGolangType creates a new Schema and returns its SchemaRef.
    41  func (oai *OpenApiV3) newSchemaRefWithGolangType(golangType reflect.Type, tagMap map[string]string) (*SchemaRef, error) {
    42  	var (
    43  		err       error
    44  		oaiType   = oai.golangTypeToOAIType(golangType)
    45  		oaiFormat = oai.golangTypeToOAIFormat(golangType)
    46  		typeName  = golangType.Name()
    47  		pkgPath   = golangType.PkgPath()
    48  		schemaRef = &SchemaRef{}
    49  		schema    = &Schema{
    50  			Type:        oaiType,
    51  			Format:      oaiFormat,
    52  			XExtensions: make(XExtensions),
    53  		}
    54  	)
    55  	if pkgPath == "" {
    56  		switch golangType.Kind() {
    57  		case reflect.Ptr, reflect.Array, reflect.Slice:
    58  			pkgPath = golangType.Elem().PkgPath()
    59  			typeName = golangType.Elem().Name()
    60  		}
    61  	}
    62  
    63  	// Type enums.
    64  	var typeId = fmt.Sprintf(`%s.%s`, pkgPath, typeName)
    65  	if enums := gtag.GetEnumsByType(typeId); enums != "" {
    66  		schema.Enum = make([]interface{}, 0)
    67  		if err = json.Unmarshal([]byte(enums), &schema.Enum); err != nil {
    68  			return nil, err
    69  		}
    70  	}
    71  
    72  	if len(tagMap) > 0 {
    73  		if err := oai.tagMapToSchema(tagMap, schema); err != nil {
    74  			return nil, err
    75  		}
    76  	}
    77  	schemaRef.Value = schema
    78  	switch oaiType {
    79  	case TypeString, TypeFile:
    80  	// Nothing to do.
    81  	case TypeInteger:
    82  		if schemaRef.Value.Default != nil {
    83  			schemaRef.Value.Default = gconv.Int64(schemaRef.Value.Default)
    84  		}
    85  		// keep the default value as nil.
    86  
    87  		// example value needs to be converted just like default value
    88  		if schemaRef.Value.Example != nil {
    89  			schemaRef.Value.Example = gconv.Int64(schemaRef.Value.Example)
    90  		}
    91  		// keep the example value as nil.
    92  	case TypeNumber:
    93  		if schemaRef.Value.Default != nil {
    94  			schemaRef.Value.Default = gconv.Float64(schemaRef.Value.Default)
    95  		}
    96  		// keep the default value as nil.
    97  
    98  		// example value needs to be converted just like default value
    99  		if schemaRef.Value.Example != nil {
   100  			schemaRef.Value.Example = gconv.Float64(schemaRef.Value.Example)
   101  		}
   102  		// keep the example value as nil.
   103  	case TypeBoolean:
   104  		if schemaRef.Value.Default != nil {
   105  			schemaRef.Value.Default = gconv.Bool(schemaRef.Value.Default)
   106  		}
   107  		// keep the default value as nil.
   108  
   109  		// example value needs to be converted just like default value
   110  		if schemaRef.Value.Example != nil {
   111  			schemaRef.Value.Example = gconv.Bool(schemaRef.Value.Example)
   112  		}
   113  		// keep the example value as nil.
   114  	case
   115  		TypeArray:
   116  		subSchemaRef, err := oai.newSchemaRefWithGolangType(golangType.Elem(), nil)
   117  		if err != nil {
   118  			return nil, err
   119  		}
   120  		schema.Items = subSchemaRef
   121  		if len(schema.Enum) > 0 {
   122  			schema.Items.Value.Enum = schema.Enum
   123  			schema.Enum = nil
   124  		}
   125  
   126  	case
   127  		TypeObject:
   128  		for golangType.Kind() == reflect.Ptr {
   129  			golangType = golangType.Elem()
   130  		}
   131  		switch golangType.Kind() {
   132  		case reflect.Map:
   133  			// Specially for map type.
   134  			subSchemaRef, err := oai.newSchemaRefWithGolangType(golangType.Elem(), nil)
   135  			if err != nil {
   136  				return nil, err
   137  			}
   138  			schema.AdditionalProperties = subSchemaRef
   139  			return schemaRef, nil
   140  
   141  		case reflect.Interface:
   142  			// Specially for interface type.
   143  			var (
   144  				structTypeName = oai.golangTypeToSchemaName(golangType)
   145  			)
   146  			if oai.Components.Schemas.Get(structTypeName) == nil {
   147  				if err := oai.addSchema(reflect.New(golangType).Interface()); err != nil {
   148  					return nil, err
   149  				}
   150  			}
   151  			schemaRef.Ref = structTypeName
   152  			schemaRef.Value = nil
   153  
   154  		default:
   155  			golangTypeInstance := reflect.New(golangType).Elem().Interface()
   156  			if oai.isEmbeddedStructDefinition(golangType) {
   157  				schema, err = oai.structToSchema(golangTypeInstance)
   158  				if err != nil {
   159  					return nil, err
   160  				}
   161  				schemaRef.Ref = ""
   162  				schemaRef.Value = schema
   163  			} else {
   164  				var structTypeName = oai.golangTypeToSchemaName(golangType)
   165  				if oai.Components.Schemas.Get(structTypeName) == nil {
   166  					if err := oai.addSchema(golangTypeInstance); err != nil {
   167  						return nil, err
   168  					}
   169  				}
   170  				schemaRef.Ref = structTypeName
   171  				schemaRef.Value = nil
   172  			}
   173  		}
   174  	}
   175  	return schemaRef, nil
   176  }
   177  
   178  func (r SchemaRef) MarshalJSON() ([]byte, error) {
   179  	if r.Ref != "" {
   180  		return formatRefToBytes(r.Ref), nil
   181  	}
   182  	return json.Marshal(r.Value)
   183  }