I have a Postgres database which stores JSON as one of its fields. The structure of the table is:
type Table struct {
ID int
VehicleType string
Vehicle Vehicle `gorm:"type:jsonb"`
// ......
}
Now, Vehicle is an interface
type Vehicle interface {
GetEngineModel() string
}
It has many implementation, I will share one of them - Car
type Car struct {
CarEngineModel string //the attributes will be different for different
//implementation
}
func (car Car) GetEngineModel() string {
return car.CarEngineModel
}
In order to parse the attributes in a specific struct i.e. Car, Bike, .., I can implement Scan and Value interface of all the implementations something like this :-
func (car *Car) Scan(value interface{}) error {
//Want to use this implementation of Scan based on VehicleType
//attribute of struct table
b, ok := value.([]byte)
if !ok {
return errors.New("type assertion to []byte failed")
}
*car = json.Unmarshal(b, &car)
}
Is there a way to tell which implementation of Scan to use based on other table columns or an alternate way to do the same using GORM? I only want one table(genetic json type) so don't want to use different tables for different implementations using polymorphic association.
You can add a separate field that will hold the raw JSON data and then implement gorm specific hooks to marshal/unmarshal that data.
type Table struct {
ID int
VehicleType string
Vehicle Vehicle `gorm:"-"`
// ...
VehicleRaw []byte `gorm:"column:vehicle"`
}
func (t *Table) BeforeSave(tx *gorm.DB) (err error) {
raw, err := json.Marshal(t.Vehicle)
if err != nil {
return err
}
t.VehicleRaw = raw
return nil
}
func (t *Table) AfterFind(tx *gorm.DB) (err error) {
switch t.VehicleType {
case "CAR":
t.Vehicle = &Car{}
case "BIKE":
t.Vehicle = &Bike{}
}
return json.Unmarshal(t.VehicleRaw, t.Vehicle)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With