google-ads-googleads 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog +8 -0
  3. data/google_ads_config.rb +6 -0
  4. data/lib/google/ads/google_ads/api_versions.rb +8 -0
  5. data/lib/google/ads/google_ads/config.rb +2 -0
  6. data/lib/google/ads/google_ads/google_ads_client.rb +37 -66
  7. data/lib/google/ads/google_ads/logging_interceptor.rb +108 -36
  8. data/lib/google/ads/google_ads/lookup_util.rb +105 -0
  9. data/lib/google/ads/google_ads/partial_failure_error_decoder.rb +24 -0
  10. data/lib/google/ads/google_ads/utils/v0/proto_lookup_util.rb +4 -1
  11. data/lib/google/ads/google_ads/utils/v1/path_lookup_util.rb +11 -1
  12. data/lib/google/ads/google_ads/utils/v1/proto_lookup_util.rb +39 -6
  13. data/lib/google/ads/google_ads/v1/common/ad_asset_pb.rb +12 -0
  14. data/lib/google/ads/google_ads/v1/common/ad_type_infos_pb.rb +39 -0
  15. data/lib/google/ads/google_ads/v1/common/asset_types_pb.rb +34 -0
  16. data/lib/google/ads/google_ads/v1/common/bidding_pb.rb +4 -0
  17. data/lib/google/ads/google_ads/v1/common/criteria_pb.rb +4 -0
  18. data/lib/google/ads/google_ads/v1/common/policy_pb.rb +1 -0
  19. data/lib/google/ads/google_ads/v1/common/segments_pb.rb +2 -0
  20. data/lib/google/ads/google_ads/v1/enums/ad_group_criterion_approval_status_pb.rb +23 -0
  21. data/lib/google/ads/google_ads/v1/enums/ad_group_type_pb.rb +1 -0
  22. data/lib/google/ads/google_ads/v1/enums/ad_type_pb.rb +3 -0
  23. data/lib/google/ads/google_ads/v1/enums/advertising_channel_sub_type_pb.rb +1 -0
  24. data/lib/google/ads/google_ads/v1/enums/advertising_channel_type_pb.rb +1 -0
  25. data/lib/google/ads/google_ads/v1/enums/app_campaign_app_store_pb.rb +21 -0
  26. data/lib/google/ads/google_ads/v1/enums/app_campaign_bidding_strategy_goal_type_pb.rb +23 -0
  27. data/lib/google/ads/google_ads/v1/enums/asset_type_pb.rb +22 -0
  28. data/lib/google/ads/google_ads/v1/enums/bidding_source_pb.rb +2 -2
  29. data/lib/google/ads/google_ads/v1/enums/budget_type_pb.rb +21 -0
  30. data/lib/google/ads/google_ads/v1/enums/conversion_adjustment_type_pb.rb +21 -0
  31. data/lib/google/ads/google_ads/v1/enums/legacy_app_install_ad_app_store_pb.rb +24 -0
  32. data/lib/google/ads/google_ads/v1/enums/payment_mode_pb.rb +21 -0
  33. data/lib/google/ads/google_ads/v1/enums/recommendation_type_pb.rb +2 -0
  34. data/lib/google/ads/google_ads/v1/errors/asset_error_pb.rb +23 -0
  35. data/lib/google/ads/google_ads/v1/errors/authorization_error_pb.rb +2 -0
  36. data/lib/google/ads/google_ads/v1/errors/bidding_error_pb.rb +1 -0
  37. data/lib/google/ads/google_ads/v1/errors/campaign_error_pb.rb +1 -0
  38. data/lib/google/ads/google_ads/v1/errors/conversion_adjustment_upload_error_pb.rb +28 -0
  39. data/lib/google/ads/google_ads/v1/errors/conversion_upload_error_pb.rb +6 -0
  40. data/lib/google/ads/google_ads/v1/errors/criterion_error_pb.rb +2 -0
  41. data/lib/google/ads/google_ads/v1/errors/errors_pb.rb +4 -0
  42. data/lib/google/ads/google_ads/v1/errors/media_upload_error_pb.rb +11 -0
  43. data/lib/google/ads/google_ads/v1/errors/mutate_error_pb.rb +1 -0
  44. data/lib/google/ads/google_ads/v1/errors/policy_validation_parameter_error_pb.rb +2 -0
  45. data/lib/google/ads/google_ads/v1/errors/recommendation_error_pb.rb +1 -0
  46. data/lib/google/ads/google_ads/v1/errors/request_error_pb.rb +1 -0
  47. data/lib/google/ads/google_ads/v1/errors/youtube_video_registration_error_pb.rb +11 -0
  48. data/lib/google/ads/google_ads/v1/resources/ad_group_criterion_pb.rb +3 -0
  49. data/lib/google/ads/google_ads/v1/resources/ad_pb.rb +3 -0
  50. data/lib/google/ads/google_ads/v1/resources/asset_pb.rb +26 -0
  51. data/lib/google/ads/google_ads/v1/resources/campaign_budget_pb.rb +2 -0
  52. data/lib/google/ads/google_ads/v1/resources/campaign_criterion_pb.rb +1 -0
  53. data/lib/google/ads/google_ads/v1/resources/campaign_pb.rb +23 -11
  54. data/lib/google/ads/google_ads/v1/resources/extension_feed_item_pb.rb +2 -0
  55. data/lib/google/ads/google_ads/v1/resources/mutate_job_pb.rb +2 -0
  56. data/lib/google/ads/google_ads/v1/resources/recommendation_pb.rb +21 -8
  57. data/lib/google/ads/google_ads/v1/resources/shared_criterion_pb.rb +1 -0
  58. data/lib/google/ads/google_ads/v1/services/ad_group_criterion_service_pb.rb +2 -0
  59. data/lib/google/ads/google_ads/v1/services/asset_service_client.rb +267 -0
  60. data/lib/google/ads/google_ads/v1/services/asset_service_client_config.json +36 -0
  61. data/lib/google/ads/google_ads/v1/services/asset_service_pb.rb +35 -0
  62. data/lib/google/ads/google_ads/v1/services/asset_service_services_pb.rb +42 -0
  63. data/lib/google/ads/google_ads/v1/services/conversion_adjustment_upload_service_client.rb +222 -0
  64. data/lib/google/ads/google_ads/v1/services/conversion_adjustment_upload_service_client_config.json +31 -0
  65. data/lib/google/ads/google_ads/v1/services/conversion_adjustment_upload_service_pb.rb +56 -0
  66. data/lib/google/ads/google_ads/v1/services/conversion_adjustment_upload_service_services_pb.rb +40 -0
  67. data/lib/google/ads/google_ads/v1/services/conversion_upload_service_client.rb +53 -0
  68. data/lib/google/ads/google_ads/v1/services/conversion_upload_service_client_config.json +5 -0
  69. data/lib/google/ads/google_ads/v1/services/conversion_upload_service_pb.rb +27 -0
  70. data/lib/google/ads/google_ads/v1/services/conversion_upload_service_services_pb.rb +2 -0
  71. data/lib/google/ads/google_ads/v1/services/google_ads_service_pb.rb +5 -0
  72. data/lib/google/ads/google_ads/v1/services/recommendation_service_pb.rb +5 -0
  73. data/lib/google/ads/google_ads/v1/services/shopping_performance_view_service_client.rb +19 -6
  74. data/lib/google/ads/google_ads/version.rb +1 -1
  75. data/lib/google/ads/google_ads/wrapper_util.rb +4 -0
  76. data/lib/google/ads/google_ads.rb +4 -0
  77. metadata +27 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6a1a539dda2e56f08c9b1daac7d65c2a31a8f78d20906f3a1f9e393c65c8d563
4
- data.tar.gz: 0543d6351bab5085cefe55b257659145f9405252c31de9b7d7885184de995984
3
+ metadata.gz: 4cf7ec45c64d8e3b15c113cedc904e46d667d301740608146d0985537f6e3e44
4
+ data.tar.gz: 0a33073c1cf8401df2388172f6026d4c0cbe3a4f8f8e81b5da710ac57766dc01
5
5
  SHA512:
6
- metadata.gz: 775083f4e4d3f15f33607ab7cd0bdc7ff232118536617bb6d8e0abc90f1f4bec0c2cd9de32b7f46432c15905f2295af477510bf1648c6c92ec596378a7fc257f
7
- data.tar.gz: af918d18fee221dd34da5453538bb81670591d56bea0467d27a57204c0ab67f8b708d3e13ec83d2116e4789d4213b772ecccd5ad847212af9cac248c1a0d7073
6
+ metadata.gz: 0d36f3d385b11ce0efa43e7c4008af8569f4b3f1133d8c151eb1cf472958c50489c3dbd43c8180935588a21ef47413fea5135785187b84297a3ab27b28f2d012
7
+ data.tar.gz: 7c42c6b2bc5edb4f5b795ffe5b5316d0e5a539a6ceaa5dd1a913b5c7f1c54a61c4bc5f0873ea3ac8c215ebe8599699a54df712dd962a94fc3b9c6e50725bc945
data/ChangeLog CHANGED
@@ -1,3 +1,11 @@
1
+ 1.1.0:
2
+ - Adding support for Google Ads API v1_1.
3
+ - Refactored proto and path lookup utils to be accessible before client
4
+ instantiation.
5
+ - Numerous fixes to logging, including support for logging large images and
6
+ partial failure errors.
7
+ - New partial failure decoder utility.
8
+
1
9
  1.0.0:
2
10
  - Adding support for Google Ads API v1.
3
11
  - Adding support for versioned path and proto lookup utils.
data/google_ads_config.rb CHANGED
@@ -31,4 +31,10 @@ Google::Ads::GoogleAds::Config.new do |c|
31
31
  # You can provide a filename as a String, an IO object like STDOUT or STDERR,
32
32
  # or an open file.
33
33
  c.log_target = STDOUT
34
+
35
+ # Instead of specifying logging through level and target, you can also
36
+ # pass a logger directly (for e.g. passing Rails.logger in a
37
+ # config/initializer). The passed logger will override log_level and
38
+ # log_target
39
+ # c.logger = Logger.new(STDOUT)
34
40
  end
@@ -0,0 +1,8 @@
1
+ module Google
2
+ module Ads
3
+ module GoogleAds
4
+ KNOWN_API_VERSIONS = [:V0, :V1]
5
+ DEFAULT_API_VERSION = :V1
6
+ end
7
+ end
8
+ end
@@ -28,6 +28,7 @@ module Google
28
28
 
29
29
  attr_accessor :log_level
30
30
  attr_accessor :log_target
31
+ attr_accessor :logger
31
32
 
32
33
  def initialize(&block)
33
34
  @refresh_token = nil
@@ -38,6 +39,7 @@ module Google
38
39
 
39
40
  @log_level = nil
40
41
  @log_target = nil
42
+ @logger = nil
41
43
  yield self if block_given?
42
44
  end
43
45
 
@@ -55,6 +55,7 @@ require 'googleauth'
55
55
  require 'google/ads/google_ads/patches'
56
56
  require 'google/ads/google_ads/config'
57
57
  require 'google/ads/google_ads/field_mask_util'
58
+ require 'google/ads/google_ads/lookup_util'
58
59
  require 'google/ads/google_ads/wrapper_util'
59
60
  require 'google/ads/google_ads/logging_interceptor'
60
61
 
@@ -69,12 +70,12 @@ module Google
69
70
  module Ads
70
71
  module GoogleAds
71
72
  class GoogleAdsClient
72
- DEFAULT_API_VERSION = :V1
73
- KNOWN_API_VERSIONS = [:V0, :V1]
74
73
 
75
74
  DEFAULT_CONFIG_FILENAME = 'google_ads_config.rb'
76
75
 
77
76
  attr_reader :logger
77
+ # Allow setting the lookup_util manually for users who use it before creating the client.
78
+ attr_writer :lookup_util
78
79
 
79
80
  def initialize(config_path = nil, &block)
80
81
  if block_given?
@@ -103,8 +104,6 @@ module Google
103
104
  end
104
105
  @config = eval_result
105
106
  end
106
- @proto_lookup_utils = {}
107
- @path_lookup_utils = {}
108
107
 
109
108
  begin
110
109
  @logger = create_default_logger
@@ -122,21 +121,24 @@ module Google
122
121
  # :Campaign will return an instantiated CampaignServiceClient.
123
122
  #
124
123
  # Raises ArgumentError if no service can be found for the provided type.
125
- def service(name, version = DEFAULT_API_VERSION)
124
+ def service(name, version = default_api_version)
126
125
  service_path = ENV['GOOGLEADS_SERVICE_PATH']
127
126
 
128
127
  # We need a local reference to refer to from within the class block
129
128
  # below.
130
129
  logger = @logger
131
130
 
132
- class_to_return = proto_lookup_util(version).service(name)
131
+ class_to_return = lookup_util.raw_service(name, version)
133
132
  class_to_return = Class.new(class_to_return) do
134
133
  unless service_path.nil? || service_path.empty?
135
134
  const_set('SERVICE_ADDRESS', service_path.freeze)
136
135
  end
137
- logging_interceptor =
138
- Google::Ads::GoogleAds::LoggingInterceptor.new(logger)
139
- const_set('GRPC_INTERCEPTORS', [logging_interceptor])
136
+
137
+ if logger
138
+ logging_interceptor =
139
+ Google::Ads::GoogleAds::LoggingInterceptor.new(logger)
140
+ const_set('GRPC_INTERCEPTORS', [logging_interceptor])
141
+ end
140
142
  end
141
143
 
142
144
  headers = {
@@ -144,7 +146,7 @@ module Google
144
146
  }
145
147
  if @config.login_customer_id
146
148
  login_customer_id = @config.login_customer_id
147
- if !login_customer_id.is_a? Integer || login_customer_id <= 0 ||
149
+ if !login_customer_id.is_a?(Integer) || login_customer_id <= 0 ||
148
150
  login_customer_id > 9_999_999_999
149
151
  raise sprintf('Invalid login_customer_id. Must be an integer ' \
150
152
  '0 < x <= 9,999,999,999. Got %s', login_customer_id)
@@ -162,16 +164,16 @@ module Google
162
164
  # example, passing :Campaign will return an instantiated Campaign.
163
165
  #
164
166
  # Raises ArgumentError if no entity can be found for the provided type.
165
- def resource(name, version = DEFAULT_API_VERSION)
166
- proto_lookup_util(version).resource(name).new
167
+ def resource(name, version = default_api_version)
168
+ lookup_util.resource(name, version)
167
169
  end
168
170
 
169
171
  # Return an operation for the provided entity type. For example, passing
170
172
  # :Campaign will return an instantiated CampaignOperation.
171
173
  #
172
174
  # Raises ArgumentError if no entity can be found for the provided type.
173
- def operation(name, version = DEFAULT_API_VERSION)
174
- proto_lookup_util(version).operation(name).new
175
+ def operation(name, version = default_api_version)
176
+ lookup_util.operation(name, version)
175
177
  end
176
178
 
177
179
  # Return a reference to the enum class for the provided enum type. For
@@ -179,8 +181,8 @@ module Google
179
181
  # CampaignStatusEnum.
180
182
  #
181
183
  # Raises ArgumentError if no enum can be found for the provided type.
182
- def enum(name, version = DEFAULT_API_VERSION)
183
- proto_lookup_util(version).enum(name)
184
+ def enum(name, version = default_api_version)
185
+ lookup_util.enum(name, version)
184
186
  end
185
187
 
186
188
  # Returns a reference to the FieldMaskUtil class for ease of access.
@@ -194,8 +196,8 @@ module Google
194
196
  end
195
197
 
196
198
  # Returns a reference to the PathLookupUtil to generate resource names.
197
- def path(version = DEFAULT_API_VERSION)
198
- path_lookup_util(version)
199
+ def path(version = default_api_version)
200
+ lookup_util.path(version)
199
201
  end
200
202
 
201
203
  # Set the logger to use. This will only take effect on services fetched
@@ -204,6 +206,13 @@ module Google
204
206
  @logger = logger
205
207
  end
206
208
 
209
+ # Decode a partial failure error from a response.
210
+ # See Google::Ads::GoogleAds::PartialFailureErrorDecoder for full
211
+ # documentation.
212
+ def decode_partial_failure_error(pfe)
213
+ PartialFailureErrorDecoder.decode(pfe)
214
+ end
215
+
207
216
  private
208
217
 
209
218
  ERROR_TRANSFORMER = Proc.new do |gax_error|
@@ -249,59 +258,21 @@ module Google
249
258
 
250
259
  # Create the default logger, useful if the user hasn't defined one.
251
260
  def create_default_logger()
252
- logger = Logger.new(@config.log_target)
253
- logger.level = Logger.const_get(@config.log_level)
254
- return logger
255
- end
256
-
257
- def valid_version?(version)
258
- KNOWN_API_VERSIONS.include?(version)
259
- end
260
-
261
- # Load up the proto lookup util for the given version, storing a copy
262
- # of it if this is the first time we needed it.
263
- def proto_lookup_util(version)
264
- unless valid_version?(version)
265
- raise sprintf('Unknown version %s', version)
266
- end
267
- if @proto_lookup_utils[version].nil?
268
- path_version = version.downcase
269
- require sprintf('google/ads/google_ads/utils/%s/proto_lookup_util',
270
- path_version)
271
- class_path = sprintf(
272
- 'Google::Ads::GoogleAds::Utils::%s::ProtoLookupUtil',
273
- version
274
- )
275
- @proto_lookup_utils[version] = class_for_path(class_path).new
261
+ if @config.logger.nil?
262
+ logger = Logger.new(@config.log_target)
263
+ logger.level = Logger.const_get(@config.log_level)
264
+ logger
265
+ else
266
+ @config.logger
276
267
  end
277
- @proto_lookup_utils[version]
278
268
  end
279
269
 
280
- # Load up the path lookup util for the given version, storing a copy
281
- # of it if this is the first time we needed it.
282
- def path_lookup_util(version)
283
- unless valid_version?(version)
284
- raise sprintf('Unknown version %s', version)
285
- end
286
- if @path_lookup_utils[version].nil?
287
- path_version = version.downcase
288
- require sprintf('google/ads/google_ads/utils/%s/path_lookup_util',
289
- path_version)
290
- class_path = sprintf(
291
- 'Google::Ads::GoogleAds::Utils::%s::PathLookupUtil',
292
- version
293
- )
294
- @path_lookup_utils[version] = class_for_path(class_path).new(
295
- proto_lookup_util(version))
296
- end
297
- @path_lookup_utils[version]
270
+ def lookup_util
271
+ @lookup_util ||= Google::Ads::GoogleAds::LookupUtil.new
298
272
  end
299
273
 
300
- # Converts complete class path into class object.
301
- def class_for_path(path)
302
- path.split('::').inject(Kernel) do |scope, const_name|
303
- scope.const_get(const_name)
304
- end
274
+ def default_api_version
275
+ Google::Ads::GoogleAds::DEFAULT_API_VERSION
305
276
  end
306
277
  end
307
278
  end
@@ -16,6 +16,8 @@
16
16
  #
17
17
  # Interceptor to log outgoing requests and incoming responses.
18
18
 
19
+ require 'google/ads/google_ads/api_versions'
20
+ require 'google/ads/google_ads/partial_failure_error_decoder'
19
21
  require 'grpc/generic/interceptors'
20
22
  require 'json'
21
23
 
@@ -23,56 +25,126 @@ module Google
23
25
  module Ads
24
26
  module GoogleAds
25
27
  class LoggingInterceptor < GRPC::ClientInterceptor
28
+ INTERESTING_ERROR_CLASSES = ::Google::Ads::GoogleAds::KNOWN_API_VERSIONS.map { |v|
29
+ require "google/ads/google_ads/#{v.downcase}/errors/errors_pb"
30
+ const_get("Google::Ads::GoogleAds::#{v}::Errors::GoogleAdsFailure")
31
+ }
32
+
26
33
  def initialize(logger)
34
+ # Don't propagate args, parens are necessary
27
35
  super()
28
36
  @logger = logger
29
37
  end
30
38
 
31
39
  def request_response(request:, call:, method:, metadata: {})
40
+ begin
41
+ response = yield
42
+
43
+ @logger.info(build_summary_message(request, call, method, false))
44
+ @logger.debug(build_request_message(metadata, request))
45
+ @logger.debug(build_success_response_message(response))
46
+ if response.respond_to?(:partial_failure_error) && response.partial_failure_error
47
+ @logger.warn(build_partial_failure_message(response))
48
+ end
49
+ response
50
+ rescue Exception
51
+ @logger.warn(build_summary_message(request, call, method, true))
52
+ @logger.info(build_request_message(metadata, request))
53
+ @logger.info(build_error_response_message)
54
+ raise
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def build_partial_failure_message(response)
61
+ errors = PartialFailureErrorDecoder.decode(
62
+ response.partial_failure_error
63
+ )
64
+ errors.reduce("Partial failure errors: ") do |accum, error|
65
+ accum += error.to_json + "\n"
66
+ accum
67
+ end
68
+ end
69
+
70
+ def build_error_response_message
71
+ # this looks like "magic", but the Google::Gax::GaxError grabs
72
+ # the current exception as its cause, and then parses details
73
+ # out of that exception. So this sets it up so that
74
+ # most_recent_error.status_details contains useful information about
75
+ # our failure
76
+ most_recent_error = Google::Gax::GaxError.new('')
77
+ response_message = "Incoming response (errors): \n"
78
+
79
+ formatted_details = case most_recent_error.status_details
80
+ when nil
81
+ ""
82
+ when String
83
+ most_recent_error.status_details
84
+ when Array
85
+ most_recent_error.status_details.select { |detail|
86
+ INTERESTING_ERROR_CLASSES.include?(detail.class)
87
+ }.map { |detail|
88
+ response_error_from_detail(detail)
89
+ }.join("\n")
90
+ end
91
+
92
+ response_message += formatted_details
93
+ response_message
94
+ end
95
+
96
+ def build_success_response_message(response)
97
+ "Incoming response: Payload: #{response.to_json}"
98
+ end
99
+
100
+ def build_request_message(metadata, request)
101
+ # calling #to_json on some protos (specifically those with non-UTF8
102
+ # encodable byte values) causes a segfault, however #inspect works
103
+ # so we check if the proto contains a bytevalue, and if it does
104
+ # we #inspect instead of #to_json
105
+ request_inspect = if use_bytes_inspect?(request)
106
+ request.inspect
107
+ else
108
+ request.to_json
109
+ end
110
+ "Outgoing request: Headers: #{metadata.to_json} Payload: #{request_inspect}"
111
+ end
112
+
113
+ def build_summary_message(request, call, method, is_fault)
32
114
  customer_id = "N/A"
33
115
  customer_id = request.customer_id if request.respond_to?(:customer_id)
34
116
  # CustomerService get requests have a different format.
35
117
  if request.respond_to?(:resource_name)
36
118
  customer_id = request.resource_name.split('/').last
37
119
  end
38
- summary_message =
39
- sprintf("CID: %s, Host: %s, Method: %s",
40
- customer_id,
41
- call.instance_variable_get('@wrapped').peer,
42
- method
43
- )
44
- request_message = sprintf("Outgoing request: Headers: %s Payload: %s",
45
- metadata.to_json, request.to_json)
46
- begin
47
- response = yield
48
- summary_message += ", IsFault: no"
49
- response_message = sprintf("Incoming response: Payload: %s",
50
- response.to_json)
51
-
52
- @logger.info(summary_message)
53
- @logger.debug(request_message)
54
- @logger.debug(response_message)
55
- return response
56
- rescue Exception => e
57
- summary_message += sprintf(", IsFault: yes")
58
- response_message = "Incoming response (errors): \n"
59
-
60
- most_recent_error = Google::Gax::GaxError.new('')
61
- most_recent_error.status_details && most_recent_error.status_details.each do |detail|
62
- if detail.is_a?(
63
- Google::Ads::GoogleAds::V0::Errors::GoogleAdsFailure)
64
- detail.errors.each_with_index do |error, i|
65
- response_message +=
66
- sprintf("Error %d: %s\n", i + 1, error.to_json)
67
- end
68
- end
69
- end
70
120
 
71
- @logger.warn(summary_message)
72
- @logger.info(request_message)
73
- @logger.info(response_message)
74
- raise
121
+ is_fault_string = if is_fault
122
+ "yes"
123
+ else
124
+ "no"
75
125
  end
126
+
127
+ [
128
+ "CID: #{customer_id}",
129
+ "Host: #{call.instance_variable_get('@wrapped').peer}",
130
+ "Method: #{method}",
131
+ "IsFault: #{is_fault_string}",
132
+ ].join(", ")
133
+ end
134
+
135
+ def response_error_from_detail(detail)
136
+ detail.errors.map.with_index { |error, i|
137
+ "Error #{i + 1}: #{error.to_json}"
138
+ }.join("\n")
139
+ end
140
+
141
+ def use_bytes_inspect?(request)
142
+ contains_bytes_field?(request.class.descriptor)
143
+ end
144
+
145
+ def contains_bytes_field?(descriptor)
146
+ return false if descriptor.nil?
147
+ descriptor.map { |x| x.type == :bytes || (x.type == :message && contains_bytes_field?(x.subtype)) }.any?
76
148
  end
77
149
  end
78
150
  end
@@ -0,0 +1,105 @@
1
+ module Google
2
+ module Ads
3
+ module GoogleAds
4
+ class LookupUtil
5
+
6
+ def initialize
7
+ @proto_lookup_utils = {}
8
+ @path_lookup_utils = {}
9
+ end
10
+
11
+ # Return a resource or common entity for the provided entity type. For
12
+ # example, passing :Campaign will return an instantiated Campaign.
13
+ #
14
+ # Raises ArgumentError if no entity can be found for the provided type.
15
+ def resource(name, version)
16
+ proto_lookup_util(version).resource(name).new
17
+ end
18
+
19
+ # Return an operation for the provided entity type. For example, passing
20
+ # :Campaign will return an instantiated CampaignOperation.
21
+ #
22
+ # Raises ArgumentError if no entity can be found for the provided type.
23
+ def operation(name, version)
24
+ proto_lookup_util(version).operation(name).new
25
+ end
26
+
27
+ # Return a reference to the enum class for the provided enum type. For
28
+ # example, passing :CampaignStatus will return a reference to the
29
+ # CampaignStatusEnum.
30
+ #
31
+ # Raises ArgumentError if no enum can be found for the provided type.
32
+ def enum(name, version)
33
+ proto_lookup_util(version).enum(name)
34
+ end
35
+
36
+ # Return a service for the provided entity type. For example, passing
37
+ # :Campaign will return an instantiated CampaignServiceClient.
38
+ #
39
+ # Raises ArgumentError if no service can be found for the provided type.
40
+ def raw_service(name, version)
41
+ proto_lookup_util(version).service(name)
42
+ end
43
+
44
+ # Returns a reference to the PathLookupUtil to generate resource names.
45
+ def path(version)
46
+ path_lookup_util(version)
47
+ end
48
+
49
+ private
50
+
51
+ attr_reader :proto_lookup_utils, :path_lookup_utils
52
+
53
+ # Load up the proto lookup util for the given version, storing a copy
54
+ # of it if this is the first time we needed it.
55
+ def proto_lookup_util(version)
56
+ unless valid_version?(version)
57
+ raise sprintf('Unknown version %s', version)
58
+ end
59
+ if proto_lookup_utils[version].nil?
60
+ path_version = version.downcase
61
+ require sprintf('google/ads/google_ads/utils/%s/proto_lookup_util',
62
+ path_version)
63
+ class_path = sprintf(
64
+ 'Google::Ads::GoogleAds::Utils::%s::ProtoLookupUtil',
65
+ version
66
+ )
67
+ proto_lookup_utils[version] = class_for_path(class_path).new
68
+ end
69
+ proto_lookup_utils[version]
70
+ end
71
+
72
+ # Load up the path lookup util for the given version, storing a copy
73
+ # of it if this is the first time we needed it.
74
+ def path_lookup_util(version)
75
+ unless valid_version?(version)
76
+ raise sprintf('Unknown version %s', version)
77
+ end
78
+ if path_lookup_utils[version].nil?
79
+ path_version = version.downcase
80
+ require sprintf('google/ads/google_ads/utils/%s/path_lookup_util',
81
+ path_version)
82
+ class_path = sprintf(
83
+ 'Google::Ads::GoogleAds::Utils::%s::PathLookupUtil',
84
+ version
85
+ )
86
+ path_lookup_utils[version] = class_for_path(class_path).new(
87
+ proto_lookup_util(version))
88
+ end
89
+ path_lookup_utils[version]
90
+ end
91
+
92
+ # Converts complete class path into class object.
93
+ def class_for_path(path)
94
+ path.split('::').inject(Kernel) do |scope, const_name|
95
+ scope.const_get(const_name)
96
+ end
97
+ end
98
+
99
+ def valid_version?(version)
100
+ Google::Ads::GoogleAds.valid_version?(version)
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,24 @@
1
+ module Google
2
+ module Ads
3
+ module GoogleAds
4
+ class PartialFailureErrorDecoder
5
+ # decodes a partial_failure_error (Google::Rpc::Status instance) to
6
+ # an array of meaningful error protos
7
+ #
8
+ # Return an Array of protobuf objects, typed depending on what was
9
+ # in the passed object (which will mostly be Google::Protobuf::Any,
10
+ # so the types could be any valid protobuf type)
11
+ def self.decode(partial_failure_error)
12
+ partial_failure_error.details.select { |detail|
13
+ Google::Protobuf::Any === detail
14
+ }.map { |detail|
15
+ type = Google::Protobuf::DescriptorPool.generated_pool.lookup(
16
+ detail.type_name
17
+ ).msgclass
18
+ detail.unpack(type)
19
+ }
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -272,7 +272,10 @@ module Google
272
272
  KeywordParameters: ['services', 'recommendation_service_pb', 'ApplyRecommendationOperation::KeywordParameters'],
273
273
  TargetCpaOptInParameters: ['services', 'recommendation_service_pb', 'ApplyRecommendationOperation::TargetCpaOptInParameters'],
274
274
  LocationNames: ['services', 'geo_target_constant_service_pb', 'SuggestGeoTargetConstantsRequest::LocationNames'],
275
- GeoTargets: ['services', 'geo_target_constant_service_pb', 'SuggestGeoTargetConstantsRequest::GeoTargets']
275
+ GeoTargets: ['services', 'geo_target_constant_service_pb', 'SuggestGeoTargetConstantsRequest::GeoTargets'],
276
+ KeywordAndUrlSeed: ['services', 'keyword_plan_idea_service_pb', 'KeywordAndUrlSeed'],
277
+ KeywordSeed: ['services', 'keyword_plan_idea_service_pb', 'KeywordSeed'],
278
+ UrlSeed: ['services', 'keyword_plan_idea_service_pb', 'UrlSeed']
276
279
  }.freeze
277
280
 
278
281
  ENUMS = {
@@ -137,6 +137,13 @@ module Google
137
137
  )
138
138
  end
139
139
 
140
+ def asset(customer_id, asset_id)
141
+ @proto_lookup_util.service(:Asset).asset_path(
142
+ customer_id.to_s,
143
+ asset_id.to_s
144
+ )
145
+ end
146
+
140
147
  def bidding_strategy(customer_id, bidding_strategy_id)
141
148
  @proto_lookup_util.service(:BiddingStrategy).
142
149
  bidding_strategy_path(
@@ -601,7 +608,10 @@ module Google
601
608
  end
602
609
 
603
610
  def shopping_performance_view(customer_id)
604
- sprintf('customers/%s/shoppingPerformanceView', customer_id.to_s)
611
+ @proto_lookup_util.service(:ShoppingPerformanceView).
612
+ shopping_performance_view_path(
613
+ customer_id.to_s
614
+ )
605
615
  end
606
616
 
607
617
  def topic_constant(vertical_id)