diff --git a/docs/reference/config.md b/docs/reference/config.md index 96bf7fe794..a348901990 100644 --- a/docs/reference/config.md +++ b/docs/reference/config.md @@ -111,6 +111,8 @@ The `gen` mapping supports the following keys: - `emit_all_enum_values`: - If true, emit a function per enum type that returns all valid enum values. +- `json_tags_id_uppercase`: + - If true, "Id" in json tags will be uppercase. If false, will be camelcase. Defaults to `false` - `json_tags_case_style`: - `camel` for camelCase, `pascal` for PascalCase, `snake` for snake_case or `none` to use the column name in the DB. Defaults to `none`. - `output_batch_file_name`: diff --git a/internal/cmd/shim.go b/internal/cmd/shim.go index 838d344cc3..c4049ac056 100644 --- a/internal/cmd/shim.go +++ b/internal/cmd/shim.go @@ -84,6 +84,7 @@ func pluginGoCode(s config.SQLGo) *plugin.GoCode { return &plugin.GoCode{ EmitInterface: s.EmitInterface, EmitJsonTags: s.EmitJSONTags, + JsonTagsIDUppercase: s.JsonTagsIDUppercase, EmitDbTags: s.EmitDBTags, EmitPreparedQueries: s.EmitPreparedQueries, EmitExactTableNames: s.EmitExactTableNames, diff --git a/internal/codegen/golang/field.go b/internal/codegen/golang/field.go index 6a8a2b6372..0098eb9fc4 100644 --- a/internal/codegen/golang/field.go +++ b/internal/codegen/golang/field.go @@ -42,10 +42,11 @@ func TagsToString(tags map[string]string) string { func JSONTagName(name string, settings *plugin.Settings) string { style := settings.Go.JsonTagsCaseStyle + idUppercase := settings.Go.JsonTagsIDUppercase if style == "" || style == "none" { return name } else { - return SetCaseStyle(name, style) + return SetJSONCaseStyle(name, style, idUppercase) } } @@ -62,6 +63,19 @@ func SetCaseStyle(name string, style string) string { } } +func SetJSONCaseStyle(name string, style string, idUppercase bool) string { + switch style { + case "camel": + return toJsonCamelCase(name, idUppercase) + case "pascal": + return toPascalCase(name) + case "snake": + return toSnakeCase(name) + default: + panic(fmt.Sprintf("unsupported JSON tags case style: '%s'", style)) + } +} + var camelPattern = regexp.MustCompile("[^A-Z][A-Z]+") func toSnakeCase(s string) string { @@ -97,6 +111,28 @@ func toCamelInitCase(name string, initUpper bool) string { return out } +func toJsonCamelCase(name string, idUppercase bool) string { + out := "" + idStr := "Id" + + if idUppercase { + idStr = "ID" + } + + for i, p := range strings.Split(name, "_") { + if i == 0 { + out += p + continue + } + if p == "id" { + out += idStr + } else { + out += strings.Title(p) + } + } + return out +} + func toLowerCase(str string) string { if str == "" { return "" diff --git a/internal/codegen/golang/gen.go b/internal/codegen/golang/gen.go index dac9d47862..d0c21b397e 100644 --- a/internal/codegen/golang/gen.go +++ b/internal/codegen/golang/gen.go @@ -28,6 +28,7 @@ type tmplCtx struct { SourceName string EmitJSONTags bool + JsonTagsIDUppercase bool EmitDBTags bool EmitPreparedQueries bool EmitInterface bool @@ -122,6 +123,7 @@ func generate(req *plugin.CodeGenRequest, enums []Enum, structs []Struct, querie tctx := tmplCtx{ EmitInterface: golang.EmitInterface, EmitJSONTags: golang.EmitJsonTags, + JsonTagsIDUppercase: golang.JsonTagsIDUppercase, EmitDBTags: golang.EmitDbTags, EmitPreparedQueries: golang.EmitPreparedQueries, EmitEmptySlices: golang.EmitEmptySlices, diff --git a/internal/config/config.go b/internal/config/config.go index b0479a6f12..86f03f4757 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -119,6 +119,7 @@ type SQLGen struct { type SQLGo struct { EmitInterface bool `json:"emit_interface" yaml:"emit_interface"` EmitJSONTags bool `json:"emit_json_tags" yaml:"emit_json_tags"` + JsonTagsIDUppercase bool `json:"json_tags_id_uppercase" yaml:"json_tags_id_uppercase"` EmitDBTags bool `json:"emit_db_tags" yaml:"emit_db_tags"` EmitPreparedQueries bool `json:"emit_prepared_queries" yaml:"emit_prepared_queries"` EmitExactTableNames bool `json:"emit_exact_table_names,omitempty" yaml:"emit_exact_table_names"` diff --git a/internal/config/v_one.go b/internal/config/v_one.go index b0f1bfae04..1d9a29b2df 100644 --- a/internal/config/v_one.go +++ b/internal/config/v_one.go @@ -25,6 +25,7 @@ type v1PackageSettings struct { Queries Paths `json:"queries" yaml:"queries"` EmitInterface bool `json:"emit_interface" yaml:"emit_interface"` EmitJSONTags bool `json:"emit_json_tags" yaml:"emit_json_tags"` + JsonTagsIDUppercase bool `json:"json_tags_id_uppercase" yaml:"json_tags_id_uppercase"` EmitDBTags bool `json:"emit_db_tags" yaml:"emit_db_tags"` EmitPreparedQueries bool `json:"emit_prepared_queries" yaml:"emit_prepared_queries"` EmitExactTableNames bool `json:"emit_exact_table_names,omitempty" yaml:"emit_exact_table_names"` @@ -143,6 +144,7 @@ func (c *V1GenerateSettings) Translate() Config { Go: &SQLGo{ EmitInterface: pkg.EmitInterface, EmitJSONTags: pkg.EmitJSONTags, + JsonTagsIDUppercase: pkg.JsonTagsIDUppercase, EmitDBTags: pkg.EmitDBTags, EmitPreparedQueries: pkg.EmitPreparedQueries, EmitExactTableNames: pkg.EmitExactTableNames, diff --git a/internal/plugin/codegen.pb.go b/internal/plugin/codegen.pb.go index cd1caa0e31..3b91d2cfed 100644 --- a/internal/plugin/codegen.pb.go +++ b/internal/plugin/codegen.pb.go @@ -467,6 +467,7 @@ type GoCode struct { EmitPointersForNullTypes bool `protobuf:"varint,22,opt,name=emit_pointers_for_null_types,json=emitPointersForNullTypes,proto3" json:"emit_pointers_for_null_types,omitempty"` QueryParameterLimit *int32 `protobuf:"varint,23,opt,name=query_parameter_limit,json=queryParameterLimit,proto3,oneof" json:"query_parameter_limit,omitempty"` OutputBatchFileName string `protobuf:"bytes,24,opt,name=output_batch_file_name,json=outputBatchFileName,proto3" json:"output_batch_file_name,omitempty"` + JsonTagsIDUppercase bool `protobuf:"varint,26,opt,name=json_tags_id_uppercase,json=jsonTagsIdCamelcase,proto3" json:"json_tags_id_uppercase,omitempty"` } func (x *GoCode) Reset() { @@ -515,6 +516,13 @@ func (x *GoCode) GetEmitJsonTags() bool { return false } +func (x *GoCode) GetJsonTagsIDUppercase() bool { + if x != nil { + return x.JsonTagsIDUppercase + } + return true +} + func (x *GoCode) GetEmitDbTags() bool { if x != nil { return x.EmitDbTags diff --git a/internal/plugin/codegen_vtproto.pb.go b/internal/plugin/codegen_vtproto.pb.go index ea84078968..c9e50c3a2d 100644 --- a/internal/plugin/codegen_vtproto.pb.go +++ b/internal/plugin/codegen_vtproto.pb.go @@ -172,6 +172,7 @@ func (m *GoCode) CloneVT() *GoCode { r := &GoCode{ EmitInterface: m.EmitInterface, EmitJsonTags: m.EmitJsonTags, + JsonTagsIDUppercase: m.JsonTagsIDUppercase, EmitDbTags: m.EmitDbTags, EmitPreparedQueries: m.EmitPreparedQueries, EmitExactTableNames: m.EmitExactTableNames, @@ -754,6 +755,9 @@ func (this *GoCode) EqualVT(that *GoCode) bool { if this.EmitJsonTags != that.EmitJsonTags { return false } + if this.JsonTagsIDUppercase != that.JsonTagsIDUppercase { + return false + } if this.EmitDbTags != that.EmitDbTags { return false } @@ -1996,6 +2000,16 @@ func (m *GoCode) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i-- dAtA[i] = 0x10 } + if m.JsonTagsIDUppercase { + i-- + if m.JsonTagsIDUppercase { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x64 + } if m.EmitInterface { i-- if m.EmitInterface { @@ -3548,15 +3562,25 @@ func (m *GoCode) MarshalToSizedBufferVTStrict(dAtA []byte) (int, error) { i-- dAtA[i] = 0x10 } - if m.EmitInterface { + if m.EmitJsonTags { i-- - if m.EmitInterface { + if m.EmitJsonTags { dAtA[i] = 1 } else { dAtA[i] = 0 } i-- - dAtA[i] = 0x8 + dAtA[i] = 0x10 + } + if m.JsonTagsIDUppercase { + i-- + if m.JsonTagsIDUppercase { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x64 } return len(dAtA) - i, nil } @@ -4605,6 +4629,9 @@ func (m *GoCode) SizeVT() (n int) { if m.EmitJsonTags { n += 2 } + if m.JsonTagsIDUppercase { + n += 2 + } if m.EmitDbTags { n += 2 } @@ -7007,6 +7034,26 @@ func (m *GoCode) UnmarshalVT(dAtA []byte) error { } m.SqlDriver = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 26: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field JsonTagsIDUppercase", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.JsonTagsIDUppercase = bool(v != 0) default: iNdEx = preIndex skippy, err := skip(dAtA[iNdEx:])