Search code examples
goreflectiongo-gorm

Gorm Find result to interface


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