Skip to content

Commit 535136f

Browse files
committed
Type walker
1 parent 0ead7d4 commit 535136f

File tree

2 files changed

+130
-0
lines changed

2 files changed

+130
-0
lines changed

pkg/tfshim/walk/walk.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727

2828
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim"
2929
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim/schema"
30+
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/valueshim"
3031
)
3132

3233
// Represents locations in a tfshim.Schema value as a sequence of steps to locate it.
@@ -174,6 +175,32 @@ func LookupSchemaMapPath(path SchemaPath, schemaMap shim.SchemaMap) (shim.Schema
174175
return LookupSchemaPath(path, wrapSchemaMap(schemaMap))
175176
}
176177

178+
// Finds a nested Type at a given path.
179+
func LookupType(path SchemaPath, ty valueshim.Type) (valueshim.Type, error) {
180+
current := ty
181+
for i, step := range path {
182+
var subPath SchemaPath = path[0:i]
183+
switch step := step.(type) {
184+
case GetAttrStep:
185+
attr, ok := current.AttributeType(step.Name)
186+
if !ok {
187+
return nil, fmt.Errorf("LookupType mismatch: no attribute %q at path %v",
188+
step.Name, subPath)
189+
}
190+
current = attr
191+
case ElementStep:
192+
el, ok := current.ElementType()
193+
if !ok {
194+
return nil, fmt.Errorf("LookupType mismatch: no element type at path %v", subPath)
195+
}
196+
current = el
197+
default:
198+
contract.Failf("unexpected SchemaPathStep case")
199+
}
200+
}
201+
return current, nil
202+
}
203+
177204
// Represents elements of a SchemaPath.
178205
//
179206
// This interface is closed, the only the implementations given in the current package are allowed.

pkg/tfshim/walk/walk_test.go

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@ import (
1818
"fmt"
1919
"testing"
2020

21+
"github.com/hashicorp/terraform-plugin-go/tftypes"
2122
"github.com/stretchr/testify/assert"
2223
"github.com/stretchr/testify/require"
2324

2425
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim"
2526
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim/schema"
27+
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/valueshim"
2628
)
2729

2830
var strSchema = (&schema.Schema{
@@ -168,3 +170,104 @@ func TestEncodeDecodeSchemaPath(t *testing.T) {
168170
})
169171
}
170172
}
173+
174+
func TestLookupType(t *testing.T) {
175+
t.Parallel()
176+
177+
type testCase struct {
178+
p SchemaPath
179+
toplevelType valueshim.Type
180+
expectedType valueshim.Type
181+
isErr bool
182+
}
183+
184+
testCases := []testCase{
185+
{
186+
p: NewSchemaPath(),
187+
toplevelType: valueshim.FromTType(tftypes.Object{
188+
AttributeTypes: map[string]tftypes.Type{
189+
"x": tftypes.String,
190+
},
191+
}),
192+
expectedType: valueshim.FromTType(tftypes.Object{
193+
AttributeTypes: map[string]tftypes.Type{
194+
"x": tftypes.String,
195+
},
196+
}),
197+
},
198+
{
199+
p: NewSchemaPath().GetAttr("x"),
200+
toplevelType: valueshim.FromTType(tftypes.Object{
201+
AttributeTypes: map[string]tftypes.Type{
202+
"x": tftypes.String,
203+
},
204+
}),
205+
expectedType: valueshim.FromTType(tftypes.String),
206+
},
207+
{
208+
p: NewSchemaPath().GetAttr("y"),
209+
toplevelType: valueshim.FromTType(tftypes.Object{
210+
AttributeTypes: map[string]tftypes.Type{
211+
"x": tftypes.String,
212+
},
213+
}),
214+
isErr: true,
215+
},
216+
{
217+
p: NewSchemaPath().GetAttr("x").GetAttr("y"),
218+
toplevelType: valueshim.FromTType(tftypes.Object{
219+
AttributeTypes: map[string]tftypes.Type{
220+
"x": tftypes.Object{
221+
AttributeTypes: map[string]tftypes.Type{
222+
"y": tftypes.String,
223+
},
224+
},
225+
},
226+
}),
227+
expectedType: valueshim.FromTType(tftypes.String),
228+
},
229+
{
230+
p: NewSchemaPath().Element(),
231+
toplevelType: valueshim.FromTType(tftypes.Object{
232+
AttributeTypes: map[string]tftypes.Type{
233+
"x": tftypes.String,
234+
},
235+
}),
236+
isErr: true,
237+
},
238+
{
239+
p: NewSchemaPath().Element(),
240+
toplevelType: valueshim.FromTType(tftypes.Map{
241+
ElementType: tftypes.String,
242+
}),
243+
expectedType: valueshim.FromTType(tftypes.String),
244+
},
245+
{
246+
p: NewSchemaPath().Element(),
247+
toplevelType: valueshim.FromTType(tftypes.Set{
248+
ElementType: tftypes.String,
249+
}),
250+
expectedType: valueshim.FromTType(tftypes.String),
251+
},
252+
{
253+
p: NewSchemaPath().Element(),
254+
toplevelType: valueshim.FromTType(tftypes.List{
255+
ElementType: tftypes.String,
256+
}),
257+
expectedType: valueshim.FromTType(tftypes.String),
258+
},
259+
}
260+
261+
for i, tc := range testCases {
262+
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
263+
actualType, err := LookupType(tc.p, tc.toplevelType)
264+
if tc.isErr {
265+
require.NotNil(t, err)
266+
t.Logf("ERROR: %v", err)
267+
} else {
268+
require.NoError(t, err)
269+
require.Equal(t, tc.expectedType, actualType)
270+
}
271+
})
272+
}
273+
}

0 commit comments

Comments
 (0)