salesforce_bulk 0.0.1 → 0.0.3

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.
@@ -0,0 +1,54 @@
1
+ = salesforce-bulk
2
+
3
+ ==Overview
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).
6
+
7
+ ==How to use
8
+
9
+ Using this gem is simple and straight forward.
10
+
11
+ To initialize:
12
+
13
+ require 'salesforce_bulk'
14
+ salesforce = SalesforceBulk::Api.new("YOUR_SALESFORCE_USERNAME", "YOUR_SALESFORCE_PASSWORD")
15
+
16
+ Sample operations:
17
+
18
+ # Insert/Create
19
+ new_account = Hash["name" => "Test Account", "type" => "Other"] # Add as many fields per record as needed.
20
+ records_to_insert = Array.new
21
+ 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.
22
+ result = salesforce.create("Account", records_to_insert)
23
+ puts "result is: #{result.inspect}"
24
+
25
+ # Update
26
+ updated_account = Hash["name" => "Test Account -- Updated", id => "a00A0001009zA2m"] # Nearly identical to an insert, but we need to pass the salesforce id.
27
+ records_to_update = Array.new
28
+ records_to_update.push(updated_account)
29
+ salesforce.update("Account", records_to_update)
30
+
31
+ # Upsert
32
+ upserted_account = Hash["name" => "Test Account -- Upserted", "External_Field_Name" => "123456"] # Fields to be updated. External field must be included
33
+ records_to_upsert = Array.new
34
+ records_to_upsert.push(upserted_account)
35
+ salesforce.upsert("Account", records_to_upsert, "External_Field_Name") # Note that upsert accepts an extra parameter for the external field name
36
+
37
+ # Delete
38
+ deleted_account = Hash["id" => "a00A0001009zA2m"] # We only specify the id of the records to delete
39
+ records_to_delete = Array.new
40
+ records_to_delete.push(deleted_account)
41
+ salesforce.delete("Account", records_to_delete)
42
+
43
+ # Query
44
+ res = salesforce.query("Account", "select id, name, createddate from Account limit 3") # We just need to pass the sobject name and the query string
45
+
46
+ ==Installation
47
+ [sudo] gem install salesforce_bulk
48
+
49
+ == Copyright
50
+
51
+ Copyright (c) 2011 Jorge Valdivia.
52
+
53
+ ===end
54
+
@@ -51,7 +51,7 @@ module SalesforceBulk
51
51
 
52
52
  state = job.check_batch_status()
53
53
  while true
54
- puts "\nstate is #{state}\n"
54
+ #puts "\nstate is #{state}\n"
55
55
  state = job.check_batch_status()
56
56
  if state != "Queued"
57
57
  break
@@ -0,0 +1,90 @@
1
+ module SalesforceBulk
2
+
3
+ class Connection
4
+
5
+ @@XML_HEADER = '<?xml version="1.0" encoding="utf-8" ?>'
6
+ @@API_VERSION = nil
7
+ @@LOGIN_HOST = 'login.salesforce.com'
8
+ @@INSTANCE_HOST = nil # Gets set in login()
9
+
10
+ def initialize(username, password, api_version)
11
+ @username = username
12
+ @password = password
13
+ @session_id = nil
14
+ @server_url = nil
15
+ @instance = nil
16
+ @@API_VERSION = api_version
17
+ @@LOGIN_PATH = "/services/Soap/u/#{@@API_VERSION}"
18
+ @@PATH_PREFIX = "/services/async/#{@@API_VERSION}/"
19
+
20
+ login()
21
+ end
22
+
23
+ #private
24
+
25
+ def login()
26
+
27
+ xml = '<?xml version="1.0" encoding="utf-8" ?>'
28
+ xml += "<env:Envelope xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""
29
+ xml += " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
30
+ xml += " xmlns:env=\"http://schemas.xmlsoap.org/soap/envelope/\">"
31
+ xml += " <env:Body>"
32
+ xml += " <n1:login xmlns:n1=\"urn:partner.soap.sforce.com\">"
33
+ xml += " <n1:username>#{@username}</n1:username>"
34
+ xml += " <n1:password>#{@password}</n1:password>"
35
+ xml += " </n1:login>"
36
+ xml += " </env:Body>"
37
+ xml += "</env:Envelope>"
38
+
39
+ headers = Hash['Content-Type' => 'text/xml; charset=utf-8', 'SOAPAction' => 'login']
40
+
41
+ response = post_xml(@@LOGIN_HOST, @@LOGIN_PATH, xml, headers)
42
+ response_parsed = XmlSimple.xml_in(response)
43
+
44
+ @session_id = response_parsed['Body'][0]['loginResponse'][0]['result'][0]['sessionId'][0]
45
+ @server_url = response_parsed['Body'][0]['loginResponse'][0]['result'][0]['serverUrl'][0]
46
+ @instance = parse_instance()
47
+
48
+ @@INSTANCE_HOST = "#{@instance}.salesforce.com"
49
+ end
50
+
51
+ def post_xml(host, path, xml, headers)
52
+
53
+ host = host || @@INSTANCE_HOST
54
+
55
+ if host != @@LOGIN_HOST # Not login, need to add session id to header
56
+ headers['X-SFDC-Session'] = @session_id;
57
+ #puts "session id is: #{@session_id} --- #{headers.inspect}\n"
58
+ path = "#{@@PATH_PREFIX}#{path}"
59
+ end
60
+
61
+ #puts "#{host} -- #{path} -- #{headers.inspect}\n"
62
+
63
+ http = Net::HTTP.new(host)
64
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
65
+ resp = http.post(path, xml, headers)
66
+ return resp.body
67
+ end
68
+
69
+ def get_request(host, path, headers)
70
+ host = host || @@INSTANCE_HOST
71
+ path = "#{@@PATH_PREFIX}#{path}"
72
+
73
+ if host != @@LOGIN_HOST # Not login, need to add session id to header
74
+ headers['X-SFDC-Session'] = @session_id;
75
+ end
76
+
77
+ http = Net::HTTP.new(host)
78
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
79
+ resp = http.get(path, headers)
80
+ return resp.body
81
+ end
82
+
83
+ def parse_instance()
84
+ @server_url =~ /https:\/\/([a-z]{2,2}[0-9]{1,1})-api/
85
+ @instance = $~.captures[0]
86
+ end
87
+
88
+ end
89
+
90
+ end
@@ -0,0 +1,126 @@
1
+ module SalesforceBulk
2
+
3
+ class Job
4
+
5
+ def initialize(operation, sobject, records, external_field, connection)
6
+
7
+ @@operation = operation
8
+ @@sobject = sobject
9
+ @@external_field = external_field
10
+ @@records = records
11
+ @@connection = connection
12
+ @@XML_HEADER = '<?xml version="1.0" encoding="utf-8" ?>'
13
+
14
+ end
15
+
16
+ def create_job()
17
+ xml = "#{@@XML_HEADER}<jobInfo xmlns=\"http://www.force.com/2009/06/asyncapi/dataload\">"
18
+ xml += "<operation>#{@@operation}</operation>"
19
+ xml += "<object>#{@@sobject}</object>"
20
+ if !@@external_field.nil? # This only happens on upsert
21
+ xml += "<externalIdFieldName>#{@@external_field}</externalIdFieldName>"
22
+ end
23
+ xml += "<contentType>CSV</contentType>"
24
+ xml += "</jobInfo>"
25
+
26
+ path = "job"
27
+ headers = Hash['Content-Type' => 'application/xml; charset=utf-8']
28
+
29
+ response = @@connection.post_xml(nil, path, xml, headers)
30
+ response_parsed = XmlSimple.xml_in(response)
31
+
32
+ @@job_id = response_parsed['id'][0]
33
+ end
34
+
35
+ def close_job()
36
+ xml = "#{@@XML_HEADER}<jobInfo xmlns=\"http://www.force.com/2009/06/asyncapi/dataload\">"
37
+ xml += "state>Closed</state>"
38
+ xml += "</jobInfo>"
39
+
40
+ path = "job/#{@@job_id}"
41
+ headers = Hash['Content-Type' => 'application/xml; charset=utf-8']
42
+
43
+ response = @@connection.post_xml(nil, path, xml, headers)
44
+ response_parsed = XmlSimple.xml_in(response)
45
+
46
+ #job_id = response_parsed['id'][0]
47
+ end
48
+
49
+ def add_query
50
+ path = "job/#{@@job_id}/batch/"
51
+ headers = Hash["Content-Type" => "text/csv; charset=UTF-8"]
52
+
53
+ response = @@connection.post_xml(nil, path, @@records, headers)
54
+ response_parsed = XmlSimple.xml_in(response)
55
+
56
+ @@batch_id = response_parsed['id'][0]
57
+ end
58
+
59
+ def add_batch()
60
+ keys = @@records.reduce({}) {|h,pairs| pairs.each {|k,v| (h[k] ||= []) << v}; h}.keys
61
+ headers = keys.to_csv
62
+
63
+ output_csv = headers
64
+
65
+ @@records.each do |r|
66
+ fields = Array.new
67
+ keys.each do |k|
68
+ fields.push(r[k])
69
+ end
70
+
71
+ row_csv = fields.to_csv
72
+ output_csv += row_csv
73
+ end
74
+
75
+ path = "job/#{@@job_id}/batch/"
76
+ headers = Hash["Content-Type" => "text/csv; charset=UTF-8"]
77
+
78
+ response = @@connection.post_xml(nil, path, output_csv, headers)
79
+ response_parsed = XmlSimple.xml_in(response)
80
+
81
+ @@batch_id = response_parsed['id'][0]
82
+ end
83
+
84
+ def check_batch_status()
85
+ path = "job/#{@@job_id}/batch/#{@@batch_id}"
86
+ headers = Hash.new
87
+
88
+ response = @@connection.get_request(nil, path, headers)
89
+ response_parsed = XmlSimple.xml_in(response)
90
+
91
+ begin
92
+ #puts "check: #{response_parsed.inspect}\n"
93
+ response_parsed['state'][0]
94
+ rescue Exception => e
95
+ #puts "check: #{response_parsed.inspect}\n"
96
+
97
+ nil
98
+ end
99
+ end
100
+
101
+ def get_batch_result()
102
+ path = "job/#{@@job_id}/batch/#{@@batch_id}/result"
103
+ headers = Hash["Content-Type" => "text/xml; charset=UTF-8"]
104
+
105
+ response = @@connection.get_request(nil, path, headers)
106
+
107
+ if(@@operation == "query") # The query op requires us to do another request to get the results
108
+ response_parsed = XmlSimple.xml_in(response)
109
+ result_id = response_parsed["result"][0]
110
+
111
+ path = "job/#{@@job_id}/batch/#{@@batch_id}/result/#{result_id}"
112
+ headers = Hash.new
113
+ headers = Hash["Content-Type" => "text/xml; charset=UTF-8"]
114
+ #puts "path is: #{path}\n"
115
+
116
+ response = @@connection.get_request(nil, path, headers)
117
+ #puts "\n\nres2: #{response.inspect}\n\n"
118
+
119
+ end
120
+
121
+ response = response.lines.to_a[1..-1].join
122
+ csvRows = CSV.parse(response)
123
+ end
124
+
125
+ end
126
+ end
@@ -1,3 +1,3 @@
1
1
  module SalesforceBulk
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
7
7
  s.version = SalesforceBulk::VERSION
8
8
  s.authors = ["Jorge Valdivia"]
9
9
  s.email = ["jorge@valdivia.me"]
10
- s.homepage = ""
10
+ s.homepage = "https://github.com/jorgevaldivia/salesforce_bulk"
11
11
  s.summary = %q{Ruby support for the Salesforce Bulk API}
12
12
  s.description = %q{This gem provides a super simple interface for the Salesforce Bulk API. It provides support for insert, update, upsert, delete, and query.}
13
13
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: salesforce_bulk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -21,11 +21,14 @@ extra_rdoc_files: []
21
21
  files:
22
22
  - .gitignore
23
23
  - Gemfile
24
+ - README.rdoc
24
25
  - Rakefile
25
26
  - lib/salesforce_bulk.rb
27
+ - lib/salesforce_bulk/connection.rb
28
+ - lib/salesforce_bulk/job.rb
26
29
  - lib/salesforce_bulk/version.rb
27
30
  - salesforce_bulk.gemspec
28
- homepage: ''
31
+ homepage: https://github.com/jorgevaldivia/salesforce_bulk
29
32
  licenses: []
30
33
  post_install_message:
31
34
  rdoc_options: []