protobuf icon indicating copy to clipboard operation
protobuf copied to clipboard

How correctly change the default value behavior by gogoprotobuf?

Open nurzhannogerbek opened this issue 5 years ago • 0 comments

I have city.proto file where I described the pretty simple rpc method for creating a new record. If no values are passed to the fields, an empty string is written to the database. I want null to be written to the database in case of an empty value in the fields.

Other words, in the database I see the following:

| id | created_at          | updated_at          | deleted_at | name | country |
| 1  | 2020-05-19 22:48:28 | 2020-05-19 22:48:28 | NULL       |      |         |

I'm trying to get the following result:

| id | created_at          | updated_at          | deleted_at | name | country |
| 1  | 2020-05-19 22:48:28 | 2020-05-19 22:48:28 | NULL       | NULL | NULL    |

From official documentation I know that for strings, the default value is the empty string. As you can see from my proto file I use well-known type google.protobuf.StringValue which I thought would change this default behavior.

Question: How correctly change the default value behavior by gogoprotobuf?

city.proty:

syntax = "proto3";

package proto;

import "google/api/annotations.proto";
import "google/protobuf/wrappers.proto";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";

option go_package = "./proto";

service CityService {
    rpc CreateCity(CreateCityRequest) returns (CreateCityResponse) {
        option (google.api.http) = {
            post: "/api/city"
            body: "city"
        };
    }
}

message City {
    google.protobuf.StringValue name = 1 [
        json_name = "name",
        (gogoproto.jsontag) = "name",
        (gogoproto.wktpointer) = true,
        (gogoproto.nullable) = true
    ];
    google.protobuf.StringValue country = 2 [
        json_name = "country",
        (gogoproto.jsontag) = "country",
        (gogoproto.wktpointer) = true,
        (gogoproto.nullable) = true
    ];
}

message CreateCityRequest {
    City city = 1 [
        json_name = "city",
        (gogoproto.jsontag) = "city"
    ];
}

message CreateCityResponse {}

I use a gorm package to communicate with the database.

models.go:

package models

import (
    "my_app/proto"
    "time"
)

type City struct {
    Id uint64
    CreatedAt time.Time
    UpdatedAt time.Time
    DeletedAt *time.Time
    proto.City
}

func (DealerGroup) TableName() string {
    return "my_scheme.city"
}

controllers.go:

func (server *Server) CreateCity(context context.Context, request *proto.CreateCityRequest) (*proto.CreateCityResponse, error) {
    city := models.City {
        City: *request.City,
    }

    if err := databases.DBGORM.Create(&city).Error; err != nil {
        return nil, status.Errorf(codes.Internal, err.Error())
    }

    return nil, nil
}

go version: go version go1.12.9 windows/amd64

protoc version: libprotoc 3.11.4

I used such protoc command to generate go code: protoc -I. -I%GOPATH%/src --gogofaster_out=plugins=grpc:. proto/city.proto

nurzhannogerbek avatar May 21 '20 09:05 nurzhannogerbek