Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return an array in Go with Gorm

I'm learning microservices with Node and Go.

I'm now having a problem at querying all users from database (postgres) with Gorm.

I usually query like this to get all users and it works:

    // Fetch connection and close db
    db := InitPg()
    defer db.Close()

    // Create an array of users to populate
    var users []*User
    db.Find(&users)

    // Successfully returns an array of users
    return users, nil

But now with generated protobuf, it complains:

func (s *Server) Index(ctx context.Context, _ *shop.Empty) (*shop.IndexUserResponse, error) {
    // func (s *Server) Index(ctx context.Context, request *shop.Empty) error {
    db := InitPg()
    defer db.Close()

    // Confirmed created 2 users in database
    var users []*User
    if err := db.Find(&users).Error; err != nil {
        panic(err)
    }

    // Log prints these:
    // 2020/01/04 20:13:47 [0xc0001da6c0 0xc0001da7e0]
    // 2020/01/04 20:13:51 [0xc0001dade0 0xc0001daf00]
    log.Print(users)

    // It complains right here ------------ v
    return &shop.IndexUserResponse{Users: users}, nil
}
[compiler] [E] cannot use users (variable of type []*User) as []*genproto.User value in struct literal

This is user model file:

type User struct {
    gorm.Model
    Email    string `json:"email" gorm:"type:varchar(100);unique_index" validate:"required,email"`
    Password string `json:"password" validate:"required,gte=10"`
}

Here's my proto file:

syntax = "proto3";

package shop;

service UserService {
  rpc Index(Empty) returns (IndexUserResponse) {}
}

message Empty {}

message User {
  int32 id = 1;
  string email = 2;
}

message IndexUserResponse {
  repeated User users = 1;
}

And this is from go generated proto file:

// shop.pb.go

type IndexUserResponse struct {
    Users                []*User  `protobuf:"bytes,1,rep,name=users,proto3" json:"users,omitempty"`
    XXX_NoUnkeyedLiteral struct{} `json:"-"`
    XXX_unrecognized     []byte   `json:"-"`
    XXX_sizecache        int32    `json:"-"`
}

type User struct {
    Id                   int32    `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
    Email                string   `protobuf:"bytes,2,opt,name=email,proto3" json:"email,omitempty"`
    XXX_NoUnkeyedLiteral struct{} `json:"-"`
    XXX_unrecognized     []byte   `json:"-"`
    XXX_sizecache        int32    `json:"-"`
}

How can I query and return an array users?


Edit 2:

Tried as @reda suggested, convert the []*User slice to []*genproto.User:

package main

import (
    "context"

    shop "gitlab.com/me/shop/service/user/genproto"
)

func (s *Server) Index(ctx context.Context, _ *shop.Empty) (*shop.IndexUserResponse, error) {
    db := InitPg()
    defer db.Close()

    var users []*User
    if err := db.Find(&users).Error; err != nil {
        panic(err)
    }

    pUsers := make([]*shop.User, len(users))

    for _, u := range users {
        pUsers = append(pUsers,
            &shop.User{
                Id:    int32(u.ID),
                Email: u.Email,
            })
    }

    return &shop.IndexUserResponse{Users: pUsers}, nil
}

This time got:

ERROR: 2020/01/05 10:55:43 grpc: server failed to encode response: rpc error: code = Internal desc = grpc: error while marshaling: proto: repeated field Users has nil element.

Log prints: 2020/01/05 10:56:04 [<nil> id:1 email:"[email protected]" ]

like image 842
Rario Avatar asked Jan 04 '20 14:01

Rario


Video Answer


1 Answers

You need to manually convert the []*User slice to []*genproto.User one. Golang can't let you do the cast

...

pUsers := make([]*genproto.User, 0)

for _, u := range users {
  pUsers = append(pUsers, &genproto.User{ID: u.ID, Email: u.Email})

}

return &shop.IndexUserResponse{Users: pUsers}, nil

like image 124
reda la Avatar answered Sep 17 '22 15:09

reda la