-
Notifications
You must be signed in to change notification settings - Fork 888
Expand file tree
/
Copy pathenum.go
More file actions
245 lines (212 loc) · 6.32 KB
/
enum.go
File metadata and controls
245 lines (212 loc) · 6.32 KB
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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
package core
import (
"context"
"encoding/json"
"fmt"
"github.com/dagger/dagger/dagql"
"github.com/dagger/dagger/dagql/call"
"github.com/dagger/dagger/engine/slog"
"github.com/vektah/gqlparser/v2/ast"
)
type ModuleEnumType struct {
typeDef *EnumTypeDef
mod dagql.ObjectResult[*Module]
}
var _ ModType = &ModuleEnumType{}
func (m *ModuleEnumType) SourceMod() Mod {
if m.mod.Self() == nil {
return nil
}
return NewUserMod(m.mod)
}
func (m *ModuleEnumType) TypeDef(ctx context.Context) (dagql.ObjectResult[*TypeDef], error) {
var sourceMap dagql.Optional[dagql.ID[*SourceMap]]
if m.typeDef.SourceMap.Valid {
var err error
sourceMap, err = OptionalResultIDInput(m.typeDef.SourceMap.Value)
if err != nil {
return dagql.ObjectResult[*TypeDef]{}, err
}
}
return SelectReferenceTypeDef(ctx, "withEnum", "name", m.typeDef.Name,
dagql.NamedInput{Name: "description", Value: dagql.String(m.typeDef.Description)},
dagql.NamedInput{Name: "sourceMap", Value: sourceMap},
dagql.NamedInput{Name: "sourceModuleName", Value: OptSourceModuleName(m.typeDef.SourceModuleName)},
)
}
func (m *ModuleEnumType) ConvertFromSDKResult(ctx context.Context, value any) (dagql.AnyResult, error) {
if value == nil {
slog.Warn("%T.ConvertFromSDKResult: got nil value", m)
return nil, nil
}
if enum, ok := value.(*ModuleEnum); ok {
value = enum.Name
}
switch value := value.(type) {
case string:
enum, err := m.getEnum(ctx)
if err != nil {
return nil, fmt.Errorf("%T.ConvertFromSDKResult: failed to get enum: %w", m, err)
}
val, err := enum.DecodeInput(value)
if err != nil {
return nil, fmt.Errorf("%T.ConvertFromSDKResult: invalid enum value %q for %q: %w", m, value, m.typeDef.Name, err)
}
return dagql.NewResultForCurrentCall(ctx, val)
default:
return nil, fmt.Errorf("unexpected result value type %T for enum %q", value, m.typeDef.Name)
}
}
func (m *ModuleEnumType) ConvertToSDKInput(ctx context.Context, value dagql.Typed) (any, error) {
if value == nil {
return nil, nil
}
var input any = value
if enum, ok := value.(*ModuleEnum); ok {
input = enum.Name
}
base, err := m.getEnum(ctx)
if err != nil {
return nil, fmt.Errorf("%T.ConvertFromSDKResult: failed to get enum: %w", m, err)
}
decoder := *base
decoder.Local = false
result, err := decoder.DecodeInput(input)
if err != nil {
return nil, err
}
enum := result.(*ModuleEnum)
if base.Local {
return enum.memberTypedef().OriginalName, nil
}
return enum.memberTypedef().Name, nil
}
func (m *ModuleEnumType) CollectContent(ctx context.Context, value dagql.AnyResult, content *CollectedContent) error {
if value == nil {
return content.CollectJSONable(nil)
}
return content.CollectJSONable(value.Unwrap())
}
func (m *ModuleEnumType) getEnum(ctx context.Context) (*ModuleEnum, error) {
// Check the dependencies
srv, err := m.mod.Self().Deps.Schema(ctx)
if err != nil {
return nil, fmt.Errorf("%T.getDecoder: failed to get schema: %w", m, err)
}
scalar, ok := srv.ScalarType(m.typeDef.Name)
if ok {
enum, ok := scalar.(*ModuleEnum)
if !ok {
return nil, fmt.Errorf("%T.getDecoder: incorrect type %T for scalar", m, scalar)
}
return enum, nil
}
// If not check if the enum is part of its own module
for _, enumTypeDef := range m.mod.Self().EnumDefs {
if enumTypeDef.Self().AsEnum.Value.Self().Name == m.typeDef.Name {
return &ModuleEnum{TypeDef: enumTypeDef.Self().AsEnum.Value.Self(), Local: true}, nil
}
}
return nil, fmt.Errorf("%T.getDecoder: failed to get enum type %q", m, m.typeDef.Name)
}
type ModuleEnum struct {
TypeDef *EnumTypeDef
Name string
// Local marks this enum value as local to the module that declares its
// typedef. This is so that when converting it to/from it's own module we
// can use its OriginalName, but when converting it for other modules, we
// use the declared Name.
Local bool
}
func (e *ModuleEnum) TypeName() string {
return e.TypeDef.Name
}
func (e *ModuleEnum) Type() *ast.Type {
return &ast.Type{
NamedType: e.TypeDef.Name,
NonNull: true,
}
}
func (e *ModuleEnum) TypeDescription() string {
return formatGqlDescription(e.TypeDef.Description)
}
func (e *ModuleEnum) TypeDefinition(view call.View) *ast.Definition {
def := &ast.Definition{
Kind: ast.Enum,
Name: e.TypeName(),
EnumValues: e.PossibleValues(),
Description: e.TypeDescription(),
}
if e.TypeDef.SourceMap.Valid {
def.Directives = append(def.Directives, e.TypeDef.SourceMap.Value.Self().TypeDirective())
}
return def
}
func (e *ModuleEnum) PossibleValues() ast.EnumValueList {
var values ast.EnumValueList
for _, val := range e.TypeDef.Members {
member := val.Self()
name := member.Name
if e.Local && member.OriginalName != "" {
name = member.OriginalName
}
def := &ast.EnumValueDefinition{
Name: name,
Description: member.Description,
Directives: member.EnumValueDirectives(),
}
if member.SourceMap.Valid {
def.Directives = append(def.Directives, member.SourceMap.Value.Self().TypeDirective())
}
values = append(values, def)
}
return values
}
func (e *ModuleEnum) Install(dag *dagql.Server) error {
dag.InstallScalar(e)
return nil
}
func (e *ModuleEnum) ToLiteral() call.Literal {
return call.NewLiteralEnum(e.Name)
}
func (e *ModuleEnum) Decoder() dagql.InputDecoder {
return e
}
func (e *ModuleEnum) DecodeInput(val any) (dagql.Input, error) {
v, err := (&dagql.EnumValueName{Enum: e.TypeName()}).DecodeInput(val)
if err != nil {
return nil, err
}
return e.Lookup(v.(*dagql.EnumValueName).Name)
}
func (e *ModuleEnum) Lookup(val string) (dagql.Input, error) {
if len(e.TypeDef.Members) == 0 {
// this is a fairly good indication that something wrong has happened internally
return nil, fmt.Errorf("enum %s has no members", e.TypeName())
}
for _, possible := range e.TypeDef.Members {
member := possible.Self()
name := member.Name
if e.Local && member.OriginalName != "" {
name = member.OriginalName
}
if val == name {
return &ModuleEnum{
TypeDef: e.TypeDef,
Name: member.Name,
}, nil
}
}
return nil, fmt.Errorf("invalid enum member %q for %s", val, e.TypeName())
}
func (e *ModuleEnum) memberTypedef() *EnumMemberTypeDef {
for _, possible := range e.TypeDef.Members {
if possible.Self().Name == e.Name {
return possible.Self()
}
}
return nil
}
func (e *ModuleEnum) MarshalJSON() ([]byte, error) {
return json.Marshal(e.Name)
}