examples_builder.go 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. // +build codegen
  2. package api
  3. import (
  4. "bytes"
  5. "fmt"
  6. "reflect"
  7. "sort"
  8. "strings"
  9. )
  10. type examplesBuilder interface {
  11. BuildShape(*ShapeRef, map[string]interface{}, bool) string
  12. BuildList(string, string, *ShapeRef, []interface{}) string
  13. BuildComplex(string, string, *ShapeRef, map[string]interface{}) string
  14. Imports(*API) string
  15. }
  16. type defaultExamplesBuilder struct{}
  17. // BuildShape will recursively build the referenced shape based on the json object
  18. // provided.
  19. // isMap will dictate how the field name is specified. If isMap is true, we will expect
  20. // the member name to be quotes like "Foo".
  21. func (builder defaultExamplesBuilder) BuildShape(ref *ShapeRef, shapes map[string]interface{}, isMap bool) string {
  22. order := make([]string, len(shapes))
  23. for k := range shapes {
  24. order = append(order, k)
  25. }
  26. sort.Strings(order)
  27. ret := ""
  28. for _, name := range order {
  29. if name == "" {
  30. continue
  31. }
  32. shape := shapes[name]
  33. // If the shape isn't a map, we want to export the value, since every field
  34. // defined in our shapes are exported.
  35. if len(name) > 0 && !isMap && strings.ToLower(name[0:1]) == name[0:1] {
  36. name = strings.Title(name)
  37. }
  38. memName := name
  39. if isMap {
  40. memName = fmt.Sprintf("%q", memName)
  41. }
  42. switch v := shape.(type) {
  43. case map[string]interface{}:
  44. ret += builder.BuildComplex(name, memName, ref, v)
  45. case []interface{}:
  46. ret += builder.BuildList(name, memName, ref, v)
  47. default:
  48. ret += builder.BuildScalar(name, memName, ref, v)
  49. }
  50. }
  51. return ret
  52. }
  53. // BuildList will construct a list shape based off the service's definition
  54. // of that list.
  55. func (builder defaultExamplesBuilder) BuildList(name, memName string, ref *ShapeRef, v []interface{}) string {
  56. ret := ""
  57. if len(v) == 0 || ref == nil {
  58. return ""
  59. }
  60. t := ""
  61. dataType := ""
  62. format := ""
  63. isComplex := false
  64. passRef := ref
  65. isMap := false
  66. if ref.Shape.MemberRefs[name] != nil {
  67. t = builder.GoType(&ref.Shape.MemberRefs[name].Shape.MemberRef, false)
  68. dataType = ref.Shape.MemberRefs[name].Shape.MemberRef.Shape.Type
  69. passRef = ref.Shape.MemberRefs[name]
  70. if dataType == "map" {
  71. t = fmt.Sprintf("map[string]%s", builder.GoType(&ref.Shape.MemberRefs[name].Shape.MemberRef.Shape.ValueRef, false))
  72. passRef = &ref.Shape.MemberRefs[name].Shape.MemberRef.Shape.ValueRef
  73. isMap = true
  74. }
  75. } else if ref.Shape.MemberRef.Shape != nil && ref.Shape.MemberRef.Shape.MemberRefs[name] != nil {
  76. t = builder.GoType(&ref.Shape.MemberRef.Shape.MemberRefs[name].Shape.MemberRef, false)
  77. dataType = ref.Shape.MemberRef.Shape.MemberRefs[name].Shape.MemberRef.Shape.Type
  78. passRef = &ref.Shape.MemberRef.Shape.MemberRefs[name].Shape.MemberRef
  79. } else {
  80. t = builder.GoType(&ref.Shape.MemberRef, false)
  81. dataType = ref.Shape.MemberRef.Shape.Type
  82. passRef = &ref.Shape.MemberRef
  83. }
  84. switch v[0].(type) {
  85. case string:
  86. format = "%s"
  87. case bool:
  88. format = "%t"
  89. case float64:
  90. if dataType == "integer" || dataType == "int64" {
  91. format = "%d"
  92. } else {
  93. format = "%f"
  94. }
  95. default:
  96. if ref.Shape.MemberRefs[name] != nil {
  97. } else {
  98. passRef = ref.Shape.MemberRef.Shape.MemberRefs[name]
  99. // if passRef is nil that means we are either in a map or within a nested array
  100. if passRef == nil {
  101. passRef = &ref.Shape.MemberRef
  102. }
  103. }
  104. isComplex = true
  105. }
  106. ret += fmt.Sprintf("%s: []%s {\n", memName, t)
  107. for _, elem := range v {
  108. if isComplex {
  109. ret += fmt.Sprintf("{\n%s\n},\n", builder.BuildShape(passRef, elem.(map[string]interface{}), isMap))
  110. } else {
  111. if dataType == "integer" || dataType == "int64" || dataType == "long" {
  112. elem = int(elem.(float64))
  113. }
  114. ret += fmt.Sprintf("%s,\n", getValue(t, fmt.Sprintf(format, elem)))
  115. }
  116. }
  117. ret += "},\n"
  118. return ret
  119. }
  120. // BuildScalar will build atomic Go types.
  121. func (builder defaultExamplesBuilder) BuildScalar(name, memName string, ref *ShapeRef, shape interface{}) string {
  122. if ref == nil || ref.Shape == nil {
  123. return ""
  124. } else if ref.Shape.MemberRefs[name] == nil {
  125. if ref.Shape.MemberRef.Shape != nil && ref.Shape.MemberRef.Shape.MemberRefs[name] != nil {
  126. return correctType(memName, ref.Shape.MemberRef.Shape.MemberRefs[name].Shape.Type, shape)
  127. }
  128. if ref.Shape.Type != "structure" && ref.Shape.Type != "map" {
  129. return correctType(memName, ref.Shape.Type, shape)
  130. }
  131. return ""
  132. }
  133. switch v := shape.(type) {
  134. case bool:
  135. return convertToCorrectType(memName, ref.Shape.MemberRefs[name].Shape.Type, fmt.Sprintf("%t", v))
  136. case int:
  137. if ref.Shape.MemberRefs[name].Shape.Type == "timestamp" {
  138. return parseTimeString(ref, memName, fmt.Sprintf("%d", v))
  139. }
  140. return convertToCorrectType(memName, ref.Shape.MemberRefs[name].Shape.Type, fmt.Sprintf("%d", v))
  141. case float64:
  142. dataType := ref.Shape.MemberRefs[name].Shape.Type
  143. if dataType == "integer" || dataType == "int64" || dataType == "long" {
  144. return convertToCorrectType(memName, ref.Shape.MemberRefs[name].Shape.Type, fmt.Sprintf("%d", int(shape.(float64))))
  145. }
  146. return convertToCorrectType(memName, ref.Shape.MemberRefs[name].Shape.Type, fmt.Sprintf("%f", v))
  147. case string:
  148. t := ref.Shape.MemberRefs[name].Shape.Type
  149. switch t {
  150. case "timestamp":
  151. return parseTimeString(ref, memName, fmt.Sprintf("%s", v))
  152. case "blob":
  153. if (ref.Shape.MemberRefs[name].Streaming || ref.Shape.MemberRefs[name].Shape.Streaming) && ref.Shape.Payload == name {
  154. return fmt.Sprintf("%s: aws.ReadSeekCloser(strings.NewReader(%q)),\n", memName, v)
  155. }
  156. return fmt.Sprintf("%s: []byte(%q),\n", memName, v)
  157. default:
  158. return convertToCorrectType(memName, t, v)
  159. }
  160. default:
  161. panic(fmt.Errorf("Unsupported scalar type: %v", reflect.TypeOf(v)))
  162. }
  163. return ""
  164. }
  165. func (builder defaultExamplesBuilder) BuildComplex(name, memName string, ref *ShapeRef, v map[string]interface{}) string {
  166. t := ""
  167. if ref == nil {
  168. return builder.BuildShape(nil, v, true)
  169. }
  170. member := ref.Shape.MemberRefs[name]
  171. if member != nil && member.Shape != nil {
  172. t = ref.Shape.MemberRefs[name].Shape.Type
  173. } else {
  174. t = ref.Shape.Type
  175. }
  176. switch t {
  177. case "structure":
  178. passRef := ref.Shape.MemberRefs[name]
  179. // passRef will be nil if the entry is a map. In that case
  180. // we want to pass the reference, because the previous call
  181. // passed the value reference.
  182. if passRef == nil {
  183. passRef = ref
  184. }
  185. return fmt.Sprintf(`%s: &%s{
  186. %s
  187. },
  188. `, memName, builder.GoType(passRef, true), builder.BuildShape(passRef, v, false))
  189. case "map":
  190. return fmt.Sprintf(`%s: %s{
  191. %s
  192. },
  193. `, name, builder.GoType(ref.Shape.MemberRefs[name], false), builder.BuildShape(&ref.Shape.MemberRefs[name].Shape.ValueRef, v, true))
  194. }
  195. return ""
  196. }
  197. func (builder defaultExamplesBuilder) GoType(ref *ShapeRef, elem bool) string {
  198. prefix := ""
  199. if ref.Shape.Type == "list" {
  200. ref = &ref.Shape.MemberRef
  201. prefix = "[]*"
  202. }
  203. name := ref.GoTypeWithPkgName()
  204. if elem {
  205. name = ref.GoTypeElem()
  206. if !strings.Contains(name, ".") {
  207. name = strings.Join([]string{ref.API.PackageName(), name}, ".")
  208. }
  209. }
  210. if ref.Shape.Type != "structure" && ref.Shape.Type != "list" {
  211. return name
  212. }
  213. return prefix + name
  214. }
  215. func (builder defaultExamplesBuilder) Imports(a *API) string {
  216. buf := bytes.NewBuffer(nil)
  217. buf.WriteString(`"fmt"
  218. "strings"
  219. "time"
  220. "github.com/aws/aws-sdk-go/aws"
  221. "github.com/aws/aws-sdk-go/aws/awserr"
  222. "github.com/aws/aws-sdk-go/aws/session"
  223. `)
  224. buf.WriteString(fmt.Sprintf("\"%s/%s\"", "github.com/aws/aws-sdk-go/service", a.PackageName()))
  225. return buf.String()
  226. }