feat(pkg): preserve PostgreSQL types in mapDataType function
* Add support for known PostgreSQL types and modifiers * Implement canonicalization for PostgreSQL types * Introduce unit tests for PostgreSQL type handling
This commit is contained in:
@@ -7,6 +7,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.warky.dev/wdevs/relspecgo/pkg/models"
|
"git.warky.dev/wdevs/relspecgo/pkg/models"
|
||||||
|
"git.warky.dev/wdevs/relspecgo/pkg/pgsql"
|
||||||
"git.warky.dev/wdevs/relspecgo/pkg/readers"
|
"git.warky.dev/wdevs/relspecgo/pkg/readers"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -232,7 +233,19 @@ func (r *Reader) convertField(dctxField *models.DCTXField, tableName string) ([]
|
|||||||
|
|
||||||
// mapDataType maps Clarion data types to SQL types
|
// mapDataType maps Clarion data types to SQL types
|
||||||
func (r *Reader) mapDataType(clarionType string, size int) (sqlType string, precision int) {
|
func (r *Reader) mapDataType(clarionType string, size int) (sqlType string, precision int) {
|
||||||
switch strings.ToUpper(clarionType) {
|
trimmedType := strings.TrimSpace(clarionType)
|
||||||
|
|
||||||
|
// Preserve known PostgreSQL types (including arrays and extension types)
|
||||||
|
// from DCTX input instead of coercing them to generic text.
|
||||||
|
if pgsql.IsKnownPostgresType(trimmedType) {
|
||||||
|
pgType := canonicalizePostgresType(trimmedType)
|
||||||
|
if !pgsql.HasExplicitTypeModifier(pgType) && size > 0 && pgsql.SupportsLength(pgType) {
|
||||||
|
return pgType, size
|
||||||
|
}
|
||||||
|
return pgType, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
switch strings.ToUpper(trimmedType) {
|
||||||
case "LONG":
|
case "LONG":
|
||||||
if size == 8 {
|
if size == 8 {
|
||||||
return "bigint", 0
|
return "bigint", 0
|
||||||
@@ -306,6 +319,32 @@ func (r *Reader) mapDataType(clarionType string, size int) (sqlType string, prec
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func canonicalizePostgresType(typeStr string) string {
|
||||||
|
t := strings.ToLower(strings.Join(strings.Fields(strings.TrimSpace(typeStr)), " "))
|
||||||
|
if t == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle array suffixes
|
||||||
|
arrayCount := 0
|
||||||
|
for strings.HasSuffix(t, "[]") {
|
||||||
|
arrayCount++
|
||||||
|
t = strings.TrimSpace(strings.TrimSuffix(t, "[]"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle optional type modifier
|
||||||
|
modifier := ""
|
||||||
|
if idx := strings.Index(t, "("); idx > 0 {
|
||||||
|
if end := strings.LastIndex(t, ")"); end > idx {
|
||||||
|
modifier = t[idx : end+1]
|
||||||
|
t = strings.TrimSpace(t[:idx])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
base := pgsql.CanonicalizeBaseType(t)
|
||||||
|
return base + modifier + strings.Repeat("[]", arrayCount)
|
||||||
|
}
|
||||||
|
|
||||||
// processKeys processes DCTX keys and converts them to indexes and primary keys
|
// processKeys processes DCTX keys and converts them to indexes and primary keys
|
||||||
func (r *Reader) processKeys(dctxTable *models.DCTXTable, table *models.Table, fieldGuidMap map[string]string) error {
|
func (r *Reader) processKeys(dctxTable *models.DCTXTable, table *models.Table, fieldGuidMap map[string]string) error {
|
||||||
for _, dctxKey := range dctxTable.Keys {
|
for _, dctxKey := range dctxTable.Keys {
|
||||||
|
|||||||
@@ -493,3 +493,55 @@ func TestRelationships(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMapDataType_PostgresTypes(t *testing.T) {
|
||||||
|
reader := &Reader{}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
inputType string
|
||||||
|
size int
|
||||||
|
wantType string
|
||||||
|
wantLength int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "integer array preserved",
|
||||||
|
inputType: "integer[]",
|
||||||
|
wantType: "integer[]",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "citext array preserved",
|
||||||
|
inputType: "citext[]",
|
||||||
|
wantType: "citext[]",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "vector modifier preserved",
|
||||||
|
inputType: "vector(1536)",
|
||||||
|
wantType: "vector(1536)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "alias canonicalized in array",
|
||||||
|
inputType: "int4[]",
|
||||||
|
wantType: "integer[]",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "varchar length from size",
|
||||||
|
inputType: "varchar",
|
||||||
|
size: 120,
|
||||||
|
wantType: "varchar",
|
||||||
|
wantLength: 120,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
gotType, gotLength := reader.mapDataType(tt.inputType, tt.size)
|
||||||
|
if gotType != tt.wantType {
|
||||||
|
t.Fatalf("mapDataType(%q, %d) type = %q, want %q", tt.inputType, tt.size, gotType, tt.wantType)
|
||||||
|
}
|
||||||
|
if gotLength != tt.wantLength {
|
||||||
|
t.Fatalf("mapDataType(%q, %d) length = %d, want %d", tt.inputType, tt.size, gotLength, tt.wantLength)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user