Block.AttribuuteByPath
There are a few places where we want to perform some transformation on a cty.Value, but require information from the schema. Rather than create bespoke functions to walk the cty.Value and schema in concert, we can provide Attribute information from a cty.Path allowing the use of Value.Transform in these cases.
This commit is contained in:
parent
7dd570ef6c
commit
e01d37d0dc
|
@ -0,0 +1,29 @@
|
|||
package configschema
|
||||
|
||||
import (
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// AttributeByPath looks up the Attribute schema which corresponds to the given
|
||||
// cty.Path. A nil value is returned if the given path does not correspond to a
|
||||
// specific attribute.
|
||||
// TODO: this will need to be updated for nested attributes
|
||||
func (b *Block) AttributeByPath(path cty.Path) *Attribute {
|
||||
block := b
|
||||
for _, step := range path {
|
||||
switch step := step.(type) {
|
||||
case cty.GetAttrStep:
|
||||
if attr := block.Attributes[step.Name]; attr != nil {
|
||||
return attr
|
||||
}
|
||||
|
||||
if nestedBlock := block.BlockTypes[step.Name]; nestedBlock != nil {
|
||||
block = &nestedBlock.Block
|
||||
continue
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
package configschema
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
func TestAttributeByPath(t *testing.T) {
|
||||
schema := &Block{
|
||||
Attributes: map[string]*Attribute{
|
||||
"a1": {Description: "a1"},
|
||||
"a2": {Description: "a2"},
|
||||
},
|
||||
BlockTypes: map[string]*NestedBlock{
|
||||
"b1": {
|
||||
Nesting: NestingList,
|
||||
Block: Block{
|
||||
Attributes: map[string]*Attribute{
|
||||
"a3": {Description: "a3"},
|
||||
"a4": {Description: "a4"},
|
||||
},
|
||||
BlockTypes: map[string]*NestedBlock{
|
||||
"b2": {
|
||||
Nesting: NestingMap,
|
||||
Block: Block{
|
||||
Attributes: map[string]*Attribute{
|
||||
"a5": {Description: "a5"},
|
||||
"a6": {Description: "a6"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"b3": {
|
||||
Nesting: NestingMap,
|
||||
Block: Block{
|
||||
Attributes: map[string]*Attribute{
|
||||
"a7": {Description: "a7"},
|
||||
"a8": {Description: "a8"},
|
||||
},
|
||||
BlockTypes: map[string]*NestedBlock{
|
||||
"b4": {
|
||||
Nesting: NestingSet,
|
||||
Block: Block{
|
||||
Attributes: map[string]*Attribute{
|
||||
"a9": {Description: "a9"},
|
||||
"a10": {Description: "a10"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range []struct {
|
||||
path cty.Path
|
||||
attrDescription string
|
||||
exists bool
|
||||
}{
|
||||
{
|
||||
cty.GetAttrPath("a2"),
|
||||
"a2",
|
||||
true,
|
||||
},
|
||||
{
|
||||
cty.GetAttrPath("b1"),
|
||||
"block",
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.GetAttrPath("b1").IndexInt(1).GetAttr("a3"),
|
||||
"a3",
|
||||
true,
|
||||
},
|
||||
{
|
||||
cty.GetAttrPath("b1").IndexInt(1).GetAttr("b2").IndexString("foo").GetAttr("a7"),
|
||||
"missing",
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.GetAttrPath("b1").IndexInt(1).GetAttr("b2").IndexString("foo").GetAttr("a6"),
|
||||
"a6",
|
||||
true,
|
||||
},
|
||||
{
|
||||
cty.GetAttrPath("b3").IndexString("foo").GetAttr("b2").IndexString("foo").GetAttr("a7"),
|
||||
"missing_block",
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.GetAttrPath("b3").IndexString("foo").GetAttr("a7"),
|
||||
"a7",
|
||||
true,
|
||||
},
|
||||
{
|
||||
// Index steps don't apply to the schema, so the set Index value doesn't matter.
|
||||
cty.GetAttrPath("b3").IndexString("foo").GetAttr("b4").Index(cty.EmptyObjectVal).GetAttr("a9"),
|
||||
"a9",
|
||||
true,
|
||||
},
|
||||
} {
|
||||
t.Run(tc.attrDescription, func(t *testing.T) {
|
||||
attr := schema.AttributeByPath(tc.path)
|
||||
if !tc.exists && attr == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if attr == nil {
|
||||
t.Fatalf("missing attribute from path %#v\n", tc.path)
|
||||
}
|
||||
|
||||
if attr.Description != tc.attrDescription {
|
||||
t.Fatalf("expected Attribute for %q, got %#v\n", tc.attrDescription, attr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue