Repository: ariga/atlas
Pull request #1728 (2023-06-08 14:37:38)

sql/sqlspec: marshal view definition after columns


Patch:
diff --git a/schemahcl/hcl.go b/schemahcl/hcl.go
index 3fc2b8b6..e8332ad4 100644
--- a/schemahcl/hcl.go
+++ b/schemahcl/hcl.go
@@ -405,15 +405,18 @@ func (s *State) encode(r *Resource) ([]byte, error) {
 }
 
 func (s *State) writeResource(b *Resource, body *hclwrite.Body) error {
-	blk := body.AppendNewBlock(b.Type, labels(b))
-	nb := blk.Body()
+	// Anonymous resources are treated as embedded blocks.
+	if b.Type != "" {
+		blk := body.AppendNewBlock(b.Type, labels(b))
+		body = blk.Body()
+	}
 	for _, attr := range b.Attrs {
-		if err := s.writeAttr(attr, nb); err != nil {
+		if err := s.writeAttr(attr, body); err != nil {
 			return err
 		}
 	}
 	for _, b := range b.Children {
-		if err := s.writeResource(b, nb); err != nil {
+		if err := s.writeResource(b, body); err != nil {
 			return err
 		}
 	}
diff --git a/sql/internal/specutil/convert.go b/sql/internal/specutil/convert.go
index 5d94f5fa..f323f4ba 100644
--- a/sql/internal/specutil/convert.go
+++ b/sql/internal/specutil/convert.go
@@ -377,21 +377,27 @@ func FromTable(t *schema.Table, colFn TableColumnSpecFunc, pkFn PrimaryKeySpecFu
 func FromView(v *schema.View, colFn ViewColumnSpecFunc) (*sqlspec.View, error) {
 	spec := &sqlspec.View{
 		Name: v.Name,
-		As:   v.Def,
-	}
-	// In case the view definition is multi-line,
-	// format it as indented heredoc with two spaces.
-	if lines := strings.Split(v.Def, "\n"); len(lines) > 1 {
-		spec.As = fmt.Sprintf("<<-SQL\n  %s\n  SQL", strings.Join(lines, "\n  "))
 	}
 	for _, c := range v.Columns {
-		col, err := colFn(c, v)
+		cs, err := colFn(c, v)
 		if err != nil {
 			return nil, err
 		}
-		spec.Columns = append(spec.Columns, col)
+		spec.Columns = append(spec.Columns, cs)
+	}
+	as := v.Def
+	// In case the view definition is multi-line,
+	// format it as indented heredoc with two spaces.
+	if lines := strings.Split(v.Def, "\n"); len(lines) > 1 {
+		as = fmt.Sprintf("<<-SQL\n  %s\n  SQL", strings.Join(lines, "\n  "))
+	}
+	embed := &schemahcl.Resource{
+		Attrs: []*schemahcl.Attr{
+			schemahcl.StringAttr("as", as),
+		},
 	}
-	convertCommentFromSchema(v.Attrs, &spec.Extra.Attrs)
+	convertCommentFromSchema(v.Attrs, &embed.Attrs)
+	spec.Extra.Children = append(spec.Extra.Children, embed)
 	return spec, nil
 }
 
diff --git a/sql/sqlspec/sqlspec.go b/sql/sqlspec/sqlspec.go
index 06de446a..d797fcaf 100644
--- a/sql/sqlspec/sqlspec.go
+++ b/sql/sqlspec/sqlspec.go
@@ -36,7 +36,8 @@ type (
 		Qualifier string         `spec:",qualifier"`
 		Schema    *schemahcl.Ref `spec:"schema"`
 		Columns   []*Column      `spec:"column"`
-		As        string         `spec:"as"`
+		// The definition is appended as additional attribute
+		// by the spec creator to marshal it after the columns.
 		schemahcl.DefaultExtension
 	}
 
@@ -94,6 +95,7 @@ type (
 )
 
 func init() {
+	schemahcl.Register("view", &View{})
 	schemahcl.Register("table", &Table{})
 	schemahcl.Register("schema", &Schema{})
 }


Test patch:
diff --git a/sql/postgres/sqlspec_test.go b/sql/postgres/sqlspec_test.go
index 629e5b74..5c0008ba 100644
--- a/sql/postgres/sqlspec_test.go
+++ b/sql/postgres/sqlspec_test.go
@@ -271,7 +271,8 @@ func TestMarshalViews(t *testing.T) {
 			schema.NewView("v3", "SELECT * FROM t3\n\tWHERE id IS NOT NULL\n\tORDER BY id").
 				AddColumns(
 					schema.NewIntColumn("id", "id"),
-				),
+				).
+				SetComment("view comment"),
 		)
 	buf, err := MarshalHCL(s)
 	require.NoError(t, err)
@@ -288,15 +289,16 @@ view "v2" {
 }
 view "v3" {
   schema = schema.public
-  as     = <<-SQL
-  SELECT * FROM t3
-  	WHERE id IS NOT NULL
-  	ORDER BY id
-  SQL
   column "id" {
     null = false
     type = sql("id")
   }
+  as      = <<-SQL
+  SELECT * FROM t3
+  	WHERE id IS NOT NULL
+  	ORDER BY id
+  SQL
+  comment = "view comment"
 }
 schema "public" {
 }