salesforce_bulk_oauth2 0.0.5

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 ADDED
@@ -0,0 +1,72 @@
1
+ = salesforce-bulk
2
+
3
+ ==Overview
4
+
5
+ Salesforce Bulk Oauth2 is an extension of jorgevaldivia's Salesforce Bulk ruby gem for connecting to and using the Salesforce Bulk API (http://www.salesforce.com/us/developer/docs/api_asynch/index.htm) via Oauth2 service instead of username/password.
6
+
7
+ ==Installation
8
+
9
+ sudo gem install salesforce_bulk
10
+
11
+ ==How to use
12
+
13
+ Using this gem is simple and straight forward.
14
+
15
+ To initialize:
16
+
17
+ require 'salesforce_bulk'
18
+ salesforce = SalesforceBulk::Api.new(:token=>"YOUR_SALESFORCE_TOKEN", :instance_url=>"YOUR_SALESFORCE_INSTANCE_URL")
19
+
20
+ Sample operations:
21
+
22
+ Same as mentioned on (https://github.com/jorgevaldivia/salesforce_bulk).
23
+
24
+ # Insert/Create
25
+ new_account = Hash["name" => "Test Account", "type" => "Other"] # Add as many fields per record as needed.
26
+ records_to_insert = Array.new
27
+ 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.
28
+ result = salesforce.create("Account", records_to_insert)
29
+ puts "result is: #{result.inspect}"
30
+
31
+ # Update
32
+ updated_account = Hash["name" => "Test Account -- Updated", "id" => "a00A0001009zA2m"] # Nearly identical to an insert, but we need to pass the salesforce id.
33
+ records_to_update = Array.new
34
+ records_to_update.push(updated_account)
35
+ salesforce.update("Account", records_to_update)
36
+
37
+ # Upsert
38
+ upserted_account = Hash["name" => "Test Account -- Upserted", "External_Field_Name" => "123456"] # Fields to be updated. External field must be included
39
+ records_to_upsert = Array.new
40
+ records_to_upsert.push(upserted_account)
41
+ salesforce.upsert("Account", records_to_upsert, "External_Field_Name") # Note that upsert accepts an extra parameter for the external field name
42
+
43
+ OR
44
+
45
+ salesforce.upsert("Account", records_to_upsert, "External_Field_Name", true) # last parameter indicates whether to wait until the batch finishes
46
+
47
+ # Delete
48
+ deleted_account = Hash["id" => "a00A0001009zA2m"] # We only specify the id of the records to delete
49
+ records_to_delete = Array.new
50
+ records_to_delete.push(deleted_account)
51
+ salesforce.delete("Account", records_to_delete)
52
+
53
+ # Query
54
+ res = salesforce.query("Account", "select id, name, createddate from Account limit 3") # We just need to pass the sobject name and the query string
55
+ puts res.result.records.inspect
56
+
57
+ Result reporting:
58
+
59
+ array of true/false depending on wether record was pushed
60
+
61
+ example: if you push an array having 10 records. Result maybe
62
+ result = [true,true,true,true,false,true,false,true,true,true]
63
+
64
+
65
+ Thanks to jorgevaldivia for Salesforce Bulk gem
66
+
67
+ == Copyright
68
+
69
+ Copyright (c) 2012 Bhushan Lodha.
70
+
71
+ ===end
72
+
@@ -0,0 +1,70 @@
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(api_version,client)
11
+ #@username = username
12
+ @client=client
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
+
28
+ @session_id=@client.oauth_token
29
+
30
+ @server_url=@client.instance_url
31
+ @instance = parse_instance()
32
+ @@INSTANCE_HOST = "#{@instance}.salesforce.com"
33
+ end
34
+
35
+ def post_xml(host, path, xml, headers)
36
+ host = host || @@INSTANCE_HOST
37
+ if host != @@LOGIN_HOST # Not login, need to add session id to header
38
+ headers['X-SFDC-Session'] = @session_id;
39
+ path = "#{@@PATH_PREFIX}#{path}"
40
+ end
41
+ https(host).post(path, xml, headers).body
42
+ end
43
+
44
+ def get_request(host, path, headers)
45
+ host = host || @@INSTANCE_HOST
46
+ path = "#{@@PATH_PREFIX}#{path}"
47
+
48
+ if host != @@LOGIN_HOST # Not login, need to add session id to header
49
+ headers['X-SFDC-Session'] = @session_id;
50
+ end
51
+
52
+ https(host).get(path, headers).body
53
+ end
54
+
55
+ def https(host)
56
+ req = Net::HTTP.new(host, 443)
57
+ req.use_ssl = true
58
+ req.verify_mode = OpenSSL::SSL::VERIFY_NONE
59
+ req
60
+ end
61
+
62
+ def parse_instance()
63
+ @instance=@server_url.match(/https:\/\/[a-z]{2}[0-9]{1,2}/).to_s.gsub("https://","")
64
+ #@server_url =~ /https:\/\/[a-z]{2}[0-9]{1,2}/
65
+ #@instance = "ap1"
66
+ end
67
+
68
+ end
69
+
70
+ end
@@ -0,0 +1,125 @@
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>XML</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
+ @@job_id = response_parsed['id'][0]
32
+ end
33
+
34
+ def close_job()
35
+ xml = "#{@@XML_HEADER}<jobInfo xmlns=\"http://www.force.com/2009/06/asyncapi/dataload\">"
36
+ xml += "<state>Closed</state>"
37
+ xml += "</jobInfo>"
38
+
39
+ path = "job/#{@@job_id}"
40
+ headers = Hash['Content-Type' => 'application/xml; charset=utf-8']
41
+
42
+ response = @@connection.post_xml(nil, path, xml, headers)
43
+ response_parsed = XmlSimple.xml_in(response)
44
+
45
+ #job_id = response_parsed['id'][0]
46
+ end
47
+
48
+ def add_query
49
+ path = "job/#{@@job_id}/batch/"
50
+ headers = Hash["Content-Type" => "application/xml; charset=UTF-8"]
51
+ response = @@connection.post_xml(nil, path, @@records, headers)
52
+ response_parsed = XmlSimple.xml_in(response)
53
+ @@batch_id = response_parsed['id'][0]
54
+ end
55
+
56
+ def add_batch()
57
+ keys = @@records.inject({}) {|h,pairs| pairs.each {|k,v| (h[k] ||= []) << v}; h}.keys ## Target here
58
+ headers = keys
59
+ @@records_dup=@@records.clone
60
+ super_records=[]
61
+ (@@records_dup.size/10000).times do
62
+ super_records<<@@records_dup.pop(10000)
63
+ end
64
+ super_records<<@@records_dup
65
+
66
+ super_records.each do|batch|
67
+ xml = "#{@@XML_HEADER}<sObjects xmlns=\"http://www.force.com/2009/06/asyncapi/dataload\">"
68
+ batch.each do |r|
69
+ xml += "<sObject>"
70
+ keys.each do |k|
71
+ xml += "<#{k}>#{r[k]}</#{k}>"
72
+ end
73
+ xml += "</sObject>"
74
+ end
75
+ xml += "</sObjects>"
76
+
77
+
78
+ path = "job/#{@@job_id}/batch/"
79
+ headers = Hash["Content-Type" => "application/xml; charset=UTF-8"]
80
+ response = @@connection.post_xml(nil, path, xml, headers)
81
+ response_parsed = XmlSimple.xml_in(response)
82
+ @@batch_id = response_parsed['id'][0]
83
+ puts @@batch_id
84
+ end
85
+ end
86
+
87
+ def check_batch_status()
88
+ headers = Hash.new
89
+ response = @@connection.get_request(nil, path, headers)
90
+ response_parsed = XmlSimple.xml_in(response)
91
+ puts response_parsed
92
+ begin
93
+ #puts "check: #{response_parsed.inspect}\n"
94
+ response_parsed['state'][0]
95
+ rescue Exception => e
96
+ #puts "check: #{response_parsed.inspect}\n"
97
+
98
+ nil
99
+ end
100
+ end
101
+
102
+ def get_batch_result()
103
+ path = "job/#{@@job_id}/batch/#{@@batch_id}/result"
104
+ headers = Hash["Content-Type" => "application/xml; charset=UTF-8"]
105
+
106
+ response = @@connection.get_request(nil, path, headers)
107
+
108
+ if(@@operation == "query") # The query op requires us to do another request to get the results
109
+ response_parsed = XmlSimple.xml_in(response)
110
+ result_id = response_parsed["result"][0]
111
+
112
+ path = "job/#{@@job_id}/batch/#{@@batch_id}/result/#{result_id}"
113
+ headers = Hash.new
114
+ headers = Hash["Content-Type" => "application/xml; charset=UTF-8"]
115
+ response = @@connection.get_request(nil, path, headers)
116
+ end
117
+ titles = []
118
+ doc = REXML::Document.new(response)
119
+ doc.elements.each('results/result/success') do |ele|
120
+ titles << ele.text
121
+ end
122
+ return titles
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,3 @@
1
+ module SalesforceBulk
2
+ VERSION = "0.0.5"
3
+ end
@@ -0,0 +1,78 @@
1
+ require 'net/https'
2
+ require 'rubygems'
3
+ require 'xmlsimple'
4
+ require 'csv'
5
+ require "#{File.dirname(File.expand_path(__FILE__))}/salesforce_bulk/version"
6
+ require "#{File.dirname(File.expand_path(__FILE__))}/salesforce_bulk/job"
7
+ require "#{File.dirname(File.expand_path(__FILE__))}/salesforce_bulk/connection"
8
+ require 'databasedotcom'
9
+
10
+ module SalesforceBulk
11
+ class Api
12
+
13
+ @@SALESFORCE_API_VERSION = '23.0'
14
+
15
+ def initialize(options)
16
+ client = databasedotcom_client(options[:token], options[:instance_url])
17
+ @connection = SalesforceBulk::Connection.new(@@SALESFORCE_API_VERSION,client)
18
+ end
19
+
20
+ def databasedotcom_client(token, instance_url)
21
+ client = Databasedotcom::Client.new("#{Rails.root}/config/databasedotcom.yml")
22
+ client.authenticate :token => token, :instance_url => instance_url
23
+ client
24
+ end
25
+
26
+ def upsert(sobject, records, external_field)
27
+ self.do_operation('upsert', sobject, records, external_field)
28
+ end
29
+
30
+ def update(sobject, records)
31
+ self.do_operation('update', sobject, records, nil)
32
+ end
33
+
34
+ def create(sobject, records)
35
+ self.do_operation('insert', sobject, records, nil)
36
+ end
37
+
38
+ def delete(sobject, records)
39
+ self.do_operation('delete', sobject, records, nil)
40
+ end
41
+
42
+ def query(sobject, query)
43
+ self.do_operation('query', sobject, query, nil)
44
+ end
45
+
46
+ #private
47
+
48
+ def do_operation(operation, sobject, records, external_field)
49
+ job = SalesforceBulk::Job.new(operation, sobject, records, external_field, @connection)
50
+
51
+ # TODO: put this in one function
52
+ job_id = job.create_job()
53
+ if(operation == "query")
54
+ batch_id = job.add_query()
55
+ else
56
+ batch_id = job.add_batch()
57
+ end
58
+ job.close_job()
59
+
60
+ while true
61
+ state = job.check_batch_status()
62
+ #puts "\nstate is #{state}\n"
63
+ if state != "Queued" && state != "InProgress"
64
+ break
65
+ end
66
+ sleep(2) # wait x seconds and check again
67
+ end
68
+
69
+ if state == 'Completed'
70
+ return job.get_batch_result()
71
+ else
72
+ return ["error"]
73
+ end
74
+
75
+ end
76
+
77
+ end # End class
78
+ end
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: salesforce_bulk_oauth2
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.5
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Bhushan Lodha
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-31 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: xml-simple
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: databasedotcom
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: This gem provides a super simple interface for the Salesforce Bulk API
47
+ through Oauth2. It provides support for insert, update, upsert, delete, and query.
48
+ email:
49
+ - bhushanlodha@gmail.com
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - README.rdoc
55
+ - lib/salesforce_bulk/connection.rb
56
+ - lib/salesforce_bulk/job.rb
57
+ - lib/salesforce_bulk/version.rb
58
+ - lib/salesforce_bulk_oauth2.rb
59
+ homepage: https://github.com/bhushan/salesforce_bulk_oauth2
60
+ licenses: []
61
+ post_install_message:
62
+ rdoc_options: []
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ requirements: []
78
+ rubyforge_project:
79
+ rubygems_version: 1.8.24
80
+ signing_key:
81
+ specification_version: 3
82
+ summary: Ruby support for the Salesforce Bulk API using Oauth2
83
+ test_files: []