golang unmarshal using db tags

Viewed 66

I have a sql query which fetches the list of cities nested inside provinces nested inside countries

SELECT
    C.*,
    P.provinces
FROM
    countries AS C
LEFT JOIN (
    SELECT
        P.country_id,
        json_agg(json_build_object(
            'id', P.id,
            'name', P.name,
            'slug', P.slug,
            'cities', Ci.cities
        )) AS provinces
    FROM
        provinces AS P
    LEFT JOIN (
        SELECT
            Ci.province_id,
            json_agg(json_build_object(
                'id', Ci.id,
                'name', Ci.name,
                'slug', Ci.slug
            )) AS cities
        FROM
            cities AS Ci
        GROUP BY Ci.province_id
    ) AS Ci ON Ci.province_id = P.id
    GROUP BY P.country_id
) AS P ON P.country_id = C.id

I am fetching this data into slice of countries

type Country struct {
    Id         int64         `json:"id" db:"id"`
    ISOCode2   string        `json:"isoCode2" db:"iso_code_2"`
    ISOCode3   string        `json:"isoCode3" db:"iso_code_3"`
    ISONumCode string        `json:"isoNumCode" db:"iso_num_code"`
    Name       string        `json:"name" db:"name"`
    Slug       string        `json:"slug" db:"slug"`
    Provinces  SliceProvince `json:"provinces" db:"provinces"`
}

type SliceProvince []Province

func (provinces *SliceProvince) Scan(src any) (err error) {
    if src == nil {
        return
    }
    var source []byte
    switch src := src.(type) {
    case []byte:
        source = src
    case string:
        source = []byte(src)
    default:
        return fmt.Errorf("unsupported type in scan:%v", src)
    }
    err = json.Unmarshal(source, provinces)
    return
}

type Province struct {
    Id     int64     `json:"id" db:"id"`
    Name   string    `json:"name" db:"name"`
    Slug   string    `json:"slug" db:"slug"`
    Cities SliceCity `json:"cities" db:"cities"`
}

type SliceCity []City

func (cities *SliceCity) Scan(src any) (err error) {
    if src == nil {
        return
    }
    var source []byte
    switch src := src.(type) {
    case []byte:
        source = src
    case string:
        source = []byte(src)
    default:
        return fmt.Errorf("unsupported type in scan")
    }
    err = json.Unmarshal(source, cities)
    return
}

type City struct {
    Id   int64  `json:"id" db:"id"`
    Name string `json:"name" db:"name"`
    Slug string `json:"slug" db:"slug"`
}

Now, my main query is that in the scan methods for these models, I want to do unmarshalling using db tags instead of json tags. Is there any workaround which I can do for this.

I came up with a thought of unmarshalling it to a map, then change their keys from db tag ones to json tag ones, then marshal and unmarshal it to the corresponding struct. But when there would be nesting of models, or slices involved, that would increase the complexity

0 Answers
Related