diff --git a/sql/internal/specutil/convert.go b/sql/internal/specutil/convert.go index bb006b363e6..605e586aa30 100644 --- a/sql/internal/specutil/convert.go +++ b/sql/internal/specutil/convert.go @@ -5,6 +5,7 @@ package specutil import ( + "errors" "fmt" "strconv" "strings" @@ -380,7 +381,13 @@ func Default(d cty.Value) (schema.Expr, error) { case d.Type() == cty.String: x = &schema.Literal{V: d.AsString()} case d.Type() == cty.Number: - x = &schema.Literal{V: d.AsBigFloat().String()} + f := d.AsBigFloat() + // If the number is an integer, convert it to an integer. + if f.IsInt() { + x = &schema.Literal{V: f.Text('f', -1)} + } else { + x = &schema.Literal{V: f.String()} + } case d.Type() == cty.Bool: x = &schema.Literal{V: strconv.FormatBool(d.True())} case d.Type().IsCapsuleType(): @@ -879,11 +886,18 @@ func ColumnDefault(c *schema.Column) (cty.Value, error) { } return cty.NumberFloatVal(f), nil case sqlx.IsLiteralNumber(x.V): - i, err := strconv.ParseInt(x.V, 10, 64) - if err != nil { + switch i, err := strconv.ParseInt(x.V, 10, 64); { + case errors.Is(err, strconv.ErrRange): + u, err := strconv.ParseUint(x.V, 10, 64) + if err != nil { + return cty.NilVal, err + } + return cty.NumberUIntVal(u), nil + case err != nil: return cty.NilVal, err + default: + return cty.NumberIntVal(i), nil } - return cty.NumberIntVal(i), nil default: switch c.Type.Type.(type) { // Literal values (non-expressions) are returned diff --git a/sql/internal/specutil/convert_test.go b/sql/internal/specutil/convert_test.go index e16695c3e07..8448c8f7cf4 100644 --- a/sql/internal/specutil/convert_test.go +++ b/sql/internal/specutil/convert_test.go @@ -5,6 +5,7 @@ package specutil import ( + "math" "testing" "ariga.io/atlas/schemahcl" @@ -12,6 +13,7 @@ import ( "ariga.io/atlas/sql/sqlspec" "github.com/stretchr/testify/require" + "github.com/zclconf/go-cty/cty" ) func TestFromSpec_SchemaName(t *testing.T) { @@ -94,3 +96,52 @@ func TestFromForeignKey(t *testing.T) { }, }, key) } + +func TestDefault(t *testing.T) { + for _, tt := range []struct { + v cty.Value + x string + }{ + { + v: cty.NumberUIntVal(1), + x: "1", + }, + { + v: cty.NumberIntVal(1), + x: "1", + }, + { + v: cty.NumberFloatVal(1), + x: "1", + }, + { + v: cty.NumberIntVal(-100), + x: "-100", + }, + { + v: cty.NumberFloatVal(-100), + x: "-100", + }, + { + v: cty.NumberUIntVal(math.MaxUint64), + x: "18446744073709551615", + }, + { + v: cty.NumberIntVal(math.MinInt64), + x: "-9223372036854775808", + }, + { + v: cty.NumberFloatVal(-1024.1024), + x: "-1024.1024", + }, + } { + // From cty.Value (HCL) to database literal. + x, err := Default(tt.v) + require.NoError(t, err) + require.Equal(t, tt.x, x.(*schema.Literal).V) + // From database literal to cty.Value (HCL). + v, err := ColumnDefault(schema.NewColumn("").SetDefault(&schema.Literal{V: tt.x})) + require.NoError(t, err) + require.True(t, tt.v.Equals(v).True()) + } +}