bulkforce 1.0.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 +7 -0
- data/.gitignore +8 -0
- data/.rspec +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +19 -0
- data/Gemfile +14 -0
- data/Guardfile +8 -0
- data/LICENSE +9 -0
- data/README.md +211 -0
- data/Rakefile +6 -0
- data/bulkforce.gemspec +35 -0
- data/lib/bulkforce.rb +109 -0
- data/lib/bulkforce/batch.rb +61 -0
- data/lib/bulkforce/configuration.rb +42 -0
- data/lib/bulkforce/connection.rb +114 -0
- data/lib/bulkforce/connection_builder.rb +40 -0
- data/lib/bulkforce/helper.rb +77 -0
- data/lib/bulkforce/http.rb +272 -0
- data/lib/bulkforce/version.rb +3 -0
- data/spec/integration/delete_spec.rb +18 -0
- data/spec/integration/insert_spec.rb +22 -0
- data/spec/integration/query_spec.rb +25 -0
- data/spec/integration/update_spec.rb +18 -0
- data/spec/integration/upsert_spec.rb +22 -0
- data/spec/lib/bulkforce/batch_spec.rb +128 -0
- data/spec/lib/bulkforce/configuration_spec.rb +121 -0
- data/spec/lib/bulkforce/connection_builder_spec.rb +114 -0
- data/spec/lib/bulkforce/connection_spec.rb +99 -0
- data/spec/lib/bulkforce/helper_spec.rb +249 -0
- data/spec/lib/bulkforce/http_spec.rb +375 -0
- data/spec/lib/bulkforce_spec.rb +128 -0
- data/spec/spec_helper.rb +34 -0
- data/spec/support/integration_helpers.rb +64 -0
- data/spec/support/shared_examples.rb +21 -0
- metadata +199 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
class Bulkforce
|
2
|
+
class Batch
|
3
|
+
attr_reader :job_id
|
4
|
+
|
5
|
+
def initialize connection, job_id, batch_id
|
6
|
+
@connection = connection
|
7
|
+
@job_id = job_id
|
8
|
+
@batch_id = batch_id
|
9
|
+
|
10
|
+
if @batch_id == -1
|
11
|
+
@final_status = {
|
12
|
+
state: "Completed",
|
13
|
+
state_message: "Empty Request"
|
14
|
+
}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def final_status poll_interval=2
|
19
|
+
return @final_status if @final_status
|
20
|
+
|
21
|
+
@final_status = self.status
|
22
|
+
while ["Queued", "InProgress"].include?(@final_status[:state])
|
23
|
+
sleep poll_interval
|
24
|
+
@final_status = self.status
|
25
|
+
yield @final_status if block_given?
|
26
|
+
end
|
27
|
+
|
28
|
+
raise @final_status[:state_message] if @final_status[:state] == "Failed"
|
29
|
+
|
30
|
+
@final_status.merge({
|
31
|
+
results: results
|
32
|
+
})
|
33
|
+
end
|
34
|
+
|
35
|
+
def status
|
36
|
+
@connection.query_batch @job_id, @batch_id
|
37
|
+
end
|
38
|
+
|
39
|
+
# results returned from Salesforce can be a single page id, or an array of ids.
|
40
|
+
# if it"s an array of ids, we will fetch the results from each, and concatenate them.
|
41
|
+
def results
|
42
|
+
Array(query_result_id).map do |result_id|
|
43
|
+
@connection.query_batch_result_data(@job_id, @batch_id, result_id)
|
44
|
+
end.flatten
|
45
|
+
end
|
46
|
+
|
47
|
+
def raw_request
|
48
|
+
@connection.raw_request
|
49
|
+
end
|
50
|
+
|
51
|
+
def raw_result
|
52
|
+
@connection.raw_result
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
def query_result_id
|
57
|
+
result_raw = @connection.query_batch_result_id(@job_id, @batch_id)
|
58
|
+
result_raw[:result] if result_raw
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class Bulkforce
|
2
|
+
class Configuration
|
3
|
+
attr_accessor :api_version
|
4
|
+
attr_accessor :username
|
5
|
+
attr_accessor :password
|
6
|
+
attr_accessor :security_token
|
7
|
+
attr_accessor :host
|
8
|
+
attr_accessor :session_id
|
9
|
+
attr_accessor :instance
|
10
|
+
attr_accessor :client_id
|
11
|
+
attr_accessor :client_secret
|
12
|
+
attr_accessor :refresh_token
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@api_version = ENV["SALESFORCE_API_VERSION"] || "33.0"
|
16
|
+
@username = ENV["SALESFORCE_USERNAME"]
|
17
|
+
@password = ENV["SALESFORCE_PASSWORD"]
|
18
|
+
@security_token = ENV["SALESFORCE_SECURITY_TOKEN"]
|
19
|
+
@host = ENV["SALESFORCE_HOST"] || "login.salesforce.com"
|
20
|
+
@session_id = ENV["SALESFORCE_SESSION_ID"]
|
21
|
+
@instance = ENV["SALESFORCE_INSTANCE"]
|
22
|
+
@client_id = ENV["SALESFORCE_CLIENT_ID"]
|
23
|
+
@client_secret = ENV["SALESFORCE_CLIENT_SECRET"]
|
24
|
+
@refresh_token = ENV["SALESFORCE_REFRESH_TOKEN"]
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_h
|
28
|
+
{
|
29
|
+
api_version: api_version,
|
30
|
+
username: username,
|
31
|
+
password: password,
|
32
|
+
security_token: security_token,
|
33
|
+
host: host,
|
34
|
+
session_id: session_id,
|
35
|
+
instance: instance,
|
36
|
+
client_id: client_id,
|
37
|
+
client_secret: client_secret,
|
38
|
+
refresh_token: refresh_token,
|
39
|
+
}.reject { |_, v| v.nil? }.to_h
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
class Bulkforce
|
2
|
+
class Connection
|
3
|
+
attr_reader :raw_request
|
4
|
+
attr_reader :raw_result
|
5
|
+
|
6
|
+
def initialize(session_id:, instance:, api_version:)
|
7
|
+
@api_version = api_version
|
8
|
+
@session_id = session_id
|
9
|
+
@instance = instance
|
10
|
+
end
|
11
|
+
|
12
|
+
def login
|
13
|
+
response = Bulkforce::Http.login(
|
14
|
+
@host,
|
15
|
+
@username,
|
16
|
+
@password,
|
17
|
+
@api_version)
|
18
|
+
|
19
|
+
@session_id = response[:session_id]
|
20
|
+
@instance = response[:instance]
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
def org_id
|
25
|
+
@session_id.split("!").first
|
26
|
+
end
|
27
|
+
|
28
|
+
def create_job operation, sobject, content_type, external_field
|
29
|
+
Bulkforce::Http.create_job(
|
30
|
+
@instance,
|
31
|
+
@session_id,
|
32
|
+
operation,
|
33
|
+
sobject,
|
34
|
+
content_type,
|
35
|
+
@api_version,
|
36
|
+
external_field)[:id]
|
37
|
+
end
|
38
|
+
|
39
|
+
def close_job job_id
|
40
|
+
Bulkforce::Http.close_job(
|
41
|
+
@instance,
|
42
|
+
@session_id,
|
43
|
+
job_id,
|
44
|
+
@api_version)[:id]
|
45
|
+
end
|
46
|
+
|
47
|
+
def add_query job_id, data_or_soql
|
48
|
+
Bulkforce::Http.add_batch(
|
49
|
+
@instance,
|
50
|
+
@session_id,
|
51
|
+
job_id,
|
52
|
+
data_or_soql,
|
53
|
+
@api_version)[:id]
|
54
|
+
end
|
55
|
+
|
56
|
+
def query_batch job_id, batch_id
|
57
|
+
Bulkforce::Http.query_batch(
|
58
|
+
@instance,
|
59
|
+
@session_id,
|
60
|
+
job_id,
|
61
|
+
batch_id,
|
62
|
+
@api_version,
|
63
|
+
)
|
64
|
+
end
|
65
|
+
|
66
|
+
def query_batch_result_id job_id, batch_id
|
67
|
+
Bulkforce::Http.query_batch_result_id(
|
68
|
+
@instance,
|
69
|
+
@session_id,
|
70
|
+
job_id,
|
71
|
+
batch_id,
|
72
|
+
@api_version,
|
73
|
+
)
|
74
|
+
end
|
75
|
+
|
76
|
+
def query_batch_result_data job_id, batch_id, result_id
|
77
|
+
@raw_result = Bulkforce::Http.query_batch_result_data(
|
78
|
+
@instance,
|
79
|
+
@session_id,
|
80
|
+
job_id,
|
81
|
+
batch_id,
|
82
|
+
result_id,
|
83
|
+
@api_version,
|
84
|
+
)
|
85
|
+
Bulkforce::Helper.parse_csv @raw_result
|
86
|
+
end
|
87
|
+
|
88
|
+
def add_file_upload_batch job_id, filename
|
89
|
+
@raw_request = File.read(filename)
|
90
|
+
Bulkforce::Http.add_file_upload_batch(
|
91
|
+
@instance,
|
92
|
+
@session_id,
|
93
|
+
job_id,
|
94
|
+
@raw_request,
|
95
|
+
@api_version)[:id]
|
96
|
+
end
|
97
|
+
|
98
|
+
def add_batch job_id, records
|
99
|
+
return -1 if records.nil? || records.empty?
|
100
|
+
@raw_request = Bulkforce::Helper.records_to_csv(records)
|
101
|
+
|
102
|
+
Bulkforce::Http.add_batch(
|
103
|
+
@instance,
|
104
|
+
@session_id,
|
105
|
+
job_id,
|
106
|
+
@raw_request,
|
107
|
+
@api_version)[:id]
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.connect(username, password, api_version, host)
|
111
|
+
self.new(username, password, api_version, host).login
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class Bulkforce
|
2
|
+
class ConnectionBuilder
|
3
|
+
attr_reader :host
|
4
|
+
attr_reader :api_version
|
5
|
+
attr_reader :credentials
|
6
|
+
|
7
|
+
def initialize(host:, api_version:, **credentials)
|
8
|
+
@host = host
|
9
|
+
@api_version = api_version
|
10
|
+
@credentials = credentials
|
11
|
+
end
|
12
|
+
|
13
|
+
def build
|
14
|
+
base_options = { api_version: api_version }
|
15
|
+
|
16
|
+
session_options = if credentials[:session_id]
|
17
|
+
{
|
18
|
+
session_id: credentials[:session_id],
|
19
|
+
instance: credentials.fetch(:instance),
|
20
|
+
}
|
21
|
+
elsif credentials[:refresh_token]
|
22
|
+
Bulkforce::Http.oauth_login(
|
23
|
+
host,
|
24
|
+
credentials.fetch(:client_id),
|
25
|
+
credentials.fetch(:client_secret),
|
26
|
+
credentials[:refresh_token]
|
27
|
+
)
|
28
|
+
else
|
29
|
+
Bulkforce::Http.login(
|
30
|
+
host,
|
31
|
+
credentials.fetch(:username),
|
32
|
+
"#{credentials.fetch(:password)}#{credentials.fetch(:security_token)}",
|
33
|
+
api_version
|
34
|
+
)
|
35
|
+
end.select { |k, _| [:session_id, :instance].include?(k) }.to_h
|
36
|
+
|
37
|
+
Bulkforce::Connection.new(base_options.merge(session_options))
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require "csv"
|
2
|
+
|
3
|
+
class Bulkforce
|
4
|
+
module Helper
|
5
|
+
extend self
|
6
|
+
|
7
|
+
CSV_OPTIONS = {
|
8
|
+
col_sep: ",",
|
9
|
+
quote_char: "\"",
|
10
|
+
force_quotes: true,
|
11
|
+
}
|
12
|
+
|
13
|
+
def records_to_csv records
|
14
|
+
file_mock = StringIO.new
|
15
|
+
csv_client = CSV.new(file_mock, CSV_OPTIONS)
|
16
|
+
all_headers = []
|
17
|
+
all_rows = []
|
18
|
+
records.each do |hash|
|
19
|
+
row = CSV::Row.new([],[],false)
|
20
|
+
to_store = hash.inject({}) do |h, (k, v)|
|
21
|
+
if v == nil || v == "" || v == []
|
22
|
+
h[k] = "#N/A"
|
23
|
+
else
|
24
|
+
h[k] = v.class == Array ? v.join(";") : v
|
25
|
+
end
|
26
|
+
h
|
27
|
+
end
|
28
|
+
row << to_store
|
29
|
+
all_headers << row.headers
|
30
|
+
all_rows << row
|
31
|
+
end
|
32
|
+
all_headers.flatten!.uniq!
|
33
|
+
csv_client << all_headers
|
34
|
+
all_rows.each do |row|
|
35
|
+
csv_client << row.fields(*all_headers)
|
36
|
+
end
|
37
|
+
file_mock.string
|
38
|
+
end
|
39
|
+
|
40
|
+
def fetch_instance_from_server_url server_url
|
41
|
+
before_sf = server_url[/^https?:\/\/(.+)\.salesforce\.com/, 1]
|
42
|
+
before_sf.gsub(/-api$/,"")
|
43
|
+
end
|
44
|
+
|
45
|
+
def attachment_keys records
|
46
|
+
records.map do |record|
|
47
|
+
record.select do |key, value|
|
48
|
+
value.class == File
|
49
|
+
end.keys
|
50
|
+
end.flatten.uniq
|
51
|
+
end
|
52
|
+
|
53
|
+
def transform_values! records, keys
|
54
|
+
keys.each do |key|
|
55
|
+
records.each do |record|
|
56
|
+
file_handle = record[key]
|
57
|
+
if file_handle
|
58
|
+
file_path = File.absolute_path(file_handle)
|
59
|
+
record
|
60
|
+
.merge!({
|
61
|
+
key => Bulkforce::Helper.absolute_to_relative_path(file_path,"#")
|
62
|
+
})
|
63
|
+
yield file_path if block_given?
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def absolute_to_relative_path input, replacement
|
70
|
+
input.gsub(/(^C:[\/\\])|(^\/)/,replacement)
|
71
|
+
end
|
72
|
+
|
73
|
+
def parse_csv csv_string
|
74
|
+
CSV.parse(csv_string, headers: true).map{|r| r.to_hash}
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,272 @@
|
|
1
|
+
require "net/https"
|
2
|
+
require "nori"
|
3
|
+
require "csv"
|
4
|
+
|
5
|
+
class Bulkforce
|
6
|
+
module Http
|
7
|
+
extend self
|
8
|
+
|
9
|
+
def login *args
|
10
|
+
r = Http::Request.login(*args)
|
11
|
+
process_soap_response(nori.parse(process_http_request(r)))
|
12
|
+
end
|
13
|
+
|
14
|
+
def oauth_login *args
|
15
|
+
r = Http::Request.oauth_login(*args)
|
16
|
+
process_oauth_response(nori.parse(process_http_request(r)))
|
17
|
+
end
|
18
|
+
|
19
|
+
def create_job *args
|
20
|
+
r = Http::Request.create_job(*args)
|
21
|
+
process_xml_response(nori.parse(process_http_request(r)))
|
22
|
+
end
|
23
|
+
|
24
|
+
def close_job *args
|
25
|
+
r = Http::Request.close_job(*args)
|
26
|
+
process_xml_response(nori.parse(process_http_request(r)))
|
27
|
+
end
|
28
|
+
|
29
|
+
def add_batch *args
|
30
|
+
r = Http::Request.add_batch(*args)
|
31
|
+
process_xml_response(nori.parse(process_http_request(r)))
|
32
|
+
end
|
33
|
+
|
34
|
+
def query_batch *args
|
35
|
+
r = Http::Request.query_batch(*args)
|
36
|
+
process_xml_response(nori.parse(process_http_request(r)))
|
37
|
+
end
|
38
|
+
|
39
|
+
def query_batch_result_id *args
|
40
|
+
r = Http::Request.query_batch_result_id(*args)
|
41
|
+
process_xml_response(nori.parse(process_http_request(r)))
|
42
|
+
end
|
43
|
+
|
44
|
+
def query_batch_result_data *args
|
45
|
+
r = Http::Request.query_batch_result_data(*args)
|
46
|
+
normalize_csv(process_http_request(r))
|
47
|
+
end
|
48
|
+
|
49
|
+
def add_file_upload_batch instance, session_id, job_id, data, api_version
|
50
|
+
headers = {
|
51
|
+
"Content-Type" => "zip/csv",
|
52
|
+
"X-SFDC-Session" => session_id}
|
53
|
+
r = Http::Request.new(
|
54
|
+
:post,
|
55
|
+
Http::Request.instance_host(instance),
|
56
|
+
"/services/async/#{api_version}/job/#{job_id}/batch",
|
57
|
+
data,
|
58
|
+
headers)
|
59
|
+
process_xml_response(nori.parse(process_http_request(r)))
|
60
|
+
end
|
61
|
+
|
62
|
+
def process_http_request(r)
|
63
|
+
http = Net::HTTP.new(r.host, 443)
|
64
|
+
http.use_ssl = true
|
65
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
66
|
+
http_request = Net::HTTP.
|
67
|
+
const_get(r.http_method.capitalize).
|
68
|
+
new(r.path, r.headers)
|
69
|
+
http_request.body = r.body if r.body
|
70
|
+
http.request(http_request).body
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
def nori
|
75
|
+
Nori.new(
|
76
|
+
:advanced_typecasting => true,
|
77
|
+
:strip_namespaces => true,
|
78
|
+
:convert_tags_to => lambda { |tag| tag.snakecase.to_sym })
|
79
|
+
end
|
80
|
+
|
81
|
+
def process_xml_response res
|
82
|
+
if res[:error]
|
83
|
+
raise "#{res[:error][:exception_code]}: #{res[:error][:exception_message]}"
|
84
|
+
end
|
85
|
+
|
86
|
+
res.values.first
|
87
|
+
end
|
88
|
+
|
89
|
+
def normalize_csv res
|
90
|
+
res.gsub(/\n\s+/, "\n")
|
91
|
+
end
|
92
|
+
|
93
|
+
def process_soap_response res
|
94
|
+
raw_result = res.fetch(:body){ res.fetch(:envelope).fetch(:body) }
|
95
|
+
raise raw_result[:fault][:faultstring] if raw_result[:fault]
|
96
|
+
|
97
|
+
login_result = raw_result[:login_response][:result]
|
98
|
+
instance = Helper.fetch_instance_from_server_url(login_result[:server_url])
|
99
|
+
login_result.merge(instance: instance)
|
100
|
+
end
|
101
|
+
|
102
|
+
def process_oauth_response res
|
103
|
+
inner = res.fetch(:o_auth)
|
104
|
+
|
105
|
+
if inner[:error]
|
106
|
+
raise "#{inner[:error]}: #{inner[:error_description]}"
|
107
|
+
end
|
108
|
+
|
109
|
+
{
|
110
|
+
server_url: inner.fetch(:instance_url),
|
111
|
+
session_id: inner.fetch(:access_token),
|
112
|
+
instance: Helper.fetch_instance_from_server_url(inner.fetch(:instance_url)),
|
113
|
+
}
|
114
|
+
end
|
115
|
+
|
116
|
+
class Request
|
117
|
+
attr_reader :path
|
118
|
+
attr_reader :host
|
119
|
+
attr_reader :body
|
120
|
+
attr_reader :headers
|
121
|
+
attr_reader :http_method
|
122
|
+
|
123
|
+
def initialize http_method, host, path, body, headers
|
124
|
+
@http_method = http_method
|
125
|
+
@host = host
|
126
|
+
@path = path
|
127
|
+
@body = body
|
128
|
+
@headers = headers
|
129
|
+
end
|
130
|
+
|
131
|
+
def self.login host, username, password, api_version
|
132
|
+
body = %Q{<?xml version="1.0" encoding="utf-8" ?>
|
133
|
+
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
134
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
135
|
+
xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
|
136
|
+
<env:Body>
|
137
|
+
<n1:login xmlns:n1="urn:partner.soap.sforce.com">
|
138
|
+
<n1:username>#{username}</n1:username>
|
139
|
+
<n1:password>#{password}</n1:password>
|
140
|
+
</n1:login>
|
141
|
+
</env:Body>
|
142
|
+
</env:Envelope>}
|
143
|
+
headers = {
|
144
|
+
"Content-Type" => "text/xml; charset=utf-8",
|
145
|
+
"SOAPAction" => "login"
|
146
|
+
}
|
147
|
+
Http::Request.new(
|
148
|
+
:post,
|
149
|
+
host,
|
150
|
+
"/services/Soap/u/#{api_version}",
|
151
|
+
body,
|
152
|
+
headers)
|
153
|
+
end
|
154
|
+
|
155
|
+
def self.oauth_login(host, client_id, client_secret, refresh_token)
|
156
|
+
headers = {
|
157
|
+
"Content-Type" => "application/x-www-form-urlencoded",
|
158
|
+
"Accept" => "application/xml",
|
159
|
+
}
|
160
|
+
|
161
|
+
body = {
|
162
|
+
grant_type: "refresh_token",
|
163
|
+
client_id: client_id,
|
164
|
+
client_secret: client_secret,
|
165
|
+
refresh_token: refresh_token
|
166
|
+
}.inject("") do |string, (k,v)|
|
167
|
+
string += "#{k}=#{v}&"
|
168
|
+
end
|
169
|
+
|
170
|
+
Http::Request.new(
|
171
|
+
:post,
|
172
|
+
host,
|
173
|
+
"/services/oauth2/token",
|
174
|
+
body,
|
175
|
+
headers)
|
176
|
+
end
|
177
|
+
|
178
|
+
def self.create_job instance, session_id, operation, sobject, content_type, api_version, external_field = nil
|
179
|
+
external_field_line = external_field ?
|
180
|
+
"<externalIdFieldName>#{external_field}</externalIdFieldName>" : nil
|
181
|
+
body = %Q{<?xml version="1.0" encoding="utf-8" ?>
|
182
|
+
<jobInfo xmlns="http://www.force.com/2009/06/asyncapi/dataload">
|
183
|
+
<operation>#{operation}</operation>
|
184
|
+
<object>#{sobject}</object>
|
185
|
+
#{external_field_line}
|
186
|
+
<contentType>#{content_type}</contentType>
|
187
|
+
</jobInfo>
|
188
|
+
}
|
189
|
+
headers = {
|
190
|
+
"Content-Type" => "application/xml; charset=utf-8",
|
191
|
+
"X-SFDC-Session" => session_id}
|
192
|
+
Http::Request.new(
|
193
|
+
:post,
|
194
|
+
instance_host(instance),
|
195
|
+
"/services/async/#{api_version}/job",
|
196
|
+
body,
|
197
|
+
headers)
|
198
|
+
end
|
199
|
+
|
200
|
+
def self.close_job instance, session_id, job_id, api_version
|
201
|
+
body = %Q{<?xml version="1.0" encoding="utf-8" ?>
|
202
|
+
<jobInfo xmlns="http://www.force.com/2009/06/asyncapi/dataload">
|
203
|
+
<state>Closed</state>
|
204
|
+
</jobInfo>
|
205
|
+
}
|
206
|
+
headers = {
|
207
|
+
"Content-Type" => "application/xml; charset=utf-8",
|
208
|
+
"X-SFDC-Session" => session_id}
|
209
|
+
Http::Request.new(
|
210
|
+
:post,
|
211
|
+
instance_host(instance),
|
212
|
+
"/services/async/#{api_version}/job/#{job_id}",
|
213
|
+
body,
|
214
|
+
headers)
|
215
|
+
end
|
216
|
+
|
217
|
+
def self.add_batch instance, session_id, job_id, data, api_version
|
218
|
+
headers = {"Content-Type" => "text/csv; charset=UTF-8", "X-SFDC-Session" => session_id}
|
219
|
+
Http::Request.new(
|
220
|
+
:post,
|
221
|
+
instance_host(instance),
|
222
|
+
"/services/async/#{api_version}/job/#{job_id}/batch",
|
223
|
+
data,
|
224
|
+
headers)
|
225
|
+
end
|
226
|
+
|
227
|
+
def self.query_batch instance, session_id, job_id, batch_id, api_version
|
228
|
+
headers = {"X-SFDC-Session" => session_id}
|
229
|
+
Http::Request.new(
|
230
|
+
:get,
|
231
|
+
instance_host(instance),
|
232
|
+
"/services/async/#{api_version}/job/#{job_id}/batch/#{batch_id}",
|
233
|
+
nil,
|
234
|
+
headers)
|
235
|
+
end
|
236
|
+
|
237
|
+
def self.query_batch_result_id instance, session_id, job_id, batch_id, api_version
|
238
|
+
headers = {
|
239
|
+
"Content-Type" => "application/xml; charset=utf-8",
|
240
|
+
"X-SFDC-Session" => session_id}
|
241
|
+
Http::Request.new(
|
242
|
+
:get,
|
243
|
+
instance_host(instance),
|
244
|
+
"/services/async/#{api_version}/job/#{job_id}/batch/#{batch_id}/result",
|
245
|
+
nil,
|
246
|
+
headers)
|
247
|
+
end
|
248
|
+
|
249
|
+
def self.query_batch_result_data(instance,
|
250
|
+
session_id,
|
251
|
+
job_id,
|
252
|
+
batch_id,
|
253
|
+
result_id,
|
254
|
+
api_version)
|
255
|
+
headers = {
|
256
|
+
"Content-Type" => "text/csv; charset=UTF-8",
|
257
|
+
"X-SFDC-Session" => session_id}
|
258
|
+
Http::Request.new(
|
259
|
+
:get,
|
260
|
+
instance_host(instance),
|
261
|
+
"/services/async/#{api_version}" \
|
262
|
+
"/job/#{job_id}/batch/#{batch_id}/result/#{result_id}",
|
263
|
+
nil,
|
264
|
+
headers)
|
265
|
+
end
|
266
|
+
|
267
|
+
def self.instance_host instance
|
268
|
+
"#{instance}.salesforce.com"
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|