diff --git a/README.md b/README.md index 689fdfe..18b43fe 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ go get github.com/GoogleCloudPlatform/protoc-gen-bq-schema ``` ## Usage - protoc --bq-schema\_out=path/to/outdir \[--bq-schema_opt=single-message\] foo.proto + protoc --bq-schema\_out=path/to/outdir \[--bq-schema_opt=single-message,use-json-names\] foo.proto `protoc` and `protoc-gen-bq-schema` commands must be found in $PATH. @@ -72,6 +72,9 @@ The message `foo.Baz` is ignored because it doesn't have option `gen_bq_schema.b `protoc --bq-schema_out=. --bq-schema_opt=single-message single_message.proto` will generate a file named `foo/single_message.schema`. The message `foo.Baz` is also ignored because it is not the first message in the file. +`protoc --bq-schema_out=. --bq-schema_opt=use-json-names foo.proto` will generate a schema whose fields are named using `json_name`. +This is equivalent to tagging every message as `use_json_names = true` and provided for convenience. + ### Support for PolicyTags `protoc-gen-bq-schema` now supports [policyTags](https://cloud.google.com/bigquery/docs/column-level-security-intro). diff --git a/main.go b/main.go index 7c668db..798b4a4 100644 --- a/main.go +++ b/main.go @@ -53,6 +53,8 @@ var ( comments: make(map[string]Comments), path: make(map[string]string), } + + globallyUseJsonNames = false ) // Field describes the schema of a field in BigQuery. @@ -238,7 +240,7 @@ func convertField( field := &Field{ Name: desc.GetName(), } - if msgOpts.GetUseJsonNames() && desc.GetJsonName() != "" { + if (msgOpts.GetUseJsonNames() || globallyUseJsonNames) && desc.GetJsonName() != "" { field.Name = desc.GetJsonName() } @@ -505,7 +507,21 @@ func handleSingleMessageOpt(file *descriptor.FileDescriptorProto, requestParam s }) } +// handleUseJsonNamesOpt handles --bq-schema_opt=use-json-names in protoc params. +// providing that param tells protoc-gen-bq-schema to always use a field's json_name +// as the corresponding BigQuery column name. +// it is equivalent to setting the option use_json_name as true to every message. +func handleUseJsonNamesOpt(requestParam string) { + if !strings.Contains(requestParam, "use-json-names") { + return + } + + globallyUseJsonNames = true +} + func convert(req *plugin.CodeGeneratorRequest) (*plugin.CodeGeneratorResponse, error) { + handleUseJsonNamesOpt(req.GetParameter()) + generateTargets := make(map[string]bool) for _, file := range req.GetFileToGenerate() { generateTargets[file] = true diff --git a/plugin_test.go b/plugin_test.go index e2757c2..d95fb6c 100644 --- a/plugin_test.go +++ b/plugin_test.go @@ -504,3 +504,37 @@ func TestExtraFields(t *testing.T) { ]`, }) } + +func TestGloballyUseJsonNamesOpt(t *testing.T) { + globallyUseJsonNames = true + testConvert(t, ` + file_to_generate: "foo.proto" + proto_file < + name: "foo.proto" + package: "example_package.nested" + message_type < + name: "FooProto" + field < name: "str" number: 1 type: TYPE_STRING label: LABEL_OPTIONAL json_name: "someJsonSpecificName" > + field < + name: "nested_message" number: 2 type: TYPE_MESSAGE label: LABEL_OPTIONAL + type_name: ".example_package.nested.FooProto.Nested" json_name: "nestedMessage" + > + nested_type < + name: "Nested" + field < name: "some_field" number: 1 type: TYPE_STRING label: LABEL_OPTIONAL json_name: "someField" > + > + options < [gen_bq_schema.bigquery_opts] > + > + > + `, + map[string]string{ + "example_package/nested/foo_table.schema": `[ + { "name": "someJsonSpecificName", "type": "STRING", "mode": "NULLABLE" }, + { + "name": "nestedMessage", "type": "RECORD", "mode": "NULLABLE", + "fields": [{ "name": "someField", "type": "STRING", "mode": "NULLABLE" }] + } + ]`, + }) + globallyUseJsonNames = false +}