示例#1
0
// Parse data type in context
func (p *ParamAnalyzer) parseDataType(path string, child *gen.ActionParam) gen.DataType {
	param := p.rawParams[path].(map[string]interface{})
	class := "String"
	if c, ok := param["class"].(string); ok {
		class = c
	}
	var res gen.DataType
	switch class {
	case "Integer":
		i := gen.BasicDataType("int")
		res = &i
	case "String":
		s := gen.BasicDataType("string")
		res = &s
	case "Array":
		if child != nil {
			res = &gen.ArrayDataType{child}
		} else {
			s := gen.BasicDataType("string")
			p := p.newParam(fmt.Sprintf("%s[item]", path),
				map[string]interface{}{}, &s)
			res = &gen.ArrayDataType{p}
		}
	case "Enumerable":
		res = new(gen.EnumerableDataType)
	case "Hash":
		if current, ok := p.parsed[path]; ok {
			res = current.Type
			o := res.(*gen.ObjectDataType)
			o.Fields = appendSorted(o.Fields, child)
		} else {
			oname := p.typeName(path)
			res = &gen.ObjectDataType{oname, []*gen.ActionParam{child}}
		}
	}
	return res
}
示例#2
0
// Analyze type given its json definition
func (a *ApiAnalyzer) AnalyzeType(typeDef map[string]interface{}, query string) (gen.DataType, error) {
	n, ok := typeDef["name"].(string)
	if !ok {
		n = "Struct" // Assume inline struct (e.g. payload types)
	}
	if strings.HasSuffix(n, "FileUpload") {
		// A little bit hacky but this is to make upload work with resticle
		// The idea is that a type named "FileUpload" is assumed to define a multipart
		// request with a file part.
		// The type must define a "name" and  "filename" string fields.
		t, ok := a.RawTypes[n]
		if !ok {
			return nil, fmt.Errorf("Unknown type %s for %s", n, prettify(typeDef))
		}
		attrs, ok := t["attributes"]
		if !ok {
			return nil, fmt.Errorf("Invalid file upload type %s for %s: no attributes", n, prettify(typeDef))
		}
		mattrs, ok := attrs.(map[string]interface{})
		if !ok {
			return nil, fmt.Errorf("Invalid file upload type %s for %s: basic type", n, prettify(typeDef))
		}
		_, ok = mattrs["name"]
		if !ok {
			return nil, fmt.Errorf("Invalid file upload type %s for %s: no name", n, prettify(typeDef))
		}
		_, ok = mattrs["filename"]
		if !ok {
			return nil, fmt.Errorf("Invalid file upload type %s for %s: no filename", n, prettify(typeDef))
		}
		return &gen.UploadDataType{TypeName: n}, nil
	}
	if isBuiltInType(n) {
		n = "String"
	}
	var dataType gen.DataType
	switch n {
	case "Integer":
		i := gen.BasicDataType("int")
		dataType = &i
	case "Float":
		f := gen.BasicDataType("float64")
		dataType = &f
	case "String":
		s := gen.BasicDataType("string")
		dataType = &s
	case "Boolean":
		b := gen.BasicDataType("bool")
		dataType = &b
	case "Object":
		o := gen.BasicDataType("interface{}")
		dataType = &o
	case "DateTime":
		t := gen.BasicDataType("*time.Time") // Need pointer for case where value is null
		a.descriptor.NeedTime = true
		dataType = &t
	case "Collection", "Ids":
		member, ok := typeDef["member_attribute"].(map[string]interface{})
		if !ok {
			return nil, fmt.Errorf("Missing \"member_attribute\" for %s", prettify(typeDef))
		}
		elemType, err := a.AnalyzeAttribute(n+"Member", query+"[]", member)
		if err != nil {
			return nil, fmt.Errorf("Failed to compute type of \"member_attribute\": %s", err)
		}
		dataType = &gen.ArrayDataType{elemType}
	case "Struct":
		attrs, ok := typeDef["attributes"].(map[string]interface{})
		if !ok {
			return nil, fmt.Errorf("Failed to retrieve attributes of struct for %s", prettify(typeDef))
		}
		obj, err := a.CreateType(query, attrs)
		if err != nil {
			return nil, err
		}
		dataType = obj
	case "Hash":
		keys, ok := typeDef["keys"].(map[string]interface{})
		if !ok {
			dataType = new(gen.EnumerableDataType)
		} else {
			obj, err := a.CreateType(query, keys)
			if err != nil {
				return nil, err
			}
			dataType = obj
		}
	default:
		// First check if we already analyzed that type
		if t := a.Registry.GetNamedType(n); t != nil {
			return t, nil
		}

		// No then analyze it
		t, ok := a.RawTypes[n]
		if !ok {
			return nil, fmt.Errorf("Unknown type %s for %s", n, prettify(typeDef))
		}
		attrs, ok := t["attributes"]
		if !ok {
			// No attribute, it's a string
			s := gen.BasicDataType("string")
			dataType = &s
		} else {
			att := attrs.(map[string]interface{})
			obj := a.Registry.CreateNamedType(n)
			obj.Fields = make([]*gen.ActionParam, len(att))

			for idx, an := range sortedKeys(att) {
				at := att[an]
				aq := fmt.Sprintf("%s[%s]", query, an)
				ap, err := a.AnalyzeAttribute(an, aq, at.(map[string]interface{}))
				if err != nil {
					return nil, err
				}
				obj.Fields[idx] = ap
			}

			// We're done
			dataType = obj
		}
	}

	return dataType, nil
}
示例#3
0
		analyzer = NewAnalyzer(params)
	})

	Context("with an empty path and a simple param", func() {
		BeforeEach(func() {
			path = ""
			params = map[string]interface{}{"foo": map[string]interface{}{"class": "String"}}
		})

		It("Analyze returns the parsed param", func() {
			analyzer.Analyze()
			params := analyzer.Params
			Ω(params).Should(HaveLen(1))
			param := params[0]
			Ω(param.Name).Should(Equal("foo"))
			s := gen.BasicDataType("string")
			Ω(param.Type).Should(BeEquivalentTo(&s))
		})
	})

	Context("with a simple array param", func() {
		BeforeEach(func() {
			path = ""
			params = map[string]interface{}{"foo": map[string]interface{}{"class": "Array"}}
		})

		It("Analyze returns the parsed param", func() {
			analyzer.Analyze()
			params := analyzer.Params
			Ω(params).Should(HaveLen(1))
			param := params[0]