workato-connector-sdk 1.1.0 → 1.3.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.
- checksums.yaml +4 -4
- data/README.md +3 -2
- data/VERSION +1 -0
- data/lib/workato/cli/edit_command.rb +3 -1
- data/lib/workato/cli/exec_command.rb +103 -17
- data/lib/workato/cli/generate_command.rb +2 -2
- data/lib/workato/cli/main.rb +17 -10
- data/lib/workato/cli/multi_auth_selected_fallback.rb +33 -0
- data/lib/workato/cli/oauth2_command.rb +50 -12
- data/lib/workato/cli/push_command.rb +2 -2
- data/lib/workato/cli/schema_command.rb +2 -2
- data/lib/workato/connector/sdk/account_properties.rb +2 -2
- data/lib/workato/connector/sdk/action.rb +20 -70
- data/lib/workato/connector/sdk/block_invocation_refinements.rb +2 -10
- data/lib/workato/connector/sdk/connection.rb +115 -30
- data/lib/workato/connector/sdk/connector.rb +71 -81
- data/lib/workato/connector/sdk/core.rb +62 -0
- data/lib/workato/connector/sdk/dsl/aws.rb +8 -5
- data/lib/workato/connector/sdk/dsl/call.rb +1 -1
- data/lib/workato/connector/sdk/dsl/csv_package.rb +133 -0
- data/lib/workato/connector/sdk/dsl/execution_context.rb +45 -0
- data/lib/workato/connector/sdk/dsl/http.rb +1 -1
- data/lib/workato/connector/sdk/dsl/reinvoke_after.rb +84 -0
- data/lib/workato/connector/sdk/dsl/stream_package.rb +65 -0
- data/lib/workato/connector/sdk/dsl/time.rb +0 -14
- data/lib/workato/connector/sdk/dsl/workato_package.rb +146 -0
- data/lib/workato/connector/sdk/dsl.rb +64 -10
- data/lib/workato/connector/sdk/errors.rb +37 -9
- data/lib/workato/connector/sdk/lookup_tables.rb +3 -1
- data/lib/workato/connector/sdk/operation.rb +33 -10
- data/lib/workato/connector/sdk/request.rb +149 -69
- data/lib/workato/connector/sdk/schema/field/convertors.rb +2 -2
- data/lib/workato/connector/sdk/schema/type/unicode_string.rb +1 -1
- data/lib/workato/connector/sdk/schema.rb +12 -8
- data/lib/workato/connector/sdk/settings.rb +14 -3
- data/lib/workato/connector/sdk/stream.rb +243 -0
- data/lib/workato/connector/sdk/streams.rb +71 -0
- data/lib/workato/connector/sdk/summarize.rb +2 -2
- data/lib/workato/connector/sdk/trigger.rb +23 -15
- data/lib/workato/connector/sdk/version.rb +1 -1
- data/lib/workato/connector/sdk.rb +21 -47
- data/lib/workato/extension/array.rb +2 -0
- data/lib/workato/extension/case_sensitive_headers.rb +0 -26
- data/lib/workato/extension/content_encoding_decoder.rb +69 -0
- data/lib/workato/extension/currency/countries.rb +79 -0
- data/lib/workato/extension/currency/countries.yml +18433 -0
- data/lib/workato/extension/currency/currencies.rb +55 -0
- data/lib/workato/extension/currency/currencies.yml +479 -0
- data/lib/workato/extension/currency.rb +73 -5
- data/lib/workato/extension/enumerable.rb +2 -2
- data/lib/workato/extension/extra_chain_cert.rb +0 -14
- data/lib/workato/extension/hash_with_indifferent_access.rb +19 -0
- data/lib/workato/extension/metadata_fix_wrap_kw_args.rb +11 -0
- data/lib/workato/extension/string.rb +16 -112
- data/lib/workato/testing/vcr_encrypted_cassette_serializer.rb +2 -0
- data/lib/workato/types/binary.rb +55 -0
- data/lib/workato/{connector/sdk → utilities}/xml.rb +4 -4
- metadata +61 -64
- data/lib/workato/connector/sdk/dsl/workato_code_lib.rb +0 -160
@@ -1,6 +1,8 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
using Workato::Extension::HashWithIndifferentAccess
|
5
|
+
|
4
6
|
module Workato
|
5
7
|
module Connector
|
6
8
|
module Sdk
|
@@ -21,15 +23,10 @@ module Workato
|
|
21
23
|
|
22
24
|
sig { params(definition: SorbetTypes::SourceHash, settings: SorbetTypes::SettingsHash).void }
|
23
25
|
def initialize(definition, settings = {})
|
24
|
-
@source = T.let(definition
|
25
|
-
@settings = T.let(settings
|
26
|
-
@connection_source = T.let(@source[:connection]
|
27
|
-
@methods_source = T.let(@source[:methods]
|
28
|
-
end
|
29
|
-
|
30
|
-
sig { params(path: String, params: T::Hash[Symbol, T.untyped]).returns(T.untyped) }
|
31
|
-
def invoke(path, params = {})
|
32
|
-
InvokePath.new(path: path, connector: self, params: params).call
|
26
|
+
@source = T.let(HashWithIndifferentAccess.wrap(definition), HashWithIndifferentAccess)
|
27
|
+
@settings = T.let(HashWithIndifferentAccess.wrap(settings), HashWithIndifferentAccess)
|
28
|
+
@connection_source = T.let(HashWithIndifferentAccess.wrap(@source[:connection]), HashWithIndifferentAccess)
|
29
|
+
@methods_source = T.let(HashWithIndifferentAccess.wrap(@source[:methods]), HashWithIndifferentAccess)
|
33
30
|
end
|
34
31
|
|
35
32
|
sig { returns(T.nilable(String)) }
|
@@ -44,7 +41,8 @@ module Workato
|
|
44
41
|
actions: source[:actions].presence || {},
|
45
42
|
methods: methods_source,
|
46
43
|
object_definitions: object_definitions,
|
47
|
-
connection: connection
|
44
|
+
connection: connection,
|
45
|
+
streams: streams
|
48
46
|
)
|
49
47
|
end
|
50
48
|
|
@@ -53,7 +51,8 @@ module Workato
|
|
53
51
|
@methods = T.let(@methods, T.nilable(MethodsProxy))
|
54
52
|
@methods ||= MethodsProxy.new(
|
55
53
|
methods: methods_source,
|
56
|
-
connection: connection
|
54
|
+
connection: connection,
|
55
|
+
streams: streams
|
57
56
|
)
|
58
57
|
end
|
59
58
|
|
@@ -77,7 +76,8 @@ module Workato
|
|
77
76
|
triggers: source[:triggers].presence || {},
|
78
77
|
methods: methods_source,
|
79
78
|
connection: connection,
|
80
|
-
object_definitions: object_definitions
|
79
|
+
object_definitions: object_definitions,
|
80
|
+
streams: streams
|
81
81
|
)
|
82
82
|
end
|
83
83
|
|
@@ -111,8 +111,34 @@ module Workato
|
|
111
111
|
)
|
112
112
|
end
|
113
113
|
|
114
|
+
sig { returns(Streams) }
|
115
|
+
def streams
|
116
|
+
@streams = T.let(@streams, T.nilable(Streams))
|
117
|
+
@streams ||= Streams.new(
|
118
|
+
streams: streams_sources,
|
119
|
+
methods: methods_source,
|
120
|
+
connection: connection
|
121
|
+
)
|
122
|
+
end
|
123
|
+
|
114
124
|
private
|
115
125
|
|
126
|
+
sig { returns(HashWithIndifferentAccess) }
|
127
|
+
def streams_sources
|
128
|
+
@streams_sources = T.let(@streams_sources, T.nilable(HashWithIndifferentAccess))
|
129
|
+
return @streams_sources if @streams_sources
|
130
|
+
|
131
|
+
@streams_sources = HashWithIndifferentAccess.new
|
132
|
+
@streams_sources.merge!(source[:streams].presence || {})
|
133
|
+
(source[:actions] || {}).values.map do |action|
|
134
|
+
@streams_sources.merge!(action[:streams] || {})
|
135
|
+
end
|
136
|
+
(source[:trigger] || {}).values.map do |trigger|
|
137
|
+
@streams_sources.merge!(trigger[:streams] || {})
|
138
|
+
end
|
139
|
+
@streams_sources
|
140
|
+
end
|
141
|
+
|
116
142
|
sig { returns(HashWithIndifferentAccess) }
|
117
143
|
attr_reader :methods_source
|
118
144
|
|
@@ -131,18 +157,20 @@ module Workato
|
|
131
157
|
actions: HashWithIndifferentAccess,
|
132
158
|
object_definitions: ObjectDefinitions,
|
133
159
|
methods: HashWithIndifferentAccess,
|
134
|
-
connection: Connection
|
160
|
+
connection: Connection,
|
161
|
+
streams: Streams
|
135
162
|
).void
|
136
163
|
end
|
137
|
-
def initialize(actions:, object_definitions:, methods:, connection:)
|
164
|
+
def initialize(actions:, object_definitions:, methods:, connection:, streams:)
|
138
165
|
@methods = methods
|
139
166
|
@connection = connection
|
140
167
|
@object_definitions = object_definitions
|
168
|
+
@streams = streams
|
141
169
|
@actions = T.let({}, T::Hash[T.any(Symbol, String), Action])
|
142
170
|
define_action_methods(actions)
|
143
171
|
end
|
144
172
|
|
145
|
-
sig { params(action: T.any(Symbol, String)).returns(
|
173
|
+
sig { params(action: T.any(Symbol, String)).returns(Action) }
|
146
174
|
def [](action)
|
147
175
|
public_send(action)
|
148
176
|
end
|
@@ -155,6 +183,9 @@ module Workato
|
|
155
183
|
sig { returns(Connection) }
|
156
184
|
attr_reader :connection
|
157
185
|
|
186
|
+
sig { returns(Streams) }
|
187
|
+
attr_reader :streams
|
188
|
+
|
158
189
|
sig { returns(ObjectDefinitions) }
|
159
190
|
attr_reader :object_definitions
|
160
191
|
|
@@ -166,7 +197,8 @@ module Workato
|
|
166
197
|
action: definition,
|
167
198
|
object_definitions: object_definitions,
|
168
199
|
methods: methods,
|
169
|
-
connection: connection
|
200
|
+
connection: connection,
|
201
|
+
streams: streams
|
170
202
|
)
|
171
203
|
return @actions[action] if input_.nil?
|
172
204
|
|
@@ -182,12 +214,14 @@ module Workato
|
|
182
214
|
sig do
|
183
215
|
params(
|
184
216
|
methods: HashWithIndifferentAccess,
|
185
|
-
connection: Connection
|
217
|
+
connection: Connection,
|
218
|
+
streams: Streams
|
186
219
|
).void
|
187
220
|
end
|
188
|
-
def initialize(methods:, connection:)
|
221
|
+
def initialize(methods:, connection:, streams:)
|
189
222
|
@methods = methods
|
190
223
|
@connection = connection
|
224
|
+
@streams = streams
|
191
225
|
@actions = T.let({}, T::Hash[T.any(Symbol, String), Action])
|
192
226
|
define_action_methods
|
193
227
|
end
|
@@ -200,6 +234,9 @@ module Workato
|
|
200
234
|
sig { returns(Connection) }
|
201
235
|
attr_reader :connection
|
202
236
|
|
237
|
+
sig { returns(Streams) }
|
238
|
+
attr_reader :streams
|
239
|
+
|
203
240
|
sig { void }
|
204
241
|
def define_action_methods
|
205
242
|
methods.each do |method, _definition|
|
@@ -209,7 +246,8 @@ module Workato
|
|
209
246
|
execute: -> { T.unsafe(self).call(method, *args) }
|
210
247
|
},
|
211
248
|
methods: methods,
|
212
|
-
connection: connection
|
249
|
+
connection: connection,
|
250
|
+
streams: streams
|
213
251
|
)
|
214
252
|
T.must(@actions[method]).execute
|
215
253
|
end
|
@@ -276,17 +314,24 @@ module Workato
|
|
276
314
|
triggers: HashWithIndifferentAccess,
|
277
315
|
object_definitions: ObjectDefinitions,
|
278
316
|
methods: HashWithIndifferentAccess,
|
279
|
-
connection: Connection
|
317
|
+
connection: Connection,
|
318
|
+
streams: Streams
|
280
319
|
).void
|
281
320
|
end
|
282
|
-
def initialize(triggers:, object_definitions:, methods:, connection:)
|
321
|
+
def initialize(triggers:, object_definitions:, methods:, connection:, streams:)
|
283
322
|
@methods = methods
|
284
323
|
@connection = connection
|
285
324
|
@object_definitions = object_definitions
|
325
|
+
@streams = streams
|
286
326
|
@triggers = T.let({}, T::Hash[T.any(Symbol, String), Trigger])
|
287
327
|
define_trigger_methods(triggers)
|
288
328
|
end
|
289
329
|
|
330
|
+
sig { params(trigger: T.any(Symbol, String)).returns(Trigger) }
|
331
|
+
def [](trigger)
|
332
|
+
public_send(trigger)
|
333
|
+
end
|
334
|
+
|
290
335
|
private
|
291
336
|
|
292
337
|
sig { returns(HashWithIndifferentAccess) }
|
@@ -295,6 +340,9 @@ module Workato
|
|
295
340
|
sig { returns(Connection) }
|
296
341
|
attr_reader :connection
|
297
342
|
|
343
|
+
sig { returns(Streams) }
|
344
|
+
attr_reader :streams
|
345
|
+
|
298
346
|
sig { returns(ObjectDefinitions) }
|
299
347
|
attr_reader :object_definitions
|
300
348
|
|
@@ -306,7 +354,8 @@ module Workato
|
|
306
354
|
trigger: definition,
|
307
355
|
object_definitions: object_definitions,
|
308
356
|
methods: methods,
|
309
|
-
connection: connection
|
357
|
+
connection: connection,
|
358
|
+
streams: streams
|
310
359
|
)
|
311
360
|
|
312
361
|
return @triggers[trigger] if input_.nil?
|
@@ -316,65 +365,6 @@ module Workato
|
|
316
365
|
end
|
317
366
|
end
|
318
367
|
end
|
319
|
-
|
320
|
-
class InvokePath
|
321
|
-
extend T::Sig
|
322
|
-
|
323
|
-
sig do
|
324
|
-
params(
|
325
|
-
path: String,
|
326
|
-
connector: Connector,
|
327
|
-
params: T::Hash[Symbol, T.untyped]
|
328
|
-
).void
|
329
|
-
end
|
330
|
-
def initialize(path:, connector:, params:)
|
331
|
-
@path = T.let(path, String)
|
332
|
-
@connector = T.let(connector, Connector)
|
333
|
-
@params = T.let(params, T::Hash[Symbol, T.untyped])
|
334
|
-
end
|
335
|
-
|
336
|
-
sig { returns(T.untyped) }
|
337
|
-
def call
|
338
|
-
invoke_path
|
339
|
-
end
|
340
|
-
|
341
|
-
private
|
342
|
-
|
343
|
-
sig { returns(String) }
|
344
|
-
attr_reader :path
|
345
|
-
|
346
|
-
sig { returns(Connector) }
|
347
|
-
attr_reader :connector
|
348
|
-
|
349
|
-
sig { returns(T::Hash[Symbol, T.untyped]) }
|
350
|
-
attr_reader :params
|
351
|
-
|
352
|
-
sig { returns(T.untyped) }
|
353
|
-
def invoke_path
|
354
|
-
methods = path.split('.')
|
355
|
-
method = methods.pop
|
356
|
-
raise ArgumentError, 'path is not found' unless method
|
357
|
-
|
358
|
-
object = methods.inject(connector) { |obj, m| obj.public_send(m) }
|
359
|
-
output = invoke_method(object, method)
|
360
|
-
if output.respond_to?(:invoke)
|
361
|
-
invoke_method(output, :invoke)
|
362
|
-
else
|
363
|
-
output
|
364
|
-
end
|
365
|
-
end
|
366
|
-
|
367
|
-
sig { params(object: T.untyped, method: T.any(Symbol, String)).returns(T.untyped) }
|
368
|
-
def invoke_method(object, method)
|
369
|
-
parameters = object.method(method).parameters.reject { |p| p[0] == :block }.map(&:second)
|
370
|
-
args = params.values_at(*parameters)
|
371
|
-
if parameters.last == :args
|
372
|
-
args = args.take(args.length - 1) + Array.wrap(args.last).flatten(1)
|
373
|
-
end
|
374
|
-
object.public_send(method, *args)
|
375
|
-
end
|
376
|
-
end
|
377
|
-
private_constant :InvokePath
|
378
368
|
end
|
379
369
|
end
|
380
370
|
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'sorbet-runtime'
|
5
|
+
require 'active_support'
|
6
|
+
require 'active_support/core_ext/object/deep_dup'
|
7
|
+
require 'active_support/core_ext/object/try'
|
8
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
9
|
+
require 'active_support/core_ext/array/wrap'
|
10
|
+
require 'active_support/core_ext/array/access'
|
11
|
+
require 'active_support/core_ext/numeric/bytes'
|
12
|
+
require 'active_support/core_ext/numeric/conversions'
|
13
|
+
require 'active_support/core_ext/numeric/time'
|
14
|
+
|
15
|
+
module Workato
|
16
|
+
module Connector
|
17
|
+
module Sdk
|
18
|
+
DEFAULT_MASTER_KEY_ENV = 'WORKATO_CONNECTOR_MASTER_KEY'
|
19
|
+
DEFAULT_MASTER_KEY_PATH = 'master.key'
|
20
|
+
|
21
|
+
DEFAULT_CONNECTOR_PATH = 'connector.rb'
|
22
|
+
|
23
|
+
DEFAULT_SETTINGS_PATH = 'settings.yaml'
|
24
|
+
DEFAULT_ENCRYPTED_SETTINGS_PATH = 'settings.yaml.enc'
|
25
|
+
|
26
|
+
DEFAULT_ACCOUNT_PROPERTIES_PATH = 'account_properties.yaml'
|
27
|
+
DEFAULT_ENCRYPTED_ACCOUNT_PROPERTIES_PATH = 'account_properties.yaml.enc'
|
28
|
+
|
29
|
+
DEFAULT_LOOKUP_TABLES_PATH = 'lookup_tables.yaml'
|
30
|
+
|
31
|
+
DEFAULT_TIME_ZONE = 'Pacific Time (US & Canada)'
|
32
|
+
|
33
|
+
DEFAULT_SCHEMAS_PATH = 'workato_schemas.json'
|
34
|
+
|
35
|
+
WORKATO_API_EMAIL_ENV = 'WORKATO_API_EMAIL'
|
36
|
+
WORKATO_API_TOKEN_ENV = 'WORKATO_API_TOKEN'
|
37
|
+
|
38
|
+
WORKATO_BASE_URL_ENV = 'WORKATO_BASE_URL'
|
39
|
+
DEFAULT_WORKATO_BASE_URL = 'https://app.workato.com'
|
40
|
+
WORKATO_BASE_URL = T.let(ENV.fetch(WORKATO_BASE_URL_ENV, DEFAULT_WORKATO_BASE_URL), String)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
require_relative '../../extension/hash_with_indifferent_access'
|
46
|
+
|
47
|
+
require_relative './errors'
|
48
|
+
require_relative './account_properties'
|
49
|
+
require_relative './operation'
|
50
|
+
require_relative './connection'
|
51
|
+
require_relative './stream'
|
52
|
+
require_relative './streams'
|
53
|
+
require_relative './action'
|
54
|
+
require_relative './lookup_tables'
|
55
|
+
require_relative './object_definitions'
|
56
|
+
require_relative './request'
|
57
|
+
require_relative './settings'
|
58
|
+
require_relative './summarize'
|
59
|
+
require_relative './trigger'
|
60
|
+
require_relative './version'
|
61
|
+
require_relative './workato_schemas'
|
62
|
+
require_relative './connector'
|
@@ -2,6 +2,9 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require 'aws-sigv4'
|
5
|
+
require 'workato/utilities/xml'
|
6
|
+
|
7
|
+
using Workato::Extension::HashWithIndifferentAccess
|
5
8
|
|
6
9
|
module Workato
|
7
10
|
module Connector
|
@@ -13,9 +16,9 @@ module Workato
|
|
13
16
|
DUMMY_AWS_IAM_EXTERNAL_ID = 'dummy-aws-iam-external-id'
|
14
17
|
DUMMY_AWS_WORKATO_ACCOUNT_ID = 'dummy-aws-workato-account-id'
|
15
18
|
|
16
|
-
AMAZON_ROLE_CLIENT_ID = ENV
|
17
|
-
AMAZON_ROLE_CLIENT_KEY = ENV
|
18
|
-
AMAZON_ROLE_CLIENT_SECRET = ENV
|
19
|
+
AMAZON_ROLE_CLIENT_ID = ENV.fetch('AMAZON_ROLE_CLIENT_ID', nil)
|
20
|
+
AMAZON_ROLE_CLIENT_KEY = ENV.fetch('AMAZON_ROLE_CLIENT_KEY', nil)
|
21
|
+
AMAZON_ROLE_CLIENT_SECRET = ENV.fetch('AMAZON_ROLE_CLIENT_SECRET', nil)
|
19
22
|
|
20
23
|
WWW_FORM_CONTENT_TYPE = 'application/x-www-form-urlencoded; charset=utf-8'
|
21
24
|
|
@@ -55,7 +58,7 @@ module Workato
|
|
55
58
|
method: method,
|
56
59
|
path: path,
|
57
60
|
params: params,
|
58
|
-
headers: (headers
|
61
|
+
headers: HashWithIndifferentAccess.wrap(headers),
|
59
62
|
payload: payload
|
60
63
|
)
|
61
64
|
|
@@ -134,7 +137,7 @@ module Workato
|
|
134
137
|
headers: headers,
|
135
138
|
method: :get
|
136
139
|
)
|
137
|
-
response = Workato::
|
140
|
+
response = Workato::Utilities::Xml.parse_xml_to_hash(response.body)
|
138
141
|
|
139
142
|
temp_credentials = response.dig('AssumeRoleResponse', 0, 'AssumeRoleResult', 0, 'Credentials', 0)
|
140
143
|
{
|
@@ -0,0 +1,133 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'csv'
|
5
|
+
|
6
|
+
module Workato
|
7
|
+
module Connector
|
8
|
+
module Sdk
|
9
|
+
CsvError = Class.new(Sdk::RuntimeError)
|
10
|
+
|
11
|
+
CsvFormatError = Class.new(CsvError)
|
12
|
+
|
13
|
+
class CsvFileTooBigError < CsvError
|
14
|
+
extend T::Sig
|
15
|
+
|
16
|
+
sig { returns(Integer) }
|
17
|
+
attr_reader :size
|
18
|
+
|
19
|
+
sig { returns(Integer) }
|
20
|
+
attr_reader :max
|
21
|
+
|
22
|
+
sig { params(size: Integer, max: Integer).void }
|
23
|
+
def initialize(size, max)
|
24
|
+
super("CSV file is too big. Max allowed: #{max.to_s(:human_size)}, got: #{size.to_s(:human_size)}")
|
25
|
+
@size = T.let(size, Integer)
|
26
|
+
@max = T.let(max, Integer)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class CsvFileTooManyLinesError < CsvError
|
31
|
+
extend T::Sig
|
32
|
+
|
33
|
+
sig { returns(Integer) }
|
34
|
+
attr_reader :max
|
35
|
+
|
36
|
+
sig { params(max: Integer).void }
|
37
|
+
def initialize(max)
|
38
|
+
super("CSV file has too many lines. Max allowed: #{max}")
|
39
|
+
@max = T.let(max, Integer)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
module Dsl
|
44
|
+
class CsvPackage
|
45
|
+
extend T::Sig
|
46
|
+
|
47
|
+
MAX_FILE_SIZE_FOR_PARSE = T.let(30.megabytes, Integer)
|
48
|
+
private_constant :MAX_FILE_SIZE_FOR_PARSE
|
49
|
+
|
50
|
+
MAX_LINES_FOR_PARSE = 65_000
|
51
|
+
private_constant :MAX_LINES_FOR_PARSE
|
52
|
+
|
53
|
+
sig do
|
54
|
+
params(
|
55
|
+
str: String,
|
56
|
+
headers: T.any(T::Boolean, T::Array[String], String),
|
57
|
+
col_sep: T.nilable(String),
|
58
|
+
row_sep: T.nilable(String),
|
59
|
+
quote_char: T.nilable(String),
|
60
|
+
skip_blanks: T.nilable(T::Boolean),
|
61
|
+
skip_first_line: T::Boolean
|
62
|
+
).returns(
|
63
|
+
T::Array[T::Hash[String, T.untyped]]
|
64
|
+
)
|
65
|
+
end
|
66
|
+
def parse(str, headers:, col_sep: nil, row_sep: nil, quote_char: nil, skip_blanks: nil,
|
67
|
+
skip_first_line: false)
|
68
|
+
if str.bytesize > MAX_FILE_SIZE_FOR_PARSE
|
69
|
+
raise CsvFileTooBigError.new(str.bytesize, MAX_FILE_SIZE_FOR_PARSE)
|
70
|
+
end
|
71
|
+
|
72
|
+
index = 0
|
73
|
+
options = { col_sep: col_sep, row_sep: row_sep, quote_char: quote_char, headers: headers,
|
74
|
+
skip_blanks: skip_blanks }.compact
|
75
|
+
Enumerator.new do |consumer|
|
76
|
+
CSV.parse(str, **options) do |row|
|
77
|
+
if index.zero? && skip_first_line
|
78
|
+
index += 1
|
79
|
+
next
|
80
|
+
end
|
81
|
+
if index == MAX_LINES_FOR_PARSE
|
82
|
+
raise CsvFileTooManyLinesError, MAX_LINES_FOR_PARSE
|
83
|
+
end
|
84
|
+
|
85
|
+
index += 1
|
86
|
+
consumer.yield(T.cast(row, CSV::Row).to_hash)
|
87
|
+
end
|
88
|
+
end.to_a
|
89
|
+
rescue CSV::MalformedCSVError => e
|
90
|
+
raise CsvFormatError, e
|
91
|
+
rescue ArgumentError => e
|
92
|
+
raise Sdk::RuntimeError, e.message
|
93
|
+
end
|
94
|
+
|
95
|
+
sig do
|
96
|
+
params(
|
97
|
+
str: T.nilable(String),
|
98
|
+
headers: T.nilable(T::Array[String]),
|
99
|
+
col_sep: T.nilable(String),
|
100
|
+
row_sep: T.nilable(String),
|
101
|
+
quote_char: T.nilable(String),
|
102
|
+
force_quotes: T.nilable(T::Boolean),
|
103
|
+
blk: T.proc.params(csv: CSV).void
|
104
|
+
).returns(
|
105
|
+
String
|
106
|
+
)
|
107
|
+
end
|
108
|
+
def generate(str = nil, headers: nil, col_sep: nil, row_sep: nil, quote_char: nil, force_quotes: nil, &blk)
|
109
|
+
options = { col_sep: col_sep, row_sep: row_sep, quote_char: quote_char, headers: headers,
|
110
|
+
force_quotes: force_quotes }.compact
|
111
|
+
options[:write_headers] = options[:headers].present?
|
112
|
+
|
113
|
+
::CSV.generate(str || String.new, **options, &blk)
|
114
|
+
rescue ArgumentError => e
|
115
|
+
raise Sdk::RuntimeError, e.message
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
T::Sig::WithoutRuntime.sig { params(symbol: T.any(String, Symbol), _args: T.untyped).void }
|
121
|
+
def method_missing(symbol, *_args)
|
122
|
+
raise UndefinedStdLibMethodError.new(symbol.to_s, 'workato.csv')
|
123
|
+
end
|
124
|
+
|
125
|
+
T::Sig::WithoutRuntime.sig { params(_args: T.untyped).returns(T::Boolean) }
|
126
|
+
def respond_to_missing?(*_args)
|
127
|
+
false
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'securerandom'
|
5
|
+
require 'active_support/core_ext/class/attribute'
|
6
|
+
|
7
|
+
module Workato
|
8
|
+
module Connector
|
9
|
+
module Sdk
|
10
|
+
module Dsl
|
11
|
+
module ExecutionContext
|
12
|
+
extend T::Sig
|
13
|
+
extend T::Helpers
|
14
|
+
extend ActiveSupport::Concern
|
15
|
+
|
16
|
+
included do
|
17
|
+
T.bind(self, Class)
|
18
|
+
|
19
|
+
# encrypted safe recipe_id
|
20
|
+
class_attribute :recipe_id, instance_predicate: false, default: SecureRandom.hex(32)
|
21
|
+
end
|
22
|
+
|
23
|
+
sig { returns(T::Hash[Symbol, T.untyped]) }
|
24
|
+
def execution_context
|
25
|
+
@execution_context ||= {
|
26
|
+
recipe_id: recipe_id
|
27
|
+
}.compact
|
28
|
+
end
|
29
|
+
|
30
|
+
# mock unencrypted recipe_id for testing only
|
31
|
+
def recipe_id!
|
32
|
+
recipe_id.reverse
|
33
|
+
end
|
34
|
+
|
35
|
+
module ClassMethods
|
36
|
+
# mock unencrypted recipe_id for testing only
|
37
|
+
def recipe_id!
|
38
|
+
T.unsafe(self).recipe_id.reverse
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Workato
|
5
|
+
module Connector
|
6
|
+
module Sdk
|
7
|
+
module Dsl
|
8
|
+
module ReinvokeAfter
|
9
|
+
extend T::Sig
|
10
|
+
|
11
|
+
sig do
|
12
|
+
params(
|
13
|
+
continue: T::Hash[T.untyped, T.untyped],
|
14
|
+
temp_output: T.nilable(T::Hash[T.untyped, T.untyped])
|
15
|
+
).void
|
16
|
+
end
|
17
|
+
def checkpoint!(continue:, temp_output: nil)
|
18
|
+
# no-op
|
19
|
+
end
|
20
|
+
|
21
|
+
sig do
|
22
|
+
params(
|
23
|
+
seconds: T.any(Integer, Float),
|
24
|
+
continue: T::Hash[T.untyped, T.untyped],
|
25
|
+
temp_output: T.nilable(T::Hash[T.untyped, T.untyped])
|
26
|
+
).void
|
27
|
+
end
|
28
|
+
def reinvoke_after(seconds:, continue:, temp_output: nil) # rubocop:disable Lint/UnusedMethodArgument
|
29
|
+
Kernel.throw REINVOKE_AFTER_SIGNAL, ReinvokeParams.new(
|
30
|
+
seconds: seconds,
|
31
|
+
continue: continue
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
MAX_REINVOKES = 5
|
38
|
+
private_constant :MAX_REINVOKES
|
39
|
+
|
40
|
+
REINVOKE_AFTER_SIGNAL = :reinvoke_after
|
41
|
+
private_constant :REINVOKE_AFTER_SIGNAL
|
42
|
+
|
43
|
+
class ReinvokeParams < T::Struct
|
44
|
+
prop :seconds, T.any(Float, Integer)
|
45
|
+
prop :continue, T::Hash[T.untyped, T.untyped]
|
46
|
+
end
|
47
|
+
private_constant :ReinvokeParams
|
48
|
+
|
49
|
+
sig { params(continue: T::Hash[T.any(Symbol, String), T.untyped], _blk: Proc).returns(T.untyped) }
|
50
|
+
def loop_reinvoke_after(continue, &_blk)
|
51
|
+
reinvokes_remaining = T.let(reinvoke_limit, Integer)
|
52
|
+
|
53
|
+
Kernel.loop do
|
54
|
+
reinvoke_after = Kernel.catch(REINVOKE_AFTER_SIGNAL) do
|
55
|
+
return yield(continue)
|
56
|
+
end
|
57
|
+
|
58
|
+
if reinvokes_remaining.zero?
|
59
|
+
Kernel.raise "Max number of reinvokes on SDK Gem reached. Current limit is #{reinvoke_limit}"
|
60
|
+
end
|
61
|
+
|
62
|
+
reinvokes_remaining -= 1
|
63
|
+
|
64
|
+
reinvoke_after = T.cast(reinvoke_after, ReinvokeParams)
|
65
|
+
reinvoke_sleep(reinvoke_after.seconds)
|
66
|
+
continue = reinvoke_after.continue
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
sig { params(seconds: T.any(Float, Integer)).void }
|
71
|
+
def reinvoke_sleep(seconds)
|
72
|
+
Kernel.sleep((ENV['WAIT_REINVOKE_AFTER'].presence || seconds).to_f)
|
73
|
+
end
|
74
|
+
|
75
|
+
sig { returns(Integer) }
|
76
|
+
def reinvoke_limit
|
77
|
+
@reinvoke_limit = T.let(@reinvoke_limit, T.nilable(Integer))
|
78
|
+
@reinvoke_limit ||= (ENV['MAX_REINVOKES'].presence || MAX_REINVOKES).to_i
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|