postgresqlgopgx

Cannot read json range as pgtype.Int4range


I am trying to read a range as json but I am seeing an issue while I do json.unmarshal.

here is a test code-

import (
    "encoding/json"
    "testing"

    "github.com/jackc/pgtype"
    "github.com/stretchr/testify/assert"
)

type TestHealthPreference struct {
    HealthRange pgtype.Int4range `json:"health_range"`
    ID          string           `json:"id"`
}

// just a test to make sure unmarshaling works
func TestPreferenceUpdateUnmarshal(t *testing.T) {
    jsonData := `{
        "health_range": "[20,30)",
        "id": "123"
    }`

    var update TestHealthPreference
    err := json.Unmarshal([]byte(jsonData), &update)
    if err != nil {
        t.Errorf("Error while unmarshalling JSON: %v", err)
    }

    assert.Equal(t, 20, update.HealthRange.Lower)
}

Error-

Error while unmarshalling JSON: json: cannot unmarshal string into Go struct field TestPreference.health_range of type pgtype.Int4range. 

Is it even possible to read it as pgtype.Int4range? I am guessing this type is for database use only? fwiw, I am using pgx github.com/jackc/pgx/v4


Solution

  • It does not work because "[20,30)" is not a valid JSON value for the struct pgtype.Int4range, and pgtype.Int4range hasn't implemented the json.Unmarshaler interface.

    You have to implement the interface yourself to unmarshal "[20,30)":

    type myInt4range pgtype.Int4range
    
    func (r *myInt4range) UnmarshalJSON(b []byte) error {
        return (*pgtype.Int4range)(r).DecodeText(nil, bytes.Trim(b, `"`))
    }
    

    BTW

    assert.Equal(t, 20, update.HealthRange.Lower)
    

    compares two different types, which should be corrected as:

    assert.Equal(t, int32(20), update.HealthRange.Lower.Int)
    

    See the full demo here: https://go.dev/play/p/gGNj3kOBB8k.