Search code examples
postgresqlgogo-gorm

Get nested object in structure in gorm


I have two structures:

type GoogleAccount struct {
     Id     uint64
     Token  string
}

It represent my custom PostgreSQL object type (i created myself):

CREATE TYPE GOOGLE_ACCOUNT AS
(
  id    NUMERIC,
  token TEXT
);

And next structure is table in DB:

type Client struct {
     IdClient       uint64          `gorm:"primary_key"`
     Name           string
     PhotoUrl       string
     ApprovalNumber uint16
     Phone          string
     Password       string
     HoursOfNotice  int8
     Google         GoogleAccount
}

And my custom object nested in type Client and named as google. I've tried to read data by the next way:

var users model.Client
db.First(&users)

But unfortunately I can't read field google (have a default value). I don't want to create separate table with google_account, or make this structure as separated fields in client table or packed it as json (created separate entity, because this structure used not only in this table and I'm searching new ways, that get the same result, but more gracefully). The task is not to simplify the presentation of data in the table. I need to make the correct mapping of the object from postgres to the entity.

Right now I found one solution - implement Scanner to GoogleAccount. But value in the input method is []uint8. As I can suppose, []uint8 can cast to string, and after that I can parse this string. This string (that keep in db) look like (x,x) - where x - is value. Is the right way, to parse string and set value to object? Or is way to get this result by ORM?

Is the possible way, to read this data as nested structure object?


Solution

  • Right now I found one solution - implement Scanner to GoogleAccount. At input of the Scan method I got []uint8, that I cast to string and parse in the end. This string (that keeping in db) look like (x,x) - where x - is value. Of course, it is not correct way to achieve my goal. But I couldn't found other solution.

    I highly recommended use classical binding by relationship or simple keeping these fields in table as simplest value (not as object).

    But if you would like to experiment with nested object in table, you can look at my realization, maybe it would be useful for you:

    type Client struct {
        // many others fields
        Google          GoogleAccount   `json:"google"`
    }
    
    type GoogleAccount struct {
        Id      uint64      `json:"id"`
        Token   string      `json:"token"`
    }
    
    func (google GoogleAccount) Value() (driver.Value, error) {
        return "(" + strconv.FormatUint(google.Id, 10) + "," + google.Token + ")", nil
    }
    
    func (google *GoogleAccount) Scan(value interface{}) error {
        values := utils.GetValuesFromObject(value)
        google.Id, _ = strconv.ParseUint(values[0], 10, 64)
        google.Token = values[1]
        return nil
    }