Repository: ariga/atlas
Pull request #1173 (2022-10-04 12:22:22)

schemahcl: support assigning variable inputs of type list to attributes


Patch:
diff --git a/schemahcl/context.go b/schemahcl/context.go
index 466a0d23..566717b3 100644
--- a/schemahcl/context.go
+++ b/schemahcl/context.go
@@ -209,7 +209,7 @@ func attrMap(attrs hclsyntax.Attributes) map[string]cty.Value {
 		if diag.HasErrors() {
 			continue
 		}
-		literalValue, err := extractLiteralValue(value)
+		literalValue, err := extractValue(value)
 		if err != nil {
 			continue
 		}
diff --git a/schemahcl/hcl.go b/schemahcl/hcl.go
index 05d70892..0282b8a7 100644
--- a/schemahcl/hcl.go
+++ b/schemahcl/hcl.go
@@ -263,7 +263,7 @@ func (s *State) toAttrs(ctx *hcl.EvalContext, hclAttrs hclsyntax.Attributes, sco
 		case value.Type().IsTupleType():
 			at.V, err = extractListValue(value)
 		default:
-			at.V, err = extractLiteralValue(value)
+			at.V, err = extractValue(value)
 		}
 		if err != nil {
 			return nil, err
@@ -313,7 +313,7 @@ func extractListValue(value cty.Value) (*ListValue, error) {
 			lst.V = append(lst.V, &Ref{V: v.GetAttr("__ref").AsString()})
 			continue
 		}
-		litv, err := extractLiteralValue(v)
+		litv, err := extractValue(v)
 		if err != nil {
 			return nil, err
 		}
@@ -322,7 +322,7 @@ func extractListValue(value cty.Value) (*ListValue, error) {
 	return lst, nil
 }
 
-func extractLiteralValue(value cty.Value) (*LiteralValue, error) {
+func extractValue(value cty.Value) (Value, error) {
 	switch value.Type() {
 	case ctySchemaLit:
 		return value.EncapsulatedValue().(*LiteralValue), nil
@@ -334,6 +334,17 @@ func extractLiteralValue(value cty.Value) (*LiteralValue, error) {
 		return &LiteralValue{V: strconv.FormatFloat(num, 'f', -1, 64)}, nil
 	case cty.Bool:
 		return &LiteralValue{V: strconv.FormatBool(value.True())}, nil
+	case cty.List(cty.String), cty.List(cty.Number), cty.List(cty.Bool):
+		l := &ListValue{V: make([]Value, 0, value.LengthInt())}
+		for it := value.ElementIterator(); it.Next(); {
+			_, v := it.Element()
+			ev, err := extractValue(v)
+			if err != nil {
+				return nil, err
+			}
+			l.V = append(l.V, ev)
+		}
+		return l, nil
 	default:
 		return nil, fmt.Errorf("schemahcl: unsupported type %q", value.Type().GoString())
 	}
@@ -373,7 +384,7 @@ func (s *State) toResource(ctx *hcl.EvalContext, block *hclsyntax.Block, scope [
 			for _, e := range v.GetAttr(blk.Labels[0]).AsValueSlice() {
 				r := &Resource{Type: blk.Labels[0]}
 				for k, v := range e.AsValueMap() {
-					av, err := extractLiteralValue(v)
+					av, err := extractValue(v)
 					if err != nil {
 						return nil, err
 					}
diff --git a/schemahcl/opts.go b/schemahcl/opts.go
index 299f16cf..d5da3573 100644
--- a/schemahcl/opts.go
+++ b/schemahcl/opts.go
@@ -57,8 +57,6 @@ func New(opts ...Option) *State {
 //			type = INVALID  // Not Allowed.
 //		}
 //	}
-//
-//
 func WithScopedEnums(path string, enums ...string) Option {
 	return func(c *Config) {
 		vars := make(map[string]cty.Value, len(enums))
@@ -162,7 +160,7 @@ func typeFuncSpecImpl(_ *function.Spec, typeSpec *TypeSpec) function.ImplFunc {
 			if attr.Kind == reflect.Slice {
 				lst := &ListValue{}
 				for _, arg := range args {
-					v, err := extractLiteralValue(arg)
+					v, err := extractValue(arg)
 					if err != nil {
 						return cty.NilVal, err
 					}
@@ -177,7 +175,7 @@ func typeFuncSpecImpl(_ *function.Spec, typeSpec *TypeSpec) function.ImplFunc {
 			// Pop the first arg and add it as a literal to the type.
 			var arg cty.Value
 			arg, args = args[0], args[1:]
-			v, err := extractLiteralValue(arg)
+			v, err := extractValue(arg)
 			if err != nil {
 				return cty.NilVal, err
 			}


Test patch:
diff --git a/schemahcl/context_test.go b/schemahcl/context_test.go
index ff051f72..d5cac59b 100644
--- a/schemahcl/context_test.go
+++ b/schemahcl/context_test.go
@@ -498,21 +498,28 @@ variable "convert_bool" {
   type = bool
 }
 
+variable "strings" {
+  type = list(string)
+  default = ["a", "b"]
+}
+
 name = var.name
 default = var.default
 int = var.int
 bool = var.bool
 convert_int = var.convert_int
 convert_bool = var.convert_bool
+strings = var.strings
 `
 	state := New()
 	var test struct {
-		Name        string `spec:"name"`
-		Default     string `spec:"default"`
-		Int         int    `spec:"int"`
-		Bool        bool   `spec:"bool"`
-		ConvertInt  int    `spec:"convert_int"`
-		ConvertBool bool   `spec:"convert_bool"`
+		Name        string   `spec:"name"`
+		Default     string   `spec:"default"`
+		Int         int      `spec:"int"`
+		Bool        bool     `spec:"bool"`
+		ConvertInt  int      `spec:"convert_int"`
+		ConvertBool bool     `spec:"convert_bool"`
+		Strings     []string `spec:"strings"`
 	}
 	err := state.EvalBytes([]byte(h), &test, map[string]cty.Value{
 		"name":         cty.StringVal("rotemtam"),
@@ -520,6 +527,7 @@ convert_bool = var.convert_bool
 		"bool":         cty.BoolVal(true),
 		"convert_int":  cty.StringVal("1"),
 		"convert_bool": cty.StringVal("true"),
+		"strings":      cty.ListVal([]cty.Value{cty.StringVal("a"), cty.StringVal("b")}),
 	})
 	require.NoError(t, err)
 	require.EqualValues(t, "rotemtam", test.Name)
@@ -528,4 +536,5 @@ convert_bool = var.convert_bool
 	require.EqualValues(t, true, test.Bool)
 	require.EqualValues(t, 1, test.ConvertInt)
 	require.EqualValues(t, true, test.ConvertBool)
+	require.EqualValues(t, []string{"a", "b"}, test.Strings)
 }