Skip to content

Commit

Permalink
Fix JSON encoding for pointer to structs implementing json.Marshaler
Browse files Browse the repository at this point in the history
  • Loading branch information
jackc committed Jul 12, 2023
1 parent 507a9e9 commit 524f661
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 0 deletions.
7 changes: 7 additions & 0 deletions pgtype/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
24 changes: 24 additions & 0 deletions pgtype/json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
})
}
10 changes: 10 additions & 0 deletions pgtype/jsonb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
})
}

0 comments on commit 524f661

Please sign in to comment.