jmoiron / sqlx

general purpose extensions to golang's database/sql
http://jmoiron.github.io/sqlx/
MIT License
15.79k stars 1.07k forks source link

sqlx StructScan + protobuf #239

Open plandem opened 8 years ago

plandem commented 8 years ago

is it possible to use StructScan to scan into protobuf? I can't find how to handle NULL values from DB, in common way, i would use sql.NullString as field at struct, but it's impossible with protobuf. At protobuf3 every field is optional. So i would like to skip somehow NULL values from db. I tried to play with mapper, but still no success.

sh0umik commented 7 years ago

Yes it is . I am using it . But you need a Custom Mapper .

    // snake_case Mapping for autogenerated json tag
    dbX.Mapper = reflectx.NewMapperFunc("json", func(str string) (string) {
        return str
    })

Tell sqlx to pick up the auto generated json tag insted of db tag and you are good to go .. Also Note that in your code your protobuffer fields has to match to your database field name like

create profile {
 first_name varchar(255) not null,
}
message Profile {
string first_name
}

if not then change your mappper accordingly ...

arthurnn commented 6 years ago

can be this closed? I actually, didn't have to do the Mapper trick. It just worked with my struct only marked as json.

tikiatua commented 6 years ago

Hi everyone,

We have a similar problem with specific null types. Protoc will always generate pointers to struct properties of null types. This is somewhat problematic for us, since NULL database values will then not be scanned into the null types but will result in nil. This requires us to always check for nils to avoid panics instead of being able to use the functionality of the null types.

Has anyone found a solution for this?

// proto example 
syntax = "proto3";

package organigram;

// this package implements a null-timestamp type
import "dkfbasel/protobuf/timestamp.proto";

// User returns information about a specific user
message User {
    string id = 1;         // unique id of the user
    string email = 4;      // email address
    dkfbasel.protobuf.Timestamp last_visit = 6; // last visit of the user
}
// go struct generated by protoc
// User returns information about a specific user
type User struct {
    Id        string                       `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"`
    Email     string                       `protobuf:"bytes,4,opt,name=email" json:"email,omitempty"`
    LastVisit *dkfbasel_protobuf.Timestamp `protobuf:"bytes,6,opt,name=last_visit,json=lastVisit" json:"last_visit,omitempty"`
}
stmt := `...some sql...`
var dta User
sqlxSession.Get(&dta, stmt)

// dta.LastVisit -> nil, 
// would be great if it was a timestamp.Timestamp{Valid:false, Milliseconds:0}
k1ng440 commented 5 years ago

hello @tikiatua were you available to solve this issue?

tikiatua commented 5 years ago

Hi @k1ng440

Yes and no.. Actually the go struct generated from proto will also automatically get a function called GetLastVisit() which will return an empty last visit if the pointer is nil. This more or less solves the problem. However, you need to always access the properties via these functions.

Anything else would lead to other problems when using protobufs.