schema.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. package main
  2. import (
  3. "reflect"
  4. "sort"
  5. "strings"
  6. )
  7. type Schema struct {
  8. Name string
  9. Package string
  10. Fields []Field
  11. Doc string
  12. }
  13. type Alias struct {
  14. Name string
  15. Package string
  16. Underlying TypeRef
  17. }
  18. type Field struct {
  19. JSONName string
  20. GoName string
  21. Type TypeRef
  22. Optional bool
  23. Skip bool
  24. Validate []ValidateRule
  25. Doc string
  26. Example string
  27. }
  28. type TypeRef struct {
  29. Kind TypeKind
  30. Name string
  31. Element *TypeRef
  32. Key *TypeRef
  33. Value *TypeRef
  34. Inner *TypeRef
  35. }
  36. type TypeKind string
  37. const (
  38. KindString TypeKind = "string"
  39. KindNumber TypeKind = "number"
  40. KindInt TypeKind = "int"
  41. KindBool TypeKind = "boolean"
  42. KindArray TypeKind = "array"
  43. KindMap TypeKind = "map"
  44. KindObject TypeKind = "object"
  45. KindRef TypeKind = "ref"
  46. KindUnknown TypeKind = "unknown"
  47. KindAny TypeKind = "any"
  48. KindRaw TypeKind = "raw"
  49. )
  50. type ValidateRule struct {
  51. Name string
  52. Param string
  53. }
  54. func parseStructTag(raw string) (json string, validate string, example string, gormHasDash bool) {
  55. tag := reflect.StructTag(strings.Trim(raw, "`"))
  56. json = tag.Get("json")
  57. validate = tag.Get("validate")
  58. example = tag.Get("example")
  59. if g := tag.Get("gorm"); g != "" {
  60. for part := range strings.SplitSeq(g, ";") {
  61. if strings.TrimSpace(part) == "-" {
  62. gormHasDash = true
  63. }
  64. }
  65. }
  66. return
  67. }
  68. func parseJSONTag(tag string) (name string, omit bool, omitempty bool) {
  69. if tag == "" {
  70. return "", false, false
  71. }
  72. parts := strings.Split(tag, ",")
  73. name = parts[0]
  74. if name == "-" {
  75. return "", true, false
  76. }
  77. for _, p := range parts[1:] {
  78. if p == "omitempty" {
  79. omitempty = true
  80. }
  81. }
  82. return
  83. }
  84. func parseValidateTag(tag string) []ValidateRule {
  85. if tag == "" {
  86. return nil
  87. }
  88. var rules []ValidateRule
  89. for part := range strings.SplitSeq(tag, ",") {
  90. part = strings.TrimSpace(part)
  91. if part == "" {
  92. continue
  93. }
  94. before, after, ok := strings.Cut(part, "=")
  95. if !ok {
  96. rules = append(rules, ValidateRule{Name: part})
  97. continue
  98. }
  99. rules = append(rules, ValidateRule{Name: before, Param: after})
  100. }
  101. return rules
  102. }
  103. func (s Schema) HasValidationOn(field string) bool {
  104. for _, f := range s.Fields {
  105. if f.JSONName == field {
  106. return len(f.Validate) > 0
  107. }
  108. }
  109. return false
  110. }
  111. func sortSchemas(in []Schema) []Schema {
  112. out := make([]Schema, len(in))
  113. copy(out, in)
  114. sort.Slice(out, func(i, j int) bool {
  115. return out[i].Name < out[j].Name
  116. })
  117. return out
  118. }
  119. func sortAliases(in []Alias) []Alias {
  120. out := make([]Alias, len(in))
  121. copy(out, in)
  122. sort.Slice(out, func(i, j int) bool {
  123. return out[i].Name < out[j].Name
  124. })
  125. return out
  126. }
  127. func flattenEmbedded(schemas []Schema) []Schema {
  128. byName := make(map[string]Schema, len(schemas))
  129. for _, s := range schemas {
  130. byName[s.Name] = s
  131. }
  132. out := make([]Schema, 0, len(schemas))
  133. for _, s := range schemas {
  134. var resolved []Field
  135. seen := make(map[string]bool, len(s.Fields))
  136. for _, f := range s.Fields {
  137. if f.Type.Kind == KindRef && f.Type.Name != "nullable" {
  138. if embedded, ok := byName[f.Type.Name]; ok && f.GoName == f.Type.Name {
  139. for _, ef := range embedded.Fields {
  140. if seen[ef.JSONName] {
  141. continue
  142. }
  143. seen[ef.JSONName] = true
  144. resolved = append(resolved, ef)
  145. }
  146. continue
  147. }
  148. }
  149. if seen[f.JSONName] {
  150. continue
  151. }
  152. seen[f.JSONName] = true
  153. resolved = append(resolved, f)
  154. }
  155. s.Fields = resolved
  156. out = append(out, s)
  157. }
  158. return out
  159. }