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