├── .codecov.yml ├── .deepsource.toml ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── Makefile ├── README.md ├── datastore-translator ├── exclude_index_test.go ├── translator.go ├── translator_integration_test.go ├── translator_test.go └── ts_struct_test.go ├── examples └── main.go ├── go.mod ├── go.sum ├── models ├── example │ └── example.pb.go ├── execution │ └── execution.pb.go └── unsupported │ └── unsupported.pb.go ├── proto ├── example.proto ├── execution.proto └── unsupported.proto └── scripts └── run-datastore-emulator.sh /.codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | # pull-requests only 4 | patch: 5 | default: 6 | threshold: 5% 7 | precision: 2 8 | round: down 9 | range: 70...100 10 | 11 | comment: 12 | layout: "header, diff, tree" 13 | behavior: default 14 | require_changes: false 15 | branches: null 16 | flags: null 17 | paths: null -------------------------------------------------------------------------------- /.deepsource.toml: -------------------------------------------------------------------------------- 1 | version = 1 2 | 3 | [[analyzers]] 4 | name = "go" 5 | enabled = true 6 | 7 | [analyzers.meta] 8 | import_path = "github.com/Sheshagiri/go-protobuf-cloud-datastore-entity-translator" 9 | dependencies_vendored = true 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | vendor/* 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.12.x 5 | - 1.13.x 6 | 7 | os: linux 8 | dist: xenial 9 | 10 | sudo: false 11 | 12 | branches: 13 | only: 14 | - master 15 | 16 | install: 17 | - go get -u github.com/golang/protobuf/protoc-gen-go 18 | - curl -L https://github.com/protocolbuffers/protobuf/releases/download/v3.9.1/protoc-3.9.1-linux-x86_64.zip -o /tmp/protoc.zip 19 | - unzip /tmp/protoc.zip -d "$HOME"/protoc 20 | - mkdir -p "$HOME"/src && ln -s "$HOME"/protoc "$HOME"/src/protobuf 21 | - ./scripts/run-datastore-emulator.sh 22 | 23 | env: 24 | - PATH=$HOME/protoc/bin:$PATH DATASTORE_EMULATOR_HOST=127.0.0.1:8081 GO111MODULE="on" 25 | 26 | script: 27 | - echo "Generate Protobuf's" 28 | - make protobuf 29 | - echo "Unit Tests" 30 | - make unit-tests 31 | - echo "Integration Tests" 32 | - make integration-tests 33 | 34 | notifications: 35 | email: 36 | on_success: change 37 | on_failure: always 38 | 39 | after_success: 40 | - bash <(curl -s https://codecov.io/bash) 41 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | ## [1.0.3] - 23rd October 2019 5 | No major changes to the functionality. Removed indirect dependencies from `go.mod`. 6 | 7 | ## [1.0.2] - 28th September 2019 8 | This release adds support for protobuf's with `google.protobuf.Struct` from referenced/imported proto files. 9 | Following is an example. 10 | ``` 11 | message Action { 12 | string name = 1; 13 | google.protobuf.Struct parameters = 2; 14 | } 15 | 16 | message Execution { 17 | string name = 1; 18 | Action action = 2; 19 | } 20 | ``` 21 | 22 | ## [1.0.1] - 11th September 2019 23 | This release adds support for excluding the fields from being indexed by google cloud datastore using a custom extension 24 | in proto files. Following is an example. 25 | ``` 26 | datastoreEntity, err := translator.ProtoMessageToDatastoreEntity(dbModel, true, "models.exclude_from_index") 27 | ``` 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2019 Sheshagiri Rao Mallipedhi 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | deps: 2 | go mod vendor 3 | 4 | protobuf: 5 | protoc --proto_path=proto/ --go_out=models/execution proto/execution.proto 6 | protoc --proto_path=proto/ --go_out=models/example proto/example.proto 7 | protoc --proto_path=proto/ --go_out=models/unsupported proto/unsupported.proto 8 | 9 | unit-tests: deps 10 | @echo "Running Unit Tests" 11 | go test -v ./... -mod=vendor -race -coverprofile=coverage.txt -covermode=atomic 12 | 13 | integration-tests: deps 14 | @echo "Running Integration Tests" 15 | go test -v ./... -mod=vendor -race -tags=integration 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Translate any proto message to Google Datastore Entity and vice-versa 2 | 3 | 4 | [![Build Status](https://travis-ci.org/Sheshagiri/go-protobuf-cloud-datastore-entity-translator.svg?branch=master)](https://travis-ci.org/Sheshagiri/go-protobuf-cloud-datastore-entity-translator) 5 | [![codecov](https://codecov.io/gh/Sheshagiri/go-protobuf-cloud-datastore-entity-translator/branch/master/graph/badge.svg)](https://codecov.io/gh/Sheshagiri/go-protobuf-cloud-datastore-entity-translator) 6 | 7 | 8 | # Background 9 | 10 | This is largely inspired from being able to persist protocol buffers to Google Cloud Datastore. Protobuf messages that the datstore supports are listed [here](https://github.com/googleapis/googleapis/blob/c50d9e822e19e069b7e3758736ea58cb4f35267c/google/datastore/v1/entity.proto#L188). 11 | 12 | This repository acts as a translator to translate any given ``proto.Message`` to ``datastore.Entity`` that the datastore understands and 13 | ``datastore.Entity`` to any ``proto.Message``. 14 | 15 | This repository also addresses some of the limitations that [google-cloud-go](https://github.com/googleapis/google-cloud-go/tree/master/datastore) has. 16 | Currently the go datastore library `google-cloud-go` doesn't support `maps`, `google.protobuf.Struct`, `google.protobuf.Value` types 17 | and it also doesn't expose `Put` and `Get` functions that operate on `datastore.Entity`. I added the support for being able to use `datastore.Entity` by adding `PutEntity` and `GetEntity` in a fork [here](https://github.com/Sheshagiri/google-cloud-go). 18 | 19 | Issues that inspired this solution: 20 | 21 | https://github.com/googleapis/google-cloud-go/issues/1474 22 | 23 | https://github.com/googleapis/google-cloud-go/issues/1489 24 | 25 | https://github.com/googleapis/google-cloud-go/issues/680 26 | 27 | Following is an example of the same. 28 | 29 | ``` 30 | package main 31 | import ( 32 | "context" 33 | "cloud.google.com/go/datastore" 34 | "log" 35 | "github.com/Sheshagiri/go-protobuf-cloud-datastore-entity-translator/models/execution" 36 | "github.com/golang/protobuf/ptypes" 37 | "github.com/pborman/uuid" 38 | "github.com/golang/protobuf/ptypes/struct" 39 | translator "github.com/Sheshagiri/go-protobuf-cloud-datastore-entity-translator/datastore-translator" 40 | ) 41 | func main() { 42 | ctx := context.Background() 43 | 44 | // 1. create datastore client 45 | dsClient, err := datastore.NewClient(ctx,"st2-saas-prototype-dev") 46 | if err != nil { 47 | log.Fatalf("unable to connect to datastore, error: %v", err) 48 | } 49 | 50 | // 2. create a protobuf message 51 | execReq := &execution.ExecutionRequest{ 52 | StartedOn:ptypes.TimestampNow(), 53 | Uuid:uuid.New(), 54 | Action:"create_vm", 55 | Parameters: &structpb.Struct{ 56 | Fields: map[string]*structpb.Value{ 57 | "vm-name": {Kind: &structpb.Value_StringValue{StringValue:"sheshagiri-vm-1"}}, 58 | "allow-root-login": {Kind: &structpb.Value_BoolValue{BoolValue:true}}, 59 | "network-interfaces": {Kind: &structpb.Value_NumberValue{NumberValue:2}}, 60 | }, 61 | }, 62 | } 63 | 64 | // 3. translate the protobuf message to the format that datastore understands 65 | entity, err := translator.ProtoMessageToDatastoreEntity(execReq, true) 66 | if err != nil { 67 | log.Fatalf("unable to translate execution request to datastore format, error: %v", err) 68 | } 69 | 70 | // 4. create a key where we would like to store the message, think of this as a primary key 71 | parentKey := datastore.NameKey("ExecutionRequest",execReq.GetAction(), nil) 72 | childKey := datastore.NameKey(execReq.GetAction(),execReq.GetUuid(), parentKey) 73 | 74 | // 5. save it to datastore against the key 75 | _, err = dsClient.PutEntity(ctx, childKey, &entity) 76 | if err != nil { 77 | log.Fatalf("unable to translate execution request to datastore format, error: %v", err) 78 | } 79 | log.Printf("key %v is saved to datastore",childKey) 80 | 81 | // 6. Try to retrieve the key 82 | dsEntity, err := dsClient.GetEntity(ctx, childKey) 83 | if err != nil { 84 | log.Fatalf("unable to get %v from datastore", childKey) 85 | } 86 | 87 | // 7. convert the value fetched from datastore to protobuf 88 | dsExecReq, err := translator.DatastoreEntityToProtoMessage(dsEntity,&execution.ExecutionRequest{}, true) 89 | if err != nil { 90 | log.Fatalf("error while converting to proto message, %v", err) 91 | } 92 | 93 | // 8. simply log it :) 94 | log.Println(dsExecReq) 95 | } 96 | ``` 97 | 98 | ## Support for excluding the fields from being indexed buy Google Cloud Datastore 99 | By default, Google Cloud Datastore automatically indexes each entity (model) property. 100 | 101 | Indexing each field (entity property) is usually not desired nor needed. It also has some limitations (for example, 102 | size of a simple field which is to be indexed is limited to 1500 bytes, etc.). In addition to that, unnecessary 103 | indexing causes increased storage space consumption. 104 | 105 | This library allows you to define which model fields to exclude from index on the field basis utilizing Protobuf field 106 | options extension. 107 | 108 | For example: 109 | ```proto 110 | syntax = "proto3"; 111 | 112 | import "google/protobuf/descriptor.proto"; 113 | 114 | // Custom Protobuf option which specifies which model fields should be excluded 115 | // from index 116 | // NOTE: Keep in mind that it's important not to change the option name 117 | // ("exclude_from_index") since this library uses that special option name to 118 | // determine if a field should be excluded from index. 119 | extend google.protobuf.FieldOptions { 120 | bool exclude_from_index = 50000; 121 | } 122 | 123 | message ExampleDBModelWithOptions1 { 124 | string string_key_one = 1 [(exclude_from_index) = true]; 125 | string string_key_two = 2; 126 | string string_key_three = 3 [(exclude_from_index) = true]; 127 | string string_key_four = 4; 128 | int32 int32_field_one = 5; 129 | int32 int32_field_two = 6 [(exclude_from_index) = true]; 130 | } 131 | ``` 132 | In this example, fields string_key_one, string_key_three and int32_field_two won't be 133 | indexed (https://cloud.google.com/datastore/docs/concepts/indexes#unindexed_properties). 134 | 135 | Note: If the extension is imported then `.` should be passed to the `ProtoMessageToDatastoreEntity`. 136 | Following is an example 137 | ```Go 138 | datastoreEntity, err := translator.ProtoMessageToDatastoreEntity(dbModel, true, "models.exclude_from_index") 139 | ``` 140 | My colleague at work wrote an [equivalent translator in python](https://github.com/Kami/python-protobuf-cloud-datastore-entity-translator). 141 | 142 | ## Tested with go1.12.6 143 | -------------------------------------------------------------------------------- /datastore-translator/exclude_index_test.go: -------------------------------------------------------------------------------- 1 | package datastore_translator 2 | 3 | import ( 4 | "github.com/Sheshagiri/go-protobuf-cloud-datastore-entity-translator/models/execution" 5 | "github.com/golang/protobuf/ptypes" 6 | structpb "github.com/golang/protobuf/ptypes/struct" 7 | "gotest.tools/assert" 8 | 9 | "testing" 10 | ) 11 | 12 | func TestFieldsWithExclude(t *testing.T) { 13 | er := &execution.ExecutionRequest{ 14 | Uuid: "some uuid", 15 | Action: "some random action", 16 | StartedOn: ptypes.TimestampNow(), 17 | Parameters: &structpb.Struct{ 18 | Fields: map[string]*structpb.Value{ 19 | "struct-key-string": {Kind: &structpb.Value_StringValue{StringValue: "some random string in proto.Struct"}}, 20 | "struct-key-bool": {Kind: &structpb.Value_BoolValue{BoolValue: true}}, 21 | "struct-key-number": {Kind: &structpb.Value_NumberValue{NumberValue: 123456.12}}, 22 | "struct-key-null": {Kind: &structpb.Value_NullValue{}}, 23 | "struct-key-list": {Kind: &structpb.Value_ListValue{ 24 | ListValue: &structpb.ListValue{ 25 | Values: []*structpb.Value{ 26 | {Kind: &structpb.Value_NumberValue{NumberValue: 10}}, 27 | {Kind: &structpb.Value_StringValue{StringValue: "hello, world"}}, 28 | {Kind: &structpb.Value_BoolValue{BoolValue: true}}, 29 | {Kind: &structpb.Value_NumberValue{NumberValue: 200}}, 30 | }, 31 | }, 32 | }, 33 | }, 34 | }, 35 | }, 36 | Result: []byte("some large message, this will not be indexed in cloud datastore"), 37 | } 38 | entity, err := ProtoMessageToDatastoreEntity(er, true, "exclude_from_index") 39 | assert.NilError(t, err) 40 | assert.Equal(t, entity.Properties["result"].ExcludeFromIndexes, true) 41 | assert.Equal(t, entity.Properties["parameters"].ExcludeFromIndexes, true) 42 | } 43 | -------------------------------------------------------------------------------- /datastore-translator/translator.go: -------------------------------------------------------------------------------- 1 | package datastore_translator 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "log" 7 | "reflect" 8 | "strings" 9 | 10 | "regexp" 11 | 12 | "github.com/golang/protobuf/descriptor" 13 | "github.com/golang/protobuf/proto" 14 | structpb "github.com/golang/protobuf/ptypes/struct" 15 | "github.com/golang/protobuf/ptypes/timestamp" 16 | "google.golang.org/genproto/googleapis/datastore/v1" 17 | 18 | clientSDK "cloud.google.com/go/datastore" 19 | ) 20 | 21 | // ProtoMessageToDatastoreEntity will generate an Entity Protobuf that datastore understands 22 | func ProtoMessageToDatastoreEntity(src proto.Message, snakeCase bool, excludeFromIndexName ...string) (entity datastore.Entity, err error) { 23 | if len(excludeFromIndexName) > 1 { 24 | return entity, errors.New("exclude only works with one extension") 25 | } 26 | srcValues := reflect.ValueOf(src).Elem() 27 | properties := make(map[string]*datastore.Value) 28 | // see https://github.com/golang/protobuf/issues/372 29 | fd, md := descriptor.ForMessage(src.(descriptor.Message)) 30 | // this is the default name 31 | excludeFromIndexExt := "[exclude_from_index]:true " 32 | var excludeIndex string 33 | // use the Extension name is passed else derive it dynamically 34 | if excludeFromIndexName != nil && len(excludeFromIndexName) > 0 { 35 | excludeFromIndexExt = fmt.Sprintf("[%s]:true ", excludeFromIndexName[0]) 36 | excludeIndex = excludeFromIndexName[0] 37 | } else { 38 | if len(fd.GetExtension()) > 0 { 39 | excludeIndex = fd.GetExtension()[0].GetName() 40 | excludeFromIndexExt = fmt.Sprintf("[%s]:true ", excludeIndex) 41 | } 42 | } 43 | 44 | excludeFields := make(map[string]string, 0) 45 | for _, fd := range md.GetField() { 46 | if fd.GetOptions() != nil { 47 | excludeFields[fd.GetName()] = fd.GetOptions().String() 48 | } 49 | } 50 | for i := 0; i < srcValues.NumField(); i++ { 51 | fName := srcValues.Type().Field(i).Name 52 | if !strings.ContainsAny(fName, "XXX_") { 53 | var value *datastore.Value 54 | if value, err = toDatastoreValue(fName, srcValues.Field(i), snakeCase, excludeIndex); err != nil { 55 | return 56 | } else { 57 | if value != nil { 58 | if snakeCase { 59 | fName = toSnakeCase(fName) 60 | } 61 | if excludeFields[fName] == excludeFromIndexExt { 62 | value.ExcludeFromIndexes = true 63 | } 64 | properties[fName] = value 65 | } 66 | } 67 | } 68 | } 69 | entity.Properties = properties 70 | return 71 | } 72 | 73 | // DatastoreEntityToProtoMessage converts any given datastore.Entity to supplied proto.Message 74 | func DatastoreEntityToProtoMessage(src *datastore.Entity, dst proto.Message, snakeCase bool) (err error) { 75 | entity, err := clientSDK.ProtoToEntity(src, snakeCase) 76 | if err != nil { 77 | return err 78 | } 79 | 80 | err = clientSDK.EntityToStruct(dst, entity) 81 | if err != nil { 82 | if strings.ContainsAny(err.Error(), "no such struct field") || strings.ContainsAny(err.Error(), "versus map[string]") { 83 | err = nil 84 | // handle google.protobuf.Struct type here 85 | dstValues := reflect.ValueOf(dst).Elem() 86 | for i := 0; i < dstValues.NumField(); i++ { 87 | fName := dstValues.Type().Field(i).Name 88 | if !strings.Contains(fName, "XXX_") { 89 | keyName := fName 90 | if snakeCase { 91 | keyName = toSnakeCase(fName) 92 | } 93 | fValue := src.Properties[keyName] 94 | fType := dstValues.Type().Field(i).Type.Kind() 95 | // log.Printf("name: %s, type: %s\n", fName, fType) 96 | switch fType { 97 | case reflect.Map: 98 | if !reflect.ValueOf(fValue).IsNil() { 99 | entity := fValue.GetEntityValue() 100 | switch dstValues.Type().Field(i).Type.String() { 101 | // rudimentary impl, as I can't get hold of the type with Kind() here, look at Indirect() later 102 | case "map[string]string": 103 | m := make(map[string]string) 104 | for key, value := range entity.Properties { 105 | m[key] = value.GetStringValue() 106 | } 107 | dstValues.Field(i).Set(reflect.ValueOf(m)) 108 | case "map[string]int32": 109 | m := make(map[string]int32) 110 | for key, value := range entity.Properties { 111 | m[key] = int32(value.GetIntegerValue()) 112 | } 113 | dstValues.Field(i).Set(reflect.ValueOf(m)) 114 | case "map[string]*structpb.Value": 115 | m := make(map[string]*structpb.Value) 116 | for key, value := range entity.Properties { 117 | m[key] = fromDatastoreValueToStructValue(value) 118 | } 119 | dstValues.Field(i).Set(reflect.ValueOf(m)) 120 | } 121 | } 122 | case reflect.Ptr: 123 | iv := dstValues.Field(i).Interface() 124 | switch iv.(type) { 125 | case *structpb.Struct: 126 | if !reflect.ValueOf(fValue).IsNil() { 127 | switch v := reflect.ValueOf(fValue.ValueType).Interface().(type) { 128 | case *datastore.Value_EntityValue: 129 | properties := v.EntityValue.Properties 130 | if properties != nil { 131 | s := &structpb.Struct{} 132 | m := make(map[string]*structpb.Value) 133 | for key, value := range properties { 134 | // log.Printf("value type is: %T", value.ValueType) 135 | m[key] = fromDatastoreValueToStructValue(value) 136 | } 137 | s.Fields = m 138 | dstValues.Field(i).Set(reflect.ValueOf(s)) 139 | } 140 | } 141 | } 142 | // all the other pointers like referenced protobuf's 143 | default: 144 | if !reflect.ValueOf(fValue).IsNil() { 145 | switch v := reflect.ValueOf(fValue.ValueType).Interface().(type) { 146 | case *datastore.Value_EntityValue: 147 | innerModel, ok := dstValues.Field(i).Interface().(proto.Message) 148 | if !ok { 149 | return errors.New("failed to translate: %s" + fName) 150 | } 151 | err = DatastoreEntityToProtoMessage(v.EntityValue, innerModel, snakeCase) 152 | if err != nil { 153 | return nil 154 | } 155 | } 156 | } 157 | } 158 | } 159 | } 160 | } 161 | } 162 | } 163 | return err 164 | } 165 | 166 | func toDatastoreValue(fName string, fValue reflect.Value, snakeCase bool, excludeFromIndexName string) (*datastore.Value, error) { 167 | value := &datastore.Value{} 168 | var err error 169 | switch fValue.Kind() { 170 | case reflect.String: 171 | value.ValueType = &datastore.Value_StringValue{ 172 | StringValue: fValue.String(), 173 | } 174 | case reflect.Bool: 175 | value.ValueType = &datastore.Value_BooleanValue{ 176 | BooleanValue: fValue.Bool(), 177 | } 178 | case reflect.Int64, reflect.Int32: 179 | value.ValueType = &datastore.Value_IntegerValue{ 180 | IntegerValue: fValue.Int(), 181 | } 182 | case reflect.Float32, reflect.Float64: 183 | value.ValueType = &datastore.Value_DoubleValue{ 184 | DoubleValue: fValue.Float(), 185 | } 186 | case reflect.Slice: 187 | // TODO add complex type to the slice 188 | if fValue.Type().Elem().Kind() == reflect.Uint8 { 189 | // BlobValue is a string in the datastore entity proto 190 | value.ValueType = &datastore.Value_BlobValue{ 191 | BlobValue: fValue.Bytes(), 192 | } 193 | } else { 194 | size := fValue.Len() 195 | values := make([]*datastore.Value, 0) 196 | for i := 0; i < size; i++ { 197 | val, err := toDatastoreValue(fName, fValue.Index(i), snakeCase, excludeFromIndexName) 198 | if err != nil { 199 | return nil, err 200 | } 201 | values = append(values, val) 202 | } 203 | value.ValueType = &datastore.Value_ArrayValue{ 204 | ArrayValue: &datastore.ArrayValue{ 205 | Values: values, 206 | }, 207 | } 208 | } 209 | case reflect.Map: 210 | mapValues := reflect.ValueOf(fValue.Interface()) 211 | entity := &datastore.Entity{} 212 | properties := make(map[string]*datastore.Value) 213 | for _, key := range mapValues.MapKeys() { 214 | k := fmt.Sprint(key) 215 | // TODO what if there is an error? 216 | v, _ := toDatastoreValue(fName, mapValues.MapIndex(key), snakeCase, excludeFromIndexName) 217 | // fmt.Printf("key; %v, value: %v\n",k,v) 218 | properties[k] = v 219 | } 220 | entity.Properties = properties 221 | value.ValueType = &datastore.Value_EntityValue{ 222 | EntityValue: entity, 223 | } 224 | case reflect.Ptr: 225 | if fValue.IsNil() || !fValue.IsValid() { 226 | // don't return an error because we still want to retain the proto3 behaviour of having default values 227 | return nil, nil 228 | } 229 | iv := fValue.Interface() 230 | switch v := iv.(type) { 231 | case *structpb.Struct: 232 | properties := make(map[string]*datastore.Value) 233 | for key, value := range v.Fields { 234 | properties[key] = fromStructValueToDatastoreValue(value) 235 | } 236 | value.ValueType = &datastore.Value_EntityValue{ 237 | EntityValue: &datastore.Entity{ 238 | Properties: properties, 239 | }, 240 | } 241 | case *timestamp.Timestamp: 242 | ts := fValue.Interface().(*timestamp.Timestamp) 243 | value.ValueType = &datastore.Value_TimestampValue{ 244 | TimestampValue: ts, 245 | } 246 | case *structpb.Value: 247 | value = fromStructValueToDatastoreValue(v) 248 | default: 249 | // translate any imported protobuf's that we defined ourself 250 | if !fValue.IsNil() && fValue.IsValid() { 251 | if importedProto, ok := reflect.ValueOf(fValue.Interface()).Interface().(proto.Message); ok { 252 | entityOfImportedProto, err := ProtoMessageToDatastoreEntity(importedProto, snakeCase, excludeFromIndexName) 253 | if err != nil { 254 | return nil, err 255 | } 256 | value.ValueType = &datastore.Value_EntityValue{ 257 | EntityValue: &datastore.Entity{ 258 | Properties: entityOfImportedProto.Properties, 259 | }, 260 | } 261 | } 262 | } 263 | } 264 | default: 265 | errString := fmt.Sprintf("[toDatastoreValue]: datatype[%s] not supported", fValue.Type().String()) 266 | log.Println(errString) 267 | err = errors.New(errString) 268 | } 269 | 270 | return value, err 271 | } 272 | 273 | func fromStructValueToDatastoreValue(v *structpb.Value) *datastore.Value { 274 | pbValue := &datastore.Value{} 275 | switch v.GetKind().(type) { 276 | case *structpb.Value_StringValue: 277 | pbValue.ValueType = &datastore.Value_StringValue{ 278 | StringValue: v.GetStringValue(), 279 | } 280 | case *structpb.Value_BoolValue: 281 | pbValue.ValueType = &datastore.Value_BooleanValue{ 282 | BooleanValue: v.GetBoolValue(), 283 | } 284 | case *structpb.Value_NumberValue: 285 | pbValue.ValueType = &datastore.Value_DoubleValue{ 286 | DoubleValue: v.GetNumberValue(), 287 | } 288 | case *structpb.Value_NullValue: 289 | pbValue.ValueType = &datastore.Value_NullValue{ 290 | NullValue: v.GetNullValue(), 291 | } 292 | case *structpb.Value_ListValue: 293 | values := make([]*datastore.Value, 0) 294 | for _, val := range v.GetListValue().Values { 295 | values = append(values, fromStructValueToDatastoreValue(val)) 296 | } 297 | pbValue.ValueType = &datastore.Value_ArrayValue{ 298 | ArrayValue: &datastore.ArrayValue{ 299 | Values: values, 300 | }, 301 | } 302 | case *structpb.Value_StructValue: 303 | structValue := v.GetStructValue() 304 | properties := make(map[string]*datastore.Value, 0) 305 | for key, value := range structValue.GetFields() { 306 | properties[key] = fromStructValueToDatastoreValue(value) 307 | } 308 | pbValue.ValueType = &datastore.Value_EntityValue{ 309 | EntityValue: &datastore.Entity{ 310 | Properties: properties, 311 | }, 312 | } 313 | } 314 | return pbValue 315 | } 316 | 317 | func fromDatastoreValueToStructValue(v *datastore.Value) *structpb.Value { 318 | pbValue := &structpb.Value{} 319 | iv := reflect.ValueOf(v.ValueType).Interface() 320 | switch v := iv.(type) { 321 | case *datastore.Value_BooleanValue: 322 | pbValue.Kind = &structpb.Value_BoolValue{BoolValue: v.BooleanValue} 323 | case *datastore.Value_StringValue: 324 | pbValue.Kind = &structpb.Value_StringValue{StringValue: v.StringValue} 325 | case *datastore.Value_DoubleValue: 326 | pbValue.Kind = &structpb.Value_NumberValue{NumberValue: v.DoubleValue} 327 | case *datastore.Value_NullValue: 328 | pbValue.Kind = &structpb.Value_NullValue{} 329 | case *datastore.Value_EntityValue: 330 | entityValue := v.EntityValue 331 | fields := make(map[string]*structpb.Value) 332 | for key, value := range entityValue.GetProperties() { 333 | fields[key] = fromDatastoreValueToStructValue(value) 334 | } 335 | pbValue.Kind = &structpb.Value_StructValue{ 336 | StructValue: &structpb.Struct{ 337 | Fields: fields, 338 | }, 339 | } 340 | case *datastore.Value_ArrayValue: 341 | values := make([]*structpb.Value, 0) 342 | for _, val := range v.ArrayValue.Values { 343 | values = append(values, fromDatastoreValueToStructValue(val)) 344 | } 345 | pbValue.Kind = &structpb.Value_ListValue{ 346 | ListValue: &structpb.ListValue{ 347 | Values: values, 348 | }, 349 | } 350 | } 351 | return pbValue 352 | } 353 | 354 | func toSnakeCase(name string) string { 355 | var matchFirstCap = regexp.MustCompile("(.)([A-Z][a-z]+)") 356 | var matchAllCap = regexp.MustCompile("([a-z0-9])([A-Z])") 357 | snake := matchFirstCap.ReplaceAllString(name, "${1}_${2}") 358 | snake = matchAllCap.ReplaceAllString(snake, "${1}_${2}") 359 | return strings.ToLower(snake) 360 | } 361 | -------------------------------------------------------------------------------- /datastore-translator/translator_integration_test.go: -------------------------------------------------------------------------------- 1 | // +build integration 2 | 3 | package datastore_translator 4 | 5 | import ( 6 | "context" 7 | "log" 8 | "testing" 9 | "time" 10 | 11 | "cloud.google.com/go/datastore" 12 | "github.com/Sheshagiri/go-protobuf-cloud-datastore-entity-translator/models/example" 13 | "github.com/golang/protobuf/ptypes" 14 | structpb "github.com/golang/protobuf/ptypes/struct" 15 | "gotest.tools/assert" 16 | ) 17 | 18 | const DatastoreConnectTimeout = 5 * time.Second 19 | 20 | func TestIntegration(t *testing.T) { 21 | ctx := context.Background() 22 | 23 | // 1. create a new datastore client 24 | client, err := datastore.NewClient(ctx, "translator-tests") 25 | assert.NilError(t, err) 26 | 27 | ctx, cancel := context.WithTimeout(ctx, DatastoreConnectTimeout) 28 | defer cancel() 29 | 30 | // 2. create a key that we plan to save into 31 | key := datastore.NameKey("Example_DB_Model", "complex_proto_2", nil) 32 | 33 | // 3. create protobuf 34 | srcProto := &example.ExampleDBModel{ 35 | StringKey: "some random string key for testing", 36 | BoolKey: true, 37 | Int32Key: int32(32), 38 | Int64Key: 64, 39 | FloatKey: float32(10.14), 40 | DoubleKey: float64(10.2121), 41 | BytesKey: []byte("this is a byte array"), 42 | StringArrayKey: []string{ 43 | "element-1", 44 | "element-2", 45 | }, 46 | Int32ArrayKey: []int32{ 47 | 1, 2, 3, 4, 5, 6, 48 | }, 49 | EnumKey: example.ExampleEnumModel_ENUM1, 50 | MapStringString: map[string]string{ 51 | "string-key-1": "k1", 52 | "string-key-2": "k2", 53 | }, 54 | MapStringInt32: map[string]int32{ 55 | "int-key-1": 1, 56 | "int-key-2": 2, 57 | }, 58 | StructKey: &structpb.Struct{ 59 | Fields: map[string]*structpb.Value{ 60 | "struct-key-string": {Kind: &structpb.Value_StringValue{StringValue: "some random string in proto.Struct"}}, 61 | "struct-key-bool": {Kind: &structpb.Value_BoolValue{BoolValue: true}}, 62 | "struct-key-number": {Kind: &structpb.Value_NumberValue{NumberValue: 123456.12}}, 63 | "struct-key-null": {Kind: &structpb.Value_NullValue{}}, 64 | }, 65 | }, 66 | TimestampKey: ptypes.TimestampNow(), 67 | } 68 | 69 | log.Printf("original proto: %v", srcProto) 70 | // 4. translate the source protobuf to datastore.Entity 71 | translatedSrcProto, err := ProtoMessageToDatastoreEntity(srcProto, true) 72 | assert.NilError(t, err) 73 | 74 | // 5. save the translated protobuf to datastore 75 | _, err = client.PutEntity(ctx, key, &translatedSrcProto) 76 | assert.NilError(t, err) 77 | 78 | // 6. get the saved protobuf from cloud datastore 79 | datastoreEntity, err := client.GetEntity(ctx, key) 80 | assert.NilError(t, err) 81 | log.Printf("entity from cloud datastore: %v", datastoreEntity) 82 | 83 | // 7. create a protobuf that we plan to decode into 84 | dstProto := &example.ExampleDBModel{} 85 | 86 | // 8. translate the protobuf from datastore.Entity{} to our own protobuf 87 | err = DatastoreEntityToProtoMessage(datastoreEntity, dstProto, true) 88 | assert.NilError(t, err) 89 | 90 | log.Printf("original proto : %v", srcProto) 91 | log.Printf("datastore entity to proto message: %v", dstProto) 92 | 93 | // 9. start validating srcProto and dstProto should be equal 94 | assert.Equal(t, srcProto.GetStringKey(), dstProto.GetStringKey()) 95 | assert.Equal(t, srcProto.GetBoolKey(), dstProto.GetBoolKey()) 96 | assert.Equal(t, srcProto.GetInt32Key(), dstProto.GetInt32Key()) 97 | assert.Equal(t, srcProto.GetInt64Key(), dstProto.GetInt64Key()) 98 | assert.Equal(t, srcProto.GetFloatKey(), dstProto.GetFloatKey()) 99 | assert.Equal(t, srcProto.GetDoubleKey(), dstProto.GetDoubleKey()) 100 | 101 | // assert string array 102 | assert.DeepEqual(t, srcProto.GetStringArrayKey(), dstProto.GetStringArrayKey()) 103 | // assert int32 array 104 | assert.DeepEqual(t, srcProto.Int32ArrayKey, dstProto.Int32ArrayKey) 105 | // enums are converted to int's in datastore 106 | assert.Equal(t, srcProto.GetEnumKey(), dstProto.GetEnumKey()) 107 | // assert map[string]string 108 | assert.Equal(t, srcProto.GetMapStringString()["string-key-1"], dstProto.GetMapStringString()["string-key-1"]) 109 | assert.Equal(t, srcProto.GetMapStringInt32()["int-key-2"], dstProto.GetMapStringInt32()["int-key-2"]) 110 | 111 | // TODO BlobValue returns a string 112 | assert.DeepEqual(t, srcProto.GetBytesKey(), dstProto.GetBytesKey()) 113 | 114 | // extra check to see if they are really equal 115 | assert.Equal(t, srcProto.GetStructKey().Fields["struct-key-string"].GetStringValue(), dstProto.GetStructKey().Fields["struct-key-string"].GetStringValue()) 116 | 117 | // assert google.protobuf.Struct 118 | assert.DeepEqual(t, srcProto.GetStructKey().Fields, dstProto.GetStructKey().Fields) 119 | 120 | // assert google.protobuf.timestamp 121 | assert.DeepEqual(t, srcProto.GetTimestampKey().Seconds, dstProto.GetTimestampKey().Seconds) 122 | 123 | } 124 | 125 | func TestEmptyProtoMessage(t *testing.T) { 126 | ctx := context.Background() 127 | // 1. create a new datastore client 128 | client, err := datastore.NewClient(ctx, "st2-saas-prototype-dev") 129 | assert.NilError(t, err) 130 | 131 | ctx, cancel := context.WithTimeout(ctx, DatastoreConnectTimeout) 132 | defer cancel() 133 | 134 | // 2. create a key that we plan to save into 135 | key := datastore.NameKey("Example_DB_Model", "complex_proto_empty", nil) 136 | 137 | srcProto := &example.ExampleDBModel{} 138 | translatedProto, err := ProtoMessageToDatastoreEntity(srcProto, false) 139 | assert.NilError(t, err) 140 | 141 | _, err = client.PutEntity(ctx, key, &translatedProto) 142 | // e expect an error when the whole proto is empty 143 | assert.NilError(t, err) 144 | 145 | // 6. get the saved protobuf from cloud datastore 146 | datastoreEntity, err := client.GetEntity(ctx, key) 147 | assert.NilError(t, err) 148 | 149 | // 7. create a protobuf that we plan to decode into 150 | dstProto := &example.ExampleDBModel{} 151 | 152 | // 8. translate the protobuf from datastore.Entity{} to our own protobuf 153 | err = DatastoreEntityToProtoMessage(datastoreEntity, dstProto, true) 154 | assert.NilError(t, err) 155 | } 156 | 157 | func TestProtoWithNilPointer(t *testing.T) { 158 | ctx := context.Background() 159 | // 1. create a new datastore client 160 | client, err := datastore.NewClient(ctx, "st2-saas-prototype-dev") 161 | assert.NilError(t, err) 162 | 163 | ctx, cancel := context.WithTimeout(ctx, DatastoreConnectTimeout) 164 | defer cancel() 165 | 166 | // 2. create a key that we plan to save into 167 | key := datastore.NameKey("Example_DB_Model", "complex_proto_empty", nil) 168 | 169 | srcProto := &example.ExampleDBModel{ 170 | TimestampKey: ptypes.TimestampNow(), 171 | } 172 | translatedProto, err := ProtoMessageToDatastoreEntity(srcProto, false) 173 | assert.NilError(t, err) 174 | 175 | _, err = client.PutEntity(ctx, key, &translatedProto) 176 | } 177 | -------------------------------------------------------------------------------- /datastore-translator/translator_test.go: -------------------------------------------------------------------------------- 1 | package datastore_translator 2 | 3 | import ( 4 | "log" 5 | "testing" 6 | 7 | "github.com/Sheshagiri/go-protobuf-cloud-datastore-entity-translator/models/example" 8 | "github.com/Sheshagiri/go-protobuf-cloud-datastore-entity-translator/models/execution" 9 | "github.com/Sheshagiri/go-protobuf-cloud-datastore-entity-translator/models/unsupported" 10 | "github.com/golang/protobuf/proto" 11 | "github.com/golang/protobuf/ptypes" 12 | structpb "github.com/golang/protobuf/ptypes/struct" 13 | "github.com/stretchr/testify/require" 14 | "google.golang.org/genproto/googleapis/datastore/v1" 15 | "gotest.tools/assert" 16 | ) 17 | 18 | func TestNestedModel(t *testing.T) { 19 | srcProto := &example.ExampleNestedModel{ 20 | StringKey: "some random string", 21 | Int32Key: 22, 22 | } 23 | entity, err := ProtoMessageToDatastoreEntity(srcProto, true) 24 | // make sure there is no error 25 | assert.NilError(t, err) 26 | dstProto := &example.ExampleNestedModel{} 27 | err = DatastoreEntityToProtoMessage(&entity, dstProto, true) 28 | // make sure there is no error 29 | assert.NilError(t, err) 30 | 31 | assert.Equal(t, true, proto.Equal(srcProto, dstProto), "before and after translation proto messages should be equal") 32 | } 33 | 34 | func TestProtoMessageToDatastoreEntityWithExcludeFieldsFromIndex(t *testing.T) { 35 | srcProto := &example.ExampleDBModel{ 36 | StringKey: "some random string key for testing", 37 | BoolKey: true, 38 | Int32Key: int32(32), 39 | Int64Key: 64, 40 | FloatKey: float32(10.14), 41 | DoubleKey: 10.2121, 42 | BytesKey: []byte("this is a byte array"), 43 | } 44 | 45 | // No exclude from index fields specified 46 | entity, err := ProtoMessageToDatastoreEntity(srcProto, true) 47 | assert.NilError(t, err) 48 | assert.Equal(t, entity.Properties["string_key"].ExcludeFromIndexes, false) 49 | assert.Equal(t, entity.Properties["bytes_key"].ExcludeFromIndexes, false) 50 | assert.Equal(t, entity.Properties["float_key"].ExcludeFromIndexes, false) 51 | 52 | assert.Equal(t, entity.Properties["bool_key"].ExcludeFromIndexes, false) 53 | assert.Equal(t, entity.Properties["int32_key"].ExcludeFromIndexes, false) 54 | assert.Equal(t, entity.Properties["double_key"].ExcludeFromIndexes, false) 55 | } 56 | 57 | func TestFullyPopulatedModel(t *testing.T) { 58 | srcProto := &example.ExampleDBModel{ 59 | StringKey: "some random string key for testing", 60 | BoolKey: true, 61 | Int32Key: int32(32), 62 | Int64Key: 64, 63 | FloatKey: float32(10.14), 64 | DoubleKey: 10.2121, 65 | BytesKey: []byte("this is a byte array"), 66 | StringArrayKey: []string{ 67 | "element-1", 68 | "element-2", 69 | }, 70 | Int32ArrayKey: []int32{ 71 | 1, 2, 3, 4, 5, 6, 72 | }, 73 | EnumKey: example.ExampleEnumModel_ENUM1, 74 | MapStringString: map[string]string{ 75 | "string-key-1": "k1", 76 | "string-key-2": "k2", 77 | }, 78 | MapStringInt32: map[string]int32{ 79 | "int-key-1": 1, 80 | "int-key-2": 2, 81 | }, 82 | StructKey: &structpb.Struct{ 83 | Fields: map[string]*structpb.Value{ 84 | "struct-key-string": {Kind: &structpb.Value_StringValue{StringValue: "some random string in proto.Struct"}}, 85 | "struct-key-bool": {Kind: &structpb.Value_BoolValue{BoolValue: true}}, 86 | "struct-key-number": {Kind: &structpb.Value_NumberValue{NumberValue: 123456.12}}, 87 | "struct-key-null": {Kind: &structpb.Value_NullValue{}}, 88 | "struct-key-list": {Kind: &structpb.Value_ListValue{ 89 | ListValue: &structpb.ListValue{ 90 | Values: []*structpb.Value{ 91 | {Kind: &structpb.Value_NumberValue{NumberValue: 10}}, 92 | {Kind: &structpb.Value_StringValue{StringValue: "hello, world"}}, 93 | {Kind: &structpb.Value_BoolValue{BoolValue: true}}, 94 | {Kind: &structpb.Value_NumberValue{NumberValue: 200}}, 95 | }, 96 | }, 97 | }, 98 | }, 99 | }, 100 | }, 101 | TimestampKey: ptypes.TimestampNow(), 102 | } 103 | entity, err := ProtoMessageToDatastoreEntity(srcProto, true) 104 | 105 | // make sure there is no error 106 | assert.NilError(t, err) 107 | log.Println(entity) 108 | dstProto := &example.ExampleDBModel{} 109 | 110 | err = DatastoreEntityToProtoMessage(&entity, dstProto, true) 111 | // make sure there is no error 112 | require.NoError(t, err) 113 | 114 | assert.Equal(t, true, proto.Equal(srcProto, dstProto), "proto messages should be equal") 115 | } 116 | 117 | func TestPartialModel(t *testing.T) { 118 | partialProto := &structpb.Struct{ 119 | Fields: map[string]*structpb.Value{ 120 | "struct-key-string": {Kind: &structpb.Value_StringValue{StringValue: "some random string in proto.Struct"}}, 121 | // not ready for this yet 122 | // "struct-key-list": {Kind: &structpb.Value_ListValue{}}, 123 | "struct-key-bool": {Kind: &structpb.Value_BoolValue{BoolValue: true}}, 124 | "struct-key-number": {Kind: &structpb.Value_NumberValue{NumberValue: 123456.12}}, 125 | "struct-key-null": {Kind: &structpb.Value_NullValue{}}, 126 | }, 127 | } 128 | entity, err := ProtoMessageToDatastoreEntity(partialProto, true) 129 | assert.NilError(t, err, err) 130 | log.Println(entity) 131 | dstProto := &structpb.Struct{} 132 | err = DatastoreEntityToProtoMessage(&entity, dstProto, true) 133 | assert.NilError(t, err) 134 | // assert google.protobuf.Struct 135 | assert.DeepEqual(t, partialProto.Fields["struct-key-string"], dstProto.Fields["struct-key-string"]) 136 | } 137 | 138 | func TestUnSupportedTypes(t *testing.T) { 139 | srcProto := &unsupported.Model{ 140 | Uint32Key: uint32(10), 141 | } 142 | _, err := ProtoMessageToDatastoreEntity(srcProto, false) 143 | assert.Error(t, err, "[toDatastoreValue]: datatype[uint32] not supported") 144 | } 145 | 146 | func TestPMtoDE(t *testing.T) { 147 | srcProto := &example.ExampleNestedModel{ 148 | StringKey: "some random string", 149 | Int32Key: 22, 150 | } 151 | entity, err := ProtoMessageToDatastoreEntity(srcProto, true) 152 | assert.NilError(t, err) 153 | log.Println(entity) 154 | } 155 | 156 | func TestStructValueDatastoreValue(t *testing.T) { 157 | tests := []struct { 158 | structValue *structpb.Value 159 | datastoreValue *datastore.Value 160 | }{ 161 | { 162 | structValue: &structpb.Value{ 163 | Kind: &structpb.Value_StringValue{ 164 | StringValue: "some random string key for testing.", 165 | }, 166 | }, 167 | datastoreValue: &datastore.Value{ 168 | ValueType: &datastore.Value_StringValue{ 169 | StringValue: "some random string key for testing.", 170 | }, 171 | }, 172 | }, 173 | { 174 | structValue: &structpb.Value{ 175 | Kind: &structpb.Value_BoolValue{ 176 | BoolValue: true, 177 | }, 178 | }, 179 | datastoreValue: &datastore.Value{ 180 | ValueType: &datastore.Value_BooleanValue{ 181 | BooleanValue: true, 182 | }, 183 | }, 184 | }, 185 | { 186 | structValue: &structpb.Value{ 187 | Kind: &structpb.Value_NumberValue{ 188 | NumberValue: 15, 189 | }, 190 | }, 191 | datastoreValue: &datastore.Value{ 192 | ValueType: &datastore.Value_DoubleValue{ 193 | DoubleValue: float64(15), 194 | }, 195 | }, 196 | }, 197 | { 198 | structValue: &structpb.Value{ 199 | Kind: &structpb.Value_NullValue{}, 200 | }, 201 | datastoreValue: &datastore.Value{ 202 | ValueType: &datastore.Value_NullValue{}, 203 | }, 204 | }, 205 | { 206 | structValue: &structpb.Value{ 207 | Kind: &structpb.Value_ListValue{ 208 | ListValue: &structpb.ListValue{ 209 | Values: []*structpb.Value{ 210 | {Kind: &structpb.Value_NumberValue{NumberValue: 10}}, 211 | {Kind: &structpb.Value_StringValue{StringValue: "hello, world"}}, 212 | {Kind: &structpb.Value_BoolValue{BoolValue: true}}, 213 | {Kind: &structpb.Value_NumberValue{NumberValue: 200}}, 214 | }, 215 | }, 216 | }, 217 | }, 218 | datastoreValue: &datastore.Value{ 219 | ValueType: &datastore.Value_ArrayValue{ 220 | ArrayValue: &datastore.ArrayValue{ 221 | Values: []*datastore.Value{ 222 | {ValueType: &datastore.Value_DoubleValue{DoubleValue: 10}}, 223 | {ValueType: &datastore.Value_StringValue{StringValue: "hello, world"}}, 224 | {ValueType: &datastore.Value_BooleanValue{BooleanValue: true}}, 225 | {ValueType: &datastore.Value_DoubleValue{DoubleValue: 200}}, 226 | }, 227 | }, 228 | }, 229 | }, 230 | }, 231 | { 232 | structValue: &structpb.Value{ 233 | Kind: &structpb.Value_StructValue{ 234 | StructValue: &structpb.Struct{ 235 | Fields: map[string]*structpb.Value{ 236 | "struct-key-string": {Kind: &structpb.Value_StringValue{StringValue: "some random string in proto.Struct"}}, 237 | // not ready for this yet 238 | // "struct-key-list": {Kind: &structpb.Value_ListValue{}}, 239 | "struct-key-bool": {Kind: &structpb.Value_BoolValue{BoolValue: true}}, 240 | "struct-key-number": {Kind: &structpb.Value_NumberValue{NumberValue: 123456.12}}, 241 | "struct-key-null": {Kind: &structpb.Value_NullValue{}}, 242 | }, 243 | }, 244 | }, 245 | }, 246 | datastoreValue: &datastore.Value{ 247 | ValueType: &datastore.Value_EntityValue{ 248 | EntityValue: &datastore.Entity{ 249 | Properties: map[string]*datastore.Value{ 250 | "struct-key-string": {ValueType: &datastore.Value_StringValue{StringValue: "some random string in proto.Struct"}}, 251 | // not ready for this yet 252 | // "struct-key-list": {ValueType: &datastore.Value_ArrayValue{}}, 253 | "struct-key-bool": {ValueType: &datastore.Value_BooleanValue{BooleanValue: true}}, 254 | "struct-key-number": {ValueType: &datastore.Value_DoubleValue{DoubleValue: 123456.12}}, 255 | "struct-key-null": {ValueType: &datastore.Value_NullValue{}}, 256 | }, 257 | }, 258 | }, 259 | }, 260 | }, 261 | } 262 | for _, test := range tests { 263 | actualDatastoreValue := fromStructValueToDatastoreValue(test.structValue) 264 | assert.DeepEqual(t, test.datastoreValue, actualDatastoreValue) 265 | // test the other way around now 266 | 267 | actualStructValue := fromDatastoreValueToStructValue(test.datastoreValue) 268 | assert.DeepEqual(t, test.structValue, actualStructValue) 269 | } 270 | } 271 | 272 | func TestProtoWithCustomImport(t *testing.T) { 273 | srcProto := &example.ExampleDBModel{ 274 | ComplexArrayKey: []*example.ExampleNestedModel{ 275 | { 276 | Int32Key: 0, 277 | StringKey: "string in first element", 278 | }, 279 | { 280 | Int32Key: 1, 281 | StringKey: "string in second element", 282 | }, 283 | }, 284 | } 285 | 286 | srcEntity := &datastore.Entity{ 287 | Properties: map[string]*datastore.Value{ 288 | "ComplexArrayKey": { 289 | ValueType: &datastore.Value_ArrayValue{ 290 | ArrayValue: &datastore.ArrayValue{ 291 | Values: []*datastore.Value{ 292 | { 293 | ValueType: &datastore.Value_EntityValue{ 294 | EntityValue: &datastore.Entity{ 295 | Properties: map[string]*datastore.Value{ 296 | "Int32Key": {ValueType: &datastore.Value_IntegerValue{IntegerValue: 0}}, 297 | "StringKey": {ValueType: &datastore.Value_StringValue{StringValue: "string in first element"}}, 298 | }, 299 | }, 300 | }, 301 | }, 302 | { 303 | ValueType: &datastore.Value_EntityValue{ 304 | EntityValue: &datastore.Entity{ 305 | Properties: map[string]*datastore.Value{ 306 | "Int32Key": {ValueType: &datastore.Value_IntegerValue{IntegerValue: 1}}, 307 | "StringKey": {ValueType: &datastore.Value_StringValue{StringValue: "string in second element"}}, 308 | }, 309 | }, 310 | }, 311 | }, 312 | }, 313 | }, 314 | }, 315 | }, 316 | }, 317 | } 318 | 319 | dstEntity, err := ProtoMessageToDatastoreEntity(srcProto, false) 320 | assert.NilError(t, err) 321 | // our interest here only to compare the ComplexArrayKey 322 | assert.DeepEqual(t, srcEntity.GetProperties()["ComplexArrayKey"], dstEntity.GetProperties()["ComplexArrayKey"]) 323 | } 324 | 325 | func TestSlicedMessages(t *testing.T) { 326 | tests := []proto.Message{ 327 | &execution.Execution{ 328 | Name: "a", 329 | }, 330 | &execution.Execution{ 331 | Name: "b", 332 | }, 333 | } 334 | want := make([]proto.Message, 0) 335 | model := &execution.Execution{} 336 | for _, test := range tests { 337 | dsEntity, err := ProtoMessageToDatastoreEntity(test, true) 338 | require.NoError(t, err) 339 | m := proto.Clone(model) 340 | err = DatastoreEntityToProtoMessage(&dsEntity, m, true) 341 | require.NoError(t, err) 342 | want = append(want, m) 343 | } 344 | assert.DeepEqual(t, tests, want) 345 | } 346 | -------------------------------------------------------------------------------- /datastore-translator/ts_struct_test.go: -------------------------------------------------------------------------------- 1 | package datastore_translator 2 | 3 | import ( 4 | "log" 5 | "testing" 6 | 7 | "github.com/Sheshagiri/go-protobuf-cloud-datastore-entity-translator/models/example" 8 | "github.com/Sheshagiri/go-protobuf-cloud-datastore-entity-translator/models/execution" 9 | "github.com/Sheshagiri/go-protobuf-cloud-datastore-entity-translator/models/unsupported" 10 | "github.com/golang/protobuf/proto" 11 | "github.com/golang/protobuf/ptypes" 12 | structpb "github.com/golang/protobuf/ptypes/struct" 13 | "gotest.tools/assert" 14 | ) 15 | 16 | func TestAddTSSupport(t *testing.T) { 17 | src := &unsupported.TS{ 18 | StartedOn: ptypes.TimestampNow(), 19 | } 20 | log.Println("Source: ", src) 21 | srcEntity, err := ProtoMessageToDatastoreEntity(src, false) 22 | 23 | assert.NilError(t, err) 24 | log.Println("Source Datastore Entity: ", srcEntity) 25 | 26 | dst := &unsupported.TS{} 27 | 28 | err = DatastoreEntityToProtoMessage(&srcEntity, dst, false) 29 | assert.NilError(t, err) 30 | assert.DeepEqual(t, src, dst) 31 | } 32 | 33 | func TestAddStructSupport(t *testing.T) { 34 | src := &unsupported.StructMessage{ 35 | StructKey: &structpb.Struct{ 36 | Fields: map[string]*structpb.Value{ 37 | "struct-key-string": {Kind: &structpb.Value_StringValue{StringValue: "some random string in proto.Struct"}}, 38 | "struct-key-bool": {Kind: &structpb.Value_BoolValue{BoolValue: true}}, 39 | "struct-key-number": {Kind: &structpb.Value_NumberValue{NumberValue: 123456.12}}, 40 | "struct-key-null": {Kind: &structpb.Value_NullValue{}}, 41 | "struct-key-list": {Kind: &structpb.Value_ListValue{ 42 | ListValue: &structpb.ListValue{ 43 | Values: []*structpb.Value{ 44 | {Kind: &structpb.Value_NumberValue{NumberValue: 10}}, 45 | {Kind: &structpb.Value_StringValue{StringValue: "hello, world"}}, 46 | {Kind: &structpb.Value_BoolValue{BoolValue: true}}, 47 | {Kind: &structpb.Value_NumberValue{NumberValue: 200}}, 48 | }, 49 | }, 50 | }, 51 | }, 52 | }, 53 | }, 54 | } 55 | log.Println("Source: ", src) 56 | srcEntity, err := ProtoMessageToDatastoreEntity(src, false) 57 | 58 | assert.NilError(t, err) 59 | log.Println("Source Datastore Entity: ", srcEntity) 60 | 61 | dst := &unsupported.StructMessage{} 62 | 63 | err = DatastoreEntityToProtoMessage(&srcEntity, dst, false) 64 | assert.NilError(t, err) 65 | log.Println("", dst) 66 | assert.DeepEqual(t, src, dst) 67 | } 68 | 69 | func TestSliceofNestedMessages(t *testing.T) { 70 | src := &example.ExampleDBModel{ 71 | ComplexArrayKey: []*example.ExampleNestedModel{ 72 | { 73 | StringKey: "string-1", 74 | }, 75 | { 76 | StringKey: "string-2", 77 | }, 78 | }, 79 | } 80 | log.Println("Source: ", src) 81 | srcEntity, err := ProtoMessageToDatastoreEntity(src, false) 82 | assert.NilError(t, err) 83 | 84 | log.Println("Source Datastore Entity: ", srcEntity) 85 | 86 | dst := &example.ExampleDBModel{} 87 | 88 | err = DatastoreEntityToProtoMessage(&srcEntity, dst, false) 89 | assert.NilError(t, err) 90 | log.Println("Destination: ", dst) 91 | assert.DeepEqual(t, src.GetComplexArrayKey(), dst.GetComplexArrayKey()) 92 | 93 | } 94 | 95 | func TestNestedMessages(t *testing.T) { 96 | src := &unsupported.Child{ 97 | Name: "Alex-II", 98 | Parent: &unsupported.Parent{ 99 | Name: "Alex-I", 100 | }, 101 | } 102 | log.Println("Source: ", src) 103 | srcEntity, err := ProtoMessageToDatastoreEntity(src, false) 104 | assert.NilError(t, err) 105 | 106 | log.Println("Source Datastore Entity: ", srcEntity) 107 | 108 | dst := &unsupported.Child{} 109 | 110 | err = DatastoreEntityToProtoMessage(&srcEntity, dst, false) 111 | assert.NilError(t, err) 112 | log.Println("Destination: ", dst) 113 | assert.DeepEqual(t, src, dst) 114 | } 115 | 116 | func TestStructInReferencedMessage(t *testing.T) { 117 | src := &execution.Execution{ 118 | Name: "login", 119 | Action: &execution.Action{ 120 | Name: "ssh", 121 | Parameters: &structpb.Struct{ 122 | Fields: map[string]*structpb.Value{ 123 | "host": {Kind: &structpb.Value_StringValue{StringValue: "10.10.10.10"}}, 124 | "port": {Kind: &structpb.Value_NumberValue{NumberValue: 123456.12}}, 125 | }, 126 | }, 127 | }, 128 | } 129 | log.Println("Source: ", src) 130 | srcEntity, err := ProtoMessageToDatastoreEntity(src, false) 131 | assert.NilError(t, err) 132 | log.Println("Source Datastore Entity: ", srcEntity) 133 | 134 | dst := &execution.Execution{} 135 | err = DatastoreEntityToProtoMessage(&srcEntity, dst, false) 136 | assert.NilError(t, err) 137 | log.Println("Destination: ", dst) 138 | assert.Equal(t, true, proto.Equal(src, dst)) 139 | } 140 | -------------------------------------------------------------------------------- /examples/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "cloud.google.com/go/datastore" 6 | "log" 7 | "github.com/Sheshagiri/go-protobuf-cloud-datastore-entity-translator/models/execution" 8 | "github.com/golang/protobuf/ptypes" 9 | "github.com/google/uuid" 10 | "github.com/golang/protobuf/ptypes/struct" 11 | translator "github.com/Sheshagiri/go-protobuf-cloud-datastore-entity-translator/datastore-translator" 12 | ) 13 | 14 | func main() { 15 | ctx := context.Background() 16 | 17 | // 1. create datastore client 18 | dsClient, err := datastore.NewClient(ctx,"st2-saas-prototype-dev") 19 | if err != nil { 20 | log.Fatalf("unable to connect to datastore, error: %v", err) 21 | } 22 | 23 | // 2. create a protobuf message 24 | execReq := &execution.ExecutionRequest{ 25 | StartedOn:ptypes.TimestampNow(), 26 | Uuid:uuid.New().String(), 27 | Action:"create_vm", 28 | Parameters: &structpb.Struct{ 29 | Fields: map[string]*structpb.Value{ 30 | "vm-name": {Kind: &structpb.Value_StringValue{StringValue:"sheshagiri-vm-1"}}, 31 | "allow-root-login": {Kind: &structpb.Value_BoolValue{BoolValue:true}}, 32 | "network-interfaces": {Kind: &structpb.Value_NumberValue{NumberValue:2}}, 33 | }, 34 | }, 35 | } 36 | 37 | // 3. translate the protobuf message to the format that datastore understands 38 | entity, err := translator.ProtoMessageToDatastoreEntity(execReq, true) 39 | if err != nil { 40 | log.Fatalf("unable to translate execution request to datastore format, error: %v", err) 41 | } 42 | 43 | // 4. create a key where we would like to store the message, think of this as a primary key 44 | parentKey := datastore.NameKey("ExecutionRequest",execReq.GetAction(), nil) 45 | childKey := datastore.NameKey(execReq.GetAction(),execReq.GetUuid(), parentKey) 46 | 47 | // 5. save it to datastore against the key 48 | _, err = dsClient.PutEntity(ctx, childKey, &entity) 49 | if err != nil { 50 | log.Fatalf("unable to translate execution request to datastore format, error: %v", err) 51 | } 52 | log.Printf("key %v is saved to datastore",childKey) 53 | 54 | // 6. Try to retrieve the key 55 | dsEntity, err := dsClient.GetEntity(ctx, childKey) 56 | if err != nil { 57 | log.Fatalf("unable to get %v from datastore", childKey) 58 | } 59 | 60 | // 7. create an empty protobuf 61 | dsExecReq := &execution.ExecutionRequest{} 62 | 63 | // 8. convert the value fetched from datastore to protobuf 64 | err = translator.DatastoreEntityToProtoMessage(dsEntity,dsExecReq, true) 65 | if err != nil { 66 | log.Fatalf("error while converting to proto message, %v", err) 67 | } 68 | 69 | // 9. simply log it :) 70 | log.Println(dsExecReq) 71 | } 72 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/Sheshagiri/go-protobuf-cloud-datastore-entity-translator 2 | 3 | go 1.12 4 | 5 | require ( 6 | cloud.google.com/go v0.38.0 7 | github.com/golang/protobuf v1.3.2 8 | github.com/google/uuid v1.1.1 9 | github.com/stretchr/testify v1.4.0 10 | google.golang.org/genproto v0.0.0-20190708153700-3bdd9d9f5532 11 | gotest.tools v0.0.0-20181223230014-1083505acf35 12 | ) 13 | 14 | replace cloud.google.com/go => github.com/Sheshagiri/google-cloud-go v0.41.1-0.20190711043959-301311007500 15 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 2 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 3 | github.com/Sheshagiri/google-cloud-go v0.41.1-0.20190711043959-301311007500 h1:FMI6ZR35r/e+e//fObXm9MTdu6mx7cTH567sjm9WymQ= 4 | github.com/Sheshagiri/google-cloud-go v0.41.1-0.20190711043959-301311007500/go.mod h1:05T3xsDVUIfRZP+EM2ftPky59P2i67FhEj6hjkpO5GE= 5 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 6 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 7 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 8 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= 9 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 10 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 11 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 12 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 13 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 14 | github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= 15 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 16 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 17 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 18 | github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= 19 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 20 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 21 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 22 | github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= 23 | github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 24 | github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= 25 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 26 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 27 | github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= 28 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 29 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 30 | github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= 31 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 32 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 33 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 34 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 35 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 36 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= 37 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 38 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 39 | go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4= 40 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 41 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 42 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 43 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 44 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 45 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 46 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 47 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 48 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 49 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 50 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 51 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 52 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 53 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 54 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 55 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 56 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 57 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 58 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 59 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 60 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= 61 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 62 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 63 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= 64 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 65 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 66 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 67 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 68 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 69 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 70 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 71 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 72 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 73 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 74 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 75 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 76 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 77 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/xC2Run6RzeW1SyHxpc= 78 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 79 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 80 | golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= 81 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 82 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 83 | golang.org/x/tools v0.0.0-20180810170437-e96c4e24768d/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 84 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 85 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 86 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 87 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 88 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 89 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 90 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 91 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 92 | golang.org/x/tools v0.0.0-20190624190245-7f2218787638/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 93 | google.golang.org/api v0.7.0 h1:9sdfJOzWlkqPltHAuzT2Cp+yrBeY1KRVYgms8soxMwM= 94 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 95 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 96 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 97 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 98 | google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= 99 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 100 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 101 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 102 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 103 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 104 | google.golang.org/genproto v0.0.0-20190701230453-710ae3a149df/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= 105 | google.golang.org/genproto v0.0.0-20190708153700-3bdd9d9f5532 h1:5pOB7se0B2+IssELuQUs6uoBgYJenkU2AQlvopc2sRw= 106 | google.golang.org/genproto v0.0.0-20190708153700-3bdd9d9f5532/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= 107 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 108 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 109 | google.golang.org/grpc v1.21.1 h1:j6XxA85m/6txkUCHvzlV5f+HBNl/1r5cZ2A/3IEFOO8= 110 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 111 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 112 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 113 | gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= 114 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 115 | gotest.tools v0.0.0-20181223230014-1083505acf35 h1:zpdCK+REwbk+rqjJmHhiCN6iBIigrZ39glqSF0P3KF0= 116 | gotest.tools v0.0.0-20181223230014-1083505acf35/go.mod h1:R//lfYlUuTOTfblYI3lGoAAAebUdzjvbmQsuB7Ykd90= 117 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 118 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 119 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 120 | -------------------------------------------------------------------------------- /models/example/example.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: example.proto 3 | 4 | package example 5 | 6 | import ( 7 | fmt "fmt" 8 | proto "github.com/golang/protobuf/proto" 9 | _struct "github.com/golang/protobuf/ptypes/struct" 10 | timestamp "github.com/golang/protobuf/ptypes/timestamp" 11 | math "math" 12 | ) 13 | 14 | // Reference imports to suppress errors if they are not otherwise used. 15 | var _ = proto.Marshal 16 | var _ = fmt.Errorf 17 | var _ = math.Inf 18 | 19 | // This is a compile-time assertion to ensure that this generated file 20 | // is compatible with the proto package it is being compiled against. 21 | // A compilation error at this line likely means your copy of the 22 | // proto package needs to be updated. 23 | const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package 24 | 25 | type ExampleEnumModel int32 26 | 27 | const ( 28 | ExampleEnumModel_ENUM0 ExampleEnumModel = 0 29 | ExampleEnumModel_ENUM1 ExampleEnumModel = 1 30 | ExampleEnumModel_ENUM2 ExampleEnumModel = 2 31 | ) 32 | 33 | var ExampleEnumModel_name = map[int32]string{ 34 | 0: "ENUM0", 35 | 1: "ENUM1", 36 | 2: "ENUM2", 37 | } 38 | 39 | var ExampleEnumModel_value = map[string]int32{ 40 | "ENUM0": 0, 41 | "ENUM1": 1, 42 | "ENUM2": 2, 43 | } 44 | 45 | func (x ExampleEnumModel) String() string { 46 | return proto.EnumName(ExampleEnumModel_name, int32(x)) 47 | } 48 | 49 | func (ExampleEnumModel) EnumDescriptor() ([]byte, []int) { 50 | return fileDescriptor_15a1dc8d40dadaa6, []int{0} 51 | } 52 | 53 | type ExampleNestedModel struct { 54 | StringKey string `protobuf:"bytes,1,opt,name=string_key,json=stringKey,proto3" json:"string_key,omitempty"` 55 | Int32Key int32 `protobuf:"varint,2,opt,name=int32_key,json=int32Key,proto3" json:"int32_key,omitempty"` 56 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 57 | XXX_unrecognized []byte `json:"-"` 58 | XXX_sizecache int32 `json:"-"` 59 | } 60 | 61 | func (m *ExampleNestedModel) Reset() { *m = ExampleNestedModel{} } 62 | func (m *ExampleNestedModel) String() string { return proto.CompactTextString(m) } 63 | func (*ExampleNestedModel) ProtoMessage() {} 64 | func (*ExampleNestedModel) Descriptor() ([]byte, []int) { 65 | return fileDescriptor_15a1dc8d40dadaa6, []int{0} 66 | } 67 | 68 | func (m *ExampleNestedModel) XXX_Unmarshal(b []byte) error { 69 | return xxx_messageInfo_ExampleNestedModel.Unmarshal(m, b) 70 | } 71 | func (m *ExampleNestedModel) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 72 | return xxx_messageInfo_ExampleNestedModel.Marshal(b, m, deterministic) 73 | } 74 | func (m *ExampleNestedModel) XXX_Merge(src proto.Message) { 75 | xxx_messageInfo_ExampleNestedModel.Merge(m, src) 76 | } 77 | func (m *ExampleNestedModel) XXX_Size() int { 78 | return xxx_messageInfo_ExampleNestedModel.Size(m) 79 | } 80 | func (m *ExampleNestedModel) XXX_DiscardUnknown() { 81 | xxx_messageInfo_ExampleNestedModel.DiscardUnknown(m) 82 | } 83 | 84 | var xxx_messageInfo_ExampleNestedModel proto.InternalMessageInfo 85 | 86 | func (m *ExampleNestedModel) GetStringKey() string { 87 | if m != nil { 88 | return m.StringKey 89 | } 90 | return "" 91 | } 92 | 93 | func (m *ExampleNestedModel) GetInt32Key() int32 { 94 | if m != nil { 95 | return m.Int32Key 96 | } 97 | return 0 98 | } 99 | 100 | type ExampleDBModelWithKey struct { 101 | // Special field which is used for constructing a primary key 102 | // 103 | // Actual key is composed of the following components: 104 | // 105 | // - namespace_id - this is inferred from the client object passed to the 106 | // "model_pb_with_key_to_entity_pb" function 107 | // - project_id - this is inferred from the client object passed to the 108 | // "model_pb_with_key_to_entity_pb" function 109 | // - key - string value which uniquely identifies this object. This value is specified by 110 | // setting the "key" string field on this object 111 | Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` 112 | StringKey string `protobuf:"bytes,2,opt,name=string_key,json=stringKey,proto3" json:"string_key,omitempty"` 113 | Int32Key int32 `protobuf:"varint,3,opt,name=int32_key,json=int32Key,proto3" json:"int32_key,omitempty"` 114 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 115 | XXX_unrecognized []byte `json:"-"` 116 | XXX_sizecache int32 `json:"-"` 117 | } 118 | 119 | func (m *ExampleDBModelWithKey) Reset() { *m = ExampleDBModelWithKey{} } 120 | func (m *ExampleDBModelWithKey) String() string { return proto.CompactTextString(m) } 121 | func (*ExampleDBModelWithKey) ProtoMessage() {} 122 | func (*ExampleDBModelWithKey) Descriptor() ([]byte, []int) { 123 | return fileDescriptor_15a1dc8d40dadaa6, []int{1} 124 | } 125 | 126 | func (m *ExampleDBModelWithKey) XXX_Unmarshal(b []byte) error { 127 | return xxx_messageInfo_ExampleDBModelWithKey.Unmarshal(m, b) 128 | } 129 | func (m *ExampleDBModelWithKey) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 130 | return xxx_messageInfo_ExampleDBModelWithKey.Marshal(b, m, deterministic) 131 | } 132 | func (m *ExampleDBModelWithKey) XXX_Merge(src proto.Message) { 133 | xxx_messageInfo_ExampleDBModelWithKey.Merge(m, src) 134 | } 135 | func (m *ExampleDBModelWithKey) XXX_Size() int { 136 | return xxx_messageInfo_ExampleDBModelWithKey.Size(m) 137 | } 138 | func (m *ExampleDBModelWithKey) XXX_DiscardUnknown() { 139 | xxx_messageInfo_ExampleDBModelWithKey.DiscardUnknown(m) 140 | } 141 | 142 | var xxx_messageInfo_ExampleDBModelWithKey proto.InternalMessageInfo 143 | 144 | func (m *ExampleDBModelWithKey) GetKey() string { 145 | if m != nil { 146 | return m.Key 147 | } 148 | return "" 149 | } 150 | 151 | func (m *ExampleDBModelWithKey) GetStringKey() string { 152 | if m != nil { 153 | return m.StringKey 154 | } 155 | return "" 156 | } 157 | 158 | func (m *ExampleDBModelWithKey) GetInt32Key() int32 { 159 | if m != nil { 160 | return m.Int32Key 161 | } 162 | return 0 163 | } 164 | 165 | type ExampleDBModel struct { 166 | // Simple type 167 | Int32Key int32 `protobuf:"varint,1,opt,name=int32_key,json=int32Key,proto3" json:"int32_key,omitempty"` 168 | StringKey string `protobuf:"bytes,2,opt,name=string_key,json=stringKey,proto3" json:"string_key,omitempty"` 169 | BoolKey bool `protobuf:"varint,3,opt,name=bool_key,json=boolKey,proto3" json:"bool_key,omitempty"` 170 | BytesKey []byte `protobuf:"bytes,4,opt,name=bytes_key,json=bytesKey,proto3" json:"bytes_key,omitempty"` 171 | DoubleKey float64 `protobuf:"fixed64,14,opt,name=double_key,json=doubleKey,proto3" json:"double_key,omitempty"` 172 | FloatKey float32 `protobuf:"fixed32,15,opt,name=float_key,json=floatKey,proto3" json:"float_key,omitempty"` 173 | Int64Key int64 `protobuf:"varint,16,opt,name=int64_key,json=int64Key,proto3" json:"int64_key,omitempty"` 174 | // Container types with simple values 175 | MapStringString map[string]string `protobuf:"bytes,5,rep,name=map_string_string,json=mapStringString,proto3" json:"map_string_string,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` 176 | MapStringInt32 map[string]int32 `protobuf:"bytes,6,rep,name=map_string_int32,json=mapStringInt32,proto3" json:"map_string_int32,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` 177 | StringArrayKey []string `protobuf:"bytes,7,rep,name=string_array_key,json=stringArrayKey,proto3" json:"string_array_key,omitempty"` 178 | Int32ArrayKey []int32 `protobuf:"varint,8,rep,packed,name=int32_array_key,json=int32ArrayKey,proto3" json:"int32_array_key,omitempty"` 179 | // Container types with complex values 180 | ComplexArrayKey []*ExampleNestedModel `protobuf:"bytes,9,rep,name=complex_array_key,json=complexArrayKey,proto3" json:"complex_array_key,omitempty"` 181 | // Enum types 182 | EnumKey ExampleEnumModel `protobuf:"varint,10,opt,name=enum_key,json=enumKey,proto3,enum=example.ExampleEnumModel" json:"enum_key,omitempty"` 183 | // Complex types from protobuf stdlib 184 | TimestampKey *timestamp.Timestamp `protobuf:"bytes,11,opt,name=timestamp_key,json=timestampKey,proto3" json:"timestamp_key,omitempty"` 185 | StructKey *_struct.Struct `protobuf:"bytes,12,opt,name=struct_key,json=structKey,proto3" json:"struct_key,omitempty"` 186 | // Other special types 187 | NullKey _struct.NullValue `protobuf:"varint,13,opt,name=null_key,json=nullKey,proto3,enum=google.protobuf.NullValue" json:"null_key,omitempty"` 188 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 189 | XXX_unrecognized []byte `json:"-"` 190 | XXX_sizecache int32 `json:"-"` 191 | } 192 | 193 | func (m *ExampleDBModel) Reset() { *m = ExampleDBModel{} } 194 | func (m *ExampleDBModel) String() string { return proto.CompactTextString(m) } 195 | func (*ExampleDBModel) ProtoMessage() {} 196 | func (*ExampleDBModel) Descriptor() ([]byte, []int) { 197 | return fileDescriptor_15a1dc8d40dadaa6, []int{2} 198 | } 199 | 200 | func (m *ExampleDBModel) XXX_Unmarshal(b []byte) error { 201 | return xxx_messageInfo_ExampleDBModel.Unmarshal(m, b) 202 | } 203 | func (m *ExampleDBModel) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 204 | return xxx_messageInfo_ExampleDBModel.Marshal(b, m, deterministic) 205 | } 206 | func (m *ExampleDBModel) XXX_Merge(src proto.Message) { 207 | xxx_messageInfo_ExampleDBModel.Merge(m, src) 208 | } 209 | func (m *ExampleDBModel) XXX_Size() int { 210 | return xxx_messageInfo_ExampleDBModel.Size(m) 211 | } 212 | func (m *ExampleDBModel) XXX_DiscardUnknown() { 213 | xxx_messageInfo_ExampleDBModel.DiscardUnknown(m) 214 | } 215 | 216 | var xxx_messageInfo_ExampleDBModel proto.InternalMessageInfo 217 | 218 | func (m *ExampleDBModel) GetInt32Key() int32 { 219 | if m != nil { 220 | return m.Int32Key 221 | } 222 | return 0 223 | } 224 | 225 | func (m *ExampleDBModel) GetStringKey() string { 226 | if m != nil { 227 | return m.StringKey 228 | } 229 | return "" 230 | } 231 | 232 | func (m *ExampleDBModel) GetBoolKey() bool { 233 | if m != nil { 234 | return m.BoolKey 235 | } 236 | return false 237 | } 238 | 239 | func (m *ExampleDBModel) GetBytesKey() []byte { 240 | if m != nil { 241 | return m.BytesKey 242 | } 243 | return nil 244 | } 245 | 246 | func (m *ExampleDBModel) GetDoubleKey() float64 { 247 | if m != nil { 248 | return m.DoubleKey 249 | } 250 | return 0 251 | } 252 | 253 | func (m *ExampleDBModel) GetFloatKey() float32 { 254 | if m != nil { 255 | return m.FloatKey 256 | } 257 | return 0 258 | } 259 | 260 | func (m *ExampleDBModel) GetInt64Key() int64 { 261 | if m != nil { 262 | return m.Int64Key 263 | } 264 | return 0 265 | } 266 | 267 | func (m *ExampleDBModel) GetMapStringString() map[string]string { 268 | if m != nil { 269 | return m.MapStringString 270 | } 271 | return nil 272 | } 273 | 274 | func (m *ExampleDBModel) GetMapStringInt32() map[string]int32 { 275 | if m != nil { 276 | return m.MapStringInt32 277 | } 278 | return nil 279 | } 280 | 281 | func (m *ExampleDBModel) GetStringArrayKey() []string { 282 | if m != nil { 283 | return m.StringArrayKey 284 | } 285 | return nil 286 | } 287 | 288 | func (m *ExampleDBModel) GetInt32ArrayKey() []int32 { 289 | if m != nil { 290 | return m.Int32ArrayKey 291 | } 292 | return nil 293 | } 294 | 295 | func (m *ExampleDBModel) GetComplexArrayKey() []*ExampleNestedModel { 296 | if m != nil { 297 | return m.ComplexArrayKey 298 | } 299 | return nil 300 | } 301 | 302 | func (m *ExampleDBModel) GetEnumKey() ExampleEnumModel { 303 | if m != nil { 304 | return m.EnumKey 305 | } 306 | return ExampleEnumModel_ENUM0 307 | } 308 | 309 | func (m *ExampleDBModel) GetTimestampKey() *timestamp.Timestamp { 310 | if m != nil { 311 | return m.TimestampKey 312 | } 313 | return nil 314 | } 315 | 316 | func (m *ExampleDBModel) GetStructKey() *_struct.Struct { 317 | if m != nil { 318 | return m.StructKey 319 | } 320 | return nil 321 | } 322 | 323 | func (m *ExampleDBModel) GetNullKey() _struct.NullValue { 324 | if m != nil { 325 | return m.NullKey 326 | } 327 | return _struct.NullValue_NULL_VALUE 328 | } 329 | 330 | func init() { 331 | proto.RegisterEnum("example.ExampleEnumModel", ExampleEnumModel_name, ExampleEnumModel_value) 332 | proto.RegisterType((*ExampleNestedModel)(nil), "example.ExampleNestedModel") 333 | proto.RegisterType((*ExampleDBModelWithKey)(nil), "example.ExampleDBModelWithKey") 334 | proto.RegisterType((*ExampleDBModel)(nil), "example.ExampleDBModel") 335 | proto.RegisterMapType((map[string]int32)(nil), "example.ExampleDBModel.MapStringInt32Entry") 336 | proto.RegisterMapType((map[string]string)(nil), "example.ExampleDBModel.MapStringStringEntry") 337 | } 338 | 339 | func init() { proto.RegisterFile("example.proto", fileDescriptor_15a1dc8d40dadaa6) } 340 | 341 | var fileDescriptor_15a1dc8d40dadaa6 = []byte{ 342 | // 559 bytes of a gzipped FileDescriptorProto 343 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x53, 0x5d, 0x6f, 0xd3, 0x30, 344 | 0x14, 0xc5, 0x0d, 0x59, 0x92, 0xbb, 0x7e, 0x64, 0x61, 0x88, 0xae, 0x03, 0x11, 0xed, 0x01, 0x59, 345 | 0x80, 0x32, 0x68, 0x4b, 0x85, 0x78, 0x41, 0x9b, 0xa8, 0x10, 0xaa, 0x5a, 0x21, 0x8f, 0x01, 0x6f, 346 | 0x53, 0xda, 0x7a, 0xa5, 0x22, 0x1f, 0x55, 0xea, 0xa0, 0xe5, 0x8f, 0xf0, 0x7b, 0x91, 0xaf, 0xd3, 347 | 0x8f, 0x64, 0x15, 0x7d, 0x49, 0xec, 0x73, 0xcf, 0x39, 0xf7, 0xda, 0xbe, 0x17, 0x6a, 0xfc, 0xce, 348 | 0x0f, 0x17, 0x01, 0xf7, 0x16, 0x49, 0x2c, 0x62, 0xc7, 0xc8, 0xb7, 0xad, 0xa7, 0xb3, 0x38, 0x9e, 349 | 0x05, 0xfc, 0x1c, 0xe1, 0x71, 0x7a, 0x7b, 0xbe, 0x14, 0x49, 0x3a, 0x11, 0x8a, 0xd6, 0x7a, 0x5e, 350 | 0x8e, 0x8a, 0x79, 0xc8, 0x97, 0xc2, 0x0f, 0x17, 0x8a, 0x70, 0xf6, 0x15, 0x9c, 0xbe, 0x72, 0x1a, 351 | 0xf1, 0xa5, 0xe0, 0xd3, 0x61, 0x3c, 0xe5, 0x81, 0xf3, 0x0c, 0x60, 0x29, 0x92, 0x79, 0x34, 0xbb, 352 | 0xf9, 0xcd, 0xb3, 0x26, 0x71, 0x09, 0xb5, 0x98, 0xa5, 0x90, 0x01, 0xcf, 0x9c, 0x53, 0xb0, 0xe6, 353 | 0x91, 0xe8, 0xb4, 0x31, 0x5a, 0x71, 0x09, 0xd5, 0x99, 0x89, 0xc0, 0x80, 0x67, 0x67, 0x1c, 0x1e, 354 | 0xe7, 0x8e, 0x9f, 0x2e, 0xd1, 0xed, 0xc7, 0x5c, 0xfc, 0x92, 0x2a, 0x1b, 0xb4, 0x8d, 0x9b, 0x5c, 355 | 0x96, 0xd2, 0x54, 0xfe, 0x9b, 0x46, 0x2b, 0xa5, 0xf9, 0x6b, 0x40, 0xbd, 0x98, 0xa7, 0xc8, 0x27, 356 | 0x45, 0xfe, 0xbe, 0x5c, 0x27, 0x60, 0x8e, 0xe3, 0x38, 0x58, 0xa7, 0x32, 0x99, 0x21, 0xf7, 0x79, 357 | 0x19, 0xe3, 0x4c, 0xf0, 0x25, 0xc6, 0x1e, 0xba, 0x84, 0x56, 0x99, 0x89, 0x40, 0x6e, 0x3b, 0x8d, 358 | 0xd3, 0x71, 0xc0, 0x31, 0x5a, 0x77, 0x09, 0x25, 0xcc, 0x52, 0x48, 0xae, 0xbd, 0x0d, 0x62, 0x5f, 359 | 0x60, 0xb4, 0xe1, 0x12, 0x5a, 0x61, 0x26, 0x02, 0x9b, 0xf3, 0xf5, 0xba, 0x18, 0xb4, 0x5d, 0x42, 360 | 0x35, 0xac, 0xb7, 0xd7, 0x95, 0xc1, 0x9f, 0x70, 0x14, 0xfa, 0x8b, 0x9b, 0xbc, 0x66, 0xf5, 0x6b, 361 | 0xea, 0xae, 0x46, 0x0f, 0xdb, 0xaf, 0xbd, 0x55, 0x2f, 0x14, 0x2f, 0xc0, 0x1b, 0xfa, 0x8b, 0x2b, 362 | 0x24, 0xaa, 0x6f, 0x3f, 0x12, 0x49, 0xc6, 0x1a, 0x61, 0x11, 0x75, 0xae, 0xc1, 0xde, 0x72, 0xc6, 363 | 0x0b, 0x6a, 0x1e, 0xa0, 0xf1, 0xab, 0xbd, 0xc6, 0x5f, 0x24, 0x5b, 0xf9, 0xd6, 0xc3, 0x02, 0xe8, 364 | 0x50, 0xb0, 0x73, 0x4b, 0x3f, 0x49, 0xfc, 0x0c, 0x0f, 0x65, 0xb8, 0x1a, 0xb5, 0x58, 0x5d, 0xe1, 365 | 0x17, 0x12, 0x96, 0x47, 0x7b, 0x01, 0x0d, 0xf5, 0x4e, 0x1b, 0xa2, 0xe9, 0x6a, 0x54, 0x67, 0x35, 366 | 0x84, 0xd7, 0xbc, 0xcf, 0x70, 0x34, 0x89, 0x65, 0x19, 0x77, 0x5b, 0x4c, 0x0b, 0x2b, 0x3d, 0x2d, 367 | 0x57, 0xba, 0xd5, 0xbd, 0xac, 0x91, 0xab, 0xd6, 0x46, 0x5d, 0x30, 0x79, 0x94, 0x86, 0xa8, 0x07, 368 | 0x97, 0xd0, 0x7a, 0xfb, 0xa4, 0xac, 0xef, 0x47, 0x69, 0xa8, 0xd4, 0x86, 0xa4, 0x4a, 0xd5, 0x47, 369 | 0xa8, 0xad, 0xa7, 0x05, 0xa5, 0x87, 0x2e, 0xa1, 0x87, 0xed, 0x96, 0xa7, 0x66, 0xca, 0x5b, 0xcd, 370 | 0x94, 0xf7, 0x6d, 0xc5, 0x62, 0xd5, 0xb5, 0x40, 0x1a, 0xf4, 0xb0, 0xe5, 0xd2, 0x89, 0x7a, 0xfd, 371 | 0x2a, 0xaa, 0x9f, 0xdc, 0x53, 0x5f, 0x21, 0x05, 0x7b, 0x31, 0x9d, 0x60, 0x5f, 0xbc, 0x03, 0x33, 372 | 0x4a, 0x03, 0xd5, 0x8b, 0x35, 0x2c, 0xf7, 0x7e, 0xce, 0x51, 0x1a, 0x04, 0xdf, 0xfd, 0x20, 0xe5, 373 | 0xcc, 0x90, 0xdc, 0x01, 0xcf, 0x5a, 0x97, 0x70, 0xbc, 0xab, 0x01, 0x76, 0xcc, 0xdd, 0x31, 0xe8, 374 | 0x7f, 0xa4, 0x36, 0x1f, 0x03, 0xb5, 0xf9, 0x50, 0x79, 0x4f, 0x5a, 0x17, 0xf0, 0x68, 0xc7, 0x5b, 375 | 0xef, 0xb3, 0xd0, 0xb7, 0x2c, 0x5e, 0x76, 0xc0, 0x2e, 0xdf, 0xa9, 0x63, 0x81, 0xde, 0x1f, 0x5d, 376 | 0x0f, 0xdf, 0xd8, 0x0f, 0x56, 0xcb, 0xb7, 0x36, 0x59, 0x2d, 0xdb, 0x76, 0x65, 0x7c, 0x80, 0x07, 377 | 0xeb, 0xfc, 0x0b, 0x00, 0x00, 0xff, 0xff, 0x91, 0x2f, 0x5b, 0x50, 0xe6, 0x04, 0x00, 0x00, 378 | } 379 | -------------------------------------------------------------------------------- /models/execution/execution.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: execution.proto 3 | 4 | package execution 5 | 6 | import ( 7 | fmt "fmt" 8 | proto "github.com/golang/protobuf/proto" 9 | descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor" 10 | _struct "github.com/golang/protobuf/ptypes/struct" 11 | timestamp "github.com/golang/protobuf/ptypes/timestamp" 12 | math "math" 13 | ) 14 | 15 | // Reference imports to suppress errors if they are not otherwise used. 16 | var _ = proto.Marshal 17 | var _ = fmt.Errorf 18 | var _ = math.Inf 19 | 20 | // This is a compile-time assertion to ensure that this generated file 21 | // is compatible with the proto package it is being compiled against. 22 | // A compilation error at this line likely means your copy of the 23 | // proto package needs to be updated. 24 | const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package 25 | 26 | type ExecutionRequest struct { 27 | Uuid string `protobuf:"bytes,1,opt,name=uuid,proto3" json:"uuid,omitempty"` 28 | Action string `protobuf:"bytes,2,opt,name=action,proto3" json:"action,omitempty"` 29 | StartedOn *timestamp.Timestamp `protobuf:"bytes,3,opt,name=started_on,json=startedOn,proto3" json:"started_on,omitempty"` 30 | Parameters *_struct.Struct `protobuf:"bytes,4,opt,name=parameters,proto3" json:"parameters,omitempty"` 31 | Result []byte `protobuf:"bytes,5,opt,name=result,proto3" json:"result,omitempty"` 32 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 33 | XXX_unrecognized []byte `json:"-"` 34 | XXX_sizecache int32 `json:"-"` 35 | } 36 | 37 | func (m *ExecutionRequest) Reset() { *m = ExecutionRequest{} } 38 | func (m *ExecutionRequest) String() string { return proto.CompactTextString(m) } 39 | func (*ExecutionRequest) ProtoMessage() {} 40 | func (*ExecutionRequest) Descriptor() ([]byte, []int) { 41 | return fileDescriptor_776e2c5022e94aef, []int{0} 42 | } 43 | 44 | func (m *ExecutionRequest) XXX_Unmarshal(b []byte) error { 45 | return xxx_messageInfo_ExecutionRequest.Unmarshal(m, b) 46 | } 47 | func (m *ExecutionRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 48 | return xxx_messageInfo_ExecutionRequest.Marshal(b, m, deterministic) 49 | } 50 | func (m *ExecutionRequest) XXX_Merge(src proto.Message) { 51 | xxx_messageInfo_ExecutionRequest.Merge(m, src) 52 | } 53 | func (m *ExecutionRequest) XXX_Size() int { 54 | return xxx_messageInfo_ExecutionRequest.Size(m) 55 | } 56 | func (m *ExecutionRequest) XXX_DiscardUnknown() { 57 | xxx_messageInfo_ExecutionRequest.DiscardUnknown(m) 58 | } 59 | 60 | var xxx_messageInfo_ExecutionRequest proto.InternalMessageInfo 61 | 62 | func (m *ExecutionRequest) GetUuid() string { 63 | if m != nil { 64 | return m.Uuid 65 | } 66 | return "" 67 | } 68 | 69 | func (m *ExecutionRequest) GetAction() string { 70 | if m != nil { 71 | return m.Action 72 | } 73 | return "" 74 | } 75 | 76 | func (m *ExecutionRequest) GetStartedOn() *timestamp.Timestamp { 77 | if m != nil { 78 | return m.StartedOn 79 | } 80 | return nil 81 | } 82 | 83 | func (m *ExecutionRequest) GetParameters() *_struct.Struct { 84 | if m != nil { 85 | return m.Parameters 86 | } 87 | return nil 88 | } 89 | 90 | func (m *ExecutionRequest) GetResult() []byte { 91 | if m != nil { 92 | return m.Result 93 | } 94 | return nil 95 | } 96 | 97 | type Action struct { 98 | Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` 99 | Parameters *_struct.Struct `protobuf:"bytes,2,opt,name=parameters,proto3" json:"parameters,omitempty"` 100 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 101 | XXX_unrecognized []byte `json:"-"` 102 | XXX_sizecache int32 `json:"-"` 103 | } 104 | 105 | func (m *Action) Reset() { *m = Action{} } 106 | func (m *Action) String() string { return proto.CompactTextString(m) } 107 | func (*Action) ProtoMessage() {} 108 | func (*Action) Descriptor() ([]byte, []int) { 109 | return fileDescriptor_776e2c5022e94aef, []int{1} 110 | } 111 | 112 | func (m *Action) XXX_Unmarshal(b []byte) error { 113 | return xxx_messageInfo_Action.Unmarshal(m, b) 114 | } 115 | func (m *Action) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 116 | return xxx_messageInfo_Action.Marshal(b, m, deterministic) 117 | } 118 | func (m *Action) XXX_Merge(src proto.Message) { 119 | xxx_messageInfo_Action.Merge(m, src) 120 | } 121 | func (m *Action) XXX_Size() int { 122 | return xxx_messageInfo_Action.Size(m) 123 | } 124 | func (m *Action) XXX_DiscardUnknown() { 125 | xxx_messageInfo_Action.DiscardUnknown(m) 126 | } 127 | 128 | var xxx_messageInfo_Action proto.InternalMessageInfo 129 | 130 | func (m *Action) GetName() string { 131 | if m != nil { 132 | return m.Name 133 | } 134 | return "" 135 | } 136 | 137 | func (m *Action) GetParameters() *_struct.Struct { 138 | if m != nil { 139 | return m.Parameters 140 | } 141 | return nil 142 | } 143 | 144 | type Execution struct { 145 | Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` 146 | Action *Action `protobuf:"bytes,2,opt,name=action,proto3" json:"action,omitempty"` 147 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 148 | XXX_unrecognized []byte `json:"-"` 149 | XXX_sizecache int32 `json:"-"` 150 | } 151 | 152 | func (m *Execution) Reset() { *m = Execution{} } 153 | func (m *Execution) String() string { return proto.CompactTextString(m) } 154 | func (*Execution) ProtoMessage() {} 155 | func (*Execution) Descriptor() ([]byte, []int) { 156 | return fileDescriptor_776e2c5022e94aef, []int{2} 157 | } 158 | 159 | func (m *Execution) XXX_Unmarshal(b []byte) error { 160 | return xxx_messageInfo_Execution.Unmarshal(m, b) 161 | } 162 | func (m *Execution) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 163 | return xxx_messageInfo_Execution.Marshal(b, m, deterministic) 164 | } 165 | func (m *Execution) XXX_Merge(src proto.Message) { 166 | xxx_messageInfo_Execution.Merge(m, src) 167 | } 168 | func (m *Execution) XXX_Size() int { 169 | return xxx_messageInfo_Execution.Size(m) 170 | } 171 | func (m *Execution) XXX_DiscardUnknown() { 172 | xxx_messageInfo_Execution.DiscardUnknown(m) 173 | } 174 | 175 | var xxx_messageInfo_Execution proto.InternalMessageInfo 176 | 177 | func (m *Execution) GetName() string { 178 | if m != nil { 179 | return m.Name 180 | } 181 | return "" 182 | } 183 | 184 | func (m *Execution) GetAction() *Action { 185 | if m != nil { 186 | return m.Action 187 | } 188 | return nil 189 | } 190 | 191 | var E_ExcludeFromIndex = &proto.ExtensionDesc{ 192 | ExtendedType: (*descriptor.FieldOptions)(nil), 193 | ExtensionType: (*bool)(nil), 194 | Field: 50000, 195 | Name: "exclude_from_index", 196 | Tag: "varint,50000,opt,name=exclude_from_index", 197 | Filename: "execution.proto", 198 | } 199 | 200 | func init() { 201 | proto.RegisterType((*ExecutionRequest)(nil), "ExecutionRequest") 202 | proto.RegisterType((*Action)(nil), "Action") 203 | proto.RegisterType((*Execution)(nil), "Execution") 204 | proto.RegisterExtension(E_ExcludeFromIndex) 205 | } 206 | 207 | func init() { proto.RegisterFile("execution.proto", fileDescriptor_776e2c5022e94aef) } 208 | 209 | var fileDescriptor_776e2c5022e94aef = []byte{ 210 | // 328 bytes of a gzipped FileDescriptorProto 211 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x90, 0x4f, 0x4b, 0xf3, 0x40, 212 | 0x10, 0xc6, 0x49, 0xdf, 0xbc, 0xd1, 0x4e, 0x05, 0xcb, 0x1e, 0x74, 0x29, 0x95, 0x86, 0x9e, 0x7a, 213 | 0x4a, 0xa1, 0x1e, 0x44, 0x41, 0x50, 0xc1, 0x82, 0x07, 0x29, 0x44, 0x3d, 0x97, 0x34, 0x99, 0x96, 214 | 0x40, 0x92, 0x8d, 0xbb, 0xb3, 0xd0, 0xa3, 0x27, 0xbf, 0x91, 0xdf, 0xc3, 0x93, 0x9f, 0x47, 0xb2, 215 | 0xd9, 0x48, 0xff, 0x88, 0xb7, 0x9d, 0x99, 0xe7, 0xd9, 0xdf, 0xcc, 0x03, 0xc7, 0xb8, 0xc6, 0x58, 216 | 0x53, 0x2a, 0x8a, 0xa0, 0x94, 0x82, 0x44, 0x6f, 0xb0, 0x12, 0x62, 0x95, 0xe1, 0xd8, 0x54, 0x0b, 217 | 0xbd, 0x1c, 0x53, 0x9a, 0xa3, 0xa2, 0x28, 0x2f, 0xad, 0xa0, 0xbf, 0x2b, 0x50, 0x24, 0x75, 0x4c, 218 | 0x76, 0xea, 0xef, 0x4e, 0x13, 0x54, 0xb1, 0x4c, 0x4b, 0x12, 0xb2, 0x56, 0x0c, 0xbf, 0x1c, 0xe8, 219 | 0xde, 0x37, 0xd0, 0x10, 0x5f, 0x35, 0x2a, 0x62, 0x0c, 0x5c, 0xad, 0xd3, 0x84, 0x3b, 0xbe, 0x33, 220 | 0x6a, 0x87, 0xe6, 0xcd, 0x4e, 0xc0, 0x8b, 0xe2, 0x4a, 0xc4, 0x5b, 0xa6, 0x6b, 0x2b, 0x76, 0x09, 221 | 0xa0, 0x28, 0x92, 0x84, 0xc9, 0x5c, 0x14, 0xfc, 0x9f, 0xef, 0x8c, 0x3a, 0x93, 0x5e, 0x50, 0x73, 222 | 0x83, 0x86, 0x1b, 0x3c, 0x37, 0x6b, 0x87, 0x6d, 0xab, 0x9e, 0x15, 0xec, 0x1a, 0xa0, 0x8c, 0x64, 223 | 0x94, 0x23, 0xa1, 0x54, 0xdc, 0x35, 0xd6, 0xd3, 0x3d, 0xeb, 0x93, 0x39, 0xe8, 0xce, 0x7d, 0xfb, 224 | 0xe0, 0x4e, 0xb8, 0x61, 0x60, 0x7d, 0xf0, 0x24, 0x2a, 0x9d, 0x11, 0xff, 0xef, 0x3b, 0xa3, 0x23, 225 | 0xab, 0xb0, 0xbd, 0xe1, 0x0b, 0x78, 0xb7, 0xf5, 0x86, 0x0c, 0xdc, 0x22, 0xca, 0xb1, 0xb9, 0xa6, 226 | 0x7a, 0xb3, 0x8b, 0x2d, 0x74, 0xeb, 0x4f, 0xf4, 0x26, 0x74, 0x78, 0x03, 0xed, 0x9f, 0xb8, 0x7e, 227 | 0xfd, 0x79, 0xb0, 0x95, 0x53, 0x67, 0x72, 0x10, 0xd4, 0x6b, 0x34, 0x81, 0x5d, 0x3d, 0x02, 0xc3, 228 | 0x75, 0x9c, 0xe9, 0x04, 0xe7, 0x4b, 0x29, 0xf2, 0x79, 0x5a, 0x24, 0xb8, 0x66, 0x67, 0x7b, 0xf0, 229 | 0x69, 0x8a, 0x59, 0x32, 0x2b, 0x2b, 0x8f, 0xe2, 0x9f, 0xef, 0x55, 0xb2, 0x87, 0x61, 0xd7, 0x5a, 230 | 0xa7, 0x52, 0xe4, 0x0f, 0x95, 0x71, 0xe1, 0x19, 0xc3, 0xf9, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 231 | 0x15, 0xb1, 0x39, 0x0b, 0x3b, 0x02, 0x00, 0x00, 232 | } 233 | -------------------------------------------------------------------------------- /models/unsupported/unsupported.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: unsupported.proto 3 | 4 | package unsupported 5 | 6 | import ( 7 | fmt "fmt" 8 | proto "github.com/golang/protobuf/proto" 9 | _struct "github.com/golang/protobuf/ptypes/struct" 10 | timestamp "github.com/golang/protobuf/ptypes/timestamp" 11 | math "math" 12 | ) 13 | 14 | // Reference imports to suppress errors if they are not otherwise used. 15 | var _ = proto.Marshal 16 | var _ = fmt.Errorf 17 | var _ = math.Inf 18 | 19 | // This is a compile-time assertion to ensure that this generated file 20 | // is compatible with the proto package it is being compiled against. 21 | // A compilation error at this line likely means your copy of the 22 | // proto package needs to be updated. 23 | const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package 24 | 25 | type Model struct { 26 | Uint32Key uint32 `protobuf:"varint,1,opt,name=uint32_key,json=uint32Key,proto3" json:"uint32_key,omitempty"` 27 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 28 | XXX_unrecognized []byte `json:"-"` 29 | XXX_sizecache int32 `json:"-"` 30 | } 31 | 32 | func (m *Model) Reset() { *m = Model{} } 33 | func (m *Model) String() string { return proto.CompactTextString(m) } 34 | func (*Model) ProtoMessage() {} 35 | func (*Model) Descriptor() ([]byte, []int) { 36 | return fileDescriptor_86386df630750539, []int{0} 37 | } 38 | 39 | func (m *Model) XXX_Unmarshal(b []byte) error { 40 | return xxx_messageInfo_Model.Unmarshal(m, b) 41 | } 42 | func (m *Model) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 43 | return xxx_messageInfo_Model.Marshal(b, m, deterministic) 44 | } 45 | func (m *Model) XXX_Merge(src proto.Message) { 46 | xxx_messageInfo_Model.Merge(m, src) 47 | } 48 | func (m *Model) XXX_Size() int { 49 | return xxx_messageInfo_Model.Size(m) 50 | } 51 | func (m *Model) XXX_DiscardUnknown() { 52 | xxx_messageInfo_Model.DiscardUnknown(m) 53 | } 54 | 55 | var xxx_messageInfo_Model proto.InternalMessageInfo 56 | 57 | func (m *Model) GetUint32Key() uint32 { 58 | if m != nil { 59 | return m.Uint32Key 60 | } 61 | return 0 62 | } 63 | 64 | type TS struct { 65 | StartedOn *timestamp.Timestamp `protobuf:"bytes,1,opt,name=StartedOn,proto3" json:"StartedOn,omitempty"` 66 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 67 | XXX_unrecognized []byte `json:"-"` 68 | XXX_sizecache int32 `json:"-"` 69 | } 70 | 71 | func (m *TS) Reset() { *m = TS{} } 72 | func (m *TS) String() string { return proto.CompactTextString(m) } 73 | func (*TS) ProtoMessage() {} 74 | func (*TS) Descriptor() ([]byte, []int) { 75 | return fileDescriptor_86386df630750539, []int{1} 76 | } 77 | 78 | func (m *TS) XXX_Unmarshal(b []byte) error { 79 | return xxx_messageInfo_TS.Unmarshal(m, b) 80 | } 81 | func (m *TS) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 82 | return xxx_messageInfo_TS.Marshal(b, m, deterministic) 83 | } 84 | func (m *TS) XXX_Merge(src proto.Message) { 85 | xxx_messageInfo_TS.Merge(m, src) 86 | } 87 | func (m *TS) XXX_Size() int { 88 | return xxx_messageInfo_TS.Size(m) 89 | } 90 | func (m *TS) XXX_DiscardUnknown() { 91 | xxx_messageInfo_TS.DiscardUnknown(m) 92 | } 93 | 94 | var xxx_messageInfo_TS proto.InternalMessageInfo 95 | 96 | func (m *TS) GetStartedOn() *timestamp.Timestamp { 97 | if m != nil { 98 | return m.StartedOn 99 | } 100 | return nil 101 | } 102 | 103 | type StructMessage struct { 104 | StructKey *_struct.Struct `protobuf:"bytes,1,opt,name=StructKey,proto3" json:"StructKey,omitempty"` 105 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 106 | XXX_unrecognized []byte `json:"-"` 107 | XXX_sizecache int32 `json:"-"` 108 | } 109 | 110 | func (m *StructMessage) Reset() { *m = StructMessage{} } 111 | func (m *StructMessage) String() string { return proto.CompactTextString(m) } 112 | func (*StructMessage) ProtoMessage() {} 113 | func (*StructMessage) Descriptor() ([]byte, []int) { 114 | return fileDescriptor_86386df630750539, []int{2} 115 | } 116 | 117 | func (m *StructMessage) XXX_Unmarshal(b []byte) error { 118 | return xxx_messageInfo_StructMessage.Unmarshal(m, b) 119 | } 120 | func (m *StructMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 121 | return xxx_messageInfo_StructMessage.Marshal(b, m, deterministic) 122 | } 123 | func (m *StructMessage) XXX_Merge(src proto.Message) { 124 | xxx_messageInfo_StructMessage.Merge(m, src) 125 | } 126 | func (m *StructMessage) XXX_Size() int { 127 | return xxx_messageInfo_StructMessage.Size(m) 128 | } 129 | func (m *StructMessage) XXX_DiscardUnknown() { 130 | xxx_messageInfo_StructMessage.DiscardUnknown(m) 131 | } 132 | 133 | var xxx_messageInfo_StructMessage proto.InternalMessageInfo 134 | 135 | func (m *StructMessage) GetStructKey() *_struct.Struct { 136 | if m != nil { 137 | return m.StructKey 138 | } 139 | return nil 140 | } 141 | 142 | type Parent struct { 143 | Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"` 144 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 145 | XXX_unrecognized []byte `json:"-"` 146 | XXX_sizecache int32 `json:"-"` 147 | } 148 | 149 | func (m *Parent) Reset() { *m = Parent{} } 150 | func (m *Parent) String() string { return proto.CompactTextString(m) } 151 | func (*Parent) ProtoMessage() {} 152 | func (*Parent) Descriptor() ([]byte, []int) { 153 | return fileDescriptor_86386df630750539, []int{3} 154 | } 155 | 156 | func (m *Parent) XXX_Unmarshal(b []byte) error { 157 | return xxx_messageInfo_Parent.Unmarshal(m, b) 158 | } 159 | func (m *Parent) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 160 | return xxx_messageInfo_Parent.Marshal(b, m, deterministic) 161 | } 162 | func (m *Parent) XXX_Merge(src proto.Message) { 163 | xxx_messageInfo_Parent.Merge(m, src) 164 | } 165 | func (m *Parent) XXX_Size() int { 166 | return xxx_messageInfo_Parent.Size(m) 167 | } 168 | func (m *Parent) XXX_DiscardUnknown() { 169 | xxx_messageInfo_Parent.DiscardUnknown(m) 170 | } 171 | 172 | var xxx_messageInfo_Parent proto.InternalMessageInfo 173 | 174 | func (m *Parent) GetName() string { 175 | if m != nil { 176 | return m.Name 177 | } 178 | return "" 179 | } 180 | 181 | type Child struct { 182 | Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"` 183 | Parent *Parent `protobuf:"bytes,2,opt,name=Parent,proto3" json:"Parent,omitempty"` 184 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 185 | XXX_unrecognized []byte `json:"-"` 186 | XXX_sizecache int32 `json:"-"` 187 | } 188 | 189 | func (m *Child) Reset() { *m = Child{} } 190 | func (m *Child) String() string { return proto.CompactTextString(m) } 191 | func (*Child) ProtoMessage() {} 192 | func (*Child) Descriptor() ([]byte, []int) { 193 | return fileDescriptor_86386df630750539, []int{4} 194 | } 195 | 196 | func (m *Child) XXX_Unmarshal(b []byte) error { 197 | return xxx_messageInfo_Child.Unmarshal(m, b) 198 | } 199 | func (m *Child) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 200 | return xxx_messageInfo_Child.Marshal(b, m, deterministic) 201 | } 202 | func (m *Child) XXX_Merge(src proto.Message) { 203 | xxx_messageInfo_Child.Merge(m, src) 204 | } 205 | func (m *Child) XXX_Size() int { 206 | return xxx_messageInfo_Child.Size(m) 207 | } 208 | func (m *Child) XXX_DiscardUnknown() { 209 | xxx_messageInfo_Child.DiscardUnknown(m) 210 | } 211 | 212 | var xxx_messageInfo_Child proto.InternalMessageInfo 213 | 214 | func (m *Child) GetName() string { 215 | if m != nil { 216 | return m.Name 217 | } 218 | return "" 219 | } 220 | 221 | func (m *Child) GetParent() *Parent { 222 | if m != nil { 223 | return m.Parent 224 | } 225 | return nil 226 | } 227 | 228 | func init() { 229 | proto.RegisterType((*Model)(nil), "Model") 230 | proto.RegisterType((*TS)(nil), "TS") 231 | proto.RegisterType((*StructMessage)(nil), "StructMessage") 232 | proto.RegisterType((*Parent)(nil), "Parent") 233 | proto.RegisterType((*Child)(nil), "Child") 234 | } 235 | 236 | func init() { proto.RegisterFile("unsupported.proto", fileDescriptor_86386df630750539) } 237 | 238 | var fileDescriptor_86386df630750539 = []byte{ 239 | // 239 bytes of a gzipped FileDescriptorProto 240 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x8e, 0xc1, 0x4b, 0xc3, 0x30, 241 | 0x14, 0xc6, 0xd9, 0x70, 0x93, 0xbe, 0xb1, 0x83, 0xb9, 0x38, 0xc6, 0x64, 0x92, 0x83, 0x78, 0xca, 242 | 0xa0, 0x43, 0xf0, 0x20, 0x5e, 0x04, 0x2f, 0x63, 0x2a, 0xe9, 0xee, 0x92, 0xd9, 0x67, 0x2d, 0xb6, 243 | 0x4d, 0x48, 0x5e, 0x0e, 0xfb, 0xef, 0xa5, 0x49, 0x4b, 0x41, 0xbd, 0xe5, 0x7d, 0xef, 0xf7, 0xbe, 244 | 0x5f, 0xe0, 0xc2, 0x37, 0xce, 0x1b, 0xa3, 0x2d, 0x61, 0x2e, 0x8c, 0xd5, 0xa4, 0x97, 0xeb, 0x42, 245 | 0xeb, 0xa2, 0xc2, 0x4d, 0x98, 0x8e, 0xfe, 0x73, 0x43, 0x65, 0x8d, 0x8e, 0x54, 0x6d, 0x3a, 0x60, 246 | 0xf5, 0x1b, 0x70, 0x64, 0xfd, 0x07, 0xc5, 0x2d, 0xbf, 0x81, 0xc9, 0x5e, 0xe7, 0x58, 0xb1, 0x2b, 247 | 0x00, 0x5f, 0x36, 0xb4, 0x4d, 0xdf, 0xbf, 0xf1, 0xb4, 0x18, 0x5d, 0x8f, 0x6e, 0xe7, 0x32, 0x89, 248 | 0xc9, 0x0e, 0x4f, 0xfc, 0x11, 0xc6, 0x87, 0x8c, 0xdd, 0x43, 0x92, 0x91, 0x6a, 0xed, 0xaf, 0x4d, 249 | 0x60, 0x66, 0xe9, 0x52, 0xc4, 0x7e, 0xd1, 0xf7, 0x8b, 0x43, 0xff, 0x01, 0x39, 0xc0, 0xfc, 0x19, 250 | 0xe6, 0x59, 0xf0, 0xee, 0xd1, 0x39, 0x55, 0x20, 0xbb, 0x6b, 0xab, 0xda, 0x60, 0xd7, 0xe9, 0x66, 251 | 0xe9, 0xe5, 0x9f, 0xaa, 0x48, 0xc8, 0x81, 0xe4, 0x2b, 0x98, 0xbe, 0x29, 0x8b, 0x0d, 0x31, 0x06, 252 | 0x67, 0x2f, 0xaa, 0xc6, 0x70, 0x9b, 0xc8, 0xf0, 0xe6, 0x0f, 0x30, 0x79, 0xfa, 0x2a, 0xab, 0xfc, 253 | 0xbf, 0x25, 0x5b, 0xf7, 0xa7, 0x8b, 0x71, 0xd0, 0x9d, 0x8b, 0x38, 0xca, 0x2e, 0x3e, 0x4e, 0x83, 254 | 0x77, 0xfb, 0x13, 0x00, 0x00, 0xff, 0xff, 0x5a, 0xbc, 0xb4, 0xd8, 0x66, 0x01, 0x00, 0x00, 255 | } 256 | -------------------------------------------------------------------------------- /proto/example.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | import "google/protobuf/struct.proto"; 4 | import "google/protobuf/timestamp.proto"; 5 | 6 | package example; 7 | 8 | enum ExampleEnumModel { 9 | ENUM0 = 0; 10 | ENUM1 = 1; 11 | ENUM2 = 2; 12 | } 13 | 14 | message ExampleNestedModel { 15 | string string_key = 1; 16 | int32 int32_key = 2; 17 | } 18 | 19 | message ExampleDBModelWithKey { 20 | // Special field which is used for constructing a primary key 21 | // 22 | // Actual key is composed of the following components: 23 | // 24 | // - namespace_id - this is inferred from the client object passed to the 25 | // "model_pb_with_key_to_entity_pb" function 26 | // - project_id - this is inferred from the client object passed to the 27 | // "model_pb_with_key_to_entity_pb" function 28 | // - key - string value which uniquely identifies this object. This value is specified by 29 | // setting the "key" string field on this object 30 | string key = 1; 31 | 32 | string string_key= 2; 33 | int32 int32_key = 3; 34 | } 35 | 36 | message ExampleDBModel { 37 | // Simple type 38 | int32 int32_key = 1; 39 | string string_key = 2; 40 | bool bool_key = 3; 41 | bytes bytes_key = 4; 42 | double double_key = 14; 43 | float float_key = 15; 44 | int64 int64_key = 16; 45 | 46 | // Container types with simple values 47 | map map_string_string = 5; 48 | map map_string_int32 = 6; 49 | repeated string string_array_key = 7; 50 | repeated int32 int32_array_key = 8; 51 | 52 | // Container types with complex values 53 | repeated ExampleNestedModel complex_array_key = 9; 54 | 55 | // Enum types 56 | ExampleEnumModel enum_key = 10; 57 | 58 | // Complex types from protobuf stdlib 59 | google.protobuf.Timestamp timestamp_key = 11; 60 | google.protobuf.Struct struct_key = 12; 61 | 62 | // Other special types 63 | google.protobuf.NullValue null_key = 13; 64 | } -------------------------------------------------------------------------------- /proto/execution.proto: -------------------------------------------------------------------------------- 1 | syntax="proto3"; 2 | 3 | import "google/protobuf/timestamp.proto"; 4 | import "google/protobuf/struct.proto"; 5 | import "google/protobuf/descriptor.proto"; 6 | 7 | // Custom Protobuf option which specifies which model fields should be excluded 8 | // from index 9 | extend google.protobuf.FieldOptions { 10 | bool exclude_from_index = 50000; 11 | } 12 | 13 | message ExecutionRequest { 14 | string uuid = 1; 15 | string action = 2; 16 | google.protobuf.Timestamp started_on = 3; 17 | google.protobuf.Struct parameters = 4 [(exclude_from_index) = true]; 18 | bytes result = 5 [(exclude_from_index) = true]; 19 | } 20 | 21 | message Action { 22 | string name = 1; 23 | google.protobuf.Struct parameters = 2; 24 | } 25 | 26 | message Execution { 27 | string name = 1; 28 | Action action = 2; 29 | } -------------------------------------------------------------------------------- /proto/unsupported.proto: -------------------------------------------------------------------------------- 1 | syntax="proto3"; 2 | 3 | import "google/protobuf/timestamp.proto"; 4 | import "google/protobuf/struct.proto"; 5 | 6 | message Model{ 7 | uint32 uint32_key=1; 8 | } 9 | 10 | message TS { 11 | google.protobuf.Timestamp StartedOn=1; 12 | } 13 | 14 | message StructMessage { 15 | google.protobuf.Struct StructKey=1; 16 | } 17 | 18 | message Parent { 19 | string Name=1; 20 | } 21 | 22 | message Child { 23 | string Name=1; 24 | Parent Parent=2; 25 | } -------------------------------------------------------------------------------- /scripts/run-datastore-emulator.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Script which installs and starts Google Cloud Datastore Emulator 3 | 4 | # Install Cloud SDK 5 | export CLOUD_SDK_REPO="cloud-sdk-$(lsb_release -c -s)" 6 | echo "deb http://packages.cloud.google.com/apt $CLOUD_SDK_REPO main" | sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list 7 | curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add - 8 | sudo apt-get update && sudo apt-get install google-cloud-sdk google-cloud-sdk-datastore-emulator 9 | 10 | gcloud beta emulators datastore start --host-port=127.0.0.1:8081 --no-store-on-disk &> /tmp/emulator.log & 11 | EMULATOR_PID=$! 12 | 13 | # Give process some time to start up 14 | sleep 5 15 | 16 | export DATASTORE_EMULATOR_HOST=127.0.0.1:8081 17 | export DATASTORE_EMULATOR_HOST_PATH=127.0.0.1:8081/datastore 18 | export DATASTORE_HOST=http://127.0.0.1:8081 19 | export DATASTORE_PROJECT_ID=translator-tests 20 | 21 | if ps -p ${EMULATOR_PID} > /dev/null; then 22 | echo "google cloud datastore emulator successfully started" 23 | tail -30 /tmp/emulator.log 24 | exit 0 25 | else 26 | echo "Failed to start google cloud datastore emulator" 27 | tail -30 /tmp/emulator.log 28 | exit 1 29 | fi 30 | --------------------------------------------------------------------------------