Repository: ariga/atlas
Pull request #967 (2022-07-19 19:04:15)

sql/postgres: support the alias float type


Patch:
diff --git a/doc/md/ddl/sql-types.md b/doc/md/ddl/sql-types.md
index 90cf2fee..531075ce 100644
--- a/doc/md/ddl/sql-types.md
+++ b/doc/md/ddl/sql-types.md
@@ -437,6 +437,32 @@ table "t" {
 }
 ```
 
+
+### Floating Point (Float)
+
+The `real` and `double_precision` types are supported for storing
+[approximate numeric values](https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-FLOAT).
+
+```hcl
+table "t" {
+  schema = schema.test
+  column "c1" {
+    type = real
+  }
+  column "c2" {
+    type = double_precision
+  }
+  column "c3" {
+    // Equals to real when precision is between 1 to 24.
+    type = float(10)
+  }
+  column "c2" {
+    // Equals to double_precision when precision is between 1 to 24.
+    type = float(30)
+  }
+}
+```
+
 ### Geometric
 
 Atlas supports the standard PostgreSQL types for creating geometric columns.
diff --git a/sql/postgres/convert.go b/sql/postgres/convert.go
index 9193588c..abdf27ba 100644
--- a/sql/postgres/convert.go
+++ b/sql/postgres/convert.go
@@ -92,6 +92,15 @@ func FormatType(t schema.Type) (string, error) {
 			f = TypeReal
 		case TypeFloat8:
 			f = TypeDouble
+		case TypeFloat:
+			switch {
+			case t.Precision > 0 && t.Precision <= 24:
+				f = TypeReal
+			case t.Precision == 0 || (t.Precision > 24 && t.Precision <= 53):
+				f = TypeDouble
+			default:
+				return "", fmt.Errorf("postgres: precision for type float must be between 1 and 53: %d", t.Precision)
+			}
 		}
 	case *schema.DecimalType:
 		switch f = strings.ToLower(t.T); f {
@@ -228,7 +237,7 @@ func parseColumn(s string) (*columnDesc, error) {
 		if err := parseCharParts(c.parts, c); err != nil {
 			return nil, err
 		}
-	case TypeDecimal, TypeNumeric:
+	case TypeDecimal, TypeNumeric, TypeFloat:
 		if len(parts) > 1 {
 			c.precision, err = strconv.ParseInt(parts[1], 10, 64)
 			if err != nil {
diff --git a/sql/postgres/driver.go b/sql/postgres/driver.go
index 976c9eac..7a6bd739 100644
--- a/sql/postgres/driver.go
+++ b/sql/postgres/driver.go
@@ -314,6 +314,7 @@ const (
 	TypeReal   = "real"
 	TypeFloat8 = "float8" // double precision
 	TypeFloat4 = "float4" // real
+	TypeFloat  = "float"  // float(p).
 
 	TypeNumeric = "numeric"
 	TypeDecimal = "decimal" // numeric
diff --git a/sql/postgres/inspect.go b/sql/postgres/inspect.go
index 0dc726d4..fdfbc454 100644
--- a/sql/postgres/inspect.go
+++ b/sql/postgres/inspect.go
@@ -269,7 +269,7 @@ func columnType(c *columnDesc) (schema.Type, error) {
 			}
 			typ.(*IntervalType).F = f
 		}
-	case TypeReal, TypeDouble, TypeFloat4, TypeFloat8:
+	case TypeReal, TypeDouble, TypeFloat, TypeFloat4, TypeFloat8:
 		typ = &schema.FloatType{T: t, Precision: int(c.precision)}
 	case TypeJSON, TypeJSONB:
 		typ = &schema.JSONType{T: t}
diff --git a/sql/postgres/sqlspec.go b/sql/postgres/sqlspec.go
index 310d3618..a094ad13 100644
--- a/sql/postgres/sqlspec.go
+++ b/sql/postgres/sqlspec.go
@@ -552,6 +552,7 @@ var TypeRegistry = schemahcl.NewRegistry(
 		schemahcl.NewTypeSpec(TypeTimestamp, schemahcl.WithAttributes(precisionTypeAttr()), formatTime()),
 		schemahcl.AliasTypeSpec("double_precision", TypeDouble),
 		schemahcl.NewTypeSpec(TypeReal),
+		schemahcl.NewTypeSpec(TypeFloat, schemahcl.WithAttributes(precisionTypeAttr())),
 		schemahcl.NewTypeSpec(TypeFloat8),
 		schemahcl.NewTypeSpec(TypeFloat4),
 		schemahcl.NewTypeSpec(TypeNumeric, schemahcl.WithAttributes(precisionTypeAttr(), &schemahcl.TypeAttr{Name: "scale", Kind: reflect.Int, Required: false})),


Test patch:
diff --git a/internal/integration/testdata/postgres/column-float.txt b/internal/integration/testdata/postgres/column-float.txt
new file mode 100644
index 00000000..4d3bb288
--- /dev/null
+++ b/internal/integration/testdata/postgres/column-float.txt
@@ -0,0 +1,64 @@
+apply 1.hcl
+cmpshow users 1.sql
+
+apply 2.hcl
+cmpshow users 2.sql
+
+-- 1.hcl --
+schema "$db" {}
+
+table "users" {
+  schema = schema.$db
+  column "c1" {
+    type = real
+  }
+  column "c2" {
+    type = double_precision
+  }
+  column "c3" {
+    // Equals to real when precision is between 1 and 24.
+    type = float(10)
+  }
+  column "c4" {
+    // Equals to double_precision when precision is between 1 and 24.
+    type = float(30)
+  }
+}
+
+-- 1.sql --
+             Table "script_column_float.users"
+ Column |       Type       | Collation | Nullable | Default
+--------+------------------+-----------+----------+---------
+ c1     | real             |           | not null |
+ c2     | double precision |           | not null |
+ c3     | real             |           | not null |
+ c4     | double precision |           | not null |
+
+
+-- 2.hcl --
+schema "$db" {}
+
+table "users" {
+  schema = schema.$db
+  column "c1" {
+    type = double_precision
+  }
+  column "c2" {
+    type = real
+  }
+  column "c3" {
+    type = float(30)
+  }
+  column "c4" {
+    type = float(10)
+  }
+}
+
+-- 2.sql --
+             Table "script_column_float.users"
+ Column |       Type       | Collation | Nullable | Default
+--------+------------------+-----------+----------+---------
+ c1     | double precision |           | not null |
+ c2     | real             |           | not null |
+ c3     | double precision |           | not null |
+ c4     | real             |           | not null |
\ No newline at end of file
diff --git a/sql/postgres/sqlspec_test.go b/sql/postgres/sqlspec_test.go
index cdc91c37..6aaad975 100644
--- a/sql/postgres/sqlspec_test.go
+++ b/sql/postgres/sqlspec_test.go
@@ -933,6 +933,18 @@ func TestTypes(t *testing.T) {
 			typeExpr: "real",
 			expected: &schema.FloatType{T: TypeReal, Precision: 24},
 		},
+		{
+			typeExpr: "float",
+			expected: &schema.FloatType{T: TypeFloat},
+		},
+		{
+			typeExpr: "float(1)",
+			expected: &schema.FloatType{T: TypeFloat, Precision: 1},
+		},
+		{
+			typeExpr: "float(25)",
+			expected: &schema.FloatType{T: TypeFloat, Precision: 25},
+		},
 		{
 			typeExpr: "float8",
 			expected: &schema.FloatType{T: TypeFloat8, Precision: 53},