bulkforce 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|