mirror of
https://github.com/hanzoai/sqlbuilder.git
synced 2026-10-01 00:37:42 +00:00
fix #213 support typed nil in interpolation
This commit is contained in:
+13
-3
@@ -618,12 +618,22 @@ func encodeValue(buf []byte, arg interface{}, flavor Flavor) ([]byte, error) {
|
||||
buf = append(buf, "', 'YYYY-MM-DD HH24:MI:SS.FF')"...)
|
||||
}
|
||||
|
||||
case fmt.Stringer:
|
||||
buf = quoteStringValue(buf, v.String(), flavor)
|
||||
|
||||
default:
|
||||
primative := reflect.ValueOf(arg)
|
||||
|
||||
// Handle typed nil values (e.g. (*string)(nil), (*time.Time)(nil))
|
||||
// This check must come before fmt.Stringer check since nil pointers may implement interfaces
|
||||
if !primative.IsValid() || (primative.Kind() == reflect.Ptr && primative.IsNil()) {
|
||||
buf = append(buf, "NULL"...)
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
// Check for fmt.Stringer after nil pointer check
|
||||
if stringer, ok := arg.(fmt.Stringer); ok {
|
||||
buf = quoteStringValue(buf, stringer.String(), flavor)
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
switch k := primative.Kind(); k {
|
||||
case reflect.Bool:
|
||||
switch flavor {
|
||||
|
||||
@@ -389,3 +389,109 @@ func TestFlavorInterpolate(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTypedNilInterpolation(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
|
||||
// Test various typed nil pointers
|
||||
cases := []struct {
|
||||
name string
|
||||
flavor Flavor
|
||||
sql string
|
||||
args []interface{}
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "string pointer nil",
|
||||
flavor: MySQL,
|
||||
sql: "SELECT ?",
|
||||
args: []interface{}{(*string)(nil)},
|
||||
expected: "SELECT NULL",
|
||||
},
|
||||
{
|
||||
name: "int pointer nil",
|
||||
flavor: MySQL,
|
||||
sql: "SELECT ?",
|
||||
args: []interface{}{(*int)(nil)},
|
||||
expected: "SELECT NULL",
|
||||
},
|
||||
{
|
||||
name: "float64 pointer nil",
|
||||
flavor: MySQL,
|
||||
sql: "SELECT ?",
|
||||
args: []interface{}{(*float64)(nil)},
|
||||
expected: "SELECT NULL",
|
||||
},
|
||||
{
|
||||
name: "time.Time pointer nil",
|
||||
flavor: MySQL,
|
||||
sql: "SELECT ?",
|
||||
args: []interface{}{(*time.Time)(nil)},
|
||||
expected: "SELECT NULL",
|
||||
},
|
||||
{
|
||||
name: "byte slice pointer nil",
|
||||
flavor: MySQL,
|
||||
sql: "SELECT ?",
|
||||
args: []interface{}{(*[]byte)(nil)},
|
||||
expected: "SELECT NULL",
|
||||
},
|
||||
{
|
||||
name: "PostgreSQL string pointer nil",
|
||||
flavor: PostgreSQL,
|
||||
sql: "SELECT $1",
|
||||
args: []interface{}{(*string)(nil)},
|
||||
expected: "SELECT NULL",
|
||||
},
|
||||
{
|
||||
name: "SQLite int pointer nil",
|
||||
flavor: SQLite,
|
||||
sql: "SELECT ?",
|
||||
args: []interface{}{(*int)(nil)},
|
||||
expected: "SELECT NULL",
|
||||
},
|
||||
{
|
||||
name: "Oracle float pointer nil",
|
||||
flavor: Oracle,
|
||||
sql: "SELECT :1",
|
||||
args: []interface{}{(*float64)(nil)},
|
||||
expected: "SELECT NULL",
|
||||
},
|
||||
{
|
||||
name: "mixed nil types",
|
||||
flavor: MySQL,
|
||||
sql: "SELECT ?, ?, ?, ?",
|
||||
args: []interface{}{(*string)(nil), nil, (*int)(nil), (*[]byte)(nil)},
|
||||
expected: "SELECT NULL, NULL, NULL, NULL",
|
||||
},
|
||||
{
|
||||
name: "interface pointer nil",
|
||||
flavor: MySQL,
|
||||
sql: "SELECT ?",
|
||||
args: []interface{}{(*fmt.Stringer)(nil)},
|
||||
expected: "SELECT NULL",
|
||||
},
|
||||
{
|
||||
name: "slice pointer nil",
|
||||
flavor: MySQL,
|
||||
sql: "SELECT ?",
|
||||
args: []interface{}{(*[]int)(nil)},
|
||||
expected: "SELECT NULL",
|
||||
},
|
||||
{
|
||||
name: "map pointer nil",
|
||||
flavor: MySQL,
|
||||
sql: "SELECT ?",
|
||||
args: []interface{}{(*map[string]int)(nil)},
|
||||
expected: "SELECT NULL",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
query, err := tc.flavor.Interpolate(tc.sql, tc.args)
|
||||
a.NilError(err)
|
||||
a.Equal(tc.expected, query)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user