Repository: ariga/atlas
Pull request #294 (2021-12-08 12:44:51)

schema/schemaspec/schemahcl: support variadic type spec attributes
Needed to support
```hcl
status = enum("on","off","unknown")

```


Patch:
diff --git a/schema/schemaspec/schemahcl/hcl.go b/schema/schemaspec/schemahcl/hcl.go
index 885ad871..2231decf 100644
--- a/schema/schemaspec/schemahcl/hcl.go
+++ b/schema/schemaspec/schemahcl/hcl.go
@@ -301,11 +301,18 @@ func hclType(spec *schemaspec.TypeSpec, typ *schemaspec.Type) (string, error) {
 		if !ok {
 			continue
 		}
-		lit, ok := arg.V.(*schemaspec.LiteralValue)
-		if !ok {
-			return "", errors.New("expecting literal value")
+		switch val := arg.V.(type) {
+		case *schemaspec.LiteralValue:
+			args = append(args, val.V)
+		case *schemaspec.ListValue:
+			for _, li := range val.V {
+				lit, ok := li.(*schemaspec.LiteralValue)
+				if !ok {
+					return "", errors.New("expecting literal value")
+				}
+				args = append(args, lit.V)
+			}
 		}
-		args = append(args, lit.V)
 	}
 	return fmt.Sprintf("%s(%s)", typ.T, strings.Join(args, ",")), nil
 }
diff --git a/schema/schemaspec/schemahcl/opts.go b/schema/schemaspec/schemahcl/opts.go
index 0e3e0d0c..13476e5a 100644
--- a/schema/schemaspec/schemahcl/opts.go
+++ b/schema/schemaspec/schemahcl/opts.go
@@ -44,7 +44,8 @@ func EvalContext(ctx *hcl.EvalContext) Option {
 // WithTypes configures the list of given types as identifiers in the unmarshaling context.
 func WithTypes(typeSpecs []*schemaspec.TypeSpec) Option {
 	return func(config *Config) {
-		for _, typeSpec := range typeSpecs {
+		for _, ts := range typeSpecs {
+			typeSpec := ts
 			config.types = append(config.types, typeSpec)
 			if len(typeFuncArgs(typeSpec)) == 0 {
 				typ := &schemaspec.Type{T: typeSpec.T}
@@ -60,24 +61,42 @@ func WithTypes(typeSpecs []*schemaspec.TypeSpec) Option {
 					AllowNull: !arg.Required,
 				}
 				switch arg.Kind {
+				case reflect.Slice:
+					p.Type = cty.DynamicPseudoType
+					spec.VarParam = &p
 				case reflect.String:
 					p.Type = cty.String
+					spec.Params = append(spec.Params, p)
 				case reflect.Int, reflect.Float32:
 					p.Type = cty.Number
+					spec.Params = append(spec.Params, p)
 				case reflect.Bool:
 					p.Type = cty.Bool
+					spec.Params = append(spec.Params, p)
 				}
-				spec.Params = append(spec.Params, p)
 				spec.Impl = func(args []cty.Value, retType cty.Type) (cty.Value, error) {
 					t := &schemaspec.Type{
 						T: typeSpec.T,
 					}
-					for i, arg := range args {
-						v, err := extractLiteralValue(arg)
-						if err != nil {
-							return cty.NilVal, err
+					if spec.VarParam != nil {
+						lst := &schemaspec.ListValue{}
+						for _, arg := range args {
+							v, err := extractLiteralValue(arg)
+							if err != nil {
+								return cty.NilVal, err
+							}
+							lst.V = append(lst.V, v)
+						}
+						t.Attributes = append(t.Attributes, &schemaspec.Attr{K: spec.VarParam.Name, V: lst})
+					} else {
+						for i, arg := range args {
+							v, err := extractLiteralValue(arg)
+							if err != nil {
+								return cty.NilVal, err
+							}
+							attrName := typeSpec.Attributes[i].Name
+							t.Attributes = append(t.Attributes, &schemaspec.Attr{K: attrName, V: v})
 						}
-						t.Attributes = append(t.Attributes, &schemaspec.Attr{K: typeSpec.Attributes[i].Name, V: v})
 					}
 					return cty.CapsuleVal(ctyTypeSpec, t), nil
 				}


Test patch:
diff --git a/internal/integration/postgres_test.go b/internal/integration/postgres_test.go
index 0206c789..6da3c6e0 100644
--- a/internal/integration/postgres_test.go
+++ b/internal/integration/postgres_test.go
@@ -441,130 +441,386 @@ func TestPostgres_CLI(t *testing.T) {
 
 func TestPostgres_Sanity(t *testing.T) {
 	n := "atlas_types_sanity"
-	t.Run("Common", func(t *testing.T) {
-		ddl := `
+	ddl := `
+DROP TYPE IF EXISTS address;
+CREATE TYPE address AS (city VARCHAR(90), street VARCHAR(90));
 create table atlas_types_sanity
 (
-    "tBit"                 bit(10)                    default b'100'             null,
-    "tBitVar"              bit varying(10)            default b'100'             null,
-    "tBoolean"             boolean                    default false           not null,
-    "tBool"                bool                       default false           not null,
-    "tBytea"               bytea                      default E'\\001'        not null,
-    "tCharacter"           character(10)              default 'atlas'             null,
-    "tChar"                char(10)                   default 'atlas'             null,
-    "tCharVar"             character varying(10)      default 'atlas'             null,
-    "tVarChar"             varchar(10)                default 'atlas'             null,
-    "tText"                text                       default 'atlas'             null,
-    "tSmallInt"            smallint                   default '10'                null,
-    "tInteger"             integer                    default '10'                null,
-    "tBigInt"              bigint                     default '10'                null,
-    "tInt"                 int                        default '10'                null,
-    "tInt2"                int2                       default '10'                null,
-    "tInt4"                int4                       default '10'                null,
-    "tInt8"                int8                       default '10'                null
+    "tBit"                 bit(10)                     default b'100'                                   null,
+    "tBitVar"              bit varying(10)             default b'100'                                   null,
+    "tBoolean"             boolean                     default false                                not null,
+    "tBool"                bool                        default false                                not null,
+    "tBytea"               bytea                       default E'\\001'                             not null,
+    "tCharacter"           character(10)               default 'atlas'                                  null,
+    "tChar"                char(10)                    default 'atlas'                                  null,
+    "tCharVar"             character varying(10)       default 'atlas'                                  null,
+    "tVarChar"             varchar(10)                 default 'atlas'                                  null,
+    "tText"                text                        default 'atlas'                                  null,
+    "tSmallInt"            smallint                    default '10'                                     null,
+    "tInteger"             integer                     default '10'                                     null,
+    "tBigInt"              bigint                      default '10'                                     null,
+    "tInt"                 int                         default '10'                                     null,
+    "tInt2"                int2                        default '10'                                     null,
+    "tInt4"                int4                        default '10'                                     null,
+    "tInt8"                int8                        default '10'                                     null,
+    "tCIDR"                cidr                        default '127.0.0.1'                              null,
+    "tInet"                inet                        default '127.0.0.1'                              null,
+    "tMACAddr"             macaddr                     default '08:00:2b:01:02:03'                      null,
+    "tMACAddr8"            macaddr8                    default '08:00:2b:01:02:03:04:05'                null,
+    "tCircle"              circle                      default                                          null,
+    "tLine"                line                        default                                          null,
+    "tLseg"                lseg                        default                                          null, 
+    "tBox"                 box                         default                                          null,
+    "tPath"                path                        default                                          null,
+    "tPoint"               point                       default                                          null,
+    "tDate"                date                        default current_date                             null,
+    "tTime"                time                        default current_time                             null,
+    "tTimeWTZ"             time with time zone         default current_time                             null,
+    "tTimeWOTZ"            time without time zone      default current_time                             null,
+    "tTimestamp"           timestamp                   default now()                                    null,
+    "tTimestampTZ"         timestamptz                 default now()                                    null,
+    "tTimestampWTZ"        timestamp with time zone    default now()                                    null,
+    "tTimestampWOTZ"       timestamp without time zone default now()                                    null,
+    "tDouble"              double precision            default 0                                        null,
+    "tReal"                real                        default 0                                        null,
+    "tFloat8"              float8                      default 0                                        null,
+    "tFloat4"              float4                      default 0                                        null,
+    "tNumeric"             numeric                     default 0                                        null,
+    "tDecimal"             decimal                     default 0                                        null,
+    "tSmallSerial"         smallserial                                                                      ,
+    "tSerial"              serial                                                                           ,
+    "tBigSerial"           bigserial                                                                        ,
+    "tSerial2"             serial2                                                                          ,
+    "tSerial4"             serial4                                                                          ,
+    "tSerial8"             serial8                                                                          ,
+    "tArray"               text[10][10]                 default '{}'                                    null,
+    "tXML"                 xml                          default '<a>foo</a>'                            null,  
+    "tJSON"                json                         default '{"key":"value"}'                       null,
+    "tJSONB"               jsonb                        default '{"key":"value"}'                       null,
+    "tUUID"                uuid                         default  'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11' null,
+    "tMoney"               money                        default  18                                     null,
+    "tInterval"            interval                     default '4 hours'                               null, 
+    "tUserDefined"         address                      default '("ab","cd")'                           null
 );
 `
-		pgRun(t, func(t *pgTest) {
-			t.dropTables(n)
-			_, err := t.db.Exec(ddl)
-			require.NoError(t, err)
-			realm := t.loadRealm()
-			require.Len(t, realm.Schemas, 1)
-			ts, ok := realm.Schemas[0].Table(n)
-			require.True(t, ok)
-			expected := schema.Table{
-				Name:   n,
-				Schema: realm.Schemas[0],
-				Columns: []*schema.Column{
-					{
-						Name:    "tBit",
-						Type:    &schema.ColumnType{Type: &postgres.BitType{T: "bit", Len: 10}, Raw: "bit", Null: true},
-						Default: &schema.RawExpr{X: t.valueByVersion(map[string]string{"10": "B'100'::\"bit\""}, "'100'::\"bit\"")},
-					},
-					{
-						Name:    "tBitVar",
-						Type:    &schema.ColumnType{Type: &postgres.BitType{T: "bit varying", Len: 10}, Raw: "bit varying", Null: true},
-						Default: &schema.RawExpr{X: t.valueByVersion(map[string]string{"10": "B'100'::\"bit\""}, "'100'::\"bit\"")},
-					},
-					{
-						Name:    "tBoolean",
-						Type:    &schema.ColumnType{Type: &schema.BoolType{T: "boolean"}, Raw: "boolean", Null: false},
-						Default: &schema.RawExpr{X: "false"},
-					},
-					{
-						Name:    "tBool",
-						Type:    &schema.ColumnType{Type: &schema.BoolType{T: "boolean"}, Raw: "boolean", Null: false},
-						Default: &schema.RawExpr{X: "false"},
+	pgRun(t, func(t *pgTest) {
+		t.dropTables(n)
+		_, err := t.db.Exec(ddl)
+		require.NoError(t, err)
+		realm := t.loadRealm()
+		require.Len(t, realm.Schemas, 1)
+		ts, ok := realm.Schemas[0].Table(n)
+		require.True(t, ok)
+		expected := schema.Table{
+			Name:   n,
+			Schema: realm.Schemas[0],
+			Columns: []*schema.Column{
+				{
+					Name:    "tBit",
+					Type:    &schema.ColumnType{Type: &postgres.BitType{T: "bit", Len: 10}, Raw: "bit", Null: true},
+					Default: &schema.RawExpr{X: t.valueByVersion(map[string]string{"10": "B'100'::\"bit\""}, "'100'::\"bit\"")},
+				},
+				{
+					Name:    "tBitVar",
+					Type:    &schema.ColumnType{Type: &postgres.BitType{T: "bit varying", Len: 10}, Raw: "bit varying", Null: true},
+					Default: &schema.RawExpr{X: t.valueByVersion(map[string]string{"10": "B'100'::\"bit\""}, "'100'::\"bit\"")},
+				},
+				{
+					Name:    "tBoolean",
+					Type:    &schema.ColumnType{Type: &schema.BoolType{T: "boolean"}, Raw: "boolean", Null: false},
+					Default: &schema.RawExpr{X: "false"},
+				},
+				{
+					Name:    "tBool",
+					Type:    &schema.ColumnType{Type: &schema.BoolType{T: "boolean"}, Raw: "boolean", Null: false},
+					Default: &schema.RawExpr{X: "false"},
+				},
+				{
+					Name:    "tBytea",
+					Type:    &schema.ColumnType{Type: &schema.BinaryType{T: "bytea"}, Raw: "bytea", Null: false},
+					Default: &schema.RawExpr{X: "'\\x01'::bytea"},
+				},
+				{
+					Name:    "tCharacter",
+					Type:    &schema.ColumnType{Type: &schema.StringType{T: "character", Size: 10}, Raw: "character", Null: true},
+					Default: &schema.RawExpr{X: "'atlas'::bpchar"},
+				},
+				{
+					Name:    "tChar",
+					Type:    &schema.ColumnType{Type: &schema.StringType{T: "character", Size: 10}, Raw: "character", Null: true},
+					Default: &schema.RawExpr{X: "'atlas'::bpchar"},
+				},
+				{
+					Name:    "tCharVar",
+					Type:    &schema.ColumnType{Type: &schema.StringType{T: "character varying", Size: 10}, Raw: "character varying", Null: true},
+					Default: &schema.RawExpr{X: "'atlas'::character varying"},
+				},
+				{
+					Name:    "tVarChar",
+					Type:    &schema.ColumnType{Type: &schema.StringType{T: "character varying", Size: 10}, Raw: "character varying", Null: true},
+					Default: &schema.RawExpr{X: "'atlas'::character varying"},
+				},
+				{
+					Name:    "tText",
+					Type:    &schema.ColumnType{Type: &schema.StringType{T: "text"}, Raw: "text", Null: true},
+					Default: &schema.RawExpr{X: "'atlas'::text"},
+				},
+				{
+					Name:    "tSmallInt",
+					Type:    &schema.ColumnType{Type: &schema.IntegerType{T: "smallint"}, Raw: "smallint", Null: true},
+					Default: &schema.RawExpr{X: "'10'::smallint"},
+				},
+				{
+					Name:    "tInteger",
+					Type:    &schema.ColumnType{Type: &schema.IntegerType{T: "integer"}, Raw: "integer", Null: true},
+					Default: &schema.RawExpr{X: "10"},
+				},
+				{
+					Name:    "tBigInt",
+					Type:    &schema.ColumnType{Type: &schema.IntegerType{T: "bigint"}, Raw: "bigint", Null: true},
+					Default: &schema.RawExpr{X: "'10'::bigint"},
+				},
+				{
+					Name:    "tInt",
+					Type:    &schema.ColumnType{Type: &schema.IntegerType{T: "integer"}, Raw: "integer", Null: true},
+					Default: &schema.RawExpr{X: "10"},
+				},
+				{
+					Name:    "tInt2",
+					Type:    &schema.ColumnType{Type: &schema.IntegerType{T: "smallint"}, Raw: "smallint", Null: true},
+					Default: &schema.RawExpr{X: "'10'::smallint"},
+				},
+				{
+					Name:    "tInt4",
+					Type:    &schema.ColumnType{Type: &schema.IntegerType{T: "integer"}, Raw: "integer", Null: true},
+					Default: &schema.RawExpr{X: "10"},
+				},
+				{
+					Name:    "tInt8",
+					Type:    &schema.ColumnType{Type: &schema.IntegerType{T: "bigint"}, Raw: "bigint", Null: true},
+					Default: &schema.RawExpr{X: "'10'::bigint"},
+				},
+				{
+					Name:    "tCIDR",
+					Type:    &schema.ColumnType{Type: &postgres.NetworkType{T: "cidr"}, Raw: "cidr", Null: true},
+					Default: &schema.RawExpr{X: "'127.0.0.1/32'::cidr"},
+				},
+				{
+					Name:    "tInet",
+					Type:    &schema.ColumnType{Type: &postgres.NetworkType{T: "inet"}, Raw: "inet", Null: true},
+					Default: &schema.RawExpr{X: "'127.0.0.1'::inet"},
+				},
+				{
+					Name:    "tMACAddr",
+					Type:    &schema.ColumnType{Type: &postgres.NetworkType{T: "macaddr"}, Raw: "macaddr", Null: true},
+					Default: &schema.RawExpr{X: "'08:00:2b:01:02:03'::macaddr"},
+				},
+				{
+					Name:    "tMACAddr8",
+					Type:    &schema.ColumnType{Type: &postgres.NetworkType{T: "macaddr8"}, Raw: "macaddr8", Null: true},
+					Default: &schema.RawExpr{X: "'08:00:2b:01:02:03:04:05'::macaddr8"},
+				},
+				{
+					Name: "tCircle",
+					Type: &schema.ColumnType{Type: &schema.SpatialType{T: "circle"}, Raw: "circle", Null: true},
+				},
+				{
+					Name: "tLine",
+					Type: &schema.ColumnType{Type: &schema.SpatialType{T: "line"}, Raw: "line", Null: true},
+				},
+				{
+					Name: "tLseg",
+					Type: &schema.ColumnType{Type: &schema.SpatialType{T: "lseg"}, Raw: "lseg", Null: true},
+				},
+				{
+					Name: "tBox",
+					Type: &schema.ColumnType{Type: &schema.SpatialType{T: "box"}, Raw: "box", Null: true},
+				},
+				{
+					Name: "tPath",
+					Type: &schema.ColumnType{Type: &schema.SpatialType{T: "path"}, Raw: "path", Null: true},
+				},
+				{
+					Name: "tPoint",
+					Type: &schema.ColumnType{Type: &schema.SpatialType{T: "point"}, Raw: "point", Null: true},
+				},
+				{
+					Name:    "tDate",
+					Type:    &schema.ColumnType{Type: &schema.TimeType{T: "date"}, Raw: "date", Null: true},
+					Default: &schema.RawExpr{X: "CURRENT_DATE"},
+				},
+				{
+					Name:    "tTime",
+					Type:    &schema.ColumnType{Type: &schema.TimeType{T: "time without time zone"}, Raw: "time without time zone", Null: true},
+					Default: &schema.RawExpr{X: "CURRENT_TIME"},
+				},
+				{
+					Name:    "tTimeWTZ",
+					Type:    &schema.ColumnType{Type: &schema.TimeType{T: "time with time zone"}, Raw: "time with time zone", Null: true},
+					Default: &schema.RawExpr{X: "CURRENT_TIME"},
+				},
+				{
+					Name:    "tTimeWOTZ",
+					Type:    &schema.ColumnType{Type: &schema.TimeType{T: "time without time zone"}, Raw: "time without time zone", Null: true},
+					Default: &schema.RawExpr{X: "CURRENT_TIME"},
+				},
+				{
+					Name:    "tTimestamp",
+					Type:    &schema.ColumnType{Type: &schema.TimeType{T: "timestamp without time zone"}, Raw: "timestamp without time zone", Null: true},
+					Default: &schema.RawExpr{X: "now()"},
+				},
+				{
+					Name:    "tTimestampTZ",
+					Type:    &schema.ColumnType{Type: &schema.TimeType{T: "timestamp with time zone"}, Raw: "timestamp with time zone", Null: true},
+					Default: &schema.RawExpr{X: "now()"},
+				},
+				{
+					Name:    "tTimestampWTZ",
+					Type:    &schema.ColumnType{Type: &schema.TimeType{T: "timestamp with time zone"}, Raw: "timestamp with time zone", Null: true},
+					Default: &schema.RawExpr{X: "now()"},
+				},
+				{
+					Name:    "tTimestampWOTZ",
+					Type:    &schema.ColumnType{Type: &schema.TimeType{T: "timestamp without time zone"}, Raw: "timestamp without time zone", Null: true},
+					Default: &schema.RawExpr{X: "now()"},
+				},
+				{
+					Name:    "tDouble",
+					Type:    &schema.ColumnType{Type: &schema.FloatType{T: "double precision", Precision: 53}, Raw: "double precision", Null: true},
+					Default: &schema.RawExpr{X: "0"},
+				},
+				{
+					Name:    "tReal",
+					Type:    &schema.ColumnType{Type: &schema.FloatType{T: "real", Precision: 24}, Raw: "real", Null: true},
+					Default: &schema.RawExpr{X: "0"},
+				},
+				{
+					Name:    "tFloat8",
+					Type:    &schema.ColumnType{Type: &schema.FloatType{T: "double precision", Precision: 53}, Raw: "double precision", Null: true},
+					Default: &schema.RawExpr{X: "0"},
+				},
+				{
+					Name:    "tFloat4",
+					Type:    &schema.ColumnType{Type: &schema.FloatType{T: "real", Precision: 24}, Raw: "real", Null: true},
+					Default: &schema.RawExpr{X: "0"},
+				},
+				{
+					Name:    "tNumeric",
+					Type:    &schema.ColumnType{Type: &schema.DecimalType{T: "numeric", Precision: 0}, Raw: "numeric", Null: true},
+					Default: &schema.RawExpr{X: "0"},
+				},
+				{
+					Name:    "tDecimal",
+					Type:    &schema.ColumnType{Type: &schema.DecimalType{T: "numeric", Precision: 0}, Raw: "numeric", Null: true},
+					Default: &schema.RawExpr{X: "0"},
+				},
+				{
+					Name: "tSmallSerial",
+					Type: &schema.ColumnType{Type: &schema.IntegerType{T: "smallint", Unsigned: false}, Raw: "smallint", Null: false},
+					Default: &postgres.SeqFuncExpr{
+						Expr: nil,
+						X:    "nextval('\"atlas_types_sanity_tSmallSerial_seq\"'::regclass)",
 					},
-					{
-						Name:    "tBytea",
-						Type:    &schema.ColumnType{Type: &schema.BinaryType{T: "bytea"}, Raw: "bytea", Null: false},
-						Default: &schema.RawExpr{X: "'\\x01'::bytea"},
+				},
+				{
+					Name: "tSerial",
+					Type: &schema.ColumnType{Type: &schema.IntegerType{T: "integer", Unsigned: false}, Raw: "integer", Null: false},
+					Default: &postgres.SeqFuncExpr{
+						Expr: nil,
+						X:    "nextval('\"atlas_types_sanity_tSerial_seq\"'::regclass)",
 					},
-					{
-						Name:    "tCharacter",
-						Type:    &schema.ColumnType{Type: &schema.StringType{T: "character", Size: 10}, Raw: "character", Null: true},
-						Default: &schema.RawExpr{X: "'atlas'::bpchar"},
+				},
+				{
+					Name: "tBigSerial",
+					Type: &schema.ColumnType{Type: &schema.IntegerType{T: "bigint", Unsigned: false}, Raw: "bigint", Null: false},
+					Default: &postgres.SeqFuncExpr{
+						Expr: nil,
+						X:    "nextval('\"atlas_types_sanity_tBigSerial_seq\"'::regclass)",
 					},
-					{
-						Name:    "tChar",
-						Type:    &schema.ColumnType{Type: &schema.StringType{T: "character", Size: 10}, Raw: "character", Null: true},
-						Default: &schema.RawExpr{X: "'atlas'::bpchar"},
+				},
+				{
+					Name: "tSerial2",
+					Type: &schema.ColumnType{Type: &schema.IntegerType{T: "smallint", Unsigned: false}, Raw: "smallint", Null: false},
+					Default: &postgres.SeqFuncExpr{
+						Expr: nil,
+						X:    "nextval('\"atlas_types_sanity_tSerial2_seq\"'::regclass)",
 					},
-					{
-						Name:    "tCharVar",
-						Type:    &schema.ColumnType{Type: &schema.StringType{T: "character varying", Size: 10}, Raw: "character varying", Null: true},
-						Default: &schema.RawExpr{X: "'atlas'::character varying"},
+				},
+				{
+					Name: "tSerial4",
+					Type: &schema.ColumnType{Type: &schema.IntegerType{T: "integer", Unsigned: false}, Raw: "integer", Null: false},
+					Default: &postgres.SeqFuncExpr{
+						Expr: nil,
+						X:    "nextval('\"atlas_types_sanity_tSerial4_seq\"'::regclass)",
 					},
-					{
-						Name:    "tVarChar",
-						Type:    &schema.ColumnType{Type: &schema.StringType{T: "character varying", Size: 10}, Raw: "character varying", Null: true},
-						Default: &schema.RawExpr{X: "'atlas'::character varying"},
+				},
+				{
+					Name: "tSerial8",
+					Type: &schema.ColumnType{Type: &schema.IntegerType{T: "bigint", Unsigned: false}, Raw: "bigint", Null: false},
+					Default: &postgres.SeqFuncExpr{
+						Expr: nil,
+						X:    "nextval('\"atlas_types_sanity_tSerial8_seq\"'::regclass)",
 					},
-					{
-						Name:    "tText",
-						Type:    &schema.ColumnType{Type: &schema.StringType{T: "text"}, Raw: "text", Null: true},
-						Default: &schema.RawExpr{X: "'atlas'::text"},
+				},
+				{
+					Name: "tArray",
+					Type: &schema.ColumnType{Type: &postgres.ArrayType{T: "text[]"}, Raw: "ARRAY", Null: true},
+					Default: &schema.RawExpr{
+						X: "'{}'::text[]",
 					},
-					{
-						Name:    "tSmallInt",
-						Type:    &schema.ColumnType{Type: &schema.IntegerType{T: "smallint"}, Raw: "smallint", Null: true},
-						Default: &schema.RawExpr{X: "'10'::smallint"},
+				},
+				{
+					Name: "tXML",
+					Type: &schema.ColumnType{Type: &postgres.XMLType{T: "xml"}, Raw: "xml", Null: true},
+					Default: &schema.RawExpr{
+						X: "'<a>foo</a>'::xml",
 					},
-					{
-						Name:    "tInteger",
-						Type:    &schema.ColumnType{Type: &schema.IntegerType{T: "integer"}, Raw: "integer", Null: true},
-						Default: &schema.RawExpr{X: "10"},
+				},
+				{
+					Name: "tJSON",
+					Type: &schema.ColumnType{Type: &schema.JSONType{T: "json"}, Raw: "json", Null: true},
+					Default: &schema.RawExpr{
+						X: "'{\"key\":\"value\"}'::json",
 					},
-					{
-						Name:    "tBigInt",
-						Type:    &schema.ColumnType{Type: &schema.IntegerType{T: "bigint"}, Raw: "bigint", Null: true},
-						Default: &schema.RawExpr{X: "'10'::bigint"},
+				},
+				{
+					Name: "tJSONB",
+					Type: &schema.ColumnType{Type: &schema.JSONType{T: "jsonb"}, Raw: "jsonb", Null: true},
+					Default: &schema.RawExpr{
+						X: "'{\"key\": \"value\"}'::jsonb",
 					},
-					{
-						Name:    "tInt",
-						Type:    &schema.ColumnType{Type: &schema.IntegerType{T: "integer"}, Raw: "integer", Null: true},
-						Default: &schema.RawExpr{X: "10"},
+				},
+				{
+					Name: "tUUID",
+					Type: &schema.ColumnType{Type: &postgres.UUIDType{T: "uuid"}, Raw: "uuid", Null: true},
+					Default: &schema.RawExpr{
+						X: "'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid",
 					},
-					{
-						Name:    "tInt2",
-						Type:    &schema.ColumnType{Type: &schema.IntegerType{T: "smallint"}, Raw: "smallint", Null: true},
-						Default: &schema.RawExpr{X: "'10'::smallint"},
+				},
+				{
+					Name: "tMoney",
+					Type: &schema.ColumnType{Type: &postgres.CurrencyType{T: "money"}, Raw: "money", Null: true},
+					Default: &schema.RawExpr{
+						X: "18",
 					},
-					{
-						Name:    "tInt4",
-						Type:    &schema.ColumnType{Type: &schema.IntegerType{T: "integer"}, Raw: "integer", Null: true},
-						Default: &schema.RawExpr{X: "10"},
+				},
+				{
+					Name: "tInterval",
+					Type: &schema.ColumnType{Type: &schema.UnsupportedType{T: "interval"}, Raw: "interval", Null: true},
+					Default: &schema.RawExpr{
+						X: "'04:00:00'::interval",
 					},
-					{
-						Name:    "tInt8",
-						Type:    &schema.ColumnType{Type: &schema.IntegerType{T: "bigint"}, Raw: "bigint", Null: true},
-						Default: &schema.RawExpr{X: "'10'::bigint"},
+				},
+				{
+					Name: "tUserDefined",
+					Type: &schema.ColumnType{Type: &postgres.UserDefinedType{T: "address"}, Raw: "USER-DEFINED", Null: true},
+					Default: &schema.RawExpr{
+						X: "'(ab,cd)'::address",
 					},
 				},
-			}
-			require.EqualValues(t, &expected, ts)
-		})
+			},
+		}
+		require.EqualValues(t, &expected, ts)
 	})
 }
 
diff --git a/schema/schemaspec/schemahcl/context_test.go b/schema/schemaspec/schemahcl/context_test.go
index 030e9583..d4826d2c 100644
--- a/schema/schemaspec/schemahcl/context_test.go
+++ b/schema/schemaspec/schemahcl/context_test.go
@@ -352,9 +352,10 @@ x = from_ctx
 }
 
 func TestWithTypes(t *testing.T) {
-	f := `first  = int
-second = bool
-sized  = varchar(255)
+	f := `first    = int
+second   = bool
+sized    = varchar(255)
+variadic = enum("a","b","c")
 `
 	s := New(
 		WithTypes(
@@ -374,13 +375,21 @@ sized  = varchar(255)
 						{Name: "size", Kind: reflect.Int, Required: false},
 					},
 				},
+				{
+					Name: "enum",
+					T:    "enum",
+					Attributes: []*schemaspec.TypeAttr{
+						{Name: "values", Kind: reflect.Slice, Required: false},
+					},
+				},
 			},
 		),
 	)
 	var test struct {
-		First   *schemaspec.Type `spec:"first"`
-		Second  *schemaspec.Type `spec:"second"`
-		Varchar *schemaspec.Type `spec:"sized"`
+		First    *schemaspec.Type `spec:"first"`
+		Second   *schemaspec.Type `spec:"second"`
+		Varchar  *schemaspec.Type `spec:"sized"`
+		Variadic *schemaspec.Type `spec:"variadic"`
 	}
 	err := s.UnmarshalSpec([]byte(f), &test)
 	require.NoError(t, err)
@@ -392,6 +401,21 @@ sized  = varchar(255)
 			{K: "size", V: &schemaspec.LiteralValue{V: "255"}},
 		},
 	}, test.Varchar)
+	require.EqualValues(t, &schemaspec.Type{
+		T: "enum",
+		Attributes: []*schemaspec.Attr{
+			{
+				K: "values",
+				V: &schemaspec.ListValue{
+					V: []schemaspec.Value{
+						&schemaspec.LiteralValue{V: `"a"`},
+						&schemaspec.LiteralValue{V: `"b"`},
+						&schemaspec.LiteralValue{V: `"c"`},
+					},
+				},
+			},
+		},
+	}, test.Variadic)
 	after, err := s.MarshalSpec(&test)
 	require.NoError(t, err)
 	require.EqualValues(t, f, string(after))