test(drawdb): add test for converting column types with modifiers
* Implement tests to ensure explicit type modifiers are preserved during conversion. * Validate behavior for varchar, numeric, and custom vector types.
This commit is contained in:
@@ -493,18 +493,19 @@ func (w *Writer) generateColumnDefinition(col *models.Column) string {
|
||||
// Type with length/precision - convert to valid PostgreSQL type
|
||||
baseType := pgsql.ConvertSQLType(col.Type)
|
||||
typeStr := baseType
|
||||
hasExplicitTypeModifier := pgsql.HasExplicitTypeModifier(baseType)
|
||||
|
||||
// Only add size specifiers for types that support them
|
||||
if col.Length > 0 && col.Precision == 0 {
|
||||
if supportsLength(baseType) {
|
||||
if !hasExplicitTypeModifier && col.Length > 0 && col.Precision == 0 {
|
||||
if pgsql.SupportsLength(baseType) {
|
||||
typeStr = fmt.Sprintf("%s(%d)", baseType, col.Length)
|
||||
} else if isTextTypeWithoutLength(baseType) {
|
||||
// Convert text with length to varchar
|
||||
typeStr = fmt.Sprintf("varchar(%d)", col.Length)
|
||||
}
|
||||
// For types that don't support length (integer, bigint, etc.), ignore the length
|
||||
} else if col.Precision > 0 {
|
||||
if supportsPrecision(baseType) {
|
||||
} else if !hasExplicitTypeModifier && col.Precision > 0 {
|
||||
if pgsql.SupportsPrecision(baseType) {
|
||||
if col.Scale > 0 {
|
||||
typeStr = fmt.Sprintf("%s(%d,%d)", baseType, col.Precision, col.Scale)
|
||||
} else {
|
||||
@@ -1268,30 +1269,6 @@ func isTextType(colType string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// supportsLength checks if a PostgreSQL type supports length specification
|
||||
func supportsLength(colType string) bool {
|
||||
lengthTypes := []string{"varchar", "character varying", "char", "character", "bit", "bit varying", "varbit"}
|
||||
lowerType := strings.ToLower(colType)
|
||||
for _, t := range lengthTypes {
|
||||
if lowerType == t || strings.HasPrefix(lowerType, t+"(") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// supportsPrecision checks if a PostgreSQL type supports precision/scale specification
|
||||
func supportsPrecision(colType string) bool {
|
||||
precisionTypes := []string{"numeric", "decimal", "time", "timestamp", "timestamptz", "timestamp with time zone", "timestamp without time zone", "time with time zone", "time without time zone", "interval"}
|
||||
lowerType := strings.ToLower(colType)
|
||||
for _, t := range precisionTypes {
|
||||
if lowerType == t || strings.HasPrefix(lowerType, t+"(") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isTextTypeWithoutLength checks if type is text (which should convert to varchar when length is specified)
|
||||
func isTextTypeWithoutLength(colType string) bool {
|
||||
return strings.EqualFold(colType, "text")
|
||||
|
||||
@@ -426,11 +426,11 @@ func TestWriteAllConstraintTypes(t *testing.T) {
|
||||
|
||||
// Verify all constraint types are present
|
||||
expectedConstraints := map[string]string{
|
||||
"Primary Key": "PRIMARY KEY",
|
||||
"Unique": "ADD CONSTRAINT uq_order_number UNIQUE (order_number)",
|
||||
"Check (total)": "ADD CONSTRAINT ck_total_positive CHECK (total > 0)",
|
||||
"Check (status)": "ADD CONSTRAINT ck_status_valid CHECK (status IN ('pending', 'completed', 'cancelled'))",
|
||||
"Foreign Key": "FOREIGN KEY",
|
||||
"Primary Key": "PRIMARY KEY",
|
||||
"Unique": "ADD CONSTRAINT uq_order_number UNIQUE (order_number)",
|
||||
"Check (total)": "ADD CONSTRAINT ck_total_positive CHECK (total > 0)",
|
||||
"Check (status)": "ADD CONSTRAINT ck_status_valid CHECK (status IN ('pending', 'completed', 'cancelled'))",
|
||||
"Foreign Key": "FOREIGN KEY",
|
||||
}
|
||||
|
||||
for name, expected := range expectedConstraints {
|
||||
@@ -715,11 +715,11 @@ func TestColumnSizeSpecifiers(t *testing.T) {
|
||||
|
||||
// Verify valid patterns ARE present
|
||||
validPatterns := []string{
|
||||
"integer", // without size
|
||||
"bigint", // without size
|
||||
"smallint", // without size
|
||||
"varchar(100)", // text converted to varchar with length
|
||||
"varchar(50)", // varchar with length
|
||||
"integer", // without size
|
||||
"bigint", // without size
|
||||
"smallint", // without size
|
||||
"varchar(100)", // text converted to varchar with length
|
||||
"varchar(50)", // varchar with length
|
||||
"decimal(19,4)", // decimal with precision and scale
|
||||
}
|
||||
for _, pattern := range validPatterns {
|
||||
@@ -729,6 +729,56 @@ func TestColumnSizeSpecifiers(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateColumnDefinition_PreservesExplicitTypeModifiers(t *testing.T) {
|
||||
writer := NewWriter(&writers.WriterOptions{})
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
colType string
|
||||
length int
|
||||
precision int
|
||||
scale int
|
||||
wantType string
|
||||
}{
|
||||
{
|
||||
name: "character varying already includes length",
|
||||
colType: "character varying(50)",
|
||||
length: 50,
|
||||
wantType: "character varying(50)",
|
||||
},
|
||||
{
|
||||
name: "numeric already includes precision",
|
||||
colType: "numeric(10,2)",
|
||||
precision: 10,
|
||||
scale: 2,
|
||||
wantType: "numeric(10,2)",
|
||||
},
|
||||
{
|
||||
name: "custom vector modifier preserved",
|
||||
colType: "vector(1536)",
|
||||
wantType: "vector(1536)",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
col := models.InitColumn("sample", "events", "public")
|
||||
col.Type = tc.colType
|
||||
col.Length = tc.length
|
||||
col.Precision = tc.precision
|
||||
col.Scale = tc.scale
|
||||
|
||||
def := writer.generateColumnDefinition(col)
|
||||
if !strings.Contains(def, " "+tc.wantType+" ") && !strings.HasSuffix(def, " "+tc.wantType) {
|
||||
t.Fatalf("generated definition %q does not contain expected type %q", def, tc.wantType)
|
||||
}
|
||||
if strings.Contains(def, ")(") {
|
||||
t.Fatalf("generated definition %q appears to duplicate modifiers", def)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateAddColumnStatements(t *testing.T) {
|
||||
// Create a test database with tables that have new columns
|
||||
db := models.InitDatabase("testdb")
|
||||
|
||||
Reference in New Issue
Block a user