-
-
Notifications
You must be signed in to change notification settings - Fork 564
/
Copy pathconvert.go
168 lines (165 loc) Β· 5.34 KB
/
convert.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
package dsl
import (
"goa.design/goa/eval"
"goa.design/goa/expr"
)
// ConvertTo specifies an external type that instances of the generated struct
// are converted into. The generated struct is equipped with a method that makes
// it possible to instantiate the external type. The default algorithm used to
// match the external type fields to the design attributes is as follows:
//
// 1. Look for an attribute with the same name as the field
// 2. Look for an attribute with the same name as the field but with the
// first letter being lowercase
// 3. Look for an attribute with a name corresponding to the snake_case
// version of the field name
//
// This algorithm does not apply if the attribute is equipped with the
// "struct.field.external" meta. In this case the matching is done by
// looking up the field with a name corresponding to the value of the meta.
// If the value of the meta is "-" the attribute isn't matched and no
// conversion code is generated for it. In all other cases it is an error if no
// match is found or if the matching field type does not correspond to the
// attribute type.
//
// The following limitations apply on the external Go struct field types
// recursively:
//
// * struct fields must use pointers
// * pointers on slices or on maps are not supported
//
// ConvertTo must appear in Type or ResutType.
//
// ConvertTo accepts one arguments: an instance of the external type.
//
// Example:
//
// Service design:
//
// var Bottle = Type("bottle", func() {
// Description("A bottle")
// ConvertTo(models.Bottle{})
// // The "rating" attribute is matched to the external
// // typ "Rating" field.
// Attribute("rating", Int)
// Attribute("name", String, func() {
// // The "name" attribute is matched to the external
// // type "MyName" field.
// Meta("struct.field.external", "MyName")
// })
// Attribute("vineyard", String, func() {
// // The "vineyard" attribute is not converted.
// Meta("struct.field.external", "-")
// })
// })
//
// External (i.e. non design) package:
//
// package model
//
// type Bottle struct {
// Rating int
// // Mapped field
// MyName string
// // Additional fields are OK
// Description string
// }
//
func ConvertTo(obj interface{}) {
var ut expr.UserType
switch actual := eval.Current().(type) {
case *expr.AttributeExpr:
for _, t := range expr.Root.Types {
if t.Attribute() == actual {
ut = t
}
}
case *expr.ResultTypeExpr:
ut = actual
default:
eval.IncompatibleDSL()
return
}
expr.Root.Conversions =
append(expr.Root.Conversions, &expr.TypeMap{User: ut, External: obj})
}
// CreateFrom specifies an external type that instances of the generated struct
// can be initialized from. The generated struct is equipped with a method that
// initializes its fields from an instance of the external type. The default
// algorithm used to match the external type fields to the design attributes is
// as follows:
//
// 1. Look for an attribute with the same name as the field
// 2. Look for an attribute with the same name as the field but with the
// first letter being lowercase
// 3. Look for an attribute with a name corresponding to the snake_case
// version of the field name
//
// This algorithm does not apply if the attribute is equipped with the
// "struct.field.external" meta. In this case the matching is done by
// looking up the field with a name corresponding to the value of the meta.
// If the value of the meta is "-" the attribute isn't matched and no
// conversion code is generated for it. In all other cases it is an error if no
// match is found or if the matching field type does not correspond to the
// attribute type.
//
// The following limitations apply on the external Go struct field types
// recursively:
//
// * struct fields must use pointers
// * pointers on slices or on maps are not supported
//
// CreateFrom must appear in Type or ResultType.
//
// CreateFrom accepts one arguments: an instance of the external type.
//
// Example:
//
// Service design:
//
// var Bottle = Type("bottle", func() {
// Description("A bottle")
// CreateFrom(models.Bottle{})
// Attribute("rating", Int)
// Attribute("name", String, func() {
// // The "name" attribute is matched to the external
// // type "MyName" field.
// Meta("struct.field.external", "MyName")
// })
// Attribute("vineyard", String, func() {
// // The "vineyard" attribute is not initialized by the
// // generated constructor method.
// Meta("struct.field.external", "-")
// })
// })
//
// External (i.e. non design) package:
//
// package model
//
// type Bottle struct {
// Rating int
// // Mapped field
// MyName string
// // Additional fields are OK
// Description string
// }
//
func CreateFrom(obj interface{}) {
var ut expr.UserType
switch actual := eval.Current().(type) {
case *expr.AttributeExpr:
for _, t := range expr.Root.Types {
if t.Attribute() == actual {
ut = t
}
}
case *expr.ResultTypeExpr:
ut = actual
default:
eval.IncompatibleDSL()
return
}
expr.Root.Creations =
append(expr.Root.Creations, &expr.TypeMap{User: ut, External: obj})
}