How to insert slice

1.4k Views Asked by At

I have a postgres db that I would like to generate tables for and write to using Gorp, however I get an error message when I try to insert due to the slices contained within my structs "sql: converting argument $4 type: unsupported type []core.EmbeddedStruct, a slice of struct.

My structs look as follows:

type Struct1 struct {
 ID              string
 Name            string
 Location        string
 EmbeddedStruct  []EmbeddedStruct
}

type EmbeddedStruct struct {
 ID         string
 Name       string
 struct1Id  string
 EmbeddedStruct2  []EmbeddedStruct2
}

type EmbeddedStruct2 struct {
 ID               string
 Name             string
 embeddedStructId string
}

func (repo *PgStruct1Repo) Write(t *core.Struct1) error {
 trans, err := createTransaction(repo.dbMap)
 defer closeTransaction(trans)

 if err != nil {
  return err
 }

 // Check to see if struct1 item already exists
 exists, err := repo.exists(t.ID, trans)
 if err != nil {
  return err
 }

 if !exists {
  log.Debugf("saving new struct1 with ID %s", t.ID)
  err = trans.Insert(t)
  if err != nil {
   return err
  }
  return nil
 }

 return nil
}

Does anyone have any experience with/or know if Gorp supports inserting slices? From what I've read it seems to only support slices for SELECT statements

1

There are 1 best solutions below

1
dave On

Gorp supports inserting a variadic number of slices, so if you have a slice records, you can do:

 err = db.Insert(records...)

However, from your question it seems you want to save a single record that has a slice struct field.

https://github.com/go-gorp/gorp

gorp doesn't know anything about the relationships between your structs (at least not yet).

So, you have to handle the relationship yourself. The way I personally would solve this issue is to have Gorp ignore the slice on the parent:

type Struct1 struct {
    ID              string
    Name            string
    Location        string
    EmbeddedStruct  []EmbeddedStruct `db:"-"`
}

And then use the PostInsert hook to save the EmbeddedStruct (side note, this is a poor name as it is not actually an embedded struct)

func (s *Struct1) PostInsert(sql gorp.SqlExecutor) error {
    for i := range s.EmbeddedStruct {
        s.EmbeddedStruct[i].struct1Id = s.ID
    }
    return sql.Insert(s.EmbeddedStruct...)
}

And then repeat the process on EmbeddedStruct2.

Take care to setup the relationships properly on the DB side to ensure referential integrity (e.g. ON DELETE CASCADE / RESTRICT), and it would probably be a good idea to wrap the whole thing in a transaction.