gapic-generator 0.45.1 → 0.45.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0c44ace94e73e85dad3b7b20373016a28f46181631709dd52fe19672b7da80a6
4
- data.tar.gz: 2f8bdc5d63b8253687711ff7bc6d139e536cc3f5d096be9c8f1546676db60aa4
3
+ metadata.gz: 271aec2d05b52adb5498c05c65461142789397a22d3b9a99d1d09f1559e8cf4f
4
+ data.tar.gz: 16e8bbbf90f2c0eb2174939cc7972fa37552cb807cfd24ecc0d74c9ed252a642
5
5
  SHA512:
6
- metadata.gz: 3f24b95f72f3a26e89190694fff115e8b6e5206b430676fda14ef6d3669b6b2de1eefdada75d2420607f63d31789491acfb11f419cbdce237deaa1fa597fb667
7
- data.tar.gz: b88884b59cc8d3d426f793a97696617e2314b81c4c38e61fa3a507270a2d9e20e67c631fdefad2cf2cd793f5c1bae06577dd4381157a33b64092ad7c7f77ee97
6
+ metadata.gz: e46aeb79a605c9395704b0cc14d4b8b540c34c119c9ee7d33178fc8d1a384d91fecfc42e92311e7197e36f9cec7cf21cb85e3a29850256643d348eae6571e8d2
7
+ data.tar.gz: 9f953a7d82a33f19a6309b6ca6abdf5da4b0f5bec294f6f1da8b0aadec47466f335a4df091c8021dd87a9596b0a310bdfa006fd617f03af8e167067a76712d47
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Release History for gapic-generator
2
2
 
3
+ ### 0.45.3 / 2025-06-21
4
+
5
+ * Fix: correct pagination heuristic for Compute
6
+ * Fix: add libyaml to checks and configure for the prebuilt binary
7
+ * Fix: update Ruby prebuilt binary (version 3.4.3)
8
+
9
+ ### 0.45.2 / 2025-06-04
10
+
11
+ * Fix: update Ruby prebuilt binary, version 3.4.3
12
+
3
13
  ### 0.45.1 / 2025-05-01
4
14
 
5
15
  No significant changes
@@ -102,7 +102,8 @@ module Gapic
102
102
 
103
103
  def line_indent line
104
104
  m = /^( *)\S/.match line
105
- m.nil? ? nil : m[1].length
105
+ return nil unless m
106
+ m[1].length
106
107
  end
107
108
 
108
109
  def escape_line_braces line
@@ -16,6 +16,6 @@
16
16
 
17
17
  module Gapic
18
18
  module Generator
19
- VERSION = "0.45.1"
19
+ VERSION = "0.45.3"
20
20
  end
21
21
  end
@@ -160,7 +160,7 @@ module Gapic
160
160
  selector = setting[SELECTOR]
161
161
  methods = service_config.apis.filter_map do |api|
162
162
  # Removes API prefix and trailing period.
163
- selector[api.name.length + 1..].downcase if selector.start_with? api.name
163
+ selector[(api.name.length + 1)..].downcase if selector.start_with? api.name
164
164
  end
165
165
  if !methods.nil? && setting.key?(AUTO_POPULATED_FIELDS)
166
166
  @auto_populated_fields_by_method_name[methods.first] = setting[AUTO_POPULATED_FIELDS]
@@ -0,0 +1,392 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2021 Google LLC
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # https://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require "gapic/model/model_error"
18
+
19
+ module Gapic
20
+ module Presenters
21
+ module Method
22
+ ##
23
+ # Compute-specific pagination info determined from the proto method
24
+ #
25
+ # This implements the Compute-specific pagination heuristic
26
+ #
27
+ # The following steps are followed for this heuristic:
28
+ # 1. The method should not be server-streamed
29
+ # 2. The request should have a page token and page size fields
30
+ # 3. The response should have a next page token and contain a valid results field
31
+ #
32
+ # Now determining the valid results field is its own complicated sub-heuristic that should be run last.
33
+ # This sub-heuristic cannot end in "not paginated". It should either determine the results field or throw an error
34
+ #
35
+ # The following steps are followed for this sub-heuristic:
36
+ # 0. Check the exception dictionary. If the method is there as a key, use the value as the results field.
37
+ # 1. If there is exactly one map field, that field is the results field.
38
+ #
39
+ # NB: at this point the response contains either 0 or 2+ map fields
40
+ #
41
+ # 2. If there are no repeated fields there is no results field and we shall throw an error
42
+ # 3. If there is exactly one repeated field, that field is the results field.
43
+ # 4. If there are exactly 2 repeated fields, one is of message type, and the other is of type
44
+ # "String", the field of message type is the results field.
45
+ #
46
+ # At this point there are either 2 repeated fields in wrong configuration, or 3 or more repeated
47
+ # fields. The method should have been in the exception dictionary (see step 0).
48
+ # Since the method is NOT in the exception dictionary we should throw an error to prevent
49
+ # accidentally releasing a Compute library with incorrect pagination.
50
+ #
51
+ class ComputePaginationInfo
52
+ include Gapic::Helpers::NamespaceHelper
53
+
54
+ # @private Field name for Pagination Request page token
55
+ PAGE_TOKEN_NAME = "page_token"
56
+ private_constant :PAGE_TOKEN_NAME
57
+ # @private Field type for Pagination Request page token
58
+ PAGE_TOKEN_TYPE = :TYPE_STRING
59
+ private_constant :PAGE_TOKEN_TYPE
60
+
61
+ # @private Field names for Pagination Request page size
62
+ PAGE_SIZE_NAMES = ["page_size", "max_results"].freeze
63
+ private_constant :PAGE_SIZE_NAMES
64
+ # @private Field types for Pagination Request page size
65
+ PAGE_SIZE_TYPES = [:TYPE_UINT32, :TYPE_INT32].freeze
66
+ private_constant :PAGE_SIZE_TYPES
67
+
68
+ # @private Field name for Pagination Response next page token
69
+ NEXT_PAGE_TOKEN_NAME = "next_page_token"
70
+ private_constant :NEXT_PAGE_TOKEN_NAME
71
+ # @private Field type for Pagination Response next page token
72
+ NEXT_PAGE_TOKEN_TYPE = :TYPE_STRING
73
+ private_constant :NEXT_PAGE_TOKEN_TYPE
74
+
75
+ # @private A dictionary of special response messages of paginated methods and their repeated fields
76
+ # Curently contains only UsableSubnetworksAggregatedList which is a paginated field with 3 repeated fields,
77
+ # 2 of which are message-typed fields
78
+ REPEATED_FIELD_SPECIAL_DICTIONARY = {
79
+ "google.cloud.compute.v1.UsableSubnetworksAggregatedList" => "items",
80
+ "google.cloud.compute.v1beta.UsableSubnetworksAggregatedList" => "items"
81
+ }.freeze
82
+ private_constant :REPEATED_FIELD_SPECIAL_DICTIONARY
83
+
84
+ ##
85
+ # @param proto_method [Gapic::Schema::Method] the method to derive pagination info from
86
+ # @param api [Gapic::Schema::Api]
87
+ #
88
+ def initialize proto_method, api
89
+ @api = api
90
+ @method_full_name = proto_method.full_name
91
+ @request = proto_method.input
92
+ @response = proto_method.output
93
+ @server_streaming = proto_method.server_streaming
94
+ end
95
+
96
+ ##
97
+ # Whether the method should be generated as paged
98
+ #
99
+ # @return [Boolean]
100
+ def paged?
101
+ paged_candidate = !server_streaming? && paged_request? && paged_response_candidate?
102
+
103
+ # `paged_response?` can raise and should be evaluated last
104
+ paged_candidate && paged_response?
105
+ end
106
+
107
+ ##
108
+ # Name of the request's field used for page size
109
+ # For Regapic can be either `page_size` or `max_results`
110
+ #
111
+ # @return [String, nil]
112
+ def request_page_size_name
113
+ request_page_size_field&.name
114
+ end
115
+
116
+ ##
117
+ # Name of the repeated field in the response message
118
+ # For REST gapics can be either a vanilla repeated field or a map
119
+ #
120
+ # @return [String, nil]
121
+ def response_repeated_field_name
122
+ response_results_field&.name
123
+ end
124
+
125
+ ##
126
+ # Whether the repeated field in the response message is a map
127
+ #
128
+ # @return [Boolean, nil]
129
+ def repeated_field_is_a_map?
130
+ response_results_field&.map?
131
+ end
132
+
133
+ ##
134
+ # Proto type of the repeated field in the response message
135
+ #
136
+ # @return [String, nil]
137
+ def paged_element_doc_type
138
+ return nil if response_results_field.nil?
139
+ field_paginated_elem_doc_type response_results_field
140
+ end
141
+
142
+ private
143
+
144
+ ##
145
+ # Whether the underlying proto rpc is a server streaming rpc
146
+ #
147
+ # @return [Boolean]
148
+ attr_accessor :server_streaming
149
+
150
+ ##
151
+ # Whether the underlying proto rpc is a server streaming rpc
152
+ #
153
+ # @return [Boolean]
154
+ def server_streaming?
155
+ @server_streaming
156
+ end
157
+
158
+ ##
159
+ # Whether the request message for the REGAPIC rpc satisfies the criteria
160
+ # for the rpc to be classified and implemented as paged
161
+ #
162
+ # @return [Boolean]
163
+ def paged_request?
164
+ # Has a String page_token field which specifies the actual (next) page to retrieve.
165
+ # Has an int32 page_size or int32 max_results field
166
+ # which defines the maximum number of paginated resources to return in the response.
167
+ !request_page_token_field.nil? && !request_page_size_field.nil?
168
+ end
169
+
170
+ ##
171
+ # The field in the request that holds a page_token
172
+ #
173
+ # @return [Gapic::Schema::Field, nil]
174
+ def request_page_token_field
175
+ # Has a String page_token field which specifies the actual (next) page to retrieve.
176
+ @request_page_token_field ||= @request.fields.find do |f|
177
+ f.name == PAGE_TOKEN_NAME && f.type == PAGE_TOKEN_TYPE
178
+ end
179
+ end
180
+
181
+ ##
182
+ # The field in the request that holds a page_size
183
+ # For Regapic can have a name of either `page_size` or `max_results`
184
+ #
185
+ # @return [Gapic::Schema::Field, nil]
186
+ def request_page_size_field
187
+ @request_page_size_field ||=
188
+ begin
189
+ field = @request.fields.find do |f|
190
+ PAGE_SIZE_NAMES.include?(f.name) && PAGE_SIZE_TYPES.include?(f.type)
191
+ end
192
+
193
+ field
194
+ end
195
+ end
196
+
197
+ ##
198
+ # Whether the response message for the REGAPIC rpc satisfies the criteria
199
+ # for the rpc to be classified and implemented as paged
200
+ #
201
+ # @return [Boolean]
202
+ def paged_response?
203
+ # Has the string next_page_token field to be used in the next request as
204
+ # page_token to retrieve the next page.
205
+ # Passes the heuristic for paginated response
206
+ # Order is important here, since paginated response heuristic can raise and should be evaluated last
207
+ paged_response_candidate? && !response_results_field.nil?
208
+ end
209
+
210
+ ##
211
+ # Whether the response message for the REGAPIC rpc satisfies the criteria
212
+ # to be a candidate for pagination. This is intentinally split from evaluating
213
+ # the paged response heuristic since that heuristic can raise.
214
+ #
215
+ # @return [Boolean]
216
+ def paged_response_candidate?
217
+ # Has the string next_page_token field to be used in the next request as
218
+ # page_token to retrieve the next page.
219
+ !response_next_page_token_field.nil?
220
+ end
221
+
222
+ ##
223
+ # The field in the response that holds a next page_token
224
+ #
225
+ # @return [Gapic::Schema::Field, nil]
226
+ def response_next_page_token_field
227
+ # Has the string next_page_token field to be used in the next request as
228
+ # page_token to retrieve the next page.
229
+ @response_next_page_token_field ||= @response.fields.find do |f|
230
+ f.name == NEXT_PAGE_TOKEN_NAME && f.type == NEXT_PAGE_TOKEN_TYPE
231
+ end
232
+ end
233
+
234
+
235
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
236
+ # The heuristic in `response_results_field` would be more confusing if spread across several methods
237
+
238
+ ##
239
+ # The field in the response that holds the results
240
+ # For Compute Regapic can be either a vanilla repeated field or a map
241
+ #
242
+ # @return [Gapic::Schema::Field, nil]
243
+ def response_results_field
244
+ # This sub-heuristic cannot end in "not paginated".
245
+ # It should either determine the results field or throw an error.
246
+ @response_results_field ||= begin
247
+ map_fields = @response.fields.find_all(&:map?)
248
+ repeated_fields = @response.fields.find_all do |f|
249
+ !f.map? && f.label == :LABEL_REPEATED
250
+ end
251
+
252
+ # The following steps are followed for this sub-heuristic:
253
+ # 0. Check the exception dictionary. If the method is there as key, use the value as the results field.
254
+ if REPEATED_FIELD_SPECIAL_DICTIONARY.key? @response.full_name
255
+ field_name = REPEATED_FIELD_SPECIAL_DICTIONARY[@response.full_name]
256
+ field = map_fields.find do |f|
257
+ f.name == field_name
258
+ end || repeated_fields.find do |f|
259
+ f.name == field_name
260
+ end
261
+
262
+ unless field
263
+ error_text = "A field of name \"#{field_name}\" is included in the special dictionary for " \
264
+ "the response type \"#{@response.full_name}\". However this field is not a map " \
265
+ "or repeated field. Failing, as the generator cannot continue."
266
+
267
+ raise ::Gapic::Model::ModelError, error_text
268
+ end
269
+
270
+ field
271
+ elsif map_fields.count == 1
272
+ # 1. If there is exactly one map field, that field is the results field.
273
+ map_fields.first
274
+ # NB: at this point the response contains either 0 or 2 map fields.
275
+ elsif repeated_fields.count.zero?
276
+ # 2. If there are no repeated fields there is no results field and we shall throw an error
277
+ error_text = "A response message \"#{@response.full_name}\" has a next page token field and " \
278
+ "is being evaluated as a candidate for pagination. However it has " \
279
+ "#{map_fields.count} (!= 1) map fields and no repeated fields. " \
280
+ "Failing, as the generator should not continue."
281
+
282
+ raise ::Gapic::Model::ModelError, error_text
283
+ elsif repeated_fields.count == 1
284
+ # 3. If there is exactly one repeated field, that field is the results field.
285
+ repeated_fields.first
286
+ elsif repeated_fields.count == 2
287
+ # 4. If there are exactly 2 repeated fields, one is of message type, and the other is of type
288
+ # "String", the field of message type is the results field.
289
+ pagination_field = repeated_fields.find(&:message?)
290
+ string_field = repeated_fields.find { |f| f.type == :TYPE_STRING }
291
+
292
+ unless pagination_field && string_field
293
+ # At this point if there are 2 repeated fields of different configuration, or 3 or more repeated
294
+ # fields the method should have been in the exception dictionary (see step 0).
295
+ error_text = "A response message \"#{@response.full_name}\" has a next page token " \
296
+ "field and is being evaluated as a candidate for pagination. However it should have " \
297
+ "a configuration of exactly 2 repeated fields, one is of message type, and the other " \
298
+ "of type \"String\". Failing, as the generator cannot continue. \n" \
299
+ "As a developer, please evaluate the message that fails this heuristic and either " \
300
+ "change the heuristic or add the message to the special dictionary."
301
+
302
+ raise ::Gapic::Model::ModelError, error_text
303
+ end
304
+
305
+ pagination_field
306
+ else
307
+ # At this point there are 3 or more repeated fields, and the method should have been in the
308
+ # exception dictionary (see step 0).
309
+ error_text = "A response message \"#{@response.full_name}\" has a next page token " \
310
+ "field and is being evaluated as a candidate for pagination. However it has " \
311
+ "#{repeated_fields.count} (>= 3) repeated fields, and not in the special dictionary " \
312
+ "for exceptions. Failing, as the generator cannot continue. \n" \
313
+ "As a developer, please evaluate the message that fails this heuristic and either " \
314
+ "change the heuristic or add the message to the special dictionary."
315
+
316
+ raise ::Gapic::Model::ModelError, error_text
317
+ end
318
+ end
319
+ end
320
+
321
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
322
+
323
+ # @private
324
+ FIELD_TYPE_MAPPING = {
325
+ TYPE_DOUBLE: "::Float",
326
+ TYPE_FLOAT: "::Float",
327
+ TYPE_INT64: "::Integer",
328
+ TYPE_UINT64: "::Integer",
329
+ TYPE_INT32: "::Integer",
330
+ TYPE_FIXED64: "::Integer",
331
+ TYPE_FIXED32: "::Integer",
332
+ TYPE_BOOL: "::Boolean",
333
+ TYPE_STRING: "::String",
334
+ TYPE_BYTES: "::String",
335
+ TYPE_UINT32: "::Integer",
336
+ TYPE_SFIXED32: "::Integer",
337
+ TYPE_SFIXED64: "::Integer",
338
+ TYPE_SINT32: "::Integer",
339
+ TYPE_SINT64: "::Integer"
340
+ }.freeze
341
+ private_constant :FIELD_TYPE_MAPPING
342
+
343
+ ##
344
+ # A helper to get a Ruby doc-type for a paginated element.
345
+ #
346
+ # @param field [Gapic::Schema::Field]
347
+ #
348
+ # @return [String]
349
+ def field_paginated_elem_doc_type field
350
+ return field_paginated_elem_map_type field if field.map?
351
+ if field.message?
352
+ message_ruby_type field.message
353
+ elsif field.enum?
354
+ # TODO: handle when arg message is nil and enum is the type
355
+ message_ruby_type field.enum
356
+ else
357
+ FIELD_TYPE_MAPPING[field.type] || "::Object"
358
+ end
359
+ end
360
+
361
+ ##
362
+ # A helper to get a Ruby doc-type for a proto map's paginated element.
363
+ #
364
+ # @param field [Gapic::Schema::Field]
365
+ #
366
+ # @return [String]
367
+ def field_paginated_elem_map_type field
368
+ key_field = field.map_key_field
369
+ value_field = field.map_val_field
370
+
371
+ if key_field && value_field
372
+ key_type = field_paginated_elem_doc_type key_field
373
+ value_type = field_paginated_elem_doc_type value_field
374
+ "#{key_type}, #{value_type}"
375
+ else
376
+ class_name
377
+ end
378
+ end
379
+
380
+ ##
381
+ # A helper to get a Ruby type for a proto message.
382
+ #
383
+ # @param message [Gapic::Schema::Message]
384
+ #
385
+ # @return [String]
386
+ def message_ruby_type message
387
+ ruby_namespace @api, message.address.join(".")
388
+ end
389
+ end
390
+ end
391
+ end
392
+ end
@@ -14,7 +14,7 @@
14
14
  # See the License for the specific language governing permissions and
15
15
  # limitations under the License.
16
16
 
17
- require "gapic/presenters/method/rest_pagination_info"
17
+ require "gapic/presenters/method/compute_pagination_info"
18
18
 
19
19
  module Gapic
20
20
  module Presenters
@@ -22,9 +22,14 @@ module Gapic
22
22
  # A presenter for rpc methods (REST submethods)
23
23
  #
24
24
  class MethodRestPresenter
25
- # @return [Gapic::Presenters::Method::RestPaginationInfo]
25
+ # @return [Gapic::Presenters::Method::ComputePaginationInfo] Special pagination presenter for Compute
26
26
  attr_reader :compute_pagination
27
27
 
28
+ ##
29
+ # Presenters for HTTP bindings, used to check whether this method should be generated in REST client
30
+ #
31
+ # @return [Array<Gapic::Presenters::Method::HttpBindingsPresenter>]
32
+ #
28
33
  attr_reader :http_bindings
29
34
 
30
35
  # @return [String] String representation of this presenter type.
@@ -39,7 +44,7 @@ module Gapic
39
44
  @http_bindings = main_method.http_bindings
40
45
  @compute_pagination =
41
46
  if @main_method.service.special_compute_behavior?
42
- Gapic::Presenters::Method::RestPaginationInfo.new main_method.method, api
47
+ Gapic::Presenters::Method::ComputePaginationInfo.new main_method.method, api
43
48
  end
44
49
  @type = "method"
45
50
  end
@@ -54,7 +59,7 @@ module Gapic
54
59
  end
55
60
 
56
61
  ##
57
- # Method name
62
+ # Method's name
58
63
  #
59
64
  # @return [String]
60
65
  #
@@ -62,8 +67,11 @@ module Gapic
62
67
  @main_method.name
63
68
  end
64
69
 
70
+ ##
65
71
  # Fully qualified proto name of the method (namespace.PascalCase)
72
+ #
66
73
  # @return [String]
74
+ #
67
75
  def grpc_full_name
68
76
  @main_method.grpc.full_name
69
77
  end
@@ -103,7 +111,10 @@ module Gapic
103
111
  end
104
112
 
105
113
  ##
106
- # @return [String] The name of the repeated field in paginated responses
114
+ # Name of the repeated field in paginated responses
115
+ # For Compute the pagination is different from GRPC and cannot be looked up in GRPC method presenter
116
+ #
117
+ # @return [String]
107
118
  #
108
119
  def paged_response_repeated_field_name
109
120
  if compute_pagination
@@ -168,7 +179,9 @@ module Gapic
168
179
  end
169
180
 
170
181
  ##
171
- # @return [Boolean] Whether the method is marked as deprecated.
182
+ # Whether the method is marked as deprecated.
183
+ #
184
+ # @return [Boolean]
172
185
  #
173
186
  def is_deprecated?
174
187
  @main_method.is_deprecated?
@@ -95,7 +95,7 @@ module Gapic
95
95
 
96
96
  def render_complex proto, json
97
97
  lines = ["{"]
98
- proto.each do |key, value_expr|
98
+ proto.sort_by { |key, _| key.to_s }.each do |key, value_expr|
99
99
  value_presenter = ExpressionPresenter.new value_expr, json[key]
100
100
  value_lines = value_presenter.render_lines
101
101
  next unless value_lines
@@ -107,9 +107,12 @@ module Gapic
107
107
  end
108
108
 
109
109
  def render_list proto, json
110
+ exprs = proto.map.with_index do |item, index|
111
+ ExpressionPresenter.new item, json[index]
112
+ end
113
+
110
114
  lines = ["["]
111
- proto.each_with_index do |item, index|
112
- expr = ExpressionPresenter.new item, json[index]
115
+ exprs.sort_by(&:render).each do |expr|
113
116
  value_lines = expr.render_lines
114
117
  lines[lines.size - 1] = "#{lines.last}," if lines.size > 1
115
118
  lines += value_lines.map { |line| " #{line}" }
@@ -118,17 +121,33 @@ module Gapic
118
121
  end
119
122
 
120
123
  def render_map proto, json
124
+ key_to_kvlines = get_key_to_kvlines proto, json
125
+
121
126
  lines = ["{"]
122
- proto.keys.zip(proto.values).each_with_index do |(key, value), index|
123
- key_lines = ExpressionPresenter.new(key, json["keys"][index]).render_lines
124
- value_lines = ExpressionPresenter.new(value, json["values"][index]).render_lines
125
- next unless key_lines && value_lines
127
+ key_to_kvlines.sort_by { |key, _| key }.each do |_, key_val_lines|
128
+ key_lines = key_val_lines[0]
129
+ value_lines = key_val_lines[1]
126
130
  elem_lines = key_lines[0..-2] + ["#{key_lines.last} => #{value_lines.first}"] + value_lines[1..]
127
131
  lines[lines.size - 1] = "#{lines.last}," if lines.size > 1
128
132
  lines += elem_lines.map { |line| " #{line}" }
129
133
  end
130
134
  lines + ["}"]
131
135
  end
136
+
137
+ # Helper method to render_map.
138
+ # Returns a map from a key rendered as a string
139
+ # to the array of key and value rendered as lines.
140
+ def get_key_to_kvlines proto, json
141
+ key_to_kvlines = {}
142
+ proto.keys.zip(proto.values).each_with_index do |(key, value), index|
143
+ key_expr = ExpressionPresenter.new key, json["keys"][index]
144
+ value_expr = ExpressionPresenter.new value, json["values"][index]
145
+ next unless key_expr.render_lines && value_expr.render_lines
146
+
147
+ key_to_kvlines[key_expr.render] = [key_expr.render_lines, value_expr.render_lines]
148
+ end
149
+ key_to_kvlines
150
+ end
132
151
  end
133
152
  end
134
153
  end
@@ -3,7 +3,7 @@ source "https://rubygems.org"
3
3
 
4
4
  gemspec
5
5
 
6
- gem "google-style", "~> 1.31.0"
6
+ gem "google-style", "~> 1.31.1"
7
7
  gem "minitest", "~> 5.22"
8
8
  gem "minitest-focus", "~> 1.4"
9
9
  gem "minitest-rg", "~> 5.3"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gapic-generator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.45.1
4
+ version: 0.45.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ernest Landrito
@@ -87,14 +87,14 @@ dependencies:
87
87
  requirements:
88
88
  - - "~>"
89
89
  - !ruby/object:Gem::Version
90
- version: 1.31.0
90
+ version: 1.31.1
91
91
  type: :runtime
92
92
  prerelease: false
93
93
  version_requirements: !ruby/object:Gem::Requirement
94
94
  requirements:
95
95
  - - "~>"
96
96
  - !ruby/object:Gem::Version
97
- version: 1.31.0
97
+ version: 1.31.1
98
98
  email:
99
99
  - landrito@google.com
100
100
  - quartzmo@gmail.com
@@ -167,8 +167,8 @@ files:
167
167
  - lib/gapic/presenters/gem_presenter.rb
168
168
  - lib/gapic/presenters/grpc_service_config_presenter.rb
169
169
  - lib/gapic/presenters/message_presenter.rb
170
+ - lib/gapic/presenters/method/compute_pagination_info.rb
170
171
  - lib/gapic/presenters/method/http_binding_presenter.rb
171
- - lib/gapic/presenters/method/rest_pagination_info.rb
172
172
  - lib/gapic/presenters/method_presenter.rb
173
173
  - lib/gapic/presenters/method_rest_presenter.rb
174
174
  - lib/gapic/presenters/package_presenter.rb
@@ -365,7 +365,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
365
365
  - !ruby/object:Gem::Version
366
366
  version: '0'
367
367
  requirements: []
368
- rubygems_version: 3.6.8
368
+ rubygems_version: 3.6.9
369
369
  specification_version: 4
370
370
  summary: An API Client Generator for Ruby in Ruby!
371
371
  test_files: []
@@ -1,255 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright 2021 Google LLC
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License");
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- # https://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an "AS IS" BASIS,
13
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- # See the License for the specific language governing permissions and
15
- # limitations under the License.
16
-
17
- module Gapic
18
- module Presenters
19
- module Method
20
- ##
21
- # Pagination info determined from the proto method
22
- #
23
- class RestPaginationInfo
24
- include Gapic::Helpers::NamespaceHelper
25
- ##
26
- # @param proto_method [Gapic::Schema::Method] the method to derive pagination info from
27
- # @param api [Gapic::Schema::Api]
28
- #
29
- def initialize proto_method, api
30
- @api = api
31
- @request = proto_method.input
32
- @response = proto_method.output
33
- @server_streaming = proto_method.server_streaming
34
- end
35
-
36
- ##
37
- # Whether the method should be generated as paged
38
- #
39
- # @return [Boolean]
40
- def paged?
41
- !server_streaming? && paged_request? && paged_response?
42
- end
43
-
44
- ##
45
- # Name of the request's field used for page size
46
- # For Regapic can be either `page_size` or `max_results`
47
- #
48
- # @return [String, nil]
49
- def request_page_size_name
50
- request_page_size_field&.name
51
- end
52
-
53
- ##
54
- # Name of the repeated field in the response message
55
- # For REST gapics can be either a vanilla repeated field or a map
56
- #
57
- # @return [String, nil]
58
- def response_repeated_field_name
59
- response_results_field&.name
60
- end
61
-
62
- ##
63
- # Whether the repeated field in the response message is a map
64
- #
65
- # @return [Boolean, nil]
66
- def repeated_field_is_a_map?
67
- response_results_field&.map?
68
- end
69
-
70
- ##
71
- # Proto type of the repeated field in the response message
72
- #
73
- # @return [String, nil]
74
- def paged_element_doc_type
75
- return nil if response_results_field.nil?
76
- field_paginated_elem_doc_type response_results_field
77
- end
78
-
79
- private
80
-
81
- # Whether the underlying proto rpc is a server streaming rpc
82
- # @return [Boolean]
83
- attr_accessor :server_streaming
84
-
85
- ##
86
- # Whether the underlying proto rpc is a server streaming rpc
87
- #
88
- # @return [Boolean]
89
- def server_streaming?
90
- @server_streaming
91
- end
92
-
93
- ##
94
- # Whether the request message for the REGAPIC rpc satisfies the criteria
95
- # for the rpc to be classified and implemented as paged
96
- #
97
- # @return [Boolean]
98
- def paged_request?
99
- # Has a String page_token field which specifies the actual (next) page to retrieve.
100
- # Has an int32 page_size or int32 max_results field
101
- # which defines the maximum number of paginated resources to return in the response.
102
- !request_page_token_field.nil? && !request_page_size_field.nil?
103
- end
104
-
105
- ##
106
- # The field in the request that holds a page_token
107
- #
108
- # @return[Gapic::Schema::Field, nil]
109
- def request_page_token_field
110
- # Has a String page_token field which specifies the actual (next) page to retrieve.
111
- @request_page_token_field ||= @request.fields.find do |f|
112
- f.name == "page_token" && f.type == :TYPE_STRING
113
- end
114
- end
115
-
116
- ##
117
- # The field in the request that holds a page_size
118
- # For Regapic can have a name of either `page_size` or `max_results`
119
- #
120
- # @return[Gapic::Schema::Field, nil]
121
- def request_page_size_field
122
- @request_page_size_field ||=
123
- begin
124
- page_size_names = ["page_size", "max_results"]
125
-
126
- # Has the int32 page_size or int32 max_results field
127
- # which defines the maximum number of paginated resources to return in the response.
128
- page_size_types = [:TYPE_UINT32, :TYPE_INT32]
129
-
130
- field = @request.fields.find do |f|
131
- page_size_names.include?(f.name) && page_size_types.include?(f.type)
132
- end
133
-
134
- field
135
- end
136
- end
137
-
138
- ##
139
- # Whether the response message for the REGAPIC rpc satisfies the criteria
140
- # for the rpc to be classified and implemented as paged
141
- #
142
- # @return [Boolean]
143
- def paged_response?
144
- # Has the string next_page_token field to be used in the next request as page_token to retrieve the next page.
145
- # Has only one repeated or map<string, ?> field containing a list of paginated resources.
146
- !response_next_page_token_field.nil? && !response_results_field.nil?
147
- end
148
-
149
- ##
150
- # The field in the response that holds a next page_token
151
- #
152
- # @return[Gapic::Schema::Field, nil]
153
- def response_next_page_token_field
154
- # Has the string next_page_token field to be used in the next request as page_token to retrieve the next page.
155
- @response_next_page_token_field ||= @response.fields.find do |f|
156
- f.name == "next_page_token" && f.type == :TYPE_STRING
157
- end
158
- end
159
-
160
- ##
161
- # The field in the response that holds the results
162
- # For Regapic can be either a vanilla repeated field or a map
163
- #
164
- # @return [Gapic::Schema::Field, nil]
165
- def response_results_field
166
- @response_results_field ||= begin
167
- map_fields = @response.fields.find_all(&:map?)
168
- repeated_fields = @response.fields.find_all do |f|
169
- !f.map? && f.label == :LABEL_REPEATED
170
- end
171
-
172
- if map_fields.count == 1
173
- # If the response message has only one map<string, ?> field
174
- # treat it as the one with paginated resources (i.e. ignore the repeated fields if any).
175
- map_fields.first
176
- elsif repeated_fields.count == 1 && map_fields.empty?
177
- # If the response message contains only one repeated field,
178
- # treat that field as the one containing the paginated resources.
179
- repeated_fields.first
180
- end
181
- # If the response message contains more than one repeated field or does not have repeated fields at all
182
- # but has more than one map<string, ?> field, do not generate any paginated methods for such rpc.
183
- end
184
- end
185
-
186
- # @private
187
- FIELD_TYPE_MAPPING = {
188
- TYPE_DOUBLE: "::Float",
189
- TYPE_FLOAT: "::Float",
190
- TYPE_INT64: "::Integer",
191
- TYPE_UINT64: "::Integer",
192
- TYPE_INT32: "::Integer",
193
- TYPE_FIXED64: "::Integer",
194
- TYPE_FIXED32: "::Integer",
195
- TYPE_BOOL: "::Boolean",
196
- TYPE_STRING: "::String",
197
- TYPE_BYTES: "::String",
198
- TYPE_UINT32: "::Integer",
199
- TYPE_SFIXED32: "::Integer",
200
- TYPE_SFIXED64: "::Integer",
201
- TYPE_SINT32: "::Integer",
202
- TYPE_SINT64: "::Integer"
203
- }.freeze
204
- private_constant :FIELD_TYPE_MAPPING
205
-
206
- ##
207
- # A helper to get a Ruby doc-type for a paginated element.
208
- #
209
- # @param field [Gapic::Schema::Field]
210
- #
211
- # @return [String]
212
- def field_paginated_elem_doc_type field
213
- return field_paginated_elem_map_type field if field.map?
214
- if field.message?
215
- message_ruby_type field.message
216
- elsif field.enum?
217
- # TODO: handle when arg message is nil and enum is the type
218
- message_ruby_type field.enum
219
- else
220
- FIELD_TYPE_MAPPING[field.type] || "::Object"
221
- end
222
- end
223
-
224
- ##
225
- # A helper to get a Ruby doc-type for a proto map's paginated element.
226
- #
227
- # @param field [Gapic::Schema::Field]
228
- #
229
- # @return [String]
230
- def field_paginated_elem_map_type field
231
- key_field = field.map_key_field
232
- value_field = field.map_val_field
233
-
234
- if key_field && value_field
235
- key_type = field_paginated_elem_doc_type key_field
236
- value_type = field_paginated_elem_doc_type value_field
237
- "#{key_type}, #{value_type}"
238
- else
239
- class_name
240
- end
241
- end
242
-
243
- ##
244
- # A helper to get a Ruby type for a proto message.
245
- #
246
- # @param message [Gapic::Schema::Message]
247
- #
248
- # @return [String]
249
- def message_ruby_type message
250
- ruby_namespace @api, message.address.join(".")
251
- end
252
- end
253
- end
254
- end
255
- end