github.com/gogf/gf/v2@v2.7.4/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/gogf/gf.
     6  
     7  package goai
     8  
     9  import (
    10  	"fmt"
    11  	"reflect"
    12  
    13  	"github.com/gogf/gf/v2/internal/json"
    14  	"github.com/gogf/gf/v2/text/gstr"
    15  	"github.com/gogf/gf/v2/util/gconv"
    16  	"github.com/gogf/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  		if oaiType == TypeArray && schema.Type == TypeFile {
    77  			schema.Type = TypeArray
    78  		}
    79  	}
    80  	schemaRef.Value = schema
    81  	switch oaiType {
    82  	case TypeString, TypeFile:
    83  	// Nothing to do.
    84  	case TypeInteger:
    85  		if schemaRef.Value.Default != nil {
    86  			schemaRef.Value.Default = gconv.Int64(schemaRef.Value.Default)
    87  		}
    88  		// keep the default value as nil.
    89  
    90  		// example value needs to be converted just like default value
    91  		if schemaRef.Value.Example != nil {
    92  			schemaRef.Value.Example = gconv.Int64(schemaRef.Value.Example)
    93  		}
    94  		// keep the example value as nil.
    95  	case TypeNumber:
    96  		if schemaRef.Value.Default != nil {
    97  			schemaRef.Value.Default = gconv.Float64(schemaRef.Value.Default)
    98  		}
    99  		// keep the default value as nil.
   100  
   101  		// example value needs to be converted just like default value
   102  		if schemaRef.Value.Example != nil {
   103  			schemaRef.Value.Example = gconv.Float64(schemaRef.Value.Example)
   104  		}
   105  		// keep the example value as nil.
   106  	case TypeBoolean:
   107  		if schemaRef.Value.Default != nil {
   108  			schemaRef.Value.Default = gconv.Bool(schemaRef.Value.Default)
   109  		}
   110  		// keep the default value as nil.
   111  
   112  		// example value needs to be converted just like default value
   113  		if schemaRef.Value.Example != nil {
   114  			schemaRef.Value.Example = gconv.Bool(schemaRef.Value.Example)
   115  		}
   116  		// keep the example value as nil.
   117  	case TypeArray:
   118  		subSchemaRef, err := oai.newSchemaRefWithGolangType(golangType.Elem(), nil)
   119  		if err != nil {
   120  			return nil, err
   121  		}
   122  		schema.Items = subSchemaRef
   123  		if len(schema.Enum) > 0 {
   124  			schema.Items.Value.Enum = schema.Enum
   125  			schema.Enum = nil
   126  		}
   127  
   128  	case TypeObject:
   129  		for golangType.Kind() == reflect.Ptr {
   130  			golangType = golangType.Elem()
   131  		}
   132  		switch golangType.Kind() {
   133  		case reflect.Map:
   134  			// Specially for map type.
   135  			subSchemaRef, err := oai.newSchemaRefWithGolangType(golangType.Elem(), nil)
   136  			if err != nil {
   137  				return nil, err
   138  			}
   139  			schema.AdditionalProperties = subSchemaRef
   140  			return schemaRef, nil
   141  
   142  		case reflect.Interface:
   143  			// Specially for interface type.
   144  			var (
   145  				structTypeName = oai.golangTypeToSchemaName(golangType)
   146  			)
   147  			if oai.Components.Schemas.Get(structTypeName) == nil {
   148  				if err := oai.addSchema(reflect.New(golangType).Interface()); err != nil {
   149  					return nil, err
   150  				}
   151  			}
   152  			schemaRef.Ref = structTypeName
   153  			schemaRef.Value = nil
   154  
   155  		default:
   156  			golangTypeInstance := reflect.New(golangType).Elem().Interface()
   157  			if oai.isEmbeddedStructDefinition(golangType) {
   158  				schema, err = oai.structToSchema(golangTypeInstance)
   159  				if err != nil {
   160  					return nil, err
   161  				}
   162  				schemaRef.Ref = ""
   163  				schemaRef.Value = schema
   164  			} else {
   165  				var structTypeName = oai.golangTypeToSchemaName(golangType)
   166  				if oai.Components.Schemas.Get(structTypeName) == nil {
   167  					if err := oai.addSchema(golangTypeInstance); err != nil {
   168  						return nil, err
   169  					}
   170  				}
   171  				schemaRef.Ref = structTypeName
   172  				schemaRef.Value = nil
   173  			}
   174  		}
   175  	}
   176  	return schemaRef, nil
   177  }
   178  
   179  func (r SchemaRef) MarshalJSON() ([]byte, error) {
   180  	if r.Ref != "" {
   181  		return formatRefToBytes(r.Ref), nil
   182  	}
   183  	return json.Marshal(r.Value)
   184  }