Avoid duplicated code when rewriting Scan and Value methods in each type when usign go sql

156 Views Asked by At

Golan SQL plus Gorp expect that all types include a Scan and Value method attached to the type in order to read the Rows to a struct. This is adding a lot of boilerplate code in my project even when the methods can be generalized because I am writing JSON to this columns.

type Type1 struct {
 Type2 Type2
 Type3 Type3
 Type4 Type4
}

type Type2 struct { some primitives... }
type Type3 struct { some primitives... }
type Type4 struct { some primitives... }


func (q Type2) Value() (driver.Value, error) {
    return json.Marshal(q)
}

func (q *Type2) Scan(src interface{}) error {
    source, _ := src.([]byte)
    if string(source) == "null" {
        return nil
    }
    return json.Unmarshal(source, q)
}

func (q Type3) Value() (driver.Value, error) {
    return json.Marshal(q)
}

func (q *Type3) Scan(src interface{}) error {
    source, _ := src.([]byte)
    if string(source) == "null" {
        return nil
    }
    return json.Unmarshal(source, q)
}

func (q Type4) Value() (driver.Value, error) {
    return json.Marshal(q)
}

func (q *Type4) Scan(src interface{}) error {
    source, _ := src.([]byte)
    if string(source) == "null" {
        return nil
    }
    return json.Unmarshal(source, q)
}

Is there a way to avoid defining all those identical Value and Scan Methods for each of my Structs?

The table should look like this:

Table: Type1
-----------------------
ROW   Type2                Type3               Type4
1     {"name": "MyName"}   {"other": "bla"}    {"other": "bla"}

I tried using composition as @danicheeta recommend:

type Base struct {} 
type Type2 struct { Base, some primitives... }

func (q Base) Value() (driver.Value, error) {
    return json.Marshal(q)
}

func (q *Base) Scan(src interface{}) error {
    source, _ := src.([]byte)
    if string(source) == "null" {
        return nil
    }
    return json.Unmarshal(source, q)
}

But if I execute an insert to the database the result is:

Table: Type1
-----------------------
ROW   Type2                Type3               Type4
1     {}                   {}                  {}

Similarly if I have already inserted "manually" in the database this:

Table: Type1
    -----------------------
    ROW   Type2                Type3               Type4
    1     {"name": "MyName"}   {"other": "bla"}    {"other": "bla"}

And try to do a select * from Type1 I get:

Type1: {
   Type2: {}
   Type3: {}
   Type4: {}
}
1

There are 1 best solutions below

7
On

here's a solution:

type Base struct {}

type Type2 struct { Base, some primitives... }
type Type3 struct { Base, some primitives... }
type Type4 struct { Base, some primitives... }

func (q Base) Value() (driver.Value, error) {
    return json.Marshal(q)
}

func (q *Base) Scan(src interface{}) error {
    source, _ := src.([]byte)
    if string(source) == "null" {
        return nil
    }
    return json.Unmarshal(source, q)
}

notice that Base embeded in structs should not have a var before it (i mean type Type2 struct { b Base, some primitives... })