Repository: ariga/atlas
Pull request #674 (2022-03-30 20:57:38)

schema/schemaspec: support refs for qualified resources
Add support for references to qualified resources and their attrs:

```hcl
user "atlas" "cli" {
	version = "v0.3.9"
}
v = user.atlas.cli.version
r = user.atlas.cli
```


Patch:
diff --git a/schema/schemaspec/schemahcl/context.go b/schema/schemaspec/schemahcl/context.go
index 9c376add..621c46d1 100644
--- a/schema/schemaspec/schemahcl/context.go
+++ b/schema/schemaspec/schemahcl/context.go
@@ -65,7 +65,7 @@ func blockVars(b *hclsyntax.Body, parentAddr string, defs *blockDef) (map[string
 		}
 		var unlabeled int
 		for _, blk := range blocks {
-			blkName := blockName(blk)
+			qualifier, blkName := blockName(blk)
 			if blkName == "" {
 				blkName = strconv.Itoa(unlabeled)
 				unlabeled++
@@ -77,7 +77,7 @@ func blockVars(b *hclsyntax.Body, parentAddr string, defs *blockDef) (map[string
 					attrs[n] = cty.NullVal(ctySchemaLit)
 				}
 			}
-			self := addr(parentAddr, name, blkName)
+			self := addr(parentAddr, name, blkName, qualifier)
 			attrs["__ref"] = cty.StringVal(self)
 			varMap, err := blockVars(blk.Body, self, def)
 			if err != nil {
@@ -87,8 +87,16 @@ func blockVars(b *hclsyntax.Body, parentAddr string, defs *blockDef) (map[string
 			for k, v := range varMap {
 				attrs[k] = v
 			}
-
-			v[blkName] = cty.ObjectVal(attrs)
+			key, obj := blkName, cty.ObjectVal(attrs)
+			if qualifier != "" {
+				obj = cty.ObjectVal(
+					map[string]cty.Value{
+						blkName: obj,
+					},
+				)
+				key = qualifier
+			}
+			v[key] = obj
 		}
 		if len(v) > 0 {
 			vars[name] = cty.ObjectVal(v)
@@ -97,19 +105,28 @@ func blockVars(b *hclsyntax.Body, parentAddr string, defs *blockDef) (map[string
 	return vars, nil
 }
 
-func addr(parentAddr, typeName, blkName string) string {
+func addr(parentAddr, typeName, blkName, qualifier string) string {
 	var prefixDot string
 	if len(parentAddr) > 0 {
 		prefixDot = "."
 	}
-	return fmt.Sprintf("%s%s$%s.%s", parentAddr, prefixDot, typeName, blkName)
+	suffix := blkName
+	if qualifier != "" {
+		suffix = qualifier + "." + blkName
+	}
+	return fmt.Sprintf("%s%s$%s.%s", parentAddr, prefixDot, typeName, suffix)
 }
 
-func blockName(blk *hclsyntax.Block) string {
-	if len(blk.Labels) == 0 {
-		return ""
+func blockName(blk *hclsyntax.Block) (qualifier string, name string) {
+	switch len(blk.Labels) {
+	case 0:
+	case 1:
+		name = blk.Labels[0]
+	default:
+		qualifier = blk.Labels[0]
+		name = blk.Labels[1]
 	}
-	return blk.Labels[0]
+	return
 }
 
 func blocksOfType(blocks hclsyntax.Blocks, typeName string) []*hclsyntax.Block {


Test patch:
diff --git a/schema/schemaspec/schemahcl/context_test.go b/schema/schemaspec/schemahcl/context_test.go
index 20c1b771..a1ddd08c 100644
--- a/schema/schemaspec/schemahcl/context_test.go
+++ b/schema/schemaspec/schemahcl/context_test.go
@@ -444,3 +444,20 @@ arg_2 = float(10,2)
 		schemautil.LitAttr("scale", "2"),
 	}, test.Arg2.Attrs)
 }
+
+func TestQualifiedRefs(t *testing.T) {
+	h := `user "atlas" "cli" {
+	version = "v0.3.9"
+}
+v = user.atlas.cli.version
+r = user.atlas.cli
+`
+	var test struct {
+		V string          `spec:"v"`
+		R *schemaspec.Ref `spec:"r"`
+	}
+	err := Unmarshal([]byte(h), &test)
+	require.NoError(t, err)
+	require.EqualValues(t, "v0.3.9", test.V)
+	require.EqualValues(t, "$user.atlas.cli", test.R.V)
+}