Skip to content

Instantly share code, notes, and snippets.

@matejkramny
Created March 5, 2021 23:06
Show Gist options
  • Save matejkramny/35e519858f6e1eddee81780fc78cb208 to your computer and use it in GitHub Desktop.
Save matejkramny/35e519858f6e1eddee81780fc78cb208 to your computer and use it in GitHub Desktop.
mongodb/naming enhancement for gogo protobuf generator
// Protocol Buffers for Go with Gadgets
//
// Copyright (c) 2015, The GoGo Authors. All rights reserved.
// http://github.com/gogo/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package main
import (
"regexp"
"strings"
"github.com/gogo/protobuf/gogoproto"
"github.com/gogo/protobuf/proto"
"github.com/gogo/protobuf/protoc-gen-gogo/descriptor"
"github.com/gogo/protobuf/protoc-gen-gogo/generator"
"github.com/gogo/protobuf/vanity"
"github.com/gogo/protobuf/vanity/command"
)
// ref https://gist.github.com/stoewer/fbe273b711e6a06315d19552dd4d33e6
var matchFirstCap = regexp.MustCompile("(.)([A-Z][a-z]+)")
var matchAllCap = regexp.MustCompile("([a-z0-9])([A-Z])")
func ToSnakeCase(str string) string {
snake := matchFirstCap.ReplaceAllString(str, "${1}_${2}")
snake = matchAllCap.ReplaceAllString(snake, "${1}_${2}")
return strings.ToLower(snake)
}
func main() {
req := command.Read()
files := req.GetProtoFile()
files = vanity.FilterFiles(files, vanity.NotGoogleProtobufDescriptorProto)
vanity.ForEachFile(files, vanity.TurnOnMarshalerAll)
vanity.ForEachFile(files, vanity.TurnOnSizerAll)
vanity.ForEachFile(files, vanity.TurnOnUnmarshalerAll)
vanity.ForEachFieldInFilesExcludingExtensions(vanity.OnlyProto2(files), vanity.TurnOffNullableForNativeTypesWithoutDefaultsOnly)
vanity.ForEachFile(files, vanity.TurnOffGoUnrecognizedAll)
vanity.ForEachFile(files, vanity.TurnOffGoUnkeyedAll)
vanity.ForEachFile(files, vanity.TurnOffGoSizecacheAll)
vanity.ForEachFile(files, vanity.TurnOffGoEnumPrefixAll)
vanity.ForEachFile(files, vanity.TurnOffGoEnumStringerAll)
vanity.ForEachFile(files, vanity.TurnOnEnumStringerAll)
vanity.ForEachFile(files, vanity.TurnOnEqualAll)
vanity.ForEachFile(files, vanity.TurnOnGoStringAll)
vanity.ForEachFile(files, vanity.TurnOffGoStringerAll)
vanity.ForEachFile(files, vanity.TurnOnStringerAll)
vanity.ForEachFieldInFiles(files, patchField)
vanity.ForEachFile(files, vanity.TurnOffGoGettersAll)
resp := command.Generate(req)
command.Write(resp)
}
func patchField(field *descriptor.FieldDescriptorProto) {
if field.Name == nil {
return
}
if field.Options == nil {
field.Options = &descriptor.FieldOptions{}
}
jsonName := ToSnakeCase(*field.Name)
jsonTag := "omitempty"
if gogoJsonTag := gogoproto.GetJsonTag(field); gogoJsonTag != nil {
split := strings.Split(*gogoJsonTag, ",")
jsonName = split[0]
if len(split) > 1 {
jsonTag = strings.Join(split[1:], ",")
}
}
if jsonName == "id" && field.TypeName != nil && strings.Contains(*field.TypeName, "types.ObjectID") {
jsonName = "_id"
}
field.JsonName = &jsonName
jsonTag = jsonName + "," + jsonTag
moreTags := `bson:"` + jsonName + `,omitempty"`
if more := gogoproto.GetMoreTags(field); more != nil && len(*more) > 0 {
if strings.Contains(*more, "bson:") {
moreTags = *more
} else {
moreTags += " " + *more
}
}
if strings.Contains(*field.Name, "_id") {
customname := generator.CamelCase(strings.Replace(*field.Name, "_id", "ID", 1))
if err := proto.SetExtension(field.Options, gogoproto.E_Customname, &customname); err != nil {
panic(err)
}
}
if jsonName == "_id" {
customname := "ID"
if err := proto.SetExtension(field.Options, gogoproto.E_Customname, &customname); err != nil {
panic(err)
}
}
if field.TypeName != nil && strings.Contains(*field.TypeName, "google.protobuf.Timestamp") {
bv := true
if err := proto.SetExtension(field.Options, gogoproto.E_Stdtime, &bv); err != nil {
panic(err)
}
}
if err := proto.SetExtension(field.Options, gogoproto.E_Jsontag, &jsonTag); err != nil {
panic(err)
}
if err := proto.SetExtension(field.Options, gogoproto.E_Moretags, &moreTags); err != nil {
panic(err)
}
}
@matejkramny
Copy link
Author

example.proto file

Screenshot_20210305_230731

Generated example.pb.go

Screenshot_20210305_230228

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment