Use wrapper to treat fmt.String as pgtype.TextValuer

query-exec-mode
Jack Christensen 2022-01-20 20:22:53 -06:00
parent 06f4e47750
commit b10eb89fe4
5 changed files with 27 additions and 4 deletions

View File

@ -491,3 +491,11 @@ func (w mapStringToStringWrapper) HstoreValue() (Hstore, error) {
} }
return hstore, nil return hstore, nil
} }
type fmtStringerWrapper struct {
s fmt.Stringer
}
func (w fmtStringerWrapper) TextValue() (Text, error) {
return Text{String: w.s.String(), Valid: true}, nil
}

View File

@ -30,8 +30,6 @@ func (EnumCodec) PlanEncode(ci *ConnInfo, oid uint32, format int16, value interf
return encodePlanTextCodecByteSlice{} return encodePlanTextCodecByteSlice{}
case rune: case rune:
return encodePlanTextCodecRune{} return encodePlanTextCodecRune{}
case fmt.Stringer:
return encodePlanTextCodecStringer{}
case TextValuer: case TextValuer:
return encodePlanTextCodecTextValuer{} return encodePlanTextCodecTextValuer{}
} }

View File

@ -1421,6 +1421,8 @@ func tryWrapBuiltinTypeEncodePlan(value interface{}) (plan WrappedEncodePlanNext
return &wrapMapStringToPointerStringEncodePlan{}, mapStringToPointerStringWrapper(value), true return &wrapMapStringToPointerStringEncodePlan{}, mapStringToPointerStringWrapper(value), true
case map[string]string: case map[string]string:
return &wrapMapStringToStringEncodePlan{}, mapStringToStringWrapper(value), true return &wrapMapStringToStringEncodePlan{}, mapStringToStringWrapper(value), true
case fmt.Stringer:
return &wrapFmtStringerEncodePlan{}, fmtStringerWrapper{value}, true
} }
return nil, nil, false return nil, nil, false
@ -1616,6 +1618,16 @@ func (plan *wrapMapStringToStringEncodePlan) Encode(value interface{}, buf []byt
return plan.next.Encode(mapStringToStringWrapper(value.(map[string]string)), buf) return plan.next.Encode(mapStringToStringWrapper(value.(map[string]string)), buf)
} }
type wrapFmtStringerEncodePlan struct {
next EncodePlan
}
func (plan *wrapFmtStringerEncodePlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *wrapFmtStringerEncodePlan) Encode(value interface{}, buf []byte) (newBuf []byte, err error) {
return plan.next.Encode(fmtStringerWrapper{value.(fmt.Stringer)}, buf)
}
// Encode appends the encoded bytes of value to buf. If value is the SQL value NULL then append nothing and return // Encode appends the encoded bytes of value to buf. If value is the SQL value NULL then append nothing and return
// (nil, nil). The caller of Encode is responsible for writing the correct NULL value or the length of the data // (nil, nil). The caller of Encode is responsible for writing the correct NULL value or the length of the data
// written. // written.

View File

@ -100,8 +100,6 @@ func (TextCodec) PlanEncode(ci *ConnInfo, oid uint32, format int16, value interf
return encodePlanTextCodecByteSlice{} return encodePlanTextCodecByteSlice{}
case rune: case rune:
return encodePlanTextCodecRune{} return encodePlanTextCodecRune{}
case fmt.Stringer:
return encodePlanTextCodecStringer{}
case TextValuer: case TextValuer:
return encodePlanTextCodecTextValuer{} return encodePlanTextCodecTextValuer{}
} }

View File

@ -9,6 +9,12 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
type someFmtStringer struct{}
func (someFmtStringer) String() string {
return "some fmt.Stringer"
}
func TestTextCodec(t *testing.T) { func TestTextCodec(t *testing.T) {
for _, pgTypeName := range []string{"text", "varchar"} { for _, pgTypeName := range []string{"text", "varchar"} {
testPgxCodec(t, pgTypeName, []PgxTranscodeTestCase{ testPgxCodec(t, pgTypeName, []PgxTranscodeTestCase{
@ -24,6 +30,7 @@ func TestTextCodec(t *testing.T) {
}, },
{nil, new(pgtype.Text), isExpectedEq(pgtype.Text{})}, {nil, new(pgtype.Text), isExpectedEq(pgtype.Text{})},
{"foo", new(string), isExpectedEq("foo")}, {"foo", new(string), isExpectedEq("foo")},
{someFmtStringer{}, new(string), isExpectedEq("some fmt.Stringer")},
{rune('R'), new(rune), isExpectedEq(rune('R'))}, {rune('R'), new(rune), isExpectedEq(rune('R'))},
}) })
} }