salesforce_bulk 0.1.0 → 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.
- data/README.rdoc +16 -7
- data/lib/salesforce_bulk.rb +22 -9
- data/lib/salesforce_bulk/connection.rb +24 -4
- data/lib/salesforce_bulk/job.rb +53 -4
- data/lib/salesforce_bulk/version.rb +1 -1
- metadata +1 -1
data/README.rdoc
CHANGED
@@ -2,8 +2,12 @@
|
|
2
2
|
|
3
3
|
==Overview
|
4
4
|
|
5
|
-
Salesforce bulk is a simple ruby gem for connecting to and using the Salesforce Bulk API (http://www.salesforce.com/us/developer/docs/api_asynch/index.htm). There are already some gems out there that provide connectivity to the Salesforce SOAP and Rest APIs, if your needs are simple, I recommend using those, specifically raygao's asf-rest-adapter (https://github.com/raygao/asf-rest-adapter).
|
5
|
+
Salesforce bulk is a simple ruby gem for connecting to and using the Salesforce Bulk API (http://www.salesforce.com/us/developer/docs/api_asynch/index.htm). There are already some gems out there that provide connectivity to the Salesforce SOAP and Rest APIs, if your needs are simple, I recommend using those, specifically raygao's asf-rest-adapter (https://github.com/raygao/asf-rest-adapter) or databasedotcom (https://rubygems.org/gems/databasedotcom).
|
6
6
|
|
7
|
+
==Installation
|
8
|
+
|
9
|
+
sudo gem install salesforce_bulk
|
10
|
+
|
7
11
|
==How to use
|
8
12
|
|
9
13
|
Using this gem is simple and straight forward.
|
@@ -28,7 +32,7 @@ Sample operations:
|
|
28
32
|
puts "result is: #{result.inspect}"
|
29
33
|
|
30
34
|
# Update
|
31
|
-
updated_account = Hash["name" => "Test Account -- Updated", id => "a00A0001009zA2m"] # Nearly identical to an insert, but we need to pass the salesforce id.
|
35
|
+
updated_account = Hash["name" => "Test Account -- Updated", "id" => "a00A0001009zA2m"] # Nearly identical to an insert, but we need to pass the salesforce id.
|
32
36
|
records_to_update = Array.new
|
33
37
|
records_to_update.push(updated_account)
|
34
38
|
salesforce.update("Account", records_to_update)
|
@@ -51,16 +55,21 @@ Sample operations:
|
|
51
55
|
|
52
56
|
# Query
|
53
57
|
res = salesforce.query("Account", "select id, name, createddate from Account limit 3") # We just need to pass the sobject name and the query string
|
58
|
+
puts res.records.inspect
|
54
59
|
|
55
|
-
|
56
|
-
sudo gem install salesforce_bulk
|
60
|
+
Result reporting:
|
57
61
|
|
58
|
-
|
59
|
-
|
62
|
+
new_account = Hash["type" => "Other"] # Missing required field "name."
|
63
|
+
records_to_insert = Array.new
|
64
|
+
records_to_insert.push(new_account) # You can add as many records as you want here, just keep in mind that Salesforce has governor limits.
|
65
|
+
result = salesforce.create("Account", records_to_insert)
|
66
|
+
puts result.success? # false
|
67
|
+
puts result.has_errors? # true
|
68
|
+
puts result.errors # An indexed hash detailing the errors
|
60
69
|
|
61
70
|
== Copyright
|
62
71
|
|
63
|
-
Copyright (c)
|
72
|
+
Copyright (c) 2012 Jorge Valdivia.
|
64
73
|
|
65
74
|
===end
|
66
75
|
|
data/lib/salesforce_bulk.rb
CHANGED
@@ -19,16 +19,16 @@ module SalesforceBulk
|
|
19
19
|
self.do_operation('upsert', sobject, records, external_field, wait)
|
20
20
|
end
|
21
21
|
|
22
|
-
def update(sobject, records)
|
23
|
-
self.do_operation('update', sobject, records, nil)
|
22
|
+
def update(sobject, records, wait=false)
|
23
|
+
self.do_operation('update', sobject, records, nil, wait)
|
24
24
|
end
|
25
25
|
|
26
|
-
def create(sobject, records)
|
27
|
-
self.do_operation('insert', sobject, records, nil)
|
26
|
+
def create(sobject, records, wait=false)
|
27
|
+
self.do_operation('insert', sobject, records, nil, wait)
|
28
28
|
end
|
29
29
|
|
30
|
-
def delete(sobject, records)
|
31
|
-
self.do_operation('delete', sobject, records, nil)
|
30
|
+
def delete(sobject, records, wait=false)
|
31
|
+
self.do_operation('delete', sobject, records, nil, wait)
|
32
32
|
end
|
33
33
|
|
34
34
|
def query(sobject, query)
|
@@ -50,7 +50,6 @@ module SalesforceBulk
|
|
50
50
|
if wait or operation == 'query'
|
51
51
|
while true
|
52
52
|
state = job.check_batch_status()
|
53
|
-
#puts "\nstate is #{state}\n"
|
54
53
|
if state != "Queued" && state != "InProgress"
|
55
54
|
break
|
56
55
|
end
|
@@ -59,12 +58,26 @@ module SalesforceBulk
|
|
59
58
|
|
60
59
|
if state == 'Completed'
|
61
60
|
job.get_batch_result()
|
61
|
+
job
|
62
62
|
else
|
63
|
-
|
63
|
+
job.result.message = "There is an error in your job. The response returned a state of #{state}. Please check your query/parameters and try again."
|
64
|
+
job.result.success = false
|
65
|
+
return job
|
66
|
+
|
64
67
|
end
|
65
68
|
else
|
66
|
-
return
|
69
|
+
return job
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
def parse_batch_result result
|
75
|
+
begin
|
76
|
+
CSV.parse(result, :headers => true)
|
77
|
+
rescue
|
78
|
+
result
|
67
79
|
end
|
68
80
|
end
|
81
|
+
|
69
82
|
end # End class
|
70
83
|
end # End module
|
@@ -40,7 +40,8 @@ module SalesforceBulk
|
|
40
40
|
headers = Hash['Content-Type' => 'text/xml; charset=utf-8', 'SOAPAction' => 'login']
|
41
41
|
|
42
42
|
response = post_xml(@@LOGIN_HOST, @@LOGIN_PATH, xml, headers)
|
43
|
-
response_parsed = XmlSimple.xml_in(response)
|
43
|
+
# response_parsed = XmlSimple.xml_in(response)
|
44
|
+
response_parsed = parse_response response
|
44
45
|
|
45
46
|
@session_id = response_parsed['Body'][0]['loginResponse'][0]['result'][0]['sessionId'][0]
|
46
47
|
@server_url = response_parsed['Body'][0]['loginResponse'][0]['result'][0]['serverUrl'][0]
|
@@ -55,12 +56,9 @@ module SalesforceBulk
|
|
55
56
|
|
56
57
|
if host != @@LOGIN_HOST # Not login, need to add session id to header
|
57
58
|
headers['X-SFDC-Session'] = @session_id;
|
58
|
-
#puts "session id is: #{@session_id} --- #{headers.inspect}\n"
|
59
59
|
path = "#{@@PATH_PREFIX}#{path}"
|
60
60
|
end
|
61
61
|
|
62
|
-
#puts "#{host} -- #{path} -- #{headers.inspect}\n"
|
63
|
-
|
64
62
|
https(host).post(path, xml, headers).body
|
65
63
|
end
|
66
64
|
|
@@ -87,6 +85,28 @@ module SalesforceBulk
|
|
87
85
|
@instance = $~.captures[0]
|
88
86
|
end
|
89
87
|
|
88
|
+
def parse_response response
|
89
|
+
response_parsed = XmlSimple.xml_in(response)
|
90
|
+
|
91
|
+
if response.downcase.include?("faultstring") || response.downcase.include?("exceptionmessage")
|
92
|
+
begin
|
93
|
+
|
94
|
+
if response.downcase.include?("faultstring")
|
95
|
+
error_message = response_parsed["Body"][0]["Fault"][0]["faultstring"][0]
|
96
|
+
elsif response.downcase.include?("exceptionmessage")
|
97
|
+
error_message = response_parsed["exceptionMessage"][0]
|
98
|
+
end
|
99
|
+
|
100
|
+
rescue
|
101
|
+
raise "An unknown error has occured within the salesforce_bulk gem. This is most likely caused by bad request, but I am unable to parse the correct error message. Here is a dump of the response for your convenience. #{response}"
|
102
|
+
end
|
103
|
+
|
104
|
+
raise error_message
|
105
|
+
end
|
106
|
+
|
107
|
+
response_parsed
|
108
|
+
end
|
109
|
+
|
90
110
|
end
|
91
111
|
|
92
112
|
end
|
data/lib/salesforce_bulk/job.rb
CHANGED
@@ -2,6 +2,8 @@ module SalesforceBulk
|
|
2
2
|
|
3
3
|
class Job
|
4
4
|
|
5
|
+
attr :result
|
6
|
+
|
5
7
|
def initialize(operation, sobject, records, external_field, connection)
|
6
8
|
|
7
9
|
@@operation = operation
|
@@ -11,6 +13,9 @@ module SalesforceBulk
|
|
11
13
|
@@connection = connection
|
12
14
|
@@XML_HEADER = '<?xml version="1.0" encoding="utf-8" ?>'
|
13
15
|
|
16
|
+
# @result = {"errors" => [], "success" => nil, "records" => [], "raw" => nil, "message" => 'The job has been queued.'}
|
17
|
+
@result = JobResult.new
|
18
|
+
|
14
19
|
end
|
15
20
|
|
16
21
|
def create_job()
|
@@ -27,7 +32,7 @@ module SalesforceBulk
|
|
27
32
|
headers = Hash['Content-Type' => 'application/xml; charset=utf-8']
|
28
33
|
|
29
34
|
response = @@connection.post_xml(nil, path, xml, headers)
|
30
|
-
response_parsed =
|
35
|
+
response_parsed = @@connection.parse_response response
|
31
36
|
|
32
37
|
@@job_id = response_parsed['id'][0]
|
33
38
|
end
|
@@ -110,16 +115,60 @@ module SalesforceBulk
|
|
110
115
|
path = "job/#{@@job_id}/batch/#{@@batch_id}/result/#{result_id}"
|
111
116
|
headers = Hash.new
|
112
117
|
headers = Hash["Content-Type" => "text/xml; charset=UTF-8"]
|
113
|
-
#puts "path is: #{path}\n"
|
114
118
|
|
115
119
|
response = @@connection.get_request(nil, path, headers)
|
116
|
-
#puts "\n\nres2: #{response.inspect}\n\n"
|
117
120
|
|
118
121
|
end
|
119
122
|
|
123
|
+
parse_results response
|
124
|
+
|
120
125
|
response = response.lines.to_a[1..-1].join
|
121
|
-
csvRows = CSV.parse(response)
|
126
|
+
# csvRows = CSV.parse(response, :headers => true)
|
122
127
|
end
|
123
128
|
|
129
|
+
def parse_results response
|
130
|
+
@result.success = true
|
131
|
+
@result.raw = response.lines.to_a[1..-1].join
|
132
|
+
csvRows = CSV.parse(response, :headers => true)
|
133
|
+
|
134
|
+
csvRows.each_with_index do |row, index|
|
135
|
+
if @@operation != "query"
|
136
|
+
row["Created"] = row["Created"] == "true" ? true : false
|
137
|
+
row["Success"] = row["Success"] == "true" ? true : false
|
138
|
+
end
|
139
|
+
|
140
|
+
@result.records.push row
|
141
|
+
if row["Success"] == false
|
142
|
+
@result.success = false
|
143
|
+
@result.errors.push({"#{index}" => row["Error"]}) if row["Error"]
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
@result.message = "The job has been closed."
|
148
|
+
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
class JobResult
|
154
|
+
attr_writer :errors, :success, :records, :raw, :message
|
155
|
+
attr_reader :errors, :success, :records, :raw, :message
|
156
|
+
|
157
|
+
def initialize
|
158
|
+
@errors = []
|
159
|
+
@success = nil
|
160
|
+
@records = []
|
161
|
+
@raw = nil
|
162
|
+
@message = 'The job has been queued.'
|
163
|
+
end
|
164
|
+
|
165
|
+
def success?
|
166
|
+
@success
|
167
|
+
end
|
168
|
+
|
169
|
+
def has_errors?
|
170
|
+
@errors.count > 0
|
171
|
+
end
|
124
172
|
end
|
173
|
+
|
125
174
|
end
|