salesforce_bulk_api 1.2.0 → 1.3.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/.env.sample +7 -0
- data/.github/workflows/ci.yml +36 -0
- data/.gitignore +1 -0
- data/.rspec +1 -1
- data/.rubocop.yml +1927 -0
- data/CHANGELOG.md +0 -0
- data/README.md +332 -18
- data/lib/salesforce_bulk_api/concerns/throttling.rb +15 -6
- data/lib/salesforce_bulk_api/connection.rb +55 -51
- data/lib/salesforce_bulk_api/job.rb +193 -74
- data/lib/salesforce_bulk_api/version.rb +1 -1
- data/lib/salesforce_bulk_api.rb +32 -21
- data/salesforce_bulk_api.gemspec +5 -2
- data/spec/salesforce_bulk_api/salesforce_bulk_api_spec.rb +70 -105
- data/spec/spec_helper.rb +3 -0
- metadata +52 -6
@@ -3,75 +3,70 @@ require "yaml"
|
|
3
3
|
require "restforce"
|
4
4
|
|
5
5
|
describe SalesforceBulkApi do
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
client_secret: sfdc_auth_hash["client_secret"],
|
15
|
-
host: sfdc_auth_hash["host"]
|
6
|
+
let(:sf_client) do
|
7
|
+
client = Restforce.new(
|
8
|
+
username: ENV["SALESFORCE_USERNAME"],
|
9
|
+
password: ENV["SALESFORCE_PASSWORD"],
|
10
|
+
client_id: ENV["SALESFORCE_CLIENT_ID"],
|
11
|
+
client_secret: ENV["SALESFORCE_CLIENT_SECRET"],
|
12
|
+
host: ENV["SALESFORCE_HOST"],
|
13
|
+
security_token: ENV["SALESFORCE_SECURITY_TOKEN"]
|
16
14
|
)
|
17
|
-
|
18
|
-
|
19
|
-
@account_id = auth_hash["salesforce"]["test_account_id"]
|
20
|
-
|
21
|
-
@api = SalesforceBulkApi::Api.new(@sf_client)
|
15
|
+
client.authenticate!
|
16
|
+
client
|
22
17
|
end
|
23
18
|
|
24
|
-
|
25
|
-
|
19
|
+
let(:account_id) { ENV["SALESFORCE_TEST_ACCOUNT_ID"] }
|
20
|
+
let(:api) { SalesforceBulkApi::Api.new(sf_client) }
|
26
21
|
|
27
22
|
describe "upsert" do
|
28
23
|
context "when not passed get_result" do
|
29
24
|
it "doesn't return the batches array" do
|
30
|
-
res =
|
31
|
-
res["batches"].
|
25
|
+
res = api.upsert("Account", [{Id: account_id, Website: "www.test.com"}], "Id")
|
26
|
+
expect(res["batches"]).to be_nil
|
32
27
|
end
|
33
28
|
end
|
34
29
|
|
35
30
|
context "when passed get_result = true" do
|
36
31
|
it "returns the batches array" do
|
37
|
-
res =
|
38
|
-
res["batches"][0]["response"].
|
32
|
+
res = api.upsert("Account", [{Id: account_id, Website: "www.test.com"}], "Id", true)
|
33
|
+
expect(res["batches"][0]["response"]).to be_a Array
|
39
34
|
|
40
|
-
res["batches"][0]["response"][0]["id"][0].
|
41
|
-
res["batches"][0]["response"][0]["success"].
|
42
|
-
res["batches"][0]["response"][0]["created"].
|
35
|
+
expect(res["batches"][0]["response"][0]["id"][0]).to start_with(account_id)
|
36
|
+
expect(res["batches"][0]["response"][0]["success"]).to eq ["true"]
|
37
|
+
expect(res["batches"][0]["response"][0]["created"]).to eq ["false"]
|
43
38
|
end
|
44
39
|
end
|
45
40
|
|
46
41
|
context "when passed send_nulls = true" do
|
47
42
|
it "sets the nil and empty attributes to NULL" do
|
48
|
-
|
49
|
-
res =
|
50
|
-
res["batches"][0]["response"][0]["Website"][0].
|
51
|
-
res["batches"][0]["response"][0]["Phone"][0].
|
52
|
-
res =
|
53
|
-
res["batches"][0]["response"][0]["id"][0].
|
54
|
-
res["batches"][0]["response"][0]["success"].
|
55
|
-
res["batches"][0]["response"][0]["created"].
|
56
|
-
res =
|
57
|
-
res["batches"][0]["response"][0]["Website"][0].
|
58
|
-
res["batches"][0]["response"][0]["Phone"][0].
|
43
|
+
api.update("Account", [{Id: account_id, Website: "abc123", Phone: "5678"}], true)
|
44
|
+
res = api.query("Account", "SELECT Website, Phone From Account WHERE Id = '#{account_id}'")
|
45
|
+
expect(res["batches"][0]["response"][0]["Website"][0]).to eq "abc123"
|
46
|
+
expect(res["batches"][0]["response"][0]["Phone"][0]).to eq "5678"
|
47
|
+
res = api.upsert("Account", [{Id: account_id, Website: "", Phone: nil}], "Id", true, true)
|
48
|
+
expect(res["batches"][0]["response"][0]["id"][0]).to start_with(account_id)
|
49
|
+
expect(res["batches"][0]["response"][0]["success"]).to eq ["true"]
|
50
|
+
expect(res["batches"][0]["response"][0]["created"]).to eq ["false"]
|
51
|
+
res = api.query("Account", "SELECT Website, Phone From Account WHERE Id = '#{account_id}'")
|
52
|
+
expect(res["batches"][0]["response"][0]["Website"][0]).to eq({"xsi:nil" => "true"})
|
53
|
+
expect(res["batches"][0]["response"][0]["Phone"][0]).to eq({"xsi:nil" => "true"})
|
59
54
|
end
|
60
55
|
end
|
61
56
|
|
62
57
|
context "when passed send_nulls = true and an array of fields not to null" do
|
63
58
|
it "sets the nil and empty attributes to NULL, except for those included in the list of fields to ignore" do
|
64
|
-
|
65
|
-
res =
|
66
|
-
res["batches"][0]["response"][0]["Website"][0].
|
67
|
-
res["batches"][0]["response"][0]["Phone"][0].
|
68
|
-
res =
|
69
|
-
res["batches"][0]["response"][0]["id"][0].
|
70
|
-
res["batches"][0]["response"][0]["success"].
|
71
|
-
res["batches"][0]["response"][0]["created"].
|
72
|
-
res =
|
73
|
-
res["batches"][0]["response"][0]["Website"][0].
|
74
|
-
res["batches"][0]["response"][0]["Phone"][0].
|
59
|
+
api.update("Account", [{Id: account_id, Website: "abc123", Phone: "5678"}], true)
|
60
|
+
res = api.query("Account", "SELECT Website, Phone From Account WHERE Id = '#{account_id}'")
|
61
|
+
expect(res["batches"][0]["response"][0]["Website"][0]).to eq "abc123"
|
62
|
+
expect(res["batches"][0]["response"][0]["Phone"][0]).to eq "5678"
|
63
|
+
res = api.upsert("Account", [{Id: account_id, Website: "", Phone: nil}], "Id", true, true, [:Website, :Phone])
|
64
|
+
expect(res["batches"][0]["response"][0]["id"][0]).to start_with(account_id)
|
65
|
+
expect(res["batches"][0]["response"][0]["success"]).to eq ["true"]
|
66
|
+
expect(res["batches"][0]["response"][0]["created"]).to eq ["false"]
|
67
|
+
res = api.query("Account", "SELECT Website, Phone From Account WHERE Id = '#{account_id}'")
|
68
|
+
expect(res["batches"][0]["response"][0]["Website"][0]).to eq("abc123")
|
69
|
+
expect(res["batches"][0]["response"][0]["Phone"][0]).to eq("5678")
|
75
70
|
end
|
76
71
|
end
|
77
72
|
end
|
@@ -80,18 +75,18 @@ describe SalesforceBulkApi do
|
|
80
75
|
context "when there is not an error" do
|
81
76
|
context "when not passed get_result" do
|
82
77
|
it "doesnt return the batches array" do
|
83
|
-
res =
|
84
|
-
res["batches"].
|
78
|
+
res = api.update("Account", [{Id: account_id, Website: "www.test.com"}])
|
79
|
+
expect(res["batches"]).to be_nil
|
85
80
|
end
|
86
81
|
end
|
87
82
|
|
88
83
|
context "when passed get_result = true" do
|
89
84
|
it "returns the batches array" do
|
90
|
-
res =
|
91
|
-
res["batches"][0]["response"].
|
92
|
-
res["batches"][0]["response"][0]["id"][0].
|
93
|
-
res["batches"][0]["response"][0]["success"].
|
94
|
-
res["batches"][0]["response"][0]["created"].
|
85
|
+
res = api.update("Account", [{Id: account_id, Website: "www.test.com"}], true)
|
86
|
+
expect(res["batches"][0]["response"]).to be_a Array
|
87
|
+
expect(res["batches"][0]["response"][0]["id"][0]).to start_with(account_id)
|
88
|
+
expect(res["batches"][0]["response"][0]["success"]).to eq ["true"]
|
89
|
+
expect(res["batches"][0]["response"][0]["created"]).to eq ["false"]
|
95
90
|
end
|
96
91
|
end
|
97
92
|
end
|
@@ -99,45 +94,37 @@ describe SalesforceBulkApi do
|
|
99
94
|
context "when there is an error" do
|
100
95
|
context "when not passed get_result" do
|
101
96
|
it "doesn't return the results array" do
|
102
|
-
res =
|
103
|
-
res["batches"].
|
97
|
+
res = api.update("Account", [{Id: account_id, Website: "www.test.com"}, {Id: "abc123", Website: "www.test.com"}])
|
98
|
+
expect(res["batches"]).to be_nil
|
104
99
|
end
|
105
100
|
end
|
106
101
|
|
107
102
|
context "when passed get_result = true with batches" do
|
108
103
|
it "returns the results array" do
|
109
|
-
res =
|
110
|
-
|
111
|
-
res["batches"][0]["response"][0]["id"][0].
|
112
|
-
res["batches"][0]["response"][0]["success"].
|
113
|
-
res["batches"][0]["response"][0]["created"].
|
114
|
-
res["batches"][0]["response"][1]["id"][0].
|
115
|
-
res["batches"][0]["response"][1]["success"].
|
116
|
-
res["batches"][0]["response"][1]["created"].
|
117
|
-
|
118
|
-
res["batches"][1]["response"][0]["id"][0].
|
119
|
-
res["batches"][1]["response"][0]["success"].
|
120
|
-
res["batches"][1]["response"][0]["created"].
|
121
|
-
res["batches"][1]["response"][1].
|
104
|
+
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)
|
105
|
+
|
106
|
+
expect(res["batches"][0]["response"][0]["id"][0]).to start_with(account_id)
|
107
|
+
expect(res["batches"][0]["response"][0]["success"]).to eq ["true"]
|
108
|
+
expect(res["batches"][0]["response"][0]["created"]).to eq ["false"]
|
109
|
+
expect(res["batches"][0]["response"][1]["id"][0]).to start_with(account_id)
|
110
|
+
expect(res["batches"][0]["response"][1]["success"]).to eq ["true"]
|
111
|
+
expect(res["batches"][0]["response"][1]["created"]).to eq ["false"]
|
112
|
+
|
113
|
+
expect(res["batches"][1]["response"][0]["id"][0]).to start_with(account_id)
|
114
|
+
expect(res["batches"][1]["response"][0]["success"]).to eq ["true"]
|
115
|
+
expect(res["batches"][1]["response"][0]["created"]).to eq ["false"]
|
116
|
+
expect(res["batches"][1]["response"][1]).to eq({"errors" => [{"fields" => ["Id"], "message" => ["Account ID: id value of incorrect type: abc123"], "statusCode" => ["MALFORMED_ID"]}], "success" => ["false"], "created" => ["false"]})
|
122
117
|
end
|
123
118
|
end
|
124
119
|
end
|
125
120
|
end
|
126
121
|
|
127
|
-
describe "create" do
|
128
|
-
pending
|
129
|
-
end
|
130
|
-
|
131
|
-
describe "delete" do
|
132
|
-
pending
|
133
|
-
end
|
134
|
-
|
135
122
|
describe "query" do
|
136
123
|
context "when there are results" do
|
137
124
|
it "returns the query results" do
|
138
|
-
res =
|
139
|
-
res["batches"][0]["response"].length.
|
140
|
-
res["batches"][0]["response"][0]["Id"].
|
125
|
+
res = api.query("Account", "SELECT id, Name From Account WHERE Name LIKE 'Test%'")
|
126
|
+
expect(res["batches"][0]["response"].length).to be > 1
|
127
|
+
expect(res["batches"][0]["response"][0]["Id"]).not_to be_nil
|
141
128
|
end
|
142
129
|
|
143
130
|
context "and there are multiple batches" do
|
@@ -148,37 +135,15 @@ describe SalesforceBulkApi do
|
|
148
135
|
|
149
136
|
context "when there are no results" do
|
150
137
|
it "returns nil" do
|
151
|
-
res =
|
152
|
-
res["batches"][0]["response"].
|
138
|
+
res = api.query("Account", "SELECT id From Account WHERE Name = 'ABC'")
|
139
|
+
expect(res["batches"][0]["response"]).to be_nil
|
153
140
|
end
|
154
141
|
end
|
155
142
|
|
156
143
|
context "when there is an error" do
|
157
144
|
it "returns nil" do
|
158
|
-
res =
|
159
|
-
res["batches"][0]["response"].
|
160
|
-
end
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
describe "counters" do
|
165
|
-
context "when read operations are called" do
|
166
|
-
it "increments operation count and http GET count" do
|
167
|
-
@api.counters[:http_get].should eq 0
|
168
|
-
@api.counters[:query].should eq 0
|
169
|
-
@api.query("Account", "SELECT Website, Phone From Account WHERE Id = '#{@account_id}'")
|
170
|
-
@api.counters[:http_get].should eq 1
|
171
|
-
@api.counters[:query].should eq 1
|
172
|
-
end
|
173
|
-
end
|
174
|
-
|
175
|
-
context "when update operations are called" do
|
176
|
-
it "increments operation count and http POST count" do
|
177
|
-
@api.counters[:http_post].should eq 0
|
178
|
-
@api.counters[:update].should eq 0
|
179
|
-
@api.update("Account", [{Id: @account_id, Website: "abc123", Phone: "5678"}], true)
|
180
|
-
@api.counters[:http_post].should eq 1
|
181
|
-
@api.counters[:update].should eq 1
|
145
|
+
res = api.query("Account", "SELECT id From Account WHERE Name = ''ABC'")
|
146
|
+
expect(res["batches"][0]["response"]).to be_nil
|
182
147
|
end
|
183
148
|
end
|
184
149
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,13 +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.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yatish Mehta
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: json
|
@@ -51,6 +51,20 @@ dependencies:
|
|
51
51
|
- - ">="
|
52
52
|
- !ruby/object:Gem::Version
|
53
53
|
version: '0'
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: logger
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
type: :runtime
|
62
|
+
prerelease: false
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
54
68
|
- !ruby/object:Gem::Dependency
|
55
69
|
name: rspec
|
56
70
|
requirement: !ruby/object:Gem::Requirement
|
@@ -71,14 +85,14 @@ dependencies:
|
|
71
85
|
requirements:
|
72
86
|
- - "~>"
|
73
87
|
- !ruby/object:Gem::Version
|
74
|
-
version:
|
88
|
+
version: 8.0.0
|
75
89
|
type: :development
|
76
90
|
prerelease: false
|
77
91
|
version_requirements: !ruby/object:Gem::Requirement
|
78
92
|
requirements:
|
79
93
|
- - "~>"
|
80
94
|
- !ruby/object:Gem::Version
|
81
|
-
version:
|
95
|
+
version: 8.0.0
|
82
96
|
- !ruby/object:Gem::Dependency
|
83
97
|
name: rake
|
84
98
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,7 +122,35 @@ dependencies:
|
|
108
122
|
- !ruby/object:Gem::Version
|
109
123
|
version: '0'
|
110
124
|
- !ruby/object:Gem::Dependency
|
111
|
-
name:
|
125
|
+
name: rubocop
|
126
|
+
requirement: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - ">="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
131
|
+
type: :development
|
132
|
+
prerelease: false
|
133
|
+
version_requirements: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - ">="
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '0'
|
138
|
+
- !ruby/object:Gem::Dependency
|
139
|
+
name: rubocop-rake
|
140
|
+
requirement: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - ">="
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
145
|
+
type: :development
|
146
|
+
prerelease: false
|
147
|
+
version_requirements: !ruby/object:Gem::Requirement
|
148
|
+
requirements:
|
149
|
+
- - ">="
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
version: '0'
|
152
|
+
- !ruby/object:Gem::Dependency
|
153
|
+
name: dotenv
|
112
154
|
requirement: !ruby/object:Gem::Requirement
|
113
155
|
requirements:
|
114
156
|
- - ">="
|
@@ -128,8 +170,12 @@ executables: []
|
|
128
170
|
extensions: []
|
129
171
|
extra_rdoc_files: []
|
130
172
|
files:
|
173
|
+
- ".env.sample"
|
174
|
+
- ".github/workflows/ci.yml"
|
131
175
|
- ".gitignore"
|
132
176
|
- ".rspec"
|
177
|
+
- ".rubocop.yml"
|
178
|
+
- CHANGELOG.md
|
133
179
|
- Gemfile
|
134
180
|
- LICENCE
|
135
181
|
- README.md
|
@@ -160,7 +206,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
160
206
|
- !ruby/object:Gem::Version
|
161
207
|
version: '0'
|
162
208
|
requirements: []
|
163
|
-
rubygems_version: 3.6.
|
209
|
+
rubygems_version: 3.6.7
|
164
210
|
specification_version: 4
|
165
211
|
summary: It uses the bulk api of salesforce to communicate with Salesforce CRM
|
166
212
|
test_files: []
|