salesforce_bulk_api 1.1.0 → 1.2.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 +4 -4
- data/LICENCE +1 -1
- data/README.md +110 -69
- data/Rakefile +3 -3
- data/lib/salesforce_bulk_api/concerns/throttling.rb +7 -18
- data/lib/salesforce_bulk_api/connection.rb +56 -62
- data/lib/salesforce_bulk_api/job.rb +84 -205
- data/lib/salesforce_bulk_api/version.rb +1 -1
- data/lib/salesforce_bulk_api.rb +35 -47
- data/salesforce_bulk_api.gemspec +17 -18
- data/spec/salesforce_bulk_api/salesforce_bulk_api_spec.rb +105 -113
- data/spec/spec_helper.rb +4 -4
- metadata +33 -10
@@ -1,193 +1,185 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require "spec_helper"
|
2
|
+
require "yaml"
|
3
|
+
require "restforce"
|
4
4
|
|
5
5
|
describe SalesforceBulkApi do
|
6
|
-
|
7
6
|
before :each do
|
8
|
-
auth_hash = YAML.load_file(
|
9
|
-
sfdc_auth_hash = auth_hash[
|
7
|
+
auth_hash = YAML.load_file("auth_credentials.yml")
|
8
|
+
sfdc_auth_hash = auth_hash["salesforce"]
|
10
9
|
|
11
10
|
@sf_client = Restforce.new(
|
12
|
-
username: sfdc_auth_hash[
|
13
|
-
password: sfdc_auth_hash[
|
14
|
-
client_id: sfdc_auth_hash[
|
15
|
-
client_secret: sfdc_auth_hash[
|
16
|
-
host: sfdc_auth_hash[
|
11
|
+
username: sfdc_auth_hash["user"],
|
12
|
+
password: sfdc_auth_hash["passwordandtoken"],
|
13
|
+
client_id: sfdc_auth_hash["client_id"],
|
14
|
+
client_secret: sfdc_auth_hash["client_secret"],
|
15
|
+
host: sfdc_auth_hash["host"]
|
16
|
+
)
|
17
17
|
@sf_client.authenticate!
|
18
18
|
|
19
|
-
@account_id = auth_hash[
|
19
|
+
@account_id = auth_hash["salesforce"]["test_account_id"]
|
20
20
|
|
21
21
|
@api = SalesforceBulkApi::Api.new(@sf_client)
|
22
22
|
end
|
23
23
|
|
24
24
|
after :each do
|
25
|
-
|
26
25
|
end
|
27
26
|
|
28
|
-
describe
|
29
|
-
|
30
|
-
context 'when not passed get_result' do
|
27
|
+
describe "upsert" do
|
28
|
+
context "when not passed get_result" do
|
31
29
|
it "doesn't return the batches array" do
|
32
|
-
res = @api.upsert(
|
33
|
-
res[
|
30
|
+
res = @api.upsert("Account", [{Id: @account_id, Website: "www.test.com"}], "Id")
|
31
|
+
res["batches"].should be_nil
|
34
32
|
end
|
35
33
|
end
|
36
34
|
|
37
|
-
context
|
38
|
-
it
|
39
|
-
res = @api.upsert(
|
40
|
-
res[
|
41
|
-
|
42
|
-
res['batches'][0]['response'][0]['id'][0].should start_with(@account_id)
|
43
|
-
res['batches'][0]['response'][0]['success'].should eq ['true']
|
44
|
-
res['batches'][0]['response'][0]['created'].should eq ['false']
|
35
|
+
context "when passed get_result = true" do
|
36
|
+
it "returns the batches array" do
|
37
|
+
res = @api.upsert("Account", [{Id: @account_id, Website: "www.test.com"}], "Id", true)
|
38
|
+
res["batches"][0]["response"].is_a? Array
|
45
39
|
|
40
|
+
res["batches"][0]["response"][0]["id"][0].should start_with(@account_id)
|
41
|
+
res["batches"][0]["response"][0]["success"].should eq ["true"]
|
42
|
+
res["batches"][0]["response"][0]["created"].should eq ["false"]
|
46
43
|
end
|
47
44
|
end
|
48
45
|
|
49
|
-
context
|
50
|
-
it
|
51
|
-
@api.update(
|
52
|
-
res = @api.query(
|
53
|
-
res[
|
54
|
-
res[
|
55
|
-
res = @api.upsert(
|
56
|
-
res[
|
57
|
-
res[
|
58
|
-
res[
|
59
|
-
res = @api.query(
|
60
|
-
res[
|
61
|
-
res[
|
46
|
+
context "when passed send_nulls = true" do
|
47
|
+
it "sets the nil and empty attributes to NULL" do
|
48
|
+
@api.update("Account", [{Id: @account_id, Website: "abc123", Phone: "5678"}], true)
|
49
|
+
res = @api.query("Account", "SELECT Website, Phone From Account WHERE Id = '#{@account_id}'")
|
50
|
+
res["batches"][0]["response"][0]["Website"][0].should eq "abc123"
|
51
|
+
res["batches"][0]["response"][0]["Phone"][0].should eq "5678"
|
52
|
+
res = @api.upsert("Account", [{Id: @account_id, Website: "", Phone: nil}], "Id", true, true)
|
53
|
+
res["batches"][0]["response"][0]["id"][0].should start_with(@account_id)
|
54
|
+
res["batches"][0]["response"][0]["success"].should eq ["true"]
|
55
|
+
res["batches"][0]["response"][0]["created"].should eq ["false"]
|
56
|
+
res = @api.query("Account", "SELECT Website, Phone From Account WHERE Id = '#{@account_id}'")
|
57
|
+
res["batches"][0]["response"][0]["Website"][0].should eq({"xsi:nil" => "true"})
|
58
|
+
res["batches"][0]["response"][0]["Phone"][0].should eq({"xsi:nil" => "true"})
|
62
59
|
end
|
63
60
|
end
|
64
61
|
|
65
|
-
context
|
66
|
-
it
|
67
|
-
@api.update(
|
68
|
-
res = @api.query(
|
69
|
-
res[
|
70
|
-
res[
|
71
|
-
res = @api.upsert(
|
72
|
-
res[
|
73
|
-
res[
|
74
|
-
res[
|
75
|
-
res = @api.query(
|
76
|
-
res[
|
77
|
-
res[
|
62
|
+
context "when passed send_nulls = true and an array of fields not to null" do
|
63
|
+
it "sets the nil and empty attributes to NULL, except for those included in the list of fields to ignore" do
|
64
|
+
@api.update("Account", [{Id: @account_id, Website: "abc123", Phone: "5678"}], true)
|
65
|
+
res = @api.query("Account", "SELECT Website, Phone From Account WHERE Id = '#{@account_id}'")
|
66
|
+
res["batches"][0]["response"][0]["Website"][0].should eq "abc123"
|
67
|
+
res["batches"][0]["response"][0]["Phone"][0].should eq "5678"
|
68
|
+
res = @api.upsert("Account", [{Id: @account_id, Website: "", Phone: nil}], "Id", true, true, [:Website, :Phone])
|
69
|
+
res["batches"][0]["response"][0]["id"][0].should start_with(@account_id)
|
70
|
+
res["batches"][0]["response"][0]["success"].should eq ["true"]
|
71
|
+
res["batches"][0]["response"][0]["created"].should eq ["false"]
|
72
|
+
res = @api.query("Account", "SELECT Website, Phone From Account WHERE Id = '#{@account_id}'")
|
73
|
+
res["batches"][0]["response"][0]["Website"][0].should eq("abc123")
|
74
|
+
res["batches"][0]["response"][0]["Phone"][0].should eq("5678")
|
78
75
|
end
|
79
76
|
end
|
80
|
-
|
81
77
|
end
|
82
78
|
|
83
|
-
describe
|
84
|
-
context
|
85
|
-
context
|
79
|
+
describe "update" do
|
80
|
+
context "when there is not an error" do
|
81
|
+
context "when not passed get_result" do
|
86
82
|
it "doesnt return the batches array" do
|
87
|
-
res = @api.update(
|
88
|
-
res[
|
83
|
+
res = @api.update("Account", [{Id: @account_id, Website: "www.test.com"}])
|
84
|
+
res["batches"].should be_nil
|
89
85
|
end
|
90
86
|
end
|
91
87
|
|
92
|
-
context
|
93
|
-
it
|
94
|
-
res = @api.update(
|
95
|
-
res[
|
96
|
-
res[
|
97
|
-
res[
|
98
|
-
res[
|
88
|
+
context "when passed get_result = true" do
|
89
|
+
it "returns the batches array" do
|
90
|
+
res = @api.update("Account", [{Id: @account_id, Website: "www.test.com"}], true)
|
91
|
+
res["batches"][0]["response"].is_a? Array
|
92
|
+
res["batches"][0]["response"][0]["id"][0].should start_with(@account_id)
|
93
|
+
res["batches"][0]["response"][0]["success"].should eq ["true"]
|
94
|
+
res["batches"][0]["response"][0]["created"].should eq ["false"]
|
99
95
|
end
|
100
96
|
end
|
101
97
|
end
|
102
98
|
|
103
|
-
context
|
104
|
-
context
|
99
|
+
context "when there is an error" do
|
100
|
+
context "when not passed get_result" do
|
105
101
|
it "doesn't return the results array" do
|
106
|
-
res = @api.update(
|
107
|
-
res[
|
102
|
+
res = @api.update("Account", [{Id: @account_id, Website: "www.test.com"}, {Id: "abc123", Website: "www.test.com"}])
|
103
|
+
res["batches"].should be_nil
|
108
104
|
end
|
109
105
|
end
|
110
106
|
|
111
|
-
context
|
112
|
-
it
|
113
|
-
res = @api.update(
|
114
|
-
|
115
|
-
res[
|
116
|
-
res[
|
117
|
-
res[
|
118
|
-
res[
|
119
|
-
res[
|
120
|
-
res[
|
121
|
-
|
122
|
-
res[
|
123
|
-
res[
|
124
|
-
res[
|
125
|
-
res[
|
107
|
+
context "when passed get_result = true with batches" do
|
108
|
+
it "returns the results array" do
|
109
|
+
res = @api.update("Account", [{Id: @account_id, Website: "www.test.com"}, {Id: @account_id, Website: "www.test.com"}, {Id: @account_id, Website: "www.test.com"}, {Id: "abc123", Website: "www.test.com"}], true, false, [], 2)
|
110
|
+
|
111
|
+
res["batches"][0]["response"][0]["id"][0].should start_with(@account_id)
|
112
|
+
res["batches"][0]["response"][0]["success"].should eq ["true"]
|
113
|
+
res["batches"][0]["response"][0]["created"].should eq ["false"]
|
114
|
+
res["batches"][0]["response"][1]["id"][0].should start_with(@account_id)
|
115
|
+
res["batches"][0]["response"][1]["success"].should eq ["true"]
|
116
|
+
res["batches"][0]["response"][1]["created"].should eq ["false"]
|
117
|
+
|
118
|
+
res["batches"][1]["response"][0]["id"][0].should start_with(@account_id)
|
119
|
+
res["batches"][1]["response"][0]["success"].should eq ["true"]
|
120
|
+
res["batches"][1]["response"][0]["created"].should eq ["false"]
|
121
|
+
res["batches"][1]["response"][1].should eq({"errors" => [{"fields" => ["Id"], "message" => ["Account ID: id value of incorrect type: abc123"], "statusCode" => ["MALFORMED_ID"]}], "success" => ["false"], "created" => ["false"]})
|
126
122
|
end
|
127
123
|
end
|
128
124
|
end
|
129
|
-
|
130
125
|
end
|
131
126
|
|
132
|
-
describe
|
127
|
+
describe "create" do
|
133
128
|
pending
|
134
129
|
end
|
135
130
|
|
136
|
-
describe
|
131
|
+
describe "delete" do
|
137
132
|
pending
|
138
133
|
end
|
139
134
|
|
140
|
-
describe
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
res
|
145
|
-
res[
|
146
|
-
res['batches'][0]['response'][0]['Id'].should_not be_nil
|
135
|
+
describe "query" do
|
136
|
+
context "when there are results" do
|
137
|
+
it "returns the query results" do
|
138
|
+
res = @api.query("Account", "SELECT id, Name From Account WHERE Name LIKE 'Test%'")
|
139
|
+
res["batches"][0]["response"].length.should > 1
|
140
|
+
res["batches"][0]["response"][0]["Id"].should_not be_nil
|
147
141
|
end
|
148
142
|
|
149
|
-
context
|
143
|
+
context "and there are multiple batches" do
|
150
144
|
# need dev to create > 10k records in dev organization
|
151
|
-
it
|
145
|
+
it "returns the query results in a merged hash"
|
152
146
|
end
|
153
147
|
end
|
154
148
|
|
155
|
-
context
|
156
|
-
it
|
157
|
-
res = @api.query(
|
158
|
-
res[
|
149
|
+
context "when there are no results" do
|
150
|
+
it "returns nil" do
|
151
|
+
res = @api.query("Account", "SELECT id From Account WHERE Name = 'ABC'")
|
152
|
+
res["batches"][0]["response"].should eq nil
|
159
153
|
end
|
160
154
|
end
|
161
155
|
|
162
|
-
context
|
163
|
-
it
|
164
|
-
res = @api.query(
|
165
|
-
res[
|
156
|
+
context "when there is an error" do
|
157
|
+
it "returns nil" do
|
158
|
+
res = @api.query("Account", "SELECT id From Account WHERE Name = ''ABC'")
|
159
|
+
res["batches"][0]["response"].should eq nil
|
166
160
|
end
|
167
161
|
end
|
168
|
-
|
169
162
|
end
|
170
163
|
|
171
|
-
describe
|
172
|
-
context
|
173
|
-
it
|
164
|
+
describe "counters" do
|
165
|
+
context "when read operations are called" do
|
166
|
+
it "increments operation count and http GET count" do
|
174
167
|
@api.counters[:http_get].should eq 0
|
175
168
|
@api.counters[:query].should eq 0
|
176
|
-
@api.query(
|
169
|
+
@api.query("Account", "SELECT Website, Phone From Account WHERE Id = '#{@account_id}'")
|
177
170
|
@api.counters[:http_get].should eq 1
|
178
171
|
@api.counters[:query].should eq 1
|
179
172
|
end
|
180
173
|
end
|
181
174
|
|
182
|
-
context
|
183
|
-
it
|
175
|
+
context "when update operations are called" do
|
176
|
+
it "increments operation count and http POST count" do
|
184
177
|
@api.counters[:http_post].should eq 0
|
185
178
|
@api.counters[:update].should eq 0
|
186
|
-
@api.update(
|
179
|
+
@api.update("Account", [{Id: @account_id, Website: "abc123", Phone: "5678"}], true)
|
187
180
|
@api.counters[:http_post].should eq 1
|
188
181
|
@api.counters[:update].should eq 1
|
189
182
|
end
|
190
183
|
end
|
191
184
|
end
|
192
|
-
|
193
185
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require "rubygems"
|
2
|
+
require "bundler/setup"
|
3
|
+
require "salesforce_bulk_api"
|
4
4
|
|
5
5
|
RSpec.configure do |c|
|
6
|
-
c.filter_run :
|
6
|
+
c.filter_run focus: true
|
7
7
|
c.run_all_when_everything_filtered = true
|
8
8
|
end
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: salesforce_bulk_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yatish Mehta
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-03-23 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: json
|
@@ -38,6 +37,20 @@ dependencies:
|
|
38
37
|
- - ">="
|
39
38
|
- !ruby/object:Gem::Version
|
40
39
|
version: '0'
|
40
|
+
- !ruby/object:Gem::Dependency
|
41
|
+
name: csv
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
type: :runtime
|
48
|
+
prerelease: false
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
41
54
|
- !ruby/object:Gem::Dependency
|
42
55
|
name: rspec
|
43
56
|
requirement: !ruby/object:Gem::Requirement
|
@@ -94,9 +107,23 @@ dependencies:
|
|
94
107
|
- - ">="
|
95
108
|
- !ruby/object:Gem::Version
|
96
109
|
version: '0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: standardrb
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
type: :development
|
118
|
+
prerelease: false
|
119
|
+
version_requirements: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - ">="
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0'
|
97
124
|
description: Salesforce Bulk API with governor limits taken care of
|
98
125
|
email:
|
99
|
-
-
|
126
|
+
- yatish27@users.noreply.github.com
|
100
127
|
executables: []
|
101
128
|
extensions: []
|
102
129
|
extra_rdoc_files: []
|
@@ -119,7 +146,6 @@ files:
|
|
119
146
|
homepage: https://github.com/yatishmehta27/salesforce_bulk_api
|
120
147
|
licenses: []
|
121
148
|
metadata: {}
|
122
|
-
post_install_message:
|
123
149
|
rdoc_options: []
|
124
150
|
require_paths:
|
125
151
|
- lib
|
@@ -134,10 +160,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
134
160
|
- !ruby/object:Gem::Version
|
135
161
|
version: '0'
|
136
162
|
requirements: []
|
137
|
-
rubygems_version: 3.5
|
138
|
-
signing_key:
|
163
|
+
rubygems_version: 3.6.5
|
139
164
|
specification_version: 4
|
140
165
|
summary: It uses the bulk api of salesforce to communicate with Salesforce CRM
|
141
|
-
test_files:
|
142
|
-
- spec/salesforce_bulk_api/salesforce_bulk_api_spec.rb
|
143
|
-
- spec/spec_helper.rb
|
166
|
+
test_files: []
|