Gorm Find result to interface

Issue

I am trying to build a generic CrudRepository struct using Gorm for my api.
I know generics are coming to GoLang in version 2 but I try to build this lib using reflection or any other lib.

In my CrudRepository:

func (repository *BaseRepository) find(result interface{}, pageSize int, page int) error {
  if page < 1 {
    return errors.ExceedsMinimumInt("page", "", 0, true, nil)
  }

  offset := (page - 1) * pageSize

  ent := reflect.Zero(reflect.TypeOf(result))

  repository.db = repository.db.Limit(pageSize).Offset(offset)
  err := repository.db.Find(&ent).Error

  result = ent

  if err != nil {
    return err
  }
  return nil
}

And calling this method sth like:

func List(){
  var entityList []MyEntity
  find(entityList, 1, 10)
}

I think, I cannot pass any interface reference into Gorm.db.Find() method
Is there any other way to succeed?

Solution

Use a pointer of a slice as input argument of custom find method.

func (repository *BaseRepository) find(result interface{}, pageSize int, page int) error {
    if page < 1 {
      return errors.ExceedsMinimumInt("page", "", 0, true, nil)
    }

    if reflect.TypeOf(result).Kind() != reflect.Slice { 👈 check ❗️
        return errors.New("`result` is not a slice")
    }

    offset := (page - 1) * pageSize

    db = db.Limit(pageSize).Offset(offset)
    
    if err := db.Find(result).Error; err  != nil {
        return err
    }
    return nil
}

usage 👇🏻

var entityList []MyEntity
err := find(&entityList, 10, 1)

Also you have to check input argument (result), because db.Find isn’t fit to find single strut 👇🏻 (Retrieving a single object)

If you want to avoid the ErrRecordNotFound error, you could use Find
like db.Limit(1).Find(&user), the Find method accepts both struct and
slice data

For example (Book table is empty):

b := Book{}
rowsAffectedQuantity := db.Find(&b).RowsAffected // 👈 0
err = db.Find(&b).Error // 👈 nil

Answered By – kozmo

Answer Checked By – Gilberto Lyons (GoLangFix Admin)

Leave a Reply

Your email address will not be published.