Fix JSON encoding for pointer to structs implementing json.Marshaler

https://github.com/jackc/pgx/issues/1681
pull/1683/head
Jack Christensen 2023-07-11 20:28:36 -05:00
parent 507a9e9ad3
commit 524f661136
3 changed files with 41 additions and 0 deletions

View File

@ -25,6 +25,13 @@ func (c JSONCodec) PlanEncode(m *Map, oid uint32, format int16, value any) Encod
case []byte:
return encodePlanJSONCodecEitherFormatByteSlice{}
// Must come before trying wrap encode plans because a pointer to a struct may be unwrapped to a struct that can be
// marshalled.
//
// https://github.com/jackc/pgx/issues/1681
case json.Marshaler:
return encodePlanJSONCodecEitherFormatMarshal{}
// Cannot rely on driver.Valuer being handled later because anything can be marshalled.
//
// https://github.com/jackc/pgx/issues/1430

View File

@ -133,3 +133,27 @@ func TestJSONCodecClearExistingValueBeforeUnmarshal(t *testing.T) {
require.Equal(t, map[string]any{"baz": "quz"}, m)
})
}
type ParentIssue1681 struct {
Child ChildIssue1681
}
func (t *ParentIssue1681) MarshalJSON() ([]byte, error) {
return []byte(`{"custom":"thing"}`), nil
}
type ChildIssue1681 struct{}
func (t ChildIssue1681) MarshalJSON() ([]byte, error) {
return []byte(`{"someVal": false}`), nil
}
// https://github.com/jackc/pgx/issues/1681
func TestJSONCodecEncodeJSONMarshalerThatCanBeWrapped(t *testing.T) {
defaultConnTestRunner.RunTest(context.Background(), t, func(ctx context.Context, t testing.TB, conn *pgx.Conn) {
var jsonStr string
err := conn.QueryRow(context.Background(), "select $1::json", &ParentIssue1681{}).Scan(&jsonStr)
require.NoError(t, err)
require.Equal(t, `{"custom":"thing"}`, jsonStr)
})
}

View File

@ -70,3 +70,13 @@ func TestJSONBCodecUnmarshalSQLNull(t *testing.T) {
require.EqualError(t, err, "can't scan into dest[0]: cannot scan NULL into *int")
})
}
// https://github.com/jackc/pgx/issues/1681
func TestJSONBCodecEncodeJSONMarshalerThatCanBeWrapped(t *testing.T) {
defaultConnTestRunner.RunTest(context.Background(), t, func(ctx context.Context, t testing.TB, conn *pgx.Conn) {
var jsonStr string
err := conn.QueryRow(context.Background(), "select $1::jsonb", &ParentIssue1681{}).Scan(&jsonStr)
require.NoError(t, err)
require.Equal(t, `{"custom": "thing"}`, jsonStr) // Note that unlike json, jsonb reformats the JSON string.
})
}