Repository: ariga/atlas
Pull request #672 (2022-03-30 14:40:54)

schema/schemaspec: adding qualifier label to blocks
adding a "Qualifier" attribute to `schemaspec.Resource`. In HCL can be defined as:

```hcl
resource "qualifier" "name" {

}
```

This is done as infrastructure for HCL document supporting two tables with the same name (but in different schemas). 



Patch:
diff --git a/schema/schemaspec/extension.go b/schema/schemaspec/extension.go
index a2abfafd..1164c1d3 100644
--- a/schema/schemaspec/extension.go
+++ b/schema/schemaspec/extension.go
@@ -88,7 +88,7 @@ func (r *Resource) As(target interface{}) error {
 		return err
 	}
 	existingAttrs, existingChildren := existingElements(r)
-	var seenName bool
+	var seenName, seenQualifier bool
 	v := reflect.ValueOf(target).Elem()
 	for _, ft := range specFields(target) {
 		field := v.FieldByName(ft.Name)
@@ -102,6 +102,12 @@ func (r *Resource) As(target interface{}) error {
 				return errors.New("schemaspec: extension isName field must be of type string")
 			}
 			field.SetString(r.Name)
+		case ft.isQualifier():
+			if seenQualifier {
+				return errors.New("schemaspec: extension must have only one qualifier field")
+			}
+			seenQualifier = true
+			field.SetString(r.Qualifier)
 		case hasAttr(r, ft.tag):
 			attr, _ := r.Attr(ft.tag)
 			if err := setField(field, attr); err != nil {
@@ -564,6 +570,8 @@ type fieldDesc struct {
 
 func (f fieldDesc) isName() bool { return f.is("name") }
 
+func (f fieldDesc) isQualifier() bool { return f.is("qualifier") }
+
 func (f fieldDesc) omitempty() bool { return f.is("omitempty") }
 
 func (f fieldDesc) is(t string) bool {
diff --git a/schema/schemaspec/schemahcl/hcl.go b/schema/schemaspec/schemahcl/hcl.go
index 9083bc72..98674d8b 100644
--- a/schema/schemaspec/schemahcl/hcl.go
+++ b/schema/schemaspec/schemahcl/hcl.go
@@ -198,8 +198,15 @@ func (s *state) toResource(ctx *hcl.EvalContext, block *hclsyntax.Block, scope [
 	spec := &schemaspec.Resource{
 		Type: block.Type,
 	}
-	if len(block.Labels) > 0 {
+	switch len(block.Labels) {
+	case 0:
+	case 1:
 		spec.Name = block.Labels[0]
+	case 2:
+		spec.Qualifier = block.Labels[0]
+		spec.Name = block.Labels[1]
+	default:
+		return nil, fmt.Errorf("too many labels for block: %s", block.Labels)
 	}
 	ctx = s.mayExtendVars(ctx, scope)
 	attrs, err := s.toAttrs(ctx, block.Body.Attributes, scope)
diff --git a/schema/schemaspec/spec.go b/schema/schemaspec/spec.go
index 4df6e21a..b8cf5b18 100644
--- a/schema/schemaspec/spec.go
+++ b/schema/schemaspec/spec.go
@@ -9,10 +9,11 @@ import (
 type (
 	// Resource is a generic container for resources described in configurations.
 	Resource struct {
-		Name     string
-		Type     string
-		Attrs    []*Attr
-		Children []*Resource
+		Name      string
+		Qualifier string
+		Type      string
+		Attrs     []*Attr
+		Children  []*Resource
 	}
 
 	// Attr is an attribute of a Resource.


Test patch:
diff --git a/schema/schemaspec/schemahcl/hcl_test.go b/schema/schemaspec/schemahcl/hcl_test.go
index 9fd9ff39..54e6fb5f 100644
--- a/schema/schemaspec/schemahcl/hcl_test.go
+++ b/schema/schemaspec/schemahcl/hcl_test.go
@@ -226,5 +226,25 @@ zoo "ramat_gan" {
 			},
 		}, test.Zoo)
 	})
+}
 
+func TestQualified(t *testing.T) {
+	type Person struct {
+		Name  string `spec:",name"`
+		Title string `spec:",qualifier"`
+	}
+	var test struct {
+		Person *Person `spec:"person"`
+	}
+	h := `
+person "dr" "jekyll" {
+  
+}
+`
+	err := Unmarshal([]byte(h), &test)
+	require.NoError(t, err)
+	require.EqualValues(t, test.Person, &Person{
+		Title: "dr",
+		Name:  "jekyll",
+	})
 }