fix(writer): update nullable type handling to use baselib

* change default nullable type from resolvespec to baselib
* update type mappings in tests to reflect new nullable types
* adjust comments for clarity on nullable type options
This commit is contained in:
2026-06-25 23:25:36 +02:00
parent e29c7e31c1
commit ab735d1f3a
8 changed files with 128 additions and 40 deletions
+45 -4
View File
@@ -20,7 +20,7 @@ type TypeMapper struct {
// an empty string defaults to resolvespec.
func NewTypeMapper(typeStyle string) *TypeMapper {
if typeStyle == "" {
typeStyle = writers.NullableTypeResolveSpec
typeStyle = writers.NullableTypeBaselib
}
return &TypeMapper{
sqlTypesAlias: "resolvespec_common",
@@ -37,11 +37,17 @@ func (tm *TypeMapper) SQLTypeToGoType(sqlType string, notNull bool) string {
baseType := tm.extractBaseType(sqlType)
if tm.typeStyle == writers.NullableTypeStdlib {
switch tm.typeStyle {
case writers.NullableTypeStdlib:
if notNull {
return tm.rawGoType(baseType)
}
return tm.stdlibNullableGoType(baseType)
case writers.NullableTypeBaselib:
if notNull {
return tm.rawGoType(baseType)
}
return tm.baselibNullableGoType(baseType)
}
// resolvespec (default): use base Go types only for simple NOT NULL fields.
@@ -183,7 +189,7 @@ func (tm *TypeMapper) bunGoType(sqlType string) string {
// arrayGoType returns the Go type for a PostgreSQL array column.
// The baseElemType is the canonical base type (e.g. "text", "integer").
func (tm *TypeMapper) arrayGoType(baseElemType string) string {
if tm.typeStyle == writers.NullableTypeStdlib {
if tm.typeStyle == writers.NullableTypeStdlib || tm.typeStyle == writers.NullableTypeBaselib {
return tm.stdlibArrayGoType(baseElemType)
}
typeMap := map[string]string{
@@ -276,6 +282,38 @@ func (tm *TypeMapper) stdlibNullableGoType(sqlType string) string {
return "sql.NullString"
}
// baselibNullableGoType returns plain Go pointer types for nullable columns.
func (tm *TypeMapper) baselibNullableGoType(sqlType string) string {
typeMap := map[string]string{
"integer": "*int32", "int": "*int32", "int4": "*int32", "serial": "*int32",
"smallint": "*int16", "int2": "*int16", "smallserial": "*int16",
"bigint": "*int64", "int8": "*int64", "bigserial": "*int64",
"boolean": "*bool", "bool": "*bool",
"real": "*float32", "float4": "*float32",
"double precision": "*float64", "float8": "*float64",
"numeric": "*float64", "decimal": "*float64", "money": "*float64",
"text": "*string", "varchar": "*string", "char": "*string",
"character": "*string", "citext": "*string", "bpchar": "*string",
"inet": "*string", "cidr": "*string", "macaddr": "*string",
"uuid": "*string", "json": "*string", "jsonb": "*string",
"timestamp": "*time.Time",
"timestamp without time zone": "*time.Time",
"timestamp with time zone": "*time.Time",
"timestamptz": "*time.Time",
"date": "*time.Time",
"time": "*time.Time",
"time without time zone": "*time.Time",
"time with time zone": "*time.Time",
"timetz": "*time.Time",
"bytea": "[]byte",
"vector": "[]float32",
}
if goType, ok := typeMap[sqlType]; ok {
return goType
}
return "*string"
}
// stdlibArrayGoType returns a plain Go slice type for array columns in stdlib mode.
func (tm *TypeMapper) stdlibArrayGoType(baseElemType string) string {
typeMap := map[string]string{
@@ -431,8 +469,11 @@ func (tm *TypeMapper) GetSQLTypesImport() string {
// GetNullableTypeImportLine returns the full Go import line for the nullable type
// package (ready to pass to AddImport). Returns empty string when no import is needed.
func (tm *TypeMapper) GetNullableTypeImportLine() string {
if tm.typeStyle == writers.NullableTypeStdlib {
switch tm.typeStyle {
case writers.NullableTypeStdlib:
return "\"database/sql\""
case writers.NullableTypeBaselib:
return ""
}
return fmt.Sprintf("%s \"%s\"", tm.sqlTypesAlias, tm.GetSQLTypesImport())
}
+19 -19
View File
@@ -73,9 +73,9 @@ func TestWriter_WriteTable(t *testing.T) {
"ID",
"int64",
"Email",
"resolvespec_common.SqlString",
"*string",
"CreatedAt",
"resolvespec_common.SqlTime",
"time.Time",
"bun:\"id",
"bun:\"email",
"func (m ModelPublicUsers) TableName() string",
@@ -564,20 +564,20 @@ func TestTypeMapper_SQLTypeToGoType_Bun(t *testing.T) {
want string
}{
{"bigint", true, "int64"},
{"bigint", false, "resolvespec_common.SqlInt64"},
{"varchar", true, "resolvespec_common.SqlString"}, // Bun uses sql types even for NOT NULL strings
{"varchar", false, "resolvespec_common.SqlString"},
{"timestamp", true, "resolvespec_common.SqlTimeStamp"},
{"timestamp", false, "resolvespec_common.SqlTimeStamp"},
{"date", false, "resolvespec_common.SqlDate"},
{"bigint", false, "*int64"},
{"varchar", true, "string"},
{"varchar", false, "*string"},
{"timestamp", true, "time.Time"},
{"timestamp", false, "*time.Time"},
{"date", false, "*time.Time"},
{"boolean", true, "bool"},
{"boolean", false, "resolvespec_common.SqlBool"},
{"uuid", false, "resolvespec_common.SqlUUID"},
{"jsonb", false, "resolvespec_common.SqlJSONB"},
{"text[]", true, "resolvespec_common.SqlStringArray"},
{"text[]", false, "resolvespec_common.SqlStringArray"},
{"integer[]", true, "resolvespec_common.SqlInt32Array"},
{"bigint[]", false, "resolvespec_common.SqlInt64Array"},
{"boolean", false, "*bool"},
{"uuid", false, "*string"},
{"jsonb", false, "*string"},
{"text[]", true, "[]string"},
{"text[]", false, "[]string"},
{"integer[]", true, "[]int32"},
{"bigint[]", false, "[]int64"},
}
for _, tt := range tests {
@@ -599,7 +599,7 @@ func TestWriter_UpdateIDTypeSafety_Bun(t *testing.T) {
forbidInt32 bool
}{
{"int32_pk", "int", "int32", "m.ID = int32(newid)", false},
{"sql_int16_pk", "smallint", "resolvespec_common.SqlInt16", "m.ID.FromString(fmt.Sprintf(\"%d\", newid))", true},
{"sql_int16_pk", "smallint", "int16", "m.ID = int16(newid)", true},
{"int64_pk", "bigint", "int64", "m.ID = int64(newid)", true},
}
@@ -680,13 +680,13 @@ func TestWriter_StringPrimaryKeyHelpers_Bun(t *testing.T) {
generated := string(content)
expectations := []string{
"resolvespec_common.SqlUUID",
"ID string",
"func (m ModelPublicAccounts) GetID() string",
"return m.ID.String()",
"return m.ID",
"func (m ModelPublicAccounts) GetIDStr() string",
"func (m ModelPublicAccounts) SetID(newid string)",
"func (m *ModelPublicAccounts) UpdateID(newid string)",
"m.ID.FromString(newid)",
"m.ID = newid",
}
for _, expected := range expectations {