Repository: ariga/atlas
Pull request #687 (2022-04-07 12:21:52)

sql/postgres: fix the way time with(out) precision are parsed


Patch:
diff --git a/sql/postgres/convert.go b/sql/postgres/convert.go
index 9542968d..c0d2d402 100644
--- a/sql/postgres/convert.go
+++ b/sql/postgres/convert.go
@@ -230,8 +230,8 @@ func parseColumn(s string) (*columnDesc, error) {
 		c.precision = 53
 	case TypeReal, TypeFloat4:
 		c.precision = 24
-	case TypeTime, TypeTimeWOTZ, TypeTimeTZ, TypeTimeWTZ, TypeTimestamp, TypeTimestampWOTZ, TypeTimestampTZ, TypeTimestampWTZ:
-		t, p := timeAlias(c.parts[0]), int64(defaultTimePrecision)
+	case TypeTime, TypeTimeTZ, TypeTimestamp, TypeTimestampTZ:
+		t, p := s, int64(defaultTimePrecision)
 		// If the second part is only one digit it is the precision argument.
 		// For cases like "timestamp(4) with time zone" make sure to not drop
 		// the rest of the type definition.
@@ -241,8 +241,9 @@ func parseColumn(s string) (*columnDesc, error) {
 				return nil, fmt.Errorf("postgres: parse time precision %q: %w", parts[1], err)
 			}
 			p = i
+			t = strings.Join(append(c.parts[:1], c.parts[2:]...), " ")
 		}
-		c.typ = t
+		c.typ = timeAlias(t)
 		c.timePrecision = &p
 	default:
 		c.typ = s


Test patch:
diff --git a/sql/postgres/sqlspec_test.go b/sql/postgres/sqlspec_test.go
index ea136cc7..ab4584d0 100644
--- a/sql/postgres/sqlspec_test.go
+++ b/sql/postgres/sqlspec_test.go
@@ -712,6 +712,92 @@ schema "test" {
 	}
 }
 
+func TestParseType_Time(t *testing.T) {
+	for _, tt := range []struct {
+		typ      string
+		expected schema.Type
+	}{
+		{
+			typ:      "timestamptz",
+			expected: &schema.TimeType{T: TypeTimestampTZ, Precision: 6},
+		},
+		{
+			typ:      "timestamptz(0)",
+			expected: &schema.TimeType{T: TypeTimestampTZ, Precision: 0},
+		},
+		{
+			typ:      "timestamptz(6)",
+			expected: &schema.TimeType{T: TypeTimestampTZ, Precision: 6},
+		},
+		{
+			typ:      "timestamp with time zone",
+			expected: &schema.TimeType{T: TypeTimestampTZ, Precision: 6},
+		},
+		{
+			typ:      "timestamp(1) with time zone",
+			expected: &schema.TimeType{T: TypeTimestampTZ, Precision: 1},
+		},
+		{
+			typ:      "timestamp",
+			expected: &schema.TimeType{T: TypeTimestamp, Precision: 6},
+		},
+		{
+			typ:      "timestamp(0)",
+			expected: &schema.TimeType{T: TypeTimestamp, Precision: 0},
+		},
+		{
+			typ:      "timestamp(6)",
+			expected: &schema.TimeType{T: TypeTimestamp, Precision: 6},
+		},
+		{
+			typ:      "timestamp without time zone",
+			expected: &schema.TimeType{T: TypeTimestamp, Precision: 6},
+		},
+		{
+			typ:      "timestamp(1) without time zone",
+			expected: &schema.TimeType{T: TypeTimestamp, Precision: 1},
+		},
+		{
+			typ:      "time",
+			expected: &schema.TimeType{T: TypeTime, Precision: 6},
+		},
+		{
+			typ:      "time(3)",
+			expected: &schema.TimeType{T: TypeTime, Precision: 3},
+		},
+		{
+			typ:      "time without time zone",
+			expected: &schema.TimeType{T: TypeTime, Precision: 6},
+		},
+		{
+			typ:      "time(3) without time zone",
+			expected: &schema.TimeType{T: TypeTime, Precision: 3},
+		},
+		{
+			typ:      "timetz",
+			expected: &schema.TimeType{T: TypeTimeTZ, Precision: 6},
+		},
+		{
+			typ:      "timetz(4)",
+			expected: &schema.TimeType{T: TypeTimeTZ, Precision: 4},
+		},
+		{
+			typ:      "time with time zone",
+			expected: &schema.TimeType{T: TypeTimeTZ, Precision: 6},
+		},
+		{
+			typ:      "time(4) with time zone",
+			expected: &schema.TimeType{T: TypeTimeTZ, Precision: 4},
+		},
+	} {
+		t.Run(tt.typ, func(t *testing.T) {
+			typ, err := ParseType(tt.typ)
+			require.NoError(t, err)
+			require.Equal(t, tt.expected, typ)
+		})
+	}
+}
+
 func TestRegistrySanity(t *testing.T) {
 	spectest.RegistrySanityTest(t, TypeRegistry, []string{"enum"})
 }