github.com/furusax0621/goa-v1@v1.4.3/design/types.go (about)

     1  // Package design defines types which describe the data types used by action controllers.
     2  // These are the data structures of the request payloads and parameters as well as the response
     3  // payloads.
     4  // There are primitive types corresponding to the JSON primitive types (bool, string, integer and
     5  // number), array types which represent a collection of another type and object types corresponding
     6  // to JSON objects (i.e. a map indexed by strings where each value may be any of the data types).
     7  // On top of these the package also defines "user types" and "media types". Both these types are
     8  // named objects with additional properties (a description and for media types the media type
     9  // identifier, links and views).
    10  package design
    11  
    12  import (
    13  	"fmt"
    14  	"mime"
    15  	"reflect"
    16  	"sort"
    17  	"strings"
    18  	"time"
    19  
    20  	"github.com/goadesign/goa/dslengine"
    21  	"github.com/gofrs/uuid"
    22  )
    23  
    24  // DefaultView is the name of the default view.
    25  const DefaultView = "default"
    26  
    27  // It returns the default view - or if not available the link view - or if not available the first
    28  // view by alphabetical order.
    29  type (
    30  	// A Kind defines the JSON type that a DataType represents.
    31  	Kind uint
    32  
    33  	// DataType is the common interface to all types.
    34  	DataType interface {
    35  		// Kind of data type, one of the Kind enum.
    36  		Kind() Kind
    37  		// Name returns the type name.
    38  		Name() string
    39  		// IsPrimitive returns true if the underlying type is one of the primitive types.
    40  		IsPrimitive() bool
    41  		// HasAttributes returns true if the underlying type has any attributes.
    42  		HasAttributes() bool
    43  		// IsObject returns true if the underlying type is an object, a user type which
    44  		// is an object or a media type whose type is an object.
    45  		IsObject() bool
    46  		// IsArray returns true if the underlying type is an array, a user type which
    47  		// is an array or a media type whose type is an array.
    48  		IsArray() bool
    49  		// IsHash returns true if the underlying type is a hash map, a user type which
    50  		// is a hash map or a media type whose type is a hash map.
    51  		IsHash() bool
    52  		// ToObject returns the underlying object if any (i.e. if IsObject returns true),
    53  		// nil otherwise.
    54  		ToObject() Object
    55  		// ToArray returns the underlying array if any (i.e. if IsArray returns true),
    56  		// nil otherwise.
    57  		ToArray() *Array
    58  		// ToHash returns the underlying hash map if any (i.e. if IsHash returns true),
    59  		// nil otherwise.
    60  		ToHash() *Hash
    61  		// CanHaveDefault returns whether the data type can have a default value.
    62  		CanHaveDefault() bool
    63  		// IsCompatible checks whether val has a Go type that is
    64  		// compatible with the data type.
    65  		IsCompatible(val interface{}) bool
    66  		// GenerateExample returns a random value for the given data type.
    67  		// If the data type has validations then the example value validates them.
    68  		// seen keeps track of the user and media types that have been traversed via
    69  		// recursion to prevent infinite loops.
    70  		GenerateExample(r *RandomGenerator, seen []string) interface{}
    71  	}
    72  
    73  	// DataStructure is the interface implemented by all data structure types.
    74  	// That is attribute definitions, user types and media types.
    75  	DataStructure interface {
    76  		// Definition returns the data structure definition.
    77  		Definition() *AttributeDefinition
    78  		// Walk traverses the data structure recursively and calls the given function once
    79  		// on each attribute starting with the attribute returned by Definition.
    80  		// User type and media type attributes are traversed once even for recursive
    81  		// definitions to avoid infinite recursion.
    82  		// Walk stops and returns the error if the function returns a non-nil error.
    83  		Walk(func(*AttributeDefinition) error) error
    84  	}
    85  
    86  	// Primitive is the type for null, boolean, integer, number, string, and time.
    87  	Primitive Kind
    88  
    89  	// Array is the type for a JSON array.
    90  	Array struct {
    91  		ElemType *AttributeDefinition
    92  	}
    93  
    94  	// ArrayVal is the value of an array used to specify the default value.
    95  	ArrayVal []interface{}
    96  
    97  	// Object is the type for a JSON object.
    98  	Object map[string]*AttributeDefinition
    99  
   100  	// Hash is the type for a hash map.
   101  	Hash struct {
   102  		KeyType  *AttributeDefinition
   103  		ElemType *AttributeDefinition
   104  	}
   105  
   106  	// HashVal is the value of a hash used to specify the default value.
   107  	HashVal map[interface{}]interface{}
   108  
   109  	// UserTypeDefinition is the type for user defined types that are not media types
   110  	// (e.g. payload types).
   111  	UserTypeDefinition struct {
   112  		// A user type is an attribute definition.
   113  		*AttributeDefinition
   114  		// Name of type
   115  		TypeName string
   116  	}
   117  
   118  	// MediaTypeDefinition describes the rendering of a resource using property and link
   119  	// definitions. A property corresponds to a single member of the media type,
   120  	// it has a name and a type as well as optional validation rules. A link has a
   121  	// name and a URL that points to a related resource.
   122  	// Media types also define views which describe which members and links to render when
   123  	// building the response body for the corresponding view.
   124  	MediaTypeDefinition struct {
   125  		// A media type is a type
   126  		*UserTypeDefinition
   127  		// Identifier is the RFC 6838 media type identifier.
   128  		Identifier string
   129  		// ContentType identifies the value written to the response "Content-Type" header.
   130  		// Defaults to Identifier.
   131  		ContentType string
   132  		// Links list the rendered links indexed by name.
   133  		Links map[string]*LinkDefinition
   134  		// Views list the supported views indexed by name.
   135  		Views map[string]*ViewDefinition
   136  		// Resource this media type is the canonical representation for if any
   137  		Resource *ResourceDefinition
   138  	}
   139  )
   140  
   141  const (
   142  	// BooleanKind represents a JSON bool.
   143  	BooleanKind Kind = iota + 1
   144  	// IntegerKind represents a JSON integer.
   145  	IntegerKind
   146  	// NumberKind represents a JSON number including integers.
   147  	NumberKind
   148  	// StringKind represents a JSON string.
   149  	StringKind
   150  	// DateTimeKind represents a JSON string that is parsed as a Go time.Time
   151  	DateTimeKind
   152  	// UUIDKind represents a JSON string that is parsed as a Go uuid.UUID
   153  	UUIDKind
   154  	// AnyKind represents a generic interface{}.
   155  	AnyKind
   156  	// ArrayKind represents a JSON array.
   157  	ArrayKind
   158  	// ObjectKind represents a JSON object.
   159  	ObjectKind
   160  	// HashKind represents a JSON object where the keys are not known in advance.
   161  	HashKind
   162  	// UserTypeKind represents a user type.
   163  	UserTypeKind
   164  	// MediaTypeKind represents a media type.
   165  	MediaTypeKind
   166  	// FileKind represents a file.
   167  	FileKind
   168  )
   169  
   170  const (
   171  	// Boolean is the type for a JSON boolean.
   172  	Boolean = Primitive(BooleanKind)
   173  
   174  	// Integer is the type for a JSON number without a fraction or exponent part.
   175  	Integer = Primitive(IntegerKind)
   176  
   177  	// Number is the type for any JSON number, including integers.
   178  	Number = Primitive(NumberKind)
   179  
   180  	// String is the type for a JSON string.
   181  	String = Primitive(StringKind)
   182  
   183  	// DateTime is the type for a JSON string parsed as a Go time.Time
   184  	// DateTime expects an RFC3339 formatted value.
   185  	DateTime = Primitive(DateTimeKind)
   186  
   187  	// UUID is the type for a JSON string parsed as a Go uuid.UUID
   188  	// UUID expects an RFC4122 formatted value.
   189  	UUID = Primitive(UUIDKind)
   190  
   191  	// Any is the type for an arbitrary JSON value (interface{} in Go).
   192  	Any = Primitive(AnyKind)
   193  
   194  	// File is the type for a file. This type can only be used in a multipart definition.
   195  	File = Primitive(FileKind)
   196  )
   197  
   198  // DataType implementation
   199  
   200  // Kind implements DataKind.
   201  func (p Primitive) Kind() Kind { return Kind(p) }
   202  
   203  // Name returns the JSON type name.
   204  func (p Primitive) Name() string {
   205  	switch p {
   206  	case Boolean:
   207  		return "boolean"
   208  	case Integer:
   209  		return "integer"
   210  	case Number:
   211  		return "number"
   212  	case String, DateTime, UUID:
   213  		return "string"
   214  	case Any:
   215  		return "any"
   216  	case File:
   217  		return "file"
   218  	default:
   219  		panic("unknown primitive type") // bug
   220  	}
   221  }
   222  
   223  // IsPrimitive returns true.
   224  func (p Primitive) IsPrimitive() bool { return true }
   225  
   226  // HasAttributes returns false.
   227  func (p Primitive) HasAttributes() bool { return false }
   228  
   229  // IsObject returns false.
   230  func (p Primitive) IsObject() bool { return false }
   231  
   232  // IsArray returns false.
   233  func (p Primitive) IsArray() bool { return false }
   234  
   235  // IsHash returns false.
   236  func (p Primitive) IsHash() bool { return false }
   237  
   238  // ToObject returns nil.
   239  func (p Primitive) ToObject() Object { return nil }
   240  
   241  // ToArray returns nil.
   242  func (p Primitive) ToArray() *Array { return nil }
   243  
   244  // ToHash returns nil.
   245  func (p Primitive) ToHash() *Hash { return nil }
   246  
   247  // CanHaveDefault returns whether the primitive can have a default value.
   248  func (p Primitive) CanHaveDefault() (ok bool) {
   249  	switch p {
   250  	case Boolean, Integer, Number, String, DateTime:
   251  		ok = true
   252  	}
   253  	return
   254  }
   255  
   256  // IsCompatible returns true if val is compatible with p.
   257  func (p Primitive) IsCompatible(val interface{}) bool {
   258  	if p != Boolean && p != Integer && p != Number && p != String && p != DateTime && p != UUID && p != Any {
   259  		panic("unknown primitive type") // bug
   260  	}
   261  	if p == Any {
   262  		return true
   263  	}
   264  	switch val.(type) {
   265  	case bool:
   266  		return p == Boolean
   267  	case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
   268  		return p == Integer || p == Number
   269  	case float32, float64:
   270  		return p == Number
   271  	case string:
   272  		if p == String {
   273  			return true
   274  		}
   275  		if p == DateTime {
   276  			_, err := time.Parse(time.RFC3339, val.(string))
   277  			return err == nil
   278  		}
   279  		if p == UUID {
   280  			_, err := uuid.FromString(val.(string))
   281  			return err == nil
   282  		}
   283  	}
   284  	return false
   285  }
   286  
   287  var anyPrimitive = []Primitive{Boolean, Integer, Number, DateTime, UUID}
   288  
   289  // GenerateExample returns an instance of the given data type.
   290  func (p Primitive) GenerateExample(r *RandomGenerator, seen []string) interface{} {
   291  	switch p {
   292  	case Boolean:
   293  		return r.Bool()
   294  	case Integer:
   295  		return r.Int()
   296  	case Number:
   297  		return r.Float64()
   298  	case String:
   299  		return r.String()
   300  	case DateTime:
   301  		return r.DateTime()
   302  	case UUID:
   303  		return r.UUID().String() // Generate string to can be JSON marshaled
   304  	case Any:
   305  		// to not make it too complicated, pick one of the primitive types
   306  		return anyPrimitive[r.Int()%len(anyPrimitive)].GenerateExample(r, seen)
   307  	case File:
   308  		return r.File()
   309  	default:
   310  		panic("unknown primitive type") // bug
   311  	}
   312  }
   313  
   314  // Kind implements DataKind.
   315  func (a *Array) Kind() Kind { return ArrayKind }
   316  
   317  // Name returns the type name.
   318  func (a *Array) Name() string {
   319  	return "array"
   320  }
   321  
   322  // IsPrimitive returns false.
   323  func (a *Array) IsPrimitive() bool { return false }
   324  
   325  // HasAttributes returns true if the array's element type is user defined.
   326  func (a *Array) HasAttributes() bool {
   327  	return a.ElemType.Type.HasAttributes()
   328  }
   329  
   330  // IsObject returns false.
   331  func (a *Array) IsObject() bool { return false }
   332  
   333  // IsArray returns true.
   334  func (a *Array) IsArray() bool { return true }
   335  
   336  // IsHash returns false.
   337  func (a *Array) IsHash() bool { return false }
   338  
   339  // ToObject returns nil.
   340  func (a *Array) ToObject() Object { return nil }
   341  
   342  // ToArray returns a.
   343  func (a *Array) ToArray() *Array { return a }
   344  
   345  // ToHash returns nil.
   346  func (a *Array) ToHash() *Hash { return nil }
   347  
   348  // CanHaveDefault returns true if the array type can have a default value.
   349  // The array type can have a default value only if the element type can
   350  // have a default value.
   351  func (a *Array) CanHaveDefault() bool {
   352  	return a.ElemType.Type.CanHaveDefault()
   353  }
   354  
   355  // IsCompatible returns true if val is compatible with p.
   356  func (a *Array) IsCompatible(val interface{}) bool {
   357  	k := reflect.TypeOf(val).Kind()
   358  	if k != reflect.Array && k != reflect.Slice {
   359  		return false
   360  	}
   361  	v := reflect.ValueOf(val)
   362  	for i := 0; i < v.Len(); i++ {
   363  		compat := (a.ElemType.Type != nil) && a.ElemType.Type.IsCompatible(v.Index(i).Interface())
   364  		if !compat {
   365  			return false
   366  		}
   367  	}
   368  	return true
   369  }
   370  
   371  // GenerateExample produces a random array value.
   372  func (a *Array) GenerateExample(r *RandomGenerator, seen []string) interface{} {
   373  	count := r.Int()%3 + 1
   374  	res := make([]interface{}, count)
   375  	for i := 0; i < count; i++ {
   376  		res[i] = a.ElemType.Type.GenerateExample(r, seen)
   377  	}
   378  	return a.MakeSlice(res)
   379  }
   380  
   381  // MakeSlice examines the key type from the Array and create a slice with builtin type if possible.
   382  // The idea is to avoid generating []interface{} and produce more known types.
   383  func (a *Array) MakeSlice(s []interface{}) interface{} {
   384  	slice := reflect.MakeSlice(toReflectType(a), 0, len(s))
   385  	for _, item := range s {
   386  		slice = reflect.Append(slice, reflect.ValueOf(item))
   387  	}
   388  	return slice.Interface()
   389  }
   390  
   391  // Kind implements DataKind.
   392  func (o Object) Kind() Kind { return ObjectKind }
   393  
   394  // Name returns the type name.
   395  func (o Object) Name() string { return "object" }
   396  
   397  // IsPrimitive returns false.
   398  func (o Object) IsPrimitive() bool { return false }
   399  
   400  // HasAttributes returns true.
   401  func (o Object) HasAttributes() bool { return true }
   402  
   403  // IsObject returns true.
   404  func (o Object) IsObject() bool { return true }
   405  
   406  // IsArray returns false.
   407  func (o Object) IsArray() bool { return false }
   408  
   409  // IsHash returns false.
   410  func (o Object) IsHash() bool { return false }
   411  
   412  // ToObject returns the underlying object.
   413  func (o Object) ToObject() Object { return o }
   414  
   415  // ToArray returns nil.
   416  func (o Object) ToArray() *Array { return nil }
   417  
   418  // ToHash returns nil.
   419  func (o Object) ToHash() *Hash { return nil }
   420  
   421  // CanHaveDefault returns false.
   422  func (o Object) CanHaveDefault() bool { return false }
   423  
   424  // Merge copies other's attributes into o overridding any pre-existing attribute with the same name.
   425  func (o Object) Merge(other Object) {
   426  	for n, att := range other {
   427  		o[n] = DupAtt(att)
   428  	}
   429  }
   430  
   431  // IsCompatible returns true if val is compatible with p.
   432  func (o Object) IsCompatible(val interface{}) bool {
   433  	k := reflect.TypeOf(val).Kind()
   434  	return k == reflect.Map || k == reflect.Struct
   435  }
   436  
   437  // GenerateExample returns a random value of the object.
   438  func (o Object) GenerateExample(r *RandomGenerator, seen []string) interface{} {
   439  	// ensure fixed ordering
   440  	keys := make([]string, 0, len(o))
   441  	for n := range o {
   442  		keys = append(keys, n)
   443  	}
   444  	sort.Strings(keys)
   445  
   446  	res := make(map[string]interface{})
   447  	for _, n := range keys {
   448  		att := o[n]
   449  		res[n] = att.Type.GenerateExample(r, seen)
   450  	}
   451  	return res
   452  }
   453  
   454  // Kind implements DataKind.
   455  func (h *Hash) Kind() Kind { return HashKind }
   456  
   457  // Name returns the type name.
   458  func (h *Hash) Name() string { return "hash" }
   459  
   460  // IsPrimitive returns false.
   461  func (h *Hash) IsPrimitive() bool { return false }
   462  
   463  // HasAttributes returns true if the either hash's key type is user defined
   464  // or the element type is user defined.
   465  func (h *Hash) HasAttributes() bool {
   466  	return h.KeyType.Type.HasAttributes() || h.ElemType.Type.HasAttributes()
   467  }
   468  
   469  // IsObject returns false.
   470  func (h *Hash) IsObject() bool { return false }
   471  
   472  // IsArray returns false.
   473  func (h *Hash) IsArray() bool { return false }
   474  
   475  // IsHash returns true.
   476  func (h *Hash) IsHash() bool { return true }
   477  
   478  // ToObject returns nil.
   479  func (h *Hash) ToObject() Object { return nil }
   480  
   481  // ToArray returns nil.
   482  func (h *Hash) ToArray() *Array { return nil }
   483  
   484  // ToHash returns the underlying hash map.
   485  func (h *Hash) ToHash() *Hash { return h }
   486  
   487  // CanHaveDefault returns true if the hash type can have a default value.
   488  // The hash type can have a default value only if both the key type and
   489  // the element type can have a default value.
   490  func (h *Hash) CanHaveDefault() bool {
   491  	return h.KeyType.Type.CanHaveDefault() && h.ElemType.Type.CanHaveDefault()
   492  }
   493  
   494  // IsCompatible returns true if val is compatible with p.
   495  func (h *Hash) IsCompatible(val interface{}) bool {
   496  	k := reflect.TypeOf(val).Kind()
   497  	if k != reflect.Map {
   498  		return false
   499  	}
   500  	v := reflect.ValueOf(val)
   501  	for _, key := range v.MapKeys() {
   502  		keyCompat := h.KeyType.Type == nil || h.KeyType.Type.IsCompatible(key.Interface())
   503  		elemCompat := h.ElemType.Type == nil || h.ElemType.Type.IsCompatible(v.MapIndex(key).Interface())
   504  		if !keyCompat || !elemCompat {
   505  			return false
   506  		}
   507  	}
   508  	return true
   509  }
   510  
   511  // GenerateExample returns a random hash value.
   512  func (h *Hash) GenerateExample(r *RandomGenerator, seen []string) interface{} {
   513  	count := r.Int()%3 + 1
   514  	pair := map[interface{}]interface{}{}
   515  	for i := 0; i < count; i++ {
   516  		pair[h.KeyType.Type.GenerateExample(r, seen)] = h.ElemType.Type.GenerateExample(r, seen)
   517  	}
   518  	return h.MakeMap(pair)
   519  }
   520  
   521  // MakeMap examines the key type from a Hash and create a map with builtin type if possible.
   522  // The idea is to avoid generating map[interface{}]interface{}, which cannot be handled by json.Marshal.
   523  func (h *Hash) MakeMap(m map[interface{}]interface{}) interface{} {
   524  	hash := reflect.MakeMap(toReflectType(h))
   525  	for key, value := range m {
   526  		hash.SetMapIndex(reflect.ValueOf(key), reflect.ValueOf(value))
   527  	}
   528  	return hash.Interface()
   529  }
   530  
   531  // AttributeIterator is the type of the function given to IterateAttributes.
   532  type AttributeIterator func(string, *AttributeDefinition) error
   533  
   534  // IterateAttributes calls the given iterator passing in each attribute sorted in alphabetical order.
   535  // Iteration stops if an iterator returns an error and in this case IterateObject returns that
   536  // error.
   537  func (o Object) IterateAttributes(it AttributeIterator) error {
   538  	names := make([]string, len(o))
   539  	i := 0
   540  	for n := range o {
   541  		names[i] = n
   542  		i++
   543  	}
   544  	sort.Strings(names)
   545  	for _, n := range names {
   546  		if err := it(n, o[n]); err != nil {
   547  			return err
   548  		}
   549  	}
   550  	return nil
   551  }
   552  
   553  // UserTypes traverses the data type recursively and collects all the user types used to
   554  // define it. The returned map is indexed by type name.
   555  func UserTypes(dt DataType) map[string]*UserTypeDefinition {
   556  	collect := func(types map[string]*UserTypeDefinition) func(*AttributeDefinition) error {
   557  		return func(at *AttributeDefinition) error {
   558  			if u, ok := at.Type.(*UserTypeDefinition); ok {
   559  				types[u.TypeName] = u
   560  			} else if m, ok := at.Type.(*MediaTypeDefinition); ok {
   561  				types[m.TypeName] = m.UserTypeDefinition
   562  			}
   563  			return nil
   564  		}
   565  	}
   566  	switch actual := dt.(type) {
   567  	case Primitive:
   568  		return nil
   569  	case *Array:
   570  		return UserTypes(actual.ElemType.Type)
   571  	case *Hash:
   572  		ktypes := UserTypes(actual.KeyType.Type)
   573  		vtypes := UserTypes(actual.ElemType.Type)
   574  		if vtypes == nil {
   575  			return ktypes
   576  		}
   577  		for n, ut := range ktypes {
   578  			vtypes[n] = ut
   579  		}
   580  		return vtypes
   581  	case Object:
   582  		types := make(map[string]*UserTypeDefinition)
   583  		for _, att := range actual {
   584  			att.Walk(collect(types))
   585  		}
   586  		if len(types) == 0 {
   587  			return nil
   588  		}
   589  		return types
   590  	case *UserTypeDefinition:
   591  		types := map[string]*UserTypeDefinition{actual.TypeName: actual}
   592  		actual.Walk(collect(types))
   593  		return types
   594  	case *MediaTypeDefinition:
   595  		types := map[string]*UserTypeDefinition{actual.TypeName: actual.UserTypeDefinition}
   596  		actual.Walk(collect(types))
   597  		return types
   598  	default:
   599  		panic("unknown type") // bug
   600  	}
   601  }
   602  
   603  // HasFile returns true if the underlying type has any file attributes.
   604  func HasFile(dt DataType) bool {
   605  	return hasFile(dt, nil)
   606  }
   607  
   608  func hasFile(dt DataType, seen map[string]struct{}) bool {
   609  	if dt == nil {
   610  		return false
   611  	}
   612  	switch {
   613  	case dt.IsPrimitive():
   614  		return dt.Kind() == FileKind
   615  	case dt.IsArray():
   616  		et := dt.ToArray().ElemType.Type
   617  		if _, ok := seen[et.Name()]; ok {
   618  			return false
   619  		}
   620  		return hasFile(et, seen)
   621  	case dt.IsHash():
   622  		if hasFile(dt.ToHash().KeyType.Type, seen) {
   623  			return true
   624  		}
   625  		return hasFile(dt.ToHash().ElemType.Type, seen)
   626  	case dt.IsObject():
   627  		if _, ok := seen[dt.Name()]; ok {
   628  			return false
   629  		}
   630  		if seen == nil {
   631  			seen = make(map[string]struct{})
   632  		}
   633  		seen[dt.Name()] = struct{}{}
   634  		for _, att := range dt.ToObject() {
   635  			if hasFile(att.Type, seen) {
   636  				return true
   637  			}
   638  		}
   639  	default:
   640  		panic("unknown type") // bug
   641  	}
   642  	return false
   643  }
   644  
   645  // ToSlice converts an ArrayVal to a slice.
   646  func (a ArrayVal) ToSlice() []interface{} {
   647  	arr := make([]interface{}, len(a))
   648  	for i, elem := range a {
   649  		switch actual := elem.(type) {
   650  		case ArrayVal:
   651  			arr[i] = actual.ToSlice()
   652  		case HashVal:
   653  			arr[i] = actual.ToMap()
   654  		default:
   655  			arr[i] = actual
   656  		}
   657  	}
   658  	return arr
   659  }
   660  
   661  // ToMap converts a HashVal to a map.
   662  func (h HashVal) ToMap() map[interface{}]interface{} {
   663  	mp := make(map[interface{}]interface{}, len(h))
   664  	for k, v := range h {
   665  		switch actual := v.(type) {
   666  		case ArrayVal:
   667  			mp[k] = actual.ToSlice()
   668  		case HashVal:
   669  			mp[k] = actual.ToMap()
   670  		default:
   671  			mp[k] = actual
   672  		}
   673  	}
   674  	return mp
   675  }
   676  
   677  // NewUserTypeDefinition creates a user type definition but does not
   678  // execute the DSL.
   679  func NewUserTypeDefinition(name string, dsl func()) *UserTypeDefinition {
   680  	return &UserTypeDefinition{
   681  		TypeName:            name,
   682  		AttributeDefinition: &AttributeDefinition{DSLFunc: dsl},
   683  	}
   684  }
   685  
   686  // Kind implements DataKind.
   687  func (u *UserTypeDefinition) Kind() Kind { return UserTypeKind }
   688  
   689  // Name returns the JSON type name.
   690  func (u *UserTypeDefinition) Name() string { return u.Type.Name() }
   691  
   692  // IsPrimitive calls IsPrimitive on the user type underlying data type.
   693  func (u *UserTypeDefinition) IsPrimitive() bool { return u.Type != nil && u.Type.IsPrimitive() }
   694  
   695  // HasAttributes calls the HasAttributes on the user type underlying data type.
   696  func (u *UserTypeDefinition) HasAttributes() bool { return u.Type.HasAttributes() }
   697  
   698  // IsObject calls IsObject on the user type underlying data type.
   699  func (u *UserTypeDefinition) IsObject() bool { return u.Type != nil && u.Type.IsObject() }
   700  
   701  // IsArray calls IsArray on the user type underlying data type.
   702  func (u *UserTypeDefinition) IsArray() bool { return u.Type != nil && u.Type.IsArray() }
   703  
   704  // IsHash calls IsHash on the user type underlying data type.
   705  func (u *UserTypeDefinition) IsHash() bool { return u.Type != nil && u.Type.IsHash() }
   706  
   707  // ToObject calls ToObject on the user type underlying data type.
   708  func (u *UserTypeDefinition) ToObject() Object { return u.Type.ToObject() }
   709  
   710  // ToArray calls ToArray on the user type underlying data type.
   711  func (u *UserTypeDefinition) ToArray() *Array { return u.Type.ToArray() }
   712  
   713  // ToHash calls ToHash on the user type underlying data type.
   714  func (u *UserTypeDefinition) ToHash() *Hash { return u.Type.ToHash() }
   715  
   716  // CanHaveDefault calls CanHaveDefault on the user type underlying data type.
   717  func (u *UserTypeDefinition) CanHaveDefault() bool { return u.Type.CanHaveDefault() }
   718  
   719  // IsCompatible returns true if val is compatible with u.
   720  func (u *UserTypeDefinition) IsCompatible(val interface{}) bool {
   721  	return u.Type == nil || u.Type.IsCompatible(val)
   722  }
   723  
   724  // Finalize merges base type attributes.
   725  func (u *UserTypeDefinition) Finalize() {
   726  	if u.Reference != nil {
   727  		if bat := u.AttributeDefinition; bat != nil {
   728  			u.AttributeDefinition.Inherit(bat)
   729  		}
   730  	}
   731  
   732  	u.GenerateExample(Design.RandomGenerator(), nil)
   733  }
   734  
   735  // NewMediaTypeDefinition creates a media type definition but does not
   736  // execute the DSL.
   737  func NewMediaTypeDefinition(name, identifier string, dsl func()) *MediaTypeDefinition {
   738  	return &MediaTypeDefinition{
   739  		UserTypeDefinition: &UserTypeDefinition{
   740  			AttributeDefinition: &AttributeDefinition{Type: Object{}, DSLFunc: dsl},
   741  			TypeName:            name,
   742  		},
   743  		Identifier: identifier,
   744  	}
   745  }
   746  
   747  // Kind implements DataKind.
   748  func (m *MediaTypeDefinition) Kind() Kind { return MediaTypeKind }
   749  
   750  // IsError returns true if the media type is implemented via a goa struct.
   751  func (m *MediaTypeDefinition) IsError() bool {
   752  	base, params, err := mime.ParseMediaType(m.Identifier)
   753  	if err != nil {
   754  		panic("invalid media type identifier " + m.Identifier) // bug
   755  	}
   756  	delete(params, "view")
   757  	return mime.FormatMediaType(base, params) == ErrorMedia.Identifier
   758  }
   759  
   760  // ComputeViews returns the media type views recursing as necessary if the media type is a
   761  // collection.
   762  func (m *MediaTypeDefinition) ComputeViews() map[string]*ViewDefinition {
   763  	if m.Views != nil {
   764  		return m.Views
   765  	}
   766  	if m.IsArray() {
   767  		if mt, ok := m.ToArray().ElemType.Type.(*MediaTypeDefinition); ok {
   768  			return mt.ComputeViews()
   769  		}
   770  	}
   771  	return nil
   772  }
   773  
   774  // Finalize sets the value of ContentType to the identifier if not set.
   775  func (m *MediaTypeDefinition) Finalize() {
   776  	if m.ContentType == "" {
   777  		m.ContentType = m.Identifier
   778  	}
   779  	m.UserTypeDefinition.Finalize()
   780  }
   781  
   782  // ViewIterator is the type of the function given to IterateViews.
   783  type ViewIterator func(*ViewDefinition) error
   784  
   785  // IterateViews calls the given iterator passing in each attribute sorted in alphabetical order.
   786  // Iteration stops if an iterator returns an error and in this case IterateViews returns that
   787  // error.
   788  func (m *MediaTypeDefinition) IterateViews(it ViewIterator) error {
   789  	o := m.Views
   790  	// gather names and sort them
   791  	names := make([]string, len(o))
   792  	i := 0
   793  	for n := range o {
   794  		names[i] = n
   795  		i++
   796  	}
   797  	sort.Strings(names)
   798  	// iterate
   799  	for _, n := range names {
   800  		if err := it(o[n]); err != nil {
   801  			return err
   802  		}
   803  	}
   804  	return nil
   805  }
   806  
   807  // Project creates a MediaTypeDefinition containing the fields defined in the given view.  The
   808  // resuling media type only defines the default view and its identifier is modified to indicate that
   809  // it was projected by adding the view as id parameter.  links is a user type of type Object where
   810  // each key corresponds to a linked media type as defined by the media type "links" attribute.
   811  func (m *MediaTypeDefinition) Project(view string) (*MediaTypeDefinition, *UserTypeDefinition, error) {
   812  	canonical := m.projectCanonical(view)
   813  	if p, ok := ProjectedMediaTypes[canonical]; ok {
   814  		var links *UserTypeDefinition
   815  		mLinks := ProjectedMediaTypes[canonical+"; links"]
   816  		if mLinks != nil {
   817  			links = mLinks.UserTypeDefinition
   818  		}
   819  		return p, links, nil
   820  	}
   821  	if m.IsArray() {
   822  		return m.projectCollection(view)
   823  	}
   824  	return m.projectSingle(view, canonical)
   825  }
   826  
   827  func (m *MediaTypeDefinition) projectSingle(view, canonical string) (p *MediaTypeDefinition, links *UserTypeDefinition, err error) {
   828  	v, ok := m.Views[view]
   829  	if !ok {
   830  		return nil, nil, fmt.Errorf("unknown view %#v", view)
   831  	}
   832  	viewObj := v.Type.ToObject()
   833  
   834  	// Compute validations - view may not have all attributes
   835  	var val *dslengine.ValidationDefinition
   836  	if m.Validation != nil {
   837  		names := m.Validation.Required
   838  		var required []string
   839  		for _, n := range names {
   840  			if _, ok := viewObj[n]; ok {
   841  				required = append(required, n)
   842  			}
   843  		}
   844  		val = m.Validation.Dup()
   845  		val.Required = required
   846  	}
   847  
   848  	// Compute description
   849  	desc := m.Description
   850  	if desc == "" {
   851  		desc = m.TypeName + " media type"
   852  	}
   853  	desc += " (" + view + " view)"
   854  
   855  	p = &MediaTypeDefinition{
   856  		Identifier: m.projectIdentifier(view),
   857  		UserTypeDefinition: &UserTypeDefinition{
   858  			TypeName: m.projectTypeName(view),
   859  			AttributeDefinition: &AttributeDefinition{
   860  				Description: desc,
   861  				Type:        Dup(v.Type),
   862  				Validation:  val,
   863  			},
   864  		},
   865  	}
   866  	p.Views = map[string]*ViewDefinition{"default": {
   867  		Name:                "default",
   868  		AttributeDefinition: DupAtt(v.AttributeDefinition),
   869  		Parent:              p,
   870  	}}
   871  
   872  	ProjectedMediaTypes[canonical] = p
   873  	projectedObj := p.Type.ToObject()
   874  	mtObj := m.Type.ToObject()
   875  	_, hasAttNamedLinks := mtObj["links"]
   876  	for n := range viewObj {
   877  		if n == "links" && !hasAttNamedLinks {
   878  			linkObj := make(Object)
   879  			for n, link := range m.Links {
   880  				linkView := link.View
   881  				if linkView == "" {
   882  					linkView = "link"
   883  				}
   884  				mtAtt, ok := mtObj[n]
   885  				if !ok {
   886  					return nil, nil, fmt.Errorf("unknown attribute %#v used in links", n)
   887  				}
   888  				mtt := mtAtt.Type.(*MediaTypeDefinition)
   889  				vl, _, err := mtt.Project(linkView)
   890  				if err != nil {
   891  					return nil, nil, err
   892  				}
   893  				linkObj[n] = &AttributeDefinition{Type: vl, Validation: mtt.Validation, Metadata: mtAtt.Metadata}
   894  			}
   895  			lTypeName := fmt.Sprintf("%sLinks", m.TypeName)
   896  			links = &UserTypeDefinition{
   897  				AttributeDefinition: &AttributeDefinition{
   898  					Description: fmt.Sprintf("%s contains links to related resources of %s.", lTypeName, m.TypeName),
   899  					Type:        linkObj,
   900  				},
   901  				TypeName: lTypeName,
   902  			}
   903  			projectedObj[n] = &AttributeDefinition{Type: links, Description: "Links to related resources"}
   904  			ProjectedMediaTypes[canonical+"; links"] = &MediaTypeDefinition{UserTypeDefinition: links}
   905  		} else {
   906  			if at := mtObj[n]; at != nil {
   907  				at = DupAtt(at)
   908  				if mt, ok := at.Type.(*MediaTypeDefinition); ok {
   909  					vatt := viewObj[n]
   910  					view := vatt.View
   911  					if view == "" {
   912  						view = at.View
   913  					}
   914  					if view == "" {
   915  						view = DefaultView
   916  					}
   917  					pr, _, err := mt.Project(view)
   918  					if err != nil {
   919  						return nil, nil, fmt.Errorf("view %#v on field %#v cannot be computed: %s", view, n, err)
   920  					}
   921  					at.Type = pr
   922  					// Force example to be generated again
   923  					// since set of attributes has changed
   924  					at.Example = nil
   925  				}
   926  				projectedObj[n] = at
   927  			}
   928  		}
   929  	}
   930  	return
   931  }
   932  
   933  func (m *MediaTypeDefinition) projectCollection(view string) (*MediaTypeDefinition, *UserTypeDefinition, error) {
   934  	// Project the collection element media type
   935  	e := m.ToArray().ElemType.Type.(*MediaTypeDefinition) // validation checked this cast would work
   936  	pe, le, err2 := e.Project(view)
   937  	if err2 != nil {
   938  		return nil, nil, fmt.Errorf("collection element: %s", err2)
   939  	}
   940  
   941  	// Build the projected collection with the results
   942  	desc := m.TypeName + " is the media type for an array of " + e.TypeName + " (" + view + " view)"
   943  	p := &MediaTypeDefinition{
   944  		Identifier: m.projectIdentifier(view),
   945  		UserTypeDefinition: &UserTypeDefinition{
   946  			AttributeDefinition: &AttributeDefinition{
   947  				Description: desc,
   948  				Type:        &Array{ElemType: &AttributeDefinition{Type: pe}},
   949  				Example:     nil,
   950  			},
   951  			TypeName: pe.TypeName + "Collection",
   952  		},
   953  	}
   954  	p.Views = map[string]*ViewDefinition{"default": {
   955  		AttributeDefinition: DupAtt(pe.Views["default"].AttributeDefinition),
   956  		Name:                "default",
   957  		Parent:              p,
   958  	}}
   959  
   960  	// Run the DSL that was created by the CollectionOf function
   961  	if !dslengine.Execute(p.DSL(), p) {
   962  		return nil, nil, dslengine.Errors
   963  	}
   964  
   965  	// Build the links user type
   966  	var links *UserTypeDefinition
   967  	if le != nil {
   968  		lTypeName := le.TypeName + "Array"
   969  		links = &UserTypeDefinition{
   970  			AttributeDefinition: &AttributeDefinition{
   971  				Type:        &Array{ElemType: &AttributeDefinition{Type: le}},
   972  				Description: fmt.Sprintf("%s contains links to related resources of %s.", lTypeName, m.TypeName),
   973  			},
   974  			TypeName: lTypeName,
   975  		}
   976  	}
   977  
   978  	return p, links, nil
   979  }
   980  
   981  // projectIdentifier computes the projected media type identifier by adding the "view" param.  We
   982  // need the projected media type identifier to be different so that looking up projected media types
   983  // from ProjectedMediaTypes works correctly. It's also good for clients.
   984  func (m *MediaTypeDefinition) projectIdentifier(view string) string {
   985  	base, params, err := mime.ParseMediaType(m.Identifier)
   986  	if err != nil {
   987  		base = m.Identifier
   988  	}
   989  	params["view"] = view
   990  	return mime.FormatMediaType(base, params)
   991  }
   992  
   993  // projectIdentifier computes the projected canonical media type identifier by adding the "view"
   994  // param if the view is not the default view.
   995  func (m *MediaTypeDefinition) projectCanonical(view string) string {
   996  	cano := CanonicalIdentifier(m.Identifier)
   997  	base, params, _ := mime.ParseMediaType(cano)
   998  	if params["view"] != "" {
   999  		return cano // Already projected
  1000  	}
  1001  	params["view"] = view
  1002  	return mime.FormatMediaType(base, params)
  1003  }
  1004  
  1005  // projectTypeName appends the view name to the media type name if the view name is not "default".
  1006  func (m *MediaTypeDefinition) projectTypeName(view string) string {
  1007  	typeName := m.TypeName
  1008  	if view != "default" {
  1009  		typeName += strings.Title(view)
  1010  	}
  1011  	return typeName
  1012  }
  1013  
  1014  // DataStructure implementation
  1015  
  1016  // Definition returns the underlying attribute definition.
  1017  // Note that this function is "inherited" by both UserTypeDefinition and
  1018  // MediaTypeDefinition.
  1019  func (a *AttributeDefinition) Definition() *AttributeDefinition {
  1020  	return a
  1021  }
  1022  
  1023  // Walk traverses the data structure recursively and calls the given function once
  1024  // on each attribute starting with the attribute returned by Definition.
  1025  func (a *AttributeDefinition) Walk(walker func(*AttributeDefinition) error) error {
  1026  	return walk(a, walker, make(map[string]bool))
  1027  }
  1028  
  1029  // Walk traverses the data structure recursively and calls the given function once
  1030  // on each attribute starting with the attribute returned by Definition.
  1031  func (u *UserTypeDefinition) Walk(walker func(*AttributeDefinition) error) error {
  1032  	return walk(u.AttributeDefinition, walker, map[string]bool{u.TypeName: true})
  1033  }
  1034  
  1035  // Recursive implementation of the Walk methods. Takes care of avoiding infinite recursions by
  1036  // keeping track of types that have already been walked.
  1037  func walk(at *AttributeDefinition, walker func(*AttributeDefinition) error, seen map[string]bool) error {
  1038  	if err := walker(at); err != nil {
  1039  		return err
  1040  	}
  1041  	walkUt := func(ut *UserTypeDefinition) error {
  1042  		if _, ok := seen[ut.TypeName]; ok {
  1043  			return nil
  1044  		}
  1045  		seen[ut.TypeName] = true
  1046  		return walk(ut.AttributeDefinition, walker, seen)
  1047  	}
  1048  	switch actual := at.Type.(type) {
  1049  	case Primitive:
  1050  		return nil
  1051  	case *Array:
  1052  		return walk(actual.ElemType, walker, seen)
  1053  	case *Hash:
  1054  		if err := walk(actual.KeyType, walker, seen); err != nil {
  1055  			return err
  1056  		}
  1057  		return walk(actual.ElemType, walker, seen)
  1058  	case Object:
  1059  		for _, cat := range actual {
  1060  			if err := walk(cat, walker, seen); err != nil {
  1061  				return err
  1062  			}
  1063  		}
  1064  	case *UserTypeDefinition:
  1065  		return walkUt(actual)
  1066  	case *MediaTypeDefinition:
  1067  		return walkUt(actual.UserTypeDefinition)
  1068  	default:
  1069  		panic("unknown attribute type") // bug
  1070  	}
  1071  	return nil
  1072  }
  1073  
  1074  // toReflectType converts the DataType to reflect.Type.
  1075  func toReflectType(dtype DataType) reflect.Type {
  1076  	switch dtype.Kind() {
  1077  	case BooleanKind:
  1078  		return reflect.TypeOf(true)
  1079  	case IntegerKind:
  1080  		return reflect.TypeOf(int(0))
  1081  	case NumberKind:
  1082  		return reflect.TypeOf(float64(0))
  1083  	case UUIDKind, StringKind:
  1084  		return reflect.TypeOf("")
  1085  	case DateTimeKind:
  1086  		return reflect.TypeOf(time.Time{})
  1087  	case ObjectKind, UserTypeKind, MediaTypeKind:
  1088  		return reflect.TypeOf(map[string]interface{}{})
  1089  	case ArrayKind:
  1090  		return reflect.SliceOf(toReflectType(dtype.ToArray().ElemType.Type))
  1091  	case HashKind:
  1092  		hash := dtype.ToHash()
  1093  		// avoid complication: not allow object as the hash key
  1094  		var ktype reflect.Type
  1095  		if !hash.KeyType.Type.IsObject() {
  1096  			ktype = toReflectType(hash.KeyType.Type)
  1097  		} else {
  1098  			ktype = reflect.TypeOf([]interface{}{}).Elem()
  1099  		}
  1100  		return reflect.MapOf(ktype, toReflectType(hash.ElemType.Type))
  1101  	default:
  1102  		return reflect.TypeOf([]interface{}{}).Elem()
  1103  	}
  1104  }