iron_bank 2.2.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.env.example +0 -2
- data/.gitignore +0 -1
- data/.reek.yml +5 -15
- data/.rspec +1 -0
- data/.rubocop.yml +9 -4
- data/.ruby-version +1 -0
- data/.travis.yml +4 -4
- data/Gemfile +1 -1
- data/Gemfile.lock +134 -0
- data/README.md +34 -14
- data/Rakefile +11 -16
- data/bin/console +8 -8
- data/iron_bank.gemspec +32 -34
- data/lib/generators/iron_bank/install/install_generator.rb +4 -4
- data/lib/generators/iron_bank/install/templates/iron_bank.rb +6 -6
- data/lib/iron_bank/action.rb +1 -1
- data/lib/iron_bank/actions/query_more.rb +1 -1
- data/lib/iron_bank/associations.rb +2 -2
- data/lib/iron_bank/authentication.rb +1 -1
- data/lib/iron_bank/authentications/cookie.rb +7 -7
- data/lib/iron_bank/authentications/token.rb +9 -9
- data/lib/iron_bank/cacheable.rb +1 -0
- data/lib/iron_bank/client.rb +6 -10
- data/lib/iron_bank/collection.rb +1 -0
- data/lib/iron_bank/configuration.rb +8 -19
- data/lib/iron_bank/csv.rb +2 -2
- data/lib/iron_bank/describe/field.rb +2 -2
- data/lib/iron_bank/describe/object.rb +5 -5
- data/lib/iron_bank/describe/related.rb +3 -3
- data/lib/iron_bank/describe/tenant.rb +2 -2
- data/lib/iron_bank/endpoint.rb +3 -3
- data/lib/iron_bank/error.rb +17 -17
- data/lib/iron_bank/local.rb +15 -7
- data/lib/iron_bank/local_records.rb +58 -20
- data/lib/iron_bank/logger.rb +3 -3
- data/lib/iron_bank/operation.rb +1 -1
- data/lib/iron_bank/query_builder.rb +4 -4
- data/lib/iron_bank/resource.rb +2 -7
- data/lib/iron_bank/resources/account.rb +6 -6
- data/lib/iron_bank/resources/export.rb +23 -0
- data/lib/iron_bank/resources/product_rate_plan.rb +2 -1
- data/lib/iron_bank/resources/product_rate_plan_charge_tier.rb +0 -44
- data/lib/iron_bank/resources/rate_plan_charge.rb +1 -1
- data/lib/iron_bank/resources/subscription.rb +4 -4
- data/lib/iron_bank/resources/usage.rb +1 -1
- data/lib/iron_bank/utils.rb +5 -5
- data/lib/iron_bank/version.rb +2 -2
- data/lib/iron_bank.rb +67 -75
- metadata +21 -52
- data/lib/iron_bank/instrumentation.rb +0 -14
- data/lib/iron_bank/open_tracing.rb +0 -18
- data/lib/iron_bank/resources/catalog_tiers/discount_amount.rb +0 -26
- data/lib/iron_bank/resources/catalog_tiers/discount_percentage.rb +0 -26
- data/lib/iron_bank/resources/catalog_tiers/price.rb +0 -26
@@ -5,8 +5,6 @@ module IronBank
|
|
5
5
|
# Get a cookie to enable authenticated calls to Zuora through Session.
|
6
6
|
#
|
7
7
|
class Cookie
|
8
|
-
include IronBank::OpenTracing
|
9
|
-
|
10
8
|
TEN_MINUTES = 600
|
11
9
|
ONE_HOUR = 3600
|
12
10
|
|
@@ -23,7 +21,7 @@ module IronBank
|
|
23
21
|
end
|
24
22
|
|
25
23
|
def header
|
26
|
-
{
|
24
|
+
{ "Cookie" => use }
|
27
25
|
end
|
28
26
|
|
29
27
|
private
|
@@ -38,7 +36,7 @@ module IronBank
|
|
38
36
|
|
39
37
|
def fetch_cookie
|
40
38
|
response = authenticate
|
41
|
-
@cookie = response.headers[
|
39
|
+
@cookie = response.headers["set-cookie"]
|
42
40
|
@zsession = fetch_zsession
|
43
41
|
@expires_at = Time.now + ONE_HOUR
|
44
42
|
end
|
@@ -49,14 +47,16 @@ module IronBank
|
|
49
47
|
end
|
50
48
|
|
51
49
|
def authenticate
|
52
|
-
connection.post(
|
50
|
+
connection.post("v1/connections", {})
|
53
51
|
end
|
54
52
|
|
55
53
|
def connection
|
56
54
|
@connection ||= Faraday.new(faraday_config) do |conn|
|
57
|
-
|
55
|
+
IronBank.configuration.middlewares.each do |klass, options|
|
56
|
+
conn.use klass, options
|
57
|
+
end
|
58
|
+
|
58
59
|
conn.request :url_encoded
|
59
|
-
conn.response :logger, IronBank.logger
|
60
60
|
conn.response :json
|
61
61
|
conn.adapter Faraday.default_adapter
|
62
62
|
end
|
@@ -5,8 +5,6 @@ module IronBank
|
|
5
5
|
# Get a bearer token to enable authenticated calls to Zuora through OAuth.
|
6
6
|
#
|
7
7
|
class Token
|
8
|
-
include IronBank::OpenTracing
|
9
|
-
|
10
8
|
# Generic token error.
|
11
9
|
#
|
12
10
|
class Error < StandardError; end
|
@@ -31,7 +29,7 @@ module IronBank
|
|
31
29
|
end
|
32
30
|
|
33
31
|
def header
|
34
|
-
{
|
32
|
+
{ "Authorization" => "Bearer #{use}" }
|
35
33
|
end
|
36
34
|
|
37
35
|
private
|
@@ -46,21 +44,23 @@ module IronBank
|
|
46
44
|
|
47
45
|
def fetch_token
|
48
46
|
response = authenticate || {}
|
49
|
-
@access_token = response.fetch(
|
50
|
-
@expires_at = Time.now + response.fetch(
|
47
|
+
@access_token = response.fetch("access_token", nil)
|
48
|
+
@expires_at = Time.now + response.fetch("expires_in", ONE_HOUR).to_i
|
51
49
|
validate_access_token
|
52
50
|
end
|
53
51
|
alias refetch_token fetch_token
|
54
52
|
|
55
53
|
def authenticate
|
56
|
-
connection.post(
|
54
|
+
connection.post("/oauth/token", authentication_params).body
|
57
55
|
end
|
58
56
|
|
59
57
|
def connection
|
60
58
|
@connection ||= Faraday.new(url: base_url) do |conn|
|
61
|
-
|
59
|
+
IronBank.configuration.middlewares.each do |klass, options|
|
60
|
+
conn.use klass, options
|
61
|
+
end
|
62
|
+
|
62
63
|
conn.request :url_encoded
|
63
|
-
conn.response :logger, IronBank.logger
|
64
64
|
conn.response :json
|
65
65
|
conn.adapter Faraday.default_adapter
|
66
66
|
end
|
@@ -70,7 +70,7 @@ module IronBank
|
|
70
70
|
{
|
71
71
|
client_id: client_id,
|
72
72
|
client_secret: client_secret,
|
73
|
-
grant_type:
|
73
|
+
grant_type: "client_credentials"
|
74
74
|
}
|
75
75
|
end
|
76
76
|
|
data/lib/iron_bank/cacheable.rb
CHANGED
data/lib/iron_bank/client.rb
CHANGED
@@ -5,9 +5,6 @@ module IronBank
|
|
5
5
|
# authenticated request, reusing the same session cookie for future requests.
|
6
6
|
#
|
7
7
|
class Client
|
8
|
-
include IronBank::Instrumentation
|
9
|
-
include IronBank::OpenTracing
|
10
|
-
|
11
8
|
# Generic client error.
|
12
9
|
#
|
13
10
|
class Error < StandardError; end
|
@@ -26,7 +23,7 @@ module IronBank
|
|
26
23
|
end
|
27
24
|
end
|
28
25
|
|
29
|
-
def initialize(domain:, client_id:, client_secret:, auth_type:
|
26
|
+
def initialize(domain:, client_id:, client_secret:, auth_type: "token")
|
30
27
|
@domain = domain
|
31
28
|
@client_id = client_id
|
32
29
|
@client_secret = client_secret
|
@@ -40,19 +37,18 @@ module IronBank
|
|
40
37
|
def connection
|
41
38
|
validate_domain
|
42
39
|
reset_connection if auth.expired?
|
40
|
+
config = IronBank.configuration
|
43
41
|
|
44
42
|
@connection ||= Faraday.new(faraday_config) do |conn|
|
43
|
+
config.middlewares.each { |klass, options| conn.use(klass, options) }
|
44
|
+
|
45
45
|
conn.request :json
|
46
|
-
conn.request :retry,
|
46
|
+
conn.request :retry, config.retry_options
|
47
47
|
|
48
48
|
conn.response :raise_error
|
49
49
|
conn.response :renew_auth, auth
|
50
|
-
conn.response :logger, IronBank.logger
|
51
50
|
conn.response :json, content_type: /\bjson$/
|
52
51
|
|
53
|
-
conn.use :ddtrace, open_tracing_options if open_tracing_enabled?
|
54
|
-
conn.use instrumenter, instrumenter_options if instrumenter
|
55
|
-
|
56
52
|
conn.adapter Faraday.default_adapter
|
57
53
|
end
|
58
54
|
end
|
@@ -103,7 +99,7 @@ module IronBank
|
|
103
99
|
end
|
104
100
|
|
105
101
|
def headers
|
106
|
-
{
|
102
|
+
{ "Content-Type" => "application/json" }.merge(auth.header)
|
107
103
|
end
|
108
104
|
|
109
105
|
def reset_connection
|
data/lib/iron_bank/collection.rb
CHANGED
@@ -4,9 +4,8 @@ module IronBank
|
|
4
4
|
# The Zuora configuration class.
|
5
5
|
#
|
6
6
|
class Configuration
|
7
|
-
#
|
8
|
-
attr_accessor :
|
9
|
-
attr_accessor :instrumenter_options
|
7
|
+
# middlewares
|
8
|
+
attr_accessor :middlewares
|
10
9
|
|
11
10
|
# Logger
|
12
11
|
attr_accessor :logger
|
@@ -26,15 +25,6 @@ module IronBank
|
|
26
25
|
# Cache store instance, optionally used by certain resources.
|
27
26
|
attr_accessor :cache
|
28
27
|
|
29
|
-
# Open Tracing
|
30
|
-
attr_accessor :open_tracing_enabled
|
31
|
-
|
32
|
-
# Open Tracing service name
|
33
|
-
attr_accessor :open_tracing_service_name
|
34
|
-
|
35
|
-
# Faraday retry options
|
36
|
-
attr_writer :retry_options
|
37
|
-
|
38
28
|
# Directory where the XML describe files are located.
|
39
29
|
attr_reader :schema_directory
|
40
30
|
|
@@ -42,12 +32,11 @@ module IronBank
|
|
42
32
|
attr_reader :export_directory
|
43
33
|
|
44
34
|
def initialize
|
45
|
-
@schema_directory
|
46
|
-
@export_directory
|
47
|
-
@logger
|
48
|
-
@auth_type
|
49
|
-
@
|
50
|
-
@open_tracing_service_name = 'ironbank'
|
35
|
+
@schema_directory = "./config/schema"
|
36
|
+
@export_directory = "./config/export"
|
37
|
+
@logger = IronBank::Logger.new
|
38
|
+
@auth_type = "token"
|
39
|
+
@middlewares = []
|
51
40
|
end
|
52
41
|
|
53
42
|
def schema_directory=(value)
|
@@ -68,7 +57,7 @@ module IronBank
|
|
68
57
|
@export_directory = value
|
69
58
|
return unless defined? IronBank::Product
|
70
59
|
|
71
|
-
IronBank::LocalRecords::
|
60
|
+
IronBank::LocalRecords::RESOURCE_QUERY_FIELDS.keys.each do |resource|
|
72
61
|
IronBank::Resources.const_get(resource).reset_store
|
73
62
|
end
|
74
63
|
end
|
data/lib/iron_bank/csv.rb
CHANGED
@@ -9,7 +9,7 @@ module IronBank
|
|
9
9
|
encoding = field.encode(CSV::ConverterEncoding)
|
10
10
|
|
11
11
|
# Match: [1, 10, 100], No match: [0.1, .1, 1., 0b10]
|
12
|
-
|
12
|
+
/^[+-]?\d+$/.match?(encoding) ? encoding.to_i : field
|
13
13
|
rescue # encoding or integer conversion
|
14
14
|
field
|
15
15
|
end
|
@@ -20,7 +20,7 @@ module IronBank
|
|
20
20
|
encoding = field.encode(CSV::ConverterEncoding)
|
21
21
|
|
22
22
|
# Match: [1.0, 1., 0.1, .1], No match: [1, 0b10]
|
23
|
-
|
23
|
+
/^[+-]?(?:\d*\.|\.\d*)\d*$/.match?(encoding) ? encoding.to_f : field
|
24
24
|
rescue # encoding or float conversion
|
25
25
|
field
|
26
26
|
end
|
@@ -33,7 +33,7 @@ module IronBank
|
|
33
33
|
|
34
34
|
# Defined separately because the node name is not ruby-friendly
|
35
35
|
def max_length
|
36
|
-
doc.at_xpath(
|
36
|
+
doc.at_xpath(".//maxlength").text.to_i
|
37
37
|
end
|
38
38
|
|
39
39
|
TEXT_VALUES.each do |val|
|
@@ -46,7 +46,7 @@ module IronBank
|
|
46
46
|
end
|
47
47
|
|
48
48
|
BOOLEAN_VALUES.each do |val|
|
49
|
-
define_method(:"#{val}?") { doc.at_xpath(".//#{val}").text ==
|
49
|
+
define_method(:"#{val}?") { doc.at_xpath(".//#{val}").text == "true" }
|
50
50
|
end
|
51
51
|
|
52
52
|
def inspect
|
@@ -31,22 +31,22 @@ module IronBank
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def export
|
34
|
-
File.open(file_path,
|
34
|
+
File.open(file_path, "w") { |file| file << doc.to_xml }
|
35
35
|
end
|
36
36
|
|
37
37
|
def name
|
38
|
-
node = doc.at_xpath(
|
38
|
+
node = doc.at_xpath(".//object/name")
|
39
39
|
raise InvalidXML unless node
|
40
40
|
|
41
41
|
node.text
|
42
42
|
end
|
43
43
|
|
44
44
|
def label
|
45
|
-
doc.at_xpath(
|
45
|
+
doc.at_xpath(".//object/label").text
|
46
46
|
end
|
47
47
|
|
48
48
|
def fields
|
49
|
-
@fields ||= doc.xpath(
|
49
|
+
@fields ||= doc.xpath(".//fields/field").map do |node|
|
50
50
|
IronBank::Describe::Field.from_xml(node)
|
51
51
|
end
|
52
52
|
end
|
@@ -56,7 +56,7 @@ module IronBank
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def related
|
59
|
-
@related ||= doc.xpath(
|
59
|
+
@related ||= doc.xpath(".//related-objects/object").map do |node|
|
60
60
|
IronBank::Describe::Related.from_xml(node)
|
61
61
|
end
|
62
62
|
end
|
@@ -13,15 +13,15 @@ module IronBank
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def type
|
16
|
-
@type ||= doc.attributes[
|
16
|
+
@type ||= doc.attributes["href"].value.split("/").last
|
17
17
|
end
|
18
18
|
|
19
19
|
def name
|
20
|
-
doc.at_xpath(
|
20
|
+
doc.at_xpath(".//name").text
|
21
21
|
end
|
22
22
|
|
23
23
|
def label
|
24
|
-
doc.at_xpath(
|
24
|
+
doc.at_xpath(".//label").text
|
25
25
|
end
|
26
26
|
|
27
27
|
def inspect
|
@@ -12,7 +12,7 @@ module IronBank
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def self.from_connection(connection)
|
15
|
-
xml = connection.get(
|
15
|
+
xml = connection.get("v1/describe").body
|
16
16
|
new(Nokogiri::XML(xml), connection)
|
17
17
|
rescue TypeError
|
18
18
|
# NOTE: Zuora returns HTTP 401 (unauthorized) roughly 1 out of 3 times
|
@@ -43,7 +43,7 @@ module IronBank
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def object_names
|
46
|
-
@object_names ||= doc.xpath(
|
46
|
+
@object_names ||= doc.xpath(".//object/name").map(&:text)
|
47
47
|
end
|
48
48
|
end
|
49
49
|
end
|
data/lib/iron_bank/endpoint.rb
CHANGED
@@ -10,18 +10,18 @@ module IronBank
|
|
10
10
|
SERVICES = /\Aservices(\d+)\.zuora\.com(:\d+)?\z/i.freeze
|
11
11
|
APISANDBOX = /\Arest.apisandbox.zuora\.com\z/i.freeze
|
12
12
|
|
13
|
-
def self.base_url(domain =
|
13
|
+
def self.base_url(domain = "")
|
14
14
|
new(domain).base_url
|
15
15
|
end
|
16
16
|
|
17
17
|
def base_url
|
18
18
|
case domain
|
19
19
|
when PRODUCTION
|
20
|
-
|
20
|
+
"https://rest.zuora.com/"
|
21
21
|
when SERVICES
|
22
22
|
"https://#{domain}/".downcase
|
23
23
|
when APISANDBOX
|
24
|
-
|
24
|
+
"https://rest.apisandbox.zuora.com/"
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
data/lib/iron_bank/error.rb
CHANGED
@@ -82,23 +82,23 @@ module IronBank
|
|
82
82
|
class LockCompetitionError < TemporaryError; end
|
83
83
|
|
84
84
|
CODE_CLASSES = {
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
85
|
+
"API_DISABLED" => ServerError,
|
86
|
+
"CANNOT_DELETE" => UnprocessableEntityError,
|
87
|
+
"DUPLICATE_VALUE" => ConflictError,
|
88
|
+
"INVALID_FIELD" => BadRequestError,
|
89
|
+
"INVALID_ID" => BadRequestError,
|
90
|
+
"INVALID_TYPE" => BadRequestError,
|
91
|
+
"INVALID_VALUE" => BadRequestError,
|
92
|
+
"LOCK_COMPETITION" => LockCompetitionError,
|
93
|
+
"MALFORMED_QUERY" => ClientError,
|
94
|
+
"MISSING_REQUIRED_VALUE" => ClientError,
|
95
|
+
"REQUEST_EXCEEDED_LIMIT" => TooManyRequestsError,
|
96
|
+
"REQUEST_EXCEEDED_RATE" => TooManyRequestsError,
|
97
|
+
"TEMPORARY_ERROR" => TemporaryError,
|
98
|
+
"TRANSACTION_FAILED" => InternalServerError,
|
99
|
+
"TRANSACTION_TERMINATED" => InternalServerError,
|
100
|
+
"TRANSACTION_TIMEOUT" => BadGatewayError,
|
101
|
+
"UNKNOWN_ERROR" => InternalServerError
|
102
102
|
}.freeze
|
103
103
|
|
104
104
|
CODE_MATCHER = /(#{CODE_CLASSES.keys.join('|')})/.freeze
|
data/lib/iron_bank/local.rb
CHANGED
@@ -33,25 +33,33 @@ module IronBank
|
|
33
33
|
|
34
34
|
private
|
35
35
|
|
36
|
+
# NOTE: Handle associations within the CSV export. E.g., when reading the
|
37
|
+
# `ProductRatePlan.csv` file, we have `ProductRatePlan.Id` and
|
38
|
+
# `Product.Id` fields. We want to end up with `id` and `product_id`
|
39
|
+
# respectively.
|
40
|
+
def underscore_header
|
41
|
+
lambda do |header|
|
42
|
+
parts = header.split(".")
|
43
|
+
header = parts.first.casecmp?(object_name) ? parts.last : parts.join
|
44
|
+
|
45
|
+
IronBank::Utils.underscore(header).to_sym
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
36
49
|
def store
|
37
50
|
@store ||= File.exist?(file_path) ? load_records : {}
|
38
51
|
end
|
39
52
|
|
40
53
|
def load_records
|
41
54
|
CSV.foreach(file_path, csv_options).with_object({}) do |row, store|
|
42
|
-
|
43
|
-
# this line, delete the other one, since `Hash#compact` is available in
|
44
|
-
# 2.4.x and we can remove two smells from `.reek` while we are at it
|
45
|
-
#
|
46
|
-
# store[row[:id]] = new(row.to_h.compact)
|
47
|
-
store[row[:id]] = new(row.to_h.reject { |_, value| value.nil? })
|
55
|
+
store[row[:id]] = new(row.to_h.compact)
|
48
56
|
end
|
49
57
|
end
|
50
58
|
|
51
59
|
def csv_options
|
52
60
|
{
|
53
61
|
headers: true,
|
54
|
-
header_converters: [
|
62
|
+
header_converters: [underscore_header],
|
55
63
|
converters: csv_converters
|
56
64
|
}
|
57
65
|
end
|
@@ -6,12 +6,12 @@ module IronBank
|
|
6
6
|
class LocalRecords
|
7
7
|
private_class_method :new
|
8
8
|
|
9
|
-
|
10
|
-
Product
|
11
|
-
ProductRatePlan
|
12
|
-
ProductRatePlanCharge
|
13
|
-
ProductRatePlanChargeTier
|
14
|
-
|
9
|
+
RESOURCE_QUERY_FIELDS = {
|
10
|
+
"Product" => ["*"],
|
11
|
+
"ProductRatePlan" => ["*", "Product.Id"],
|
12
|
+
"ProductRatePlanCharge" => ["*", "ProductRatePlan.Id"],
|
13
|
+
"ProductRatePlanChargeTier" => ["*", "ProductRatePlanCharge.Id"]
|
14
|
+
}.freeze
|
15
15
|
|
16
16
|
def self.directory
|
17
17
|
IronBank.configuration.export_directory
|
@@ -19,39 +19,77 @@ module IronBank
|
|
19
19
|
|
20
20
|
def self.export
|
21
21
|
FileUtils.mkdir_p(directory) unless Dir.exist?(directory)
|
22
|
-
|
22
|
+
RESOURCE_QUERY_FIELDS.keys.each { |resource| new(resource).save_file }
|
23
23
|
end
|
24
24
|
|
25
|
-
def
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
write_records(csv)
|
25
|
+
def save_file
|
26
|
+
until completed? || max_query?
|
27
|
+
IronBank.logger.info(export_query_info)
|
28
|
+
sleep backoff_time
|
30
29
|
end
|
30
|
+
|
31
|
+
File.open(file_path, "w") { |file| file.write(export.content) }
|
31
32
|
end
|
32
33
|
|
33
34
|
private
|
34
35
|
|
35
|
-
|
36
|
+
BACKOFF = {
|
37
|
+
max: 3,
|
38
|
+
interval: 0.5,
|
39
|
+
randomness: 0.5,
|
40
|
+
factor: 4
|
41
|
+
}.freeze
|
42
|
+
private_constant :BACKOFF
|
43
|
+
|
44
|
+
attr_reader :resource, :query_attempts
|
36
45
|
|
37
46
|
def initialize(resource)
|
38
|
-
@resource
|
47
|
+
@resource = resource
|
48
|
+
@query_attempts = 0
|
39
49
|
end
|
40
50
|
|
41
|
-
def
|
42
|
-
IronBank::
|
51
|
+
def export
|
52
|
+
@export ||= IronBank::Export.create(
|
53
|
+
"select #{RESOURCE_QUERY_FIELDS[resource].join(', ')} from #{resource}"
|
54
|
+
)
|
43
55
|
end
|
44
56
|
|
45
57
|
def file_path
|
46
58
|
File.expand_path("#{resource}.csv", self.class.directory)
|
47
59
|
end
|
48
60
|
|
49
|
-
def
|
50
|
-
|
61
|
+
def export_query_info
|
62
|
+
"Waiting for export #{export.id} to complete " \
|
63
|
+
"(attempt #{query_attempts} of #{BACKOFF[:max]})"
|
64
|
+
end
|
65
|
+
|
66
|
+
def completed?
|
67
|
+
return false unless (status = export.reload.status)
|
68
|
+
|
69
|
+
case status
|
70
|
+
when "Pending", "Processing" then false
|
71
|
+
when "Completed" then true
|
72
|
+
else raise_export_error
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def raise_export_error
|
77
|
+
raise IronBank::Error, "Export #{export.id} has status #{export.status}"
|
51
78
|
end
|
52
79
|
|
53
|
-
def
|
54
|
-
|
80
|
+
def max_query?
|
81
|
+
@query_attempts += 1
|
82
|
+
return false unless @query_attempts > BACKOFF[:max]
|
83
|
+
|
84
|
+
raise IronBank::Error, "Export query attempts exceeded"
|
85
|
+
end
|
86
|
+
|
87
|
+
def backoff_time
|
88
|
+
interval = BACKOFF[:interval]
|
89
|
+
current_interval = interval * (BACKOFF[:factor]**query_attempts)
|
90
|
+
random_interval = rand * BACKOFF[:randomness].to_f * interval
|
91
|
+
|
92
|
+
current_interval + random_interval
|
55
93
|
end
|
56
94
|
end
|
57
95
|
end
|
data/lib/iron_bank/logger.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "singleton"
|
4
|
+
require "logger"
|
5
5
|
|
6
6
|
module IronBank
|
7
7
|
# Default logger for IronBank events
|
@@ -9,7 +9,7 @@ module IronBank
|
|
9
9
|
class Logger
|
10
10
|
extend Forwardable
|
11
11
|
|
12
|
-
PROGNAME =
|
12
|
+
PROGNAME = "iron_bank"
|
13
13
|
LEVEL = ::Logger::DEBUG
|
14
14
|
|
15
15
|
def_delegators :@logger, :debug, :info, :warn, :error, :fatal
|
data/lib/iron_bank/operation.rb
CHANGED
@@ -26,7 +26,7 @@ module IronBank
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def query_fields
|
29
|
-
fields.join(
|
29
|
+
fields.join(",")
|
30
30
|
end
|
31
31
|
|
32
32
|
def query_conditions
|
@@ -41,7 +41,7 @@ module IronBank
|
|
41
41
|
def range_query_builder(field, value)
|
42
42
|
value.each.with_object([]) do |option, range_query|
|
43
43
|
range_query << "#{field}='#{option}'"
|
44
|
-
end.join(
|
44
|
+
end.join(" OR ")
|
45
45
|
end
|
46
46
|
|
47
47
|
def hash_query_conditions
|
@@ -49,7 +49,7 @@ module IronBank
|
|
49
49
|
# TODO: sanitize the value
|
50
50
|
field = IronBank::Utils.camelize(field)
|
51
51
|
filters << current_filter(field, value)
|
52
|
-
end.join(
|
52
|
+
end.join(" AND ")
|
53
53
|
end
|
54
54
|
|
55
55
|
def current_filter(field, value)
|
@@ -66,7 +66,7 @@ module IronBank
|
|
66
66
|
return if conditions.count <= 1
|
67
67
|
return unless conditions.values.any? { |value| value.is_a?(Array) }
|
68
68
|
|
69
|
-
raise
|
69
|
+
raise "Filter ranges must be used in isolation."
|
70
70
|
end
|
71
71
|
end
|
72
72
|
end
|
data/lib/iron_bank/resource.rb
CHANGED
@@ -10,7 +10,7 @@ module IronBank
|
|
10
10
|
extend IronBank::Queryable
|
11
11
|
|
12
12
|
def self.object_name
|
13
|
-
name.split(
|
13
|
+
name.split("::").last
|
14
14
|
end
|
15
15
|
|
16
16
|
def self.with_local_records
|
@@ -52,12 +52,7 @@ module IronBank
|
|
52
52
|
def reload
|
53
53
|
remove_instance_vars
|
54
54
|
@remote = self.class.find(id).remote
|
55
|
-
|
56
|
-
|
57
|
-
def to_csv_row
|
58
|
-
self.class.fields.each.with_object([]) do |field, row|
|
59
|
-
row << remote[IronBank::Utils.underscore(field).to_sym]
|
60
|
-
end
|
55
|
+
self
|
61
56
|
end
|
62
57
|
|
63
58
|
def remove_instance_vars
|