google-ads-googleads 1.0.0 → 1.1.0

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.
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)