apimatic_core 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -17,7 +17,7 @@ module CoreLibrary
17
17
  hash[key] = {}
18
18
  date_time.each do |k, v|
19
19
  hash[key][k] =
20
- v.is_a?(DateTime) ? DateTimeHelper.to_rfc1123(v) : v
20
+ v.instance_of?(DateTime) ? DateTimeHelper.to_rfc1123(v) : v
21
21
  end
22
22
  hash[key]
23
23
  end
@@ -29,13 +29,13 @@ module CoreLibrary
29
29
  return if date_time.nil?
30
30
 
31
31
  hash[key] = date_time.map do |v|
32
- v.is_a?(DateTime) ? DateTimeHelper.to_rfc1123(v) : v
32
+ v.instance_of?(DateTime) ? DateTimeHelper.to_rfc1123(v) : v
33
33
  end
34
34
  end
35
35
 
36
36
  # Safely converts a DateTime object into a unix format string.
37
37
  # @param [DateTime] date_time The DateTime object.
38
- # @return [String] The unix formatted datetime string.
38
+ # @return [Integer] The unix formatted datetime integer.
39
39
  def self.to_unix(date_time)
40
40
  date_time.to_time.utc.to_i unless date_time.nil?
41
41
  end
@@ -49,7 +49,7 @@ module CoreLibrary
49
49
  hash[key] = {}
50
50
  date_time.each do |k, v|
51
51
  hash[key][k] =
52
- v.is_a?(DateTime) ? DateTimeHelper.to_unix(v) : v
52
+ v.instance_of?(DateTime) ? DateTimeHelper.to_unix(v) : v
53
53
  end
54
54
  hash[key]
55
55
  end
@@ -61,7 +61,7 @@ module CoreLibrary
61
61
  return if date_time.nil?
62
62
 
63
63
  hash[key] = date_time.map do |v|
64
- v.is_a?(DateTime) ? DateTimeHelper.to_unix(v) : v
64
+ v.instance_of?(DateTime) ? DateTimeHelper.to_unix(v) : v
65
65
  end
66
66
  end
67
67
 
@@ -81,7 +81,7 @@ module CoreLibrary
81
81
  hash[key] = {}
82
82
  date_time.each do |k, v|
83
83
  hash[key][k] =
84
- v.is_a?(DateTime) ? DateTimeHelper.to_rfc3339(v) : v
84
+ v.instance_of?(DateTime) ? DateTimeHelper.to_rfc3339(v) : v
85
85
  end
86
86
  hash[key]
87
87
  end
@@ -93,7 +93,7 @@ module CoreLibrary
93
93
  return if date_time.nil?
94
94
 
95
95
  hash[key] = date_time.map do |v|
96
- v.is_a?(DateTime) ? DateTimeHelper.to_rfc3339(v) : v
96
+ v.instance_of?(DateTime) ? DateTimeHelper.to_rfc3339(v) : v
97
97
  end
98
98
  end
99
99
 
@@ -122,5 +122,52 @@ module CoreLibrary
122
122
  DateTime.rfc3339("#{date_time}Z")
123
123
  end
124
124
  end
125
+
126
+ def self.valid_datetime?(dt_format, dt)
127
+ case dt_format
128
+ when DateTimeFormat::HTTP_DATE_TIME
129
+ return DateTimeHelper.rfc_1123?(dt)
130
+ when DateTimeFormat::RFC3339_DATE_TIME
131
+ return DateTimeHelper.rfc_3339?(dt)
132
+ when DateTimeFormat::UNIX_DATE_TIME
133
+ return DateTimeHelper.unix_timestamp?(dt)
134
+ end
135
+
136
+ false
137
+ end
138
+
139
+ def self.valid_date?(date_value)
140
+ if date_value.instance_of?(Date)
141
+ true
142
+ elsif date_value.instance_of?(String) && date_value.match?(/^\d{4}-\d{2}-\d{2}$/)
143
+ DateTime.strptime(date_value, '%Y-%m-%d')
144
+ true
145
+ else
146
+ false
147
+ end
148
+ rescue ArgumentError
149
+ false
150
+ end
151
+
152
+ def self.rfc_1123?(datetime_value)
153
+ DateTime.strptime(datetime_value, '%a, %d %b %Y %H:%M:%S %Z')
154
+ true
155
+ rescue ArgumentError, TypeError
156
+ false
157
+ end
158
+
159
+ def self.rfc_3339?(datetime_value)
160
+ DateTime.strptime(datetime_value, '%Y-%m-%dT%H:%M:%S')
161
+ true
162
+ rescue ArgumentError, TypeError
163
+ false
164
+ end
165
+
166
+ def self.unix_timestamp?(timestamp)
167
+ Time.at(Float(timestamp))
168
+ true
169
+ rescue ArgumentError, TypeError
170
+ false
171
+ end
125
172
  end
126
173
  end
@@ -0,0 +1,298 @@
1
+ module CoreLibrary
2
+ # Helper methods for handling union types.
3
+ class UnionTypeHelper
4
+ NONE_MATCHED_ERROR_MESSAGE = 'We could not match any acceptable types against the given JSON.'.freeze
5
+ MORE_THAN_1_MATCHED_ERROR_MESSAGE = 'There are more than one acceptable type matched against the given JSON.'.freeze
6
+
7
+ def self.validate_array_of_dict_case(union_types, array_value, is_for_one_of)
8
+ return [false, []] if invalid_array_value?(array_value)
9
+
10
+ collection_cases = []
11
+ valid_cases = []
12
+ array_value.each do |item|
13
+ case_validity, inner_dictionary = validate_dict_case(union_types, item, is_for_one_of)
14
+ collection_cases << inner_dictionary
15
+ valid_cases << case_validity
16
+ end
17
+ is_valid = valid_cases.count(true) == array_value.size
18
+ [is_valid, collection_cases]
19
+ end
20
+
21
+ def self.validate_dict_of_array_case(union_types, dict_value, is_for_one_of)
22
+ return [false, []] if invalid_dict_value?(dict_value)
23
+
24
+ collection_cases = {}
25
+ valid_cases = []
26
+ dict_value.each do |key, item|
27
+ case_validity, inner_array = validate_array_case(union_types, item, is_for_one_of)
28
+ collection_cases[key] = inner_array
29
+ valid_cases << case_validity
30
+ end
31
+ is_valid = valid_cases.count(true) == dict_value.size
32
+ [is_valid, collection_cases]
33
+ end
34
+
35
+ def self.validate_dict_case(union_types, dict_value, is_for_one_of)
36
+ return [false, []] if invalid_dict_value?(dict_value)
37
+
38
+ is_valid, collection_cases = process_dict_items(union_types, dict_value, is_for_one_of)
39
+
40
+ [is_valid, collection_cases]
41
+ end
42
+
43
+ def self.process_dict_items(union_types, dict_value, is_for_one_of)
44
+ is_valid = true
45
+ collection_cases = {}
46
+
47
+ dict_value.each do |key, value|
48
+ union_type_cases = make_deep_copies(union_types)
49
+ matched_count = get_matched_count(value, union_type_cases, is_for_one_of)
50
+ is_valid = check_item_validity(is_for_one_of, is_valid, matched_count)
51
+ collection_cases[key] = union_type_cases
52
+ end
53
+
54
+ [is_valid, collection_cases]
55
+ end
56
+
57
+ def self.validate_array_case(union_types, array_value, is_for_one_of)
58
+ return [false, []] if invalid_array_value?(array_value)
59
+
60
+ is_valid, collection_cases = process_array_items(union_types, array_value, is_for_one_of)
61
+
62
+ [is_valid, collection_cases]
63
+ end
64
+
65
+ def self.process_array_items(union_types, array_value, is_for_one_of)
66
+ is_valid = true
67
+ collection_cases = []
68
+
69
+ array_value.each do |item|
70
+ union_type_cases = make_deep_copies(union_types)
71
+ matched_count = get_matched_count(item, union_type_cases, is_for_one_of)
72
+ is_valid = check_item_validity(is_for_one_of, is_valid, matched_count)
73
+ collection_cases << union_type_cases
74
+ end
75
+
76
+ [is_valid, collection_cases]
77
+ end
78
+
79
+ def self.check_item_validity(is_for_one_of, is_valid, matched_count)
80
+ if is_valid && is_for_one_of
81
+ is_valid = matched_count == 1
82
+ elsif is_valid
83
+ is_valid = matched_count >= 1
84
+ end
85
+ is_valid
86
+ end
87
+
88
+ def self.make_deep_copies(union_types)
89
+ nested_cases = []
90
+ union_types.each do |union_type|
91
+ nested_cases << union_type.dup
92
+ end
93
+ nested_cases
94
+ end
95
+
96
+ def self.get_matched_count(value, union_types, is_for_one_of)
97
+ matched_count = get_valid_cases_count(value, union_types)
98
+
99
+ if is_for_one_of && matched_count == 1
100
+ return matched_count
101
+ elsif !is_for_one_of && matched_count.positive?
102
+ return matched_count
103
+ end
104
+
105
+ matched_count = handle_discriminator_cases(value, union_types)
106
+ matched_count
107
+ end
108
+
109
+ def self.get_valid_cases_count(value, union_types)
110
+ union_types.count { |union_type| union_type.validate(value).is_valid }
111
+ end
112
+
113
+ def self.handle_discriminator_cases(value, union_types)
114
+ has_discriminator_cases = union_types.all? do |union_type|
115
+ union_type.union_type_context.discriminator && union_type.union_type_context.discriminator_value
116
+ end
117
+
118
+ if has_discriminator_cases
119
+ union_types.each do |union_type|
120
+ union_type.union_type_context.discriminator = nil
121
+ union_type.union_type_context.discriminator_value = nil
122
+ end
123
+
124
+ get_valid_cases_count(value, union_types)
125
+ else
126
+ 0
127
+ end
128
+ end
129
+
130
+ def self.optional_or_nullable_case?(current_context, inner_contexts)
131
+ current_context.nullable_or_optional? || inner_contexts.any?(&:nullable_or_optional?)
132
+ end
133
+
134
+ def self.update_nested_flag_for_union_types(nested_union_types)
135
+ nested_union_types.each do |union_type|
136
+ union_type.union_type_context.is_nested = true
137
+ end
138
+ end
139
+
140
+ def self.invalid_array_value?(value)
141
+ value.nil? || !value.instance_of?(Array)
142
+ end
143
+
144
+ def self.invalid_dict_value?(value)
145
+ value.nil? || !value.instance_of?(Hash)
146
+ end
147
+
148
+ def self.serialize_value(value, context, collection_cases, union_types)
149
+ return serialize_array_of_dict_case(value, collection_cases) if
150
+ context.is_array && context.is_dict && context.is_array_of_dict
151
+
152
+ return serialize_dict_of_array_case(value, collection_cases) if
153
+ context.is_array && context.is_dict
154
+
155
+ return serialize_array_case(value, collection_cases) if context.is_array
156
+
157
+ return serialize_dict_case(value, collection_cases) if context.is_dict
158
+
159
+ get_serialized_value(union_types, value)
160
+ end
161
+
162
+ def self.serialize_array_of_dict_case(array_value, collection_cases)
163
+ serialized_value = []
164
+ array_value.each_with_index do |item, index|
165
+ serialized_value << serialize_dict_case(item, collection_cases[index])
166
+ end
167
+ serialized_value
168
+ end
169
+
170
+ def self.serialize_dict_of_array_case(dict_value, collection_cases)
171
+ serialized_value = {}
172
+ dict_value.each do |key, value|
173
+ serialized_value[key] = serialize_array_case(value, collection_cases[key])
174
+ end
175
+ serialized_value
176
+ end
177
+
178
+ def self.serialize_dict_case(dict_value, collection_cases)
179
+ serialized_value = {}
180
+ dict_value.each do |key, value|
181
+ valid_case = collection_cases[key].find(&:is_valid)
182
+ serialized_value[key] = valid_case.serialize(value)
183
+ end
184
+ serialized_value
185
+ end
186
+
187
+ def self.serialize_array_case(array_value, collection_cases)
188
+ serialized_value = []
189
+ array_value.each_with_index do |item, index|
190
+ valid_case = collection_cases[index].find(&:is_valid)
191
+ serialized_value << valid_case.serialize(item)
192
+ end
193
+ serialized_value
194
+ end
195
+
196
+ def self.get_serialized_value(union_types, value)
197
+ union_types.find(&:is_valid).serialize(value)
198
+ end
199
+
200
+ def self.deserialize_value(value, context, collection_cases, union_types, should_symbolize: false)
201
+ return deserialize_array_of_dict_case(value, collection_cases, should_symbolize: should_symbolize) if
202
+ context.is_array && context.is_dict && context.is_array_of_dict
203
+
204
+ return deserialize_dict_of_array_case(value, collection_cases, should_symbolize: should_symbolize) if
205
+ context.is_array && context.is_dict
206
+
207
+ return deserialize_array_case(value, collection_cases, should_symbolize: should_symbolize) if context.is_array
208
+ return deserialize_dict_case(value, collection_cases, should_symbolize: should_symbolize) if context.is_dict
209
+
210
+ get_deserialized_value(union_types, value, should_symbolize: should_symbolize)
211
+ end
212
+
213
+ def self.deserialize_array_of_dict_case(array_value, collection_cases, should_symbolize: false)
214
+ deserialized_value = []
215
+ array_value.each_with_index do |item, index|
216
+ deserialized_value << deserialize_dict_case(item, collection_cases[index], should_symbolize: should_symbolize)
217
+ end
218
+ deserialized_value
219
+ end
220
+
221
+ def self.deserialize_dict_of_array_case(dict_value, collection_cases, should_symbolize: false)
222
+ deserialized_value = {}
223
+ dict_value.each do |key, value|
224
+ deserialized_value[key] = deserialize_array_case(
225
+ value,
226
+ collection_cases[key],
227
+ should_symbolize: should_symbolize
228
+ )
229
+ end
230
+ deserialized_value
231
+ end
232
+
233
+ def self.deserialize_dict_case(dict_value, collection_cases, should_symbolize: false)
234
+ deserialized_value = {}
235
+ dict_value.each do |key, value|
236
+ valid_case = collection_cases[key].find(&:is_valid)
237
+ deserialized_value[key] = valid_case.deserialize(value, should_symbolize: should_symbolize)
238
+ end
239
+ deserialized_value
240
+ end
241
+
242
+ def self.deserialize_array_case(array_value, collection_cases, should_symbolize: false)
243
+ deserialized_value = []
244
+ array_value.each_with_index do |item, index|
245
+ valid_case = collection_cases[index].find(&:is_valid)
246
+ deserialized_value << valid_case.deserialize(item, should_symbolize: should_symbolize)
247
+ end
248
+ deserialized_value
249
+ end
250
+
251
+ def self.get_deserialized_value(union_types, value, should_symbolize: false)
252
+ union_types.find(&:is_valid).deserialize(value, should_symbolize: should_symbolize)
253
+ end
254
+
255
+ def self.process_errors(value, union_types, error_messages, is_nested, is_for_one_of)
256
+ error_messages << UnionTypeHelper.get_combined_error_messages(union_types).join(', ')
257
+
258
+ unless is_nested
259
+ UnionTypeHelper.raise_validation_exception(
260
+ value,
261
+ union_types,
262
+ error_messages.to_a.join(', '),
263
+ is_for_one_of
264
+ )
265
+ end
266
+
267
+ error_messages
268
+ end
269
+
270
+ def self.get_combined_error_messages(union_types)
271
+ combined_error_messages = []
272
+ union_types.each do |union_type|
273
+ if union_type.instance_of?(LeafType)
274
+ combined_error_messages << union_type.type_to_match.name
275
+ elsif union_type.error_messages
276
+ combined_error_messages << union_type.error_messages.to_a.join(', ')
277
+ end
278
+ end
279
+ combined_error_messages
280
+ end
281
+
282
+ def self.raise_validation_exception(value, union_types, error_message, is_for_one_of)
283
+ unless is_for_one_of
284
+ raise AnyOfValidationException,
285
+ "#{UnionTypeHelper::NONE_MATCHED_ERROR_MESSAGE}" \
286
+ "\nActual Value: #{ApiHelper.json_serialize(value)}\nExpected Type: Any Of #{error_message}."
287
+
288
+ end
289
+
290
+ matched_count = union_types.count(&:is_valid)
291
+ message = matched_count > 0 ?
292
+ UnionTypeHelper::MORE_THAN_1_MATCHED_ERROR_MESSAGE : UnionTypeHelper::NONE_MATCHED_ERROR_MESSAGE
293
+
294
+ raise OneOfValidationException,
295
+ "#{message}\nActual Value: #{ApiHelper.json_serialize(value)}\nExpected Type: One Of #{error_message}."
296
+ end
297
+ end
298
+ end
data/lib/apimatic_core.rb CHANGED
@@ -14,6 +14,8 @@ require_relative 'apimatic-core/factories/http_response_factory'
14
14
  require_relative 'apimatic-core/configurations/global_configuration'
15
15
 
16
16
  require_relative 'apimatic-core/exceptions/invalid_auth_credential'
17
+ require_relative 'apimatic-core/exceptions/any_of_validation_exception'
18
+ require_relative 'apimatic-core/exceptions/one_of_validation_exception'
17
19
 
18
20
  require_relative 'apimatic-core/logger/endpoint_logger'
19
21
 
@@ -30,12 +32,18 @@ require_relative 'apimatic-core/types/sdk/validation_exception'
30
32
  require_relative 'apimatic-core/types/sdk/api_exception'
31
33
  require_relative 'apimatic-core/types/xml_attributes'
32
34
 
35
+ require_relative 'apimatic-core/types/union_types/leaf_type'
36
+ require_relative 'apimatic-core/types/union_types/any_of'
37
+ require_relative 'apimatic-core/types/union_types/one_of'
38
+ require_relative 'apimatic-core/types/union_types/union_type_context'
39
+
33
40
  require_relative 'apimatic-core/utilities/api_helper'
34
41
  require_relative 'apimatic-core/utilities/date_time_helper'
35
42
  require_relative 'apimatic-core/utilities/comparison_helper'
36
43
  require_relative 'apimatic-core/utilities/file_helper'
37
44
  require_relative 'apimatic-core/utilities/xml_helper'
38
45
  require_relative 'apimatic-core/utilities/auth_helper'
46
+ require_relative 'apimatic-core/utilities/union_type_helper'
39
47
 
40
48
  require_relative 'apimatic-core/authentication/header_auth'
41
49
  require_relative 'apimatic-core/authentication/query_auth'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: apimatic_core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - APIMatic Ltd.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-04-04 00:00:00.000000000 Z
11
+ date: 2023-07-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: apimatic_core_interfaces
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.1.0
19
+ version: 0.2.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.1.0
26
+ version: 0.2.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: nokogiri
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -179,7 +179,9 @@ files:
179
179
  - lib/apimatic-core/authentication/multiple/single_auth.rb
180
180
  - lib/apimatic-core/authentication/query_auth.rb
181
181
  - lib/apimatic-core/configurations/global_configuration.rb
182
+ - lib/apimatic-core/exceptions/any_of_validation_exception.rb
182
183
  - lib/apimatic-core/exceptions/invalid_auth_credential.rb
184
+ - lib/apimatic-core/exceptions/one_of_validation_exception.rb
183
185
  - lib/apimatic-core/factories/http_response_factory.rb
184
186
  - lib/apimatic-core/http/configurations/http_client_configuration.rb
185
187
  - lib/apimatic-core/http/request/http_request.rb
@@ -194,12 +196,17 @@ files:
194
196
  - lib/apimatic-core/types/sdk/base_model.rb
195
197
  - lib/apimatic-core/types/sdk/file_wrapper.rb
196
198
  - lib/apimatic-core/types/sdk/validation_exception.rb
199
+ - lib/apimatic-core/types/union_types/any_of.rb
200
+ - lib/apimatic-core/types/union_types/leaf_type.rb
201
+ - lib/apimatic-core/types/union_types/one_of.rb
202
+ - lib/apimatic-core/types/union_types/union_type_context.rb
197
203
  - lib/apimatic-core/types/xml_attributes.rb
198
204
  - lib/apimatic-core/utilities/api_helper.rb
199
205
  - lib/apimatic-core/utilities/auth_helper.rb
200
206
  - lib/apimatic-core/utilities/comparison_helper.rb
201
207
  - lib/apimatic-core/utilities/date_time_helper.rb
202
208
  - lib/apimatic-core/utilities/file_helper.rb
209
+ - lib/apimatic-core/utilities/union_type_helper.rb
203
210
  - lib/apimatic-core/utilities/xml_helper.rb
204
211
  - lib/apimatic_core.rb
205
212
  homepage: https://apimatic.io