Home > Article > Backend Development > How to add interface to non-native structure in golang?
I use https://github.com/lib/pq to get data from postgres. To extract the data I use a third party structure which contains the protobuf timestamp field https://pkg.go.dev/google.golang.org/protobuf/types/known/timestamppb#timestamp so So the problem is to get the job to scan from time.time to timestamppb.timestamp
type stuff struct { //this struct non-local, this is from third-party package date *timestamppb.timestamp } stuff = stuff{} scanerr := rows.scan(&stuff.date)
I try to scan the structure implementing the sql.scanner interface. That's simple. I just implemented the scan function like this:
type test struct { } func (t test) scan(src any) error { //convert value }
But it doesn't work with timestamppb.timestamp because it is a non-native type. Then I tried defining the local type and doing the same
type timestamppb timestamppb.timestamp func (t timestamppb) scan(src any) error { //convert value }
But this trick didn’t work. Additionally, I have the warning "'scan' passes lock by value: type 'timestamppb' contains 'protoimpl.messagestate' contains 'sync.mutex', i.e. 'sync.locker'" This doesn't work if I specify a pointer for timestamppb
func (t *timestamppb) scan(src any) error {
So I want to know, how to make a timestamppb.timestamp instance of sql.scanner. is it possible?
Update 1 Small example of what I tried
type TimestampPb timestamppb.Timestamp type test struct { //third-party struct, I can't modify it date *timestamppb.Timestamp } func (s *Storage) test() { rows, _ := s.db.Query("SELECT \"test_date\" FROM \"test_table\" LIMIT 1") defer func() { if rows != nil { _ = rows.Close() } }() for rows.Next() { //var value *TimestampPb //works //var value TimestampPb //works //var value *timestamppb.Timestamp //doesn't work //testStruct := test{} //doesn't work //err := rows.Scan(&value) //scan to variable //err := rows.Scan(&testStruct.date) //scan to field in the struct if err != nil { log.Fatalln(err) } } } func (tpb *TimestampPb) Scan(src any) error { return nil }
I want to know if I can use case with teststruct?
pq
The library does not support *timestamppb.timestamp
as a timestamp type. See the documentation for supported date types.
Different types are required when scanning.
I usually do this by using a helper type in the function. For example:
type row struct { Date *timestamppb.Timestamp // ... more fields here } func Query() ([]row, error) { rows, err := s.db.Query(...) if err != nil { return nil, err } defer rows.Close() var rows []row for rows.Next() { type aux struct { Date time.Time // ... more fields here } var value aux if err := rows.Scan(&value); err != nil { return nil, err } rows = append(rows, row{ Date: timestamppb.New(value.Date), // ... more fields here } } return rows, nil }
The above is the detailed content of How to add interface to non-native structure in golang?. For more information, please follow other related articles on the PHP Chinese website!