restforce-db 0.4.0 → 0.5.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/lib/file_daemon.rb +42 -0
- data/lib/restforce/db/accumulator.rb +41 -0
- data/lib/restforce/db/attribute_map.rb +132 -0
- data/lib/restforce/db/collector.rb +79 -0
- data/lib/restforce/db/initializer.rb +62 -0
- data/lib/restforce/db/instances/base.rb +1 -14
- data/lib/restforce/db/instances/salesforce.rb +7 -0
- data/lib/restforce/db/mapping.rb +33 -79
- data/lib/restforce/db/record_types/base.rb +0 -30
- data/lib/restforce/db/runner.rb +80 -0
- data/lib/restforce/db/synchronizer.rb +29 -37
- data/lib/restforce/db/version.rb +1 -1
- data/lib/restforce/db/worker.rb +53 -40
- data/lib/restforce/db.rb +6 -0
- data/test/cassettes/{Restforce_DB_Synchronizer/_run/given_a_Salesforce_record_with_an_associated_database_record/when_synchronization_is_stale/updates_the_database_record.yml → Restforce_DB_Collector/_run/given_a_Salesforce_record_with_an_associated_database_record/returns_the_attributes_from_both_records.yml} +36 -36
- data/test/cassettes/Restforce_DB_Collector/_run/given_an_existing_Salesforce_record/returns_the_attributes_from_the_Salesforce_record.yml +197 -0
- data/test/cassettes/Restforce_DB_Collector/_run/given_an_existing_database_record/returns_the_attributes_from_the_database_record.yml +81 -0
- data/test/cassettes/Restforce_DB_Initializer/_run/given_an_existing_Salesforce_record/for_a_non-root_mapping/does_not_create_a_database_record.yml +119 -0
- data/test/cassettes/{Restforce_DB_Synchronizer/_run/given_a_Salesforce_record_with_an_associated_database_record/when_synchronization_is_up-to-date/does_not_update_the_database_record.yml → Restforce_DB_Initializer/_run/given_an_existing_Salesforce_record/for_a_root_mapping/creates_a_matching_database_record.yml} +28 -28
- data/test/cassettes/{Restforce_DB_Synchronizer/_run/given_an_existing_database_record → Restforce_DB_Initializer/_run/given_an_existing_database_record/for_a_root_mapping}/populates_Salesforce_with_the_new_record.yml +44 -44
- data/test/cassettes/{Restforce_DB_Synchronizer/_run/given_an_existing_Salesforce_record/for_a_non-root_mapping/does_not_create_a_database_record.yml → Restforce_DB_Instances_Salesforce/_synced_/when_a_matching_database_record_exists/returns_true.yml} +30 -30
- data/test/cassettes/{Restforce_DB_Synchronizer/_run/given_an_existing_Salesforce_record/for_a_root_mapping/creates_a_matching_database_record.yml → Restforce_DB_Instances_Salesforce/_synced_/when_no_matching_database_record_exists/returns_false.yml} +30 -30
- data/test/cassettes/Restforce_DB_Synchronizer/_run/given_a_Salesforce_record_with_an_associated_database_record/updates_the_database_record.yml +194 -0
- data/test/cassettes/Restforce_DB_Synchronizer/_run/given_a_Salesforce_record_with_an_associated_database_record/updates_the_salesforce_record.yml +233 -0
- data/test/lib/restforce/db/accumulator_test.rb +71 -0
- data/test/lib/restforce/db/attribute_map_test.rb +70 -0
- data/test/lib/restforce/db/collector_test.rb +91 -0
- data/test/lib/restforce/db/initializer_test.rb +92 -0
- data/test/lib/restforce/db/instances/active_record_test.rb +0 -13
- data/test/lib/restforce/db/instances/salesforce_test.rb +20 -13
- data/test/lib/restforce/db/mapping_test.rb +1 -37
- data/test/lib/restforce/db/record_types/active_record_test.rb +0 -40
- data/test/lib/restforce/db/runner_test.rb +40 -0
- data/test/lib/restforce/db/synchronizer_test.rb +26 -86
- metadata +23 -7
@@ -0,0 +1,233 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: post
|
5
|
+
uri: https://<host>/services/oauth2/token
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: grant_type=password&client_id=<client_id>&client_secret=<client_secret>&username=<username>&password=<password><security_token>
|
9
|
+
headers:
|
10
|
+
User-Agent:
|
11
|
+
- Faraday v0.9.1
|
12
|
+
Content-Type:
|
13
|
+
- application/x-www-form-urlencoded
|
14
|
+
Accept-Encoding:
|
15
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
16
|
+
Accept:
|
17
|
+
- "*/*"
|
18
|
+
response:
|
19
|
+
status:
|
20
|
+
code: 200
|
21
|
+
message: OK
|
22
|
+
headers:
|
23
|
+
Date:
|
24
|
+
- Mon, 06 Apr 2015 19:27:32 GMT
|
25
|
+
Set-Cookie:
|
26
|
+
- BrowserId=H_ENFEUGR5WZTS-rk624sw;Path=/;Domain=.salesforce.com;Expires=Fri,
|
27
|
+
05-Jun-2015 19:27:32 GMT
|
28
|
+
Expires:
|
29
|
+
- Thu, 01 Jan 1970 00:00:00 GMT
|
30
|
+
Pragma:
|
31
|
+
- no-cache
|
32
|
+
Cache-Control:
|
33
|
+
- no-cache, no-store
|
34
|
+
Content-Type:
|
35
|
+
- application/json;charset=UTF-8
|
36
|
+
Transfer-Encoding:
|
37
|
+
- chunked
|
38
|
+
body:
|
39
|
+
encoding: ASCII-8BIT
|
40
|
+
string: '{"id":"https://login.salesforce.com/id/00D1a000000H3O9EAK/0051a000000UGT8AAO","issued_at":"1428348452182","token_type":"Bearer","instance_url":"https://<host>","signature":"P3OMePrj1WH7novmwXpFbmqH0DW5LbNUf9WsrRrMAUA=","access_token":"00D1a000000H3O9!AQ4AQEol4wrcAcAfVF3HH0vTJXCmqHaqBZX0.AfMcJFa2P3Ssl68tDLqC_BJKakn3tKiFCy4SzendJ0gWnbHWkqrzvFuNH6B"}'
|
41
|
+
http_version:
|
42
|
+
recorded_at: Mon, 06 Apr 2015 19:27:32 GMT
|
43
|
+
- request:
|
44
|
+
method: post
|
45
|
+
uri: https://<host>/services/data/v26.0/sobjects/CustomObject__c
|
46
|
+
body:
|
47
|
+
encoding: UTF-8
|
48
|
+
string: '{"Name":"Custom object","Example_Field__c":"Some sample text"}'
|
49
|
+
headers:
|
50
|
+
User-Agent:
|
51
|
+
- Faraday v0.9.1
|
52
|
+
Content-Type:
|
53
|
+
- application/json
|
54
|
+
Authorization:
|
55
|
+
- OAuth 00D1a000000H3O9!AQ4AQEol4wrcAcAfVF3HH0vTJXCmqHaqBZX0.AfMcJFa2P3Ssl68tDLqC_BJKakn3tKiFCy4SzendJ0gWnbHWkqrzvFuNH6B
|
56
|
+
Accept-Encoding:
|
57
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
58
|
+
Accept:
|
59
|
+
- "*/*"
|
60
|
+
response:
|
61
|
+
status:
|
62
|
+
code: 201
|
63
|
+
message: Created
|
64
|
+
headers:
|
65
|
+
Date:
|
66
|
+
- Mon, 06 Apr 2015 19:27:33 GMT
|
67
|
+
Set-Cookie:
|
68
|
+
- BrowserId=CYLdStRyQ7-Gcf0PlAt6tg;Path=/;Domain=.salesforce.com;Expires=Fri,
|
69
|
+
05-Jun-2015 19:27:33 GMT
|
70
|
+
Expires:
|
71
|
+
- Thu, 01 Jan 1970 00:00:00 GMT
|
72
|
+
Sforce-Limit-Info:
|
73
|
+
- api-usage=53/15000
|
74
|
+
Location:
|
75
|
+
- "/services/data/v26.0/sobjects/CustomObject__c/a001a000001LHpaAAG"
|
76
|
+
Content-Type:
|
77
|
+
- application/json;charset=UTF-8
|
78
|
+
Transfer-Encoding:
|
79
|
+
- chunked
|
80
|
+
body:
|
81
|
+
encoding: ASCII-8BIT
|
82
|
+
string: '{"id":"a001a000001LHpaAAG","success":true,"errors":[]}'
|
83
|
+
http_version:
|
84
|
+
recorded_at: Mon, 06 Apr 2015 19:27:33 GMT
|
85
|
+
- request:
|
86
|
+
method: get
|
87
|
+
uri: https://<host>/services/data/v26.0/query?q=select%20Id,%20SystemModstamp,%20Name,%20Example_Field__c%20from%20CustomObject__c%20where%20Id%20=%20%27a001a000001LHpaAAG%27
|
88
|
+
body:
|
89
|
+
encoding: US-ASCII
|
90
|
+
string: ''
|
91
|
+
headers:
|
92
|
+
User-Agent:
|
93
|
+
- Faraday v0.9.1
|
94
|
+
Authorization:
|
95
|
+
- OAuth 00D1a000000H3O9!AQ4AQEol4wrcAcAfVF3HH0vTJXCmqHaqBZX0.AfMcJFa2P3Ssl68tDLqC_BJKakn3tKiFCy4SzendJ0gWnbHWkqrzvFuNH6B
|
96
|
+
Accept-Encoding:
|
97
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
98
|
+
Accept:
|
99
|
+
- "*/*"
|
100
|
+
response:
|
101
|
+
status:
|
102
|
+
code: 200
|
103
|
+
message: OK
|
104
|
+
headers:
|
105
|
+
Date:
|
106
|
+
- Mon, 06 Apr 2015 19:27:34 GMT
|
107
|
+
Set-Cookie:
|
108
|
+
- BrowserId=_tii4-GdTbyU69ifAuYSlw;Path=/;Domain=.salesforce.com;Expires=Fri,
|
109
|
+
05-Jun-2015 19:27:34 GMT
|
110
|
+
Expires:
|
111
|
+
- Thu, 01 Jan 1970 00:00:00 GMT
|
112
|
+
Sforce-Limit-Info:
|
113
|
+
- api-usage=53/15000
|
114
|
+
Content-Type:
|
115
|
+
- application/json;charset=UTF-8
|
116
|
+
Transfer-Encoding:
|
117
|
+
- chunked
|
118
|
+
body:
|
119
|
+
encoding: ASCII-8BIT
|
120
|
+
string: '{"totalSize":1,"done":true,"records":[{"attributes":{"type":"CustomObject__c","url":"/services/data/v26.0/sobjects/CustomObject__c/a001a000001LHpaAAG"},"Id":"a001a000001LHpaAAG","SystemModstamp":"2015-04-06T19:27:33.000+0000","Name":"Custom
|
121
|
+
object","Example_Field__c":"Some sample text"}]}'
|
122
|
+
http_version:
|
123
|
+
recorded_at: Mon, 06 Apr 2015 19:27:34 GMT
|
124
|
+
- request:
|
125
|
+
method: patch
|
126
|
+
uri: https://<host>/services/data/v26.0/sobjects/CustomObject__c/a001a000001LHpaAAG
|
127
|
+
body:
|
128
|
+
encoding: UTF-8
|
129
|
+
string: '{"Name":"Some new name","Example_Field__c":"New sample text"}'
|
130
|
+
headers:
|
131
|
+
User-Agent:
|
132
|
+
- Faraday v0.9.1
|
133
|
+
Content-Type:
|
134
|
+
- application/json
|
135
|
+
Authorization:
|
136
|
+
- OAuth 00D1a000000H3O9!AQ4AQEol4wrcAcAfVF3HH0vTJXCmqHaqBZX0.AfMcJFa2P3Ssl68tDLqC_BJKakn3tKiFCy4SzendJ0gWnbHWkqrzvFuNH6B
|
137
|
+
Accept-Encoding:
|
138
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
139
|
+
Accept:
|
140
|
+
- "*/*"
|
141
|
+
response:
|
142
|
+
status:
|
143
|
+
code: 204
|
144
|
+
message: No Content
|
145
|
+
headers:
|
146
|
+
Date:
|
147
|
+
- Mon, 06 Apr 2015 19:27:35 GMT
|
148
|
+
Set-Cookie:
|
149
|
+
- BrowserId=w1GFuFqdRyG3lFp9_6eHRw;Path=/;Domain=.salesforce.com;Expires=Fri,
|
150
|
+
05-Jun-2015 19:27:35 GMT
|
151
|
+
Expires:
|
152
|
+
- Thu, 01 Jan 1970 00:00:00 GMT
|
153
|
+
Sforce-Limit-Info:
|
154
|
+
- api-usage=53/15000
|
155
|
+
body:
|
156
|
+
encoding: UTF-8
|
157
|
+
string: ''
|
158
|
+
http_version:
|
159
|
+
recorded_at: Mon, 06 Apr 2015 19:27:35 GMT
|
160
|
+
- request:
|
161
|
+
method: get
|
162
|
+
uri: https://<host>/services/data/v26.0/query?q=select%20Id,%20SystemModstamp,%20Name,%20Example_Field__c%20from%20CustomObject__c%20where%20Id%20=%20%27a001a000001LHpaAAG%27
|
163
|
+
body:
|
164
|
+
encoding: US-ASCII
|
165
|
+
string: ''
|
166
|
+
headers:
|
167
|
+
User-Agent:
|
168
|
+
- Faraday v0.9.1
|
169
|
+
Authorization:
|
170
|
+
- OAuth 00D1a000000H3O9!AQ4AQEol4wrcAcAfVF3HH0vTJXCmqHaqBZX0.AfMcJFa2P3Ssl68tDLqC_BJKakn3tKiFCy4SzendJ0gWnbHWkqrzvFuNH6B
|
171
|
+
Accept-Encoding:
|
172
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
173
|
+
Accept:
|
174
|
+
- "*/*"
|
175
|
+
response:
|
176
|
+
status:
|
177
|
+
code: 200
|
178
|
+
message: OK
|
179
|
+
headers:
|
180
|
+
Date:
|
181
|
+
- Mon, 06 Apr 2015 19:27:36 GMT
|
182
|
+
Set-Cookie:
|
183
|
+
- BrowserId=QeOpfDAmRk2Do-IQgxE7AQ;Path=/;Domain=.salesforce.com;Expires=Fri,
|
184
|
+
05-Jun-2015 19:27:36 GMT
|
185
|
+
Expires:
|
186
|
+
- Thu, 01 Jan 1970 00:00:00 GMT
|
187
|
+
Sforce-Limit-Info:
|
188
|
+
- api-usage=53/15000
|
189
|
+
Content-Type:
|
190
|
+
- application/json;charset=UTF-8
|
191
|
+
Transfer-Encoding:
|
192
|
+
- chunked
|
193
|
+
body:
|
194
|
+
encoding: ASCII-8BIT
|
195
|
+
string: '{"totalSize":1,"done":true,"records":[{"attributes":{"type":"CustomObject__c","url":"/services/data/v26.0/sobjects/CustomObject__c/a001a000001LHpaAAG"},"Id":"a001a000001LHpaAAG","SystemModstamp":"2015-04-06T19:27:35.000+0000","Name":"Some
|
196
|
+
new name","Example_Field__c":"New sample text"}]}'
|
197
|
+
http_version:
|
198
|
+
recorded_at: Mon, 06 Apr 2015 19:27:36 GMT
|
199
|
+
- request:
|
200
|
+
method: delete
|
201
|
+
uri: https://<host>/services/data/v26.0/sobjects/CustomObject__c/a001a000001LHpaAAG
|
202
|
+
body:
|
203
|
+
encoding: US-ASCII
|
204
|
+
string: ''
|
205
|
+
headers:
|
206
|
+
User-Agent:
|
207
|
+
- Faraday v0.9.1
|
208
|
+
Authorization:
|
209
|
+
- OAuth 00D1a000000H3O9!AQ4AQEol4wrcAcAfVF3HH0vTJXCmqHaqBZX0.AfMcJFa2P3Ssl68tDLqC_BJKakn3tKiFCy4SzendJ0gWnbHWkqrzvFuNH6B
|
210
|
+
Accept-Encoding:
|
211
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
212
|
+
Accept:
|
213
|
+
- "*/*"
|
214
|
+
response:
|
215
|
+
status:
|
216
|
+
code: 204
|
217
|
+
message: No Content
|
218
|
+
headers:
|
219
|
+
Date:
|
220
|
+
- Mon, 06 Apr 2015 19:27:37 GMT
|
221
|
+
Set-Cookie:
|
222
|
+
- BrowserId=3oZtqDLySCS_3xvQ0quJiQ;Path=/;Domain=.salesforce.com;Expires=Fri,
|
223
|
+
05-Jun-2015 19:27:37 GMT
|
224
|
+
Expires:
|
225
|
+
- Thu, 01 Jan 1970 00:00:00 GMT
|
226
|
+
Sforce-Limit-Info:
|
227
|
+
- api-usage=53/15000
|
228
|
+
body:
|
229
|
+
encoding: UTF-8
|
230
|
+
string: ''
|
231
|
+
http_version:
|
232
|
+
recorded_at: Mon, 06 Apr 2015 19:27:37 GMT
|
233
|
+
recorded_with: VCR 2.9.3
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require_relative "../../../test_helper"
|
2
|
+
|
3
|
+
describe Restforce::DB::Accumulator do
|
4
|
+
let(:accumulator) { Restforce::DB::Accumulator.new }
|
5
|
+
|
6
|
+
describe "#store" do
|
7
|
+
let(:timestamp) { Time.now }
|
8
|
+
let(:changes) { { one_fish: "Two Fish", red_fish: "Blue Fish" } }
|
9
|
+
|
10
|
+
before do
|
11
|
+
accumulator.store(timestamp, changes)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "stores the passed changeset in the accumulator" do
|
15
|
+
expect(accumulator[timestamp]).to_equal changes
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "#attributes" do
|
20
|
+
let(:timestamp) { Time.now }
|
21
|
+
let(:changes) { { one_fish: "Two Fish", red_fish: "Blue Fish" } }
|
22
|
+
|
23
|
+
before do
|
24
|
+
accumulator.store(timestamp, changes)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "returns the attributes from the recorded changeset" do
|
28
|
+
expect(accumulator.attributes).to_equal changes
|
29
|
+
end
|
30
|
+
|
31
|
+
it "combines multiple changesets" do
|
32
|
+
additional_changes = { hootie: "Blow Fish" }
|
33
|
+
|
34
|
+
accumulator.store Time.now, additional_changes
|
35
|
+
expect(accumulator.attributes).to_equal changes.merge(additional_changes)
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "with conflicting changesets" do
|
39
|
+
let(:new_changes) { { one_fish: "No Fish", red_fish: "Glow Fish" } }
|
40
|
+
|
41
|
+
it "respects the most recently updated values" do
|
42
|
+
accumulator.store timestamp + 1, new_changes
|
43
|
+
expect(accumulator.attributes).to_equal new_changes
|
44
|
+
end
|
45
|
+
|
46
|
+
it "ignores less recently updated values" do
|
47
|
+
accumulator.store timestamp - 1, new_changes
|
48
|
+
expect(accumulator.attributes).to_equal changes
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "#diff" do
|
54
|
+
let(:attributes) { { wocket: "Pocket", jertain: "Curtain", zelf: "Shelf" } }
|
55
|
+
|
56
|
+
before do
|
57
|
+
accumulator.store(Time.now, attributes)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "returns the differences from the attributes hash" do
|
61
|
+
expect(accumulator.diff(wocket: "Locket", zelf: "Belfrey")).to_equal(
|
62
|
+
wocket: "Pocket",
|
63
|
+
zelf: "Shelf",
|
64
|
+
)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "ignores attributes not set in the Accumulator" do
|
68
|
+
expect(accumulator.diff(yottle: "Bottle")).to_be :empty?
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require_relative "../../../test_helper"
|
2
|
+
|
3
|
+
describe Restforce::DB::AttributeMap do
|
4
|
+
|
5
|
+
configure!
|
6
|
+
|
7
|
+
let(:database_model) { CustomObject }
|
8
|
+
let(:salesforce_model) { "CustomObject__c" }
|
9
|
+
let(:fields) do
|
10
|
+
{
|
11
|
+
column_one: "SF_Field_One__c",
|
12
|
+
column_two: "SF_Field_Two__c",
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:attribute_map) { Restforce::DB::AttributeMap.new(database_model, salesforce_model, fields) }
|
17
|
+
|
18
|
+
describe "#attributes" do
|
19
|
+
let(:mapping) { Restforce::DB::Mapping.new(database_model, salesforce_model, fields: fields) }
|
20
|
+
|
21
|
+
it "builds a normalized Hash of database attribute values" do
|
22
|
+
attributes = attribute_map.attributes(database_model) do |attribute|
|
23
|
+
expect(mapping.database_fields.include?(attribute)).to_equal true
|
24
|
+
attribute
|
25
|
+
end
|
26
|
+
|
27
|
+
expect(attributes.keys).to_equal(mapping.database_fields)
|
28
|
+
expect(attributes.values).to_equal(mapping.database_fields)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "builds a normalized Hash of Salesforce field values" do
|
32
|
+
attributes = attribute_map.attributes(salesforce_model) do |attribute|
|
33
|
+
expect(mapping.salesforce_fields.include?(attribute)).to_equal true
|
34
|
+
attribute
|
35
|
+
end
|
36
|
+
|
37
|
+
expect(attributes.keys).to_equal(mapping.database_fields)
|
38
|
+
expect(attributes.values).to_equal(mapping.salesforce_fields)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "#convert" do
|
43
|
+
let(:attributes) { { column_one: "some value" } }
|
44
|
+
|
45
|
+
it "converts an attribute Hash to a Salesforce-compatible form" do
|
46
|
+
expect(attribute_map.convert(salesforce_model, attributes)).to_equal(
|
47
|
+
fields[attributes.keys.first] => attributes.values.first,
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "performs no special conversion for database columns" do
|
52
|
+
expect(attribute_map.convert(database_model, attributes)).to_equal(attributes)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "#convert_from_salesforce" do
|
57
|
+
let(:attributes) { { "SF_Field_One__c" => "some value" } }
|
58
|
+
|
59
|
+
it "converts an attribute Hash to a database-compatible form" do
|
60
|
+
expect(attribute_map.convert_from_salesforce(database_model, attributes)).to_equal(
|
61
|
+
fields.key(attributes.keys.first) => attributes.values.first,
|
62
|
+
)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "performs no special conversion for Salesforce fields" do
|
66
|
+
expect(attribute_map.convert_from_salesforce(salesforce_model, attributes)).to_equal(attributes)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require_relative "../../../test_helper"
|
2
|
+
|
3
|
+
describe Restforce::DB::Collector do
|
4
|
+
|
5
|
+
configure!
|
6
|
+
mappings!
|
7
|
+
|
8
|
+
let(:collector) { Restforce::DB::Collector.new(mapping) }
|
9
|
+
|
10
|
+
describe "#run", vcr: { match_requests_on: [:method, VCR.request_matchers.uri_without_param(:q)] } do
|
11
|
+
let(:attributes) do
|
12
|
+
{
|
13
|
+
name: "Custom object",
|
14
|
+
example: "Some sample text",
|
15
|
+
}
|
16
|
+
end
|
17
|
+
let(:salesforce_id) do
|
18
|
+
Salesforce.create!(
|
19
|
+
salesforce_model,
|
20
|
+
mapping.convert(salesforce_model, attributes),
|
21
|
+
)
|
22
|
+
end
|
23
|
+
let(:key) { [salesforce_id, salesforce_model] }
|
24
|
+
|
25
|
+
subject { collector.run }
|
26
|
+
|
27
|
+
describe "given an existing Salesforce record" do
|
28
|
+
before { salesforce_id }
|
29
|
+
|
30
|
+
it "returns the attributes from the Salesforce record" do
|
31
|
+
record = mapping.salesforce_record_type.find(salesforce_id)
|
32
|
+
|
33
|
+
expect(subject[key]).to_equal(
|
34
|
+
record.last_update => {
|
35
|
+
"Name" => attributes[:name],
|
36
|
+
"Example_Field__c" => attributes[:example],
|
37
|
+
},
|
38
|
+
)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "given an existing database record" do
|
43
|
+
let(:salesforce_id) { "a001a000001E1vREAL" }
|
44
|
+
let(:database_metadata) { { salesforce_id: salesforce_id, synchronized_at: Time.now } }
|
45
|
+
let(:database_record) { database_model.create!(attributes.merge(database_metadata)) }
|
46
|
+
|
47
|
+
before { database_record }
|
48
|
+
|
49
|
+
it "returns the attributes from the database record" do
|
50
|
+
record = mapping.database_record_type.find(salesforce_id)
|
51
|
+
|
52
|
+
expect(subject[key]).to_equal(
|
53
|
+
record.last_update => {
|
54
|
+
"Name" => attributes[:name],
|
55
|
+
"Example_Field__c" => attributes[:example],
|
56
|
+
},
|
57
|
+
)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe "given a Salesforce record with an associated database record" do
|
62
|
+
let(:database_attributes) do
|
63
|
+
{
|
64
|
+
name: "Some existing name",
|
65
|
+
example: "Some existing sample text",
|
66
|
+
}
|
67
|
+
end
|
68
|
+
let(:database_metadata) { { salesforce_id: salesforce_id, synchronized_at: Time.now } }
|
69
|
+
let(:database_record) { database_model.create!(database_attributes.merge(database_metadata)) }
|
70
|
+
|
71
|
+
before { database_record }
|
72
|
+
|
73
|
+
it "returns the attributes from both records" do
|
74
|
+
sf_record = mapping.salesforce_record_type.find(salesforce_id)
|
75
|
+
db_record = mapping.database_record_type.find(salesforce_id)
|
76
|
+
|
77
|
+
expect(subject[key]).to_equal(
|
78
|
+
sf_record.last_update => {
|
79
|
+
"Name" => attributes[:name],
|
80
|
+
"Example_Field__c" => attributes[:example],
|
81
|
+
},
|
82
|
+
db_record.last_update => {
|
83
|
+
"Name" => database_attributes[:name],
|
84
|
+
"Example_Field__c" => database_attributes[:example],
|
85
|
+
},
|
86
|
+
)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require_relative "../../../test_helper"
|
2
|
+
|
3
|
+
describe Restforce::DB::Initializer do
|
4
|
+
|
5
|
+
configure!
|
6
|
+
mappings!
|
7
|
+
|
8
|
+
let(:initializer) { Restforce::DB::Initializer.new(mapping) }
|
9
|
+
|
10
|
+
describe "#run", vcr: { match_requests_on: [:method, VCR.request_matchers.uri_without_param(:q)] } do
|
11
|
+
let(:attributes) do
|
12
|
+
{
|
13
|
+
name: "Custom object",
|
14
|
+
example: "Some sample text",
|
15
|
+
}
|
16
|
+
end
|
17
|
+
let(:salesforce_id) do
|
18
|
+
Salesforce.create!(
|
19
|
+
salesforce_model,
|
20
|
+
mapping.convert(salesforce_model, attributes),
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "given an existing Salesforce record" do
|
25
|
+
before do
|
26
|
+
salesforce_id
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "for a root mapping" do
|
30
|
+
before do
|
31
|
+
initializer.run
|
32
|
+
end
|
33
|
+
|
34
|
+
it "creates a matching database record" do
|
35
|
+
record = database_model.last
|
36
|
+
|
37
|
+
expect(record.name).to_equal attributes[:name]
|
38
|
+
expect(record.example).to_equal attributes[:example]
|
39
|
+
expect(record.salesforce_id).to_equal salesforce_id
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "for a non-root mapping" do
|
44
|
+
let(:through) { "SomeField__c" }
|
45
|
+
|
46
|
+
before do
|
47
|
+
initializer.run
|
48
|
+
end
|
49
|
+
|
50
|
+
it "does not create a database record" do
|
51
|
+
expect(database_model.last).to_be_nil
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "given an existing database record" do
|
57
|
+
let(:database_record) { database_model.create!(attributes) }
|
58
|
+
let(:salesforce_id) { database_record.reload.salesforce_id }
|
59
|
+
|
60
|
+
before do
|
61
|
+
database_record
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "for a root mapping" do
|
65
|
+
before do
|
66
|
+
initializer.run
|
67
|
+
Salesforce.records << [salesforce_model, salesforce_id]
|
68
|
+
end
|
69
|
+
|
70
|
+
it "populates Salesforce with the new record" do
|
71
|
+
record = mapping.salesforce_record_type.find(salesforce_id).record
|
72
|
+
|
73
|
+
expect(record.Name).to_equal attributes[:name]
|
74
|
+
expect(record.Example_Field__c).to_equal attributes[:example]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "for a non-root mapping" do
|
79
|
+
let(:through) { "SomeField__c" }
|
80
|
+
|
81
|
+
before do
|
82
|
+
initializer.run
|
83
|
+
end
|
84
|
+
|
85
|
+
it "does not create a Salesforce record" do
|
86
|
+
expect(salesforce_id).to_be_nil
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
@@ -29,17 +29,4 @@ describe Restforce::DB::Instances::ActiveRecord do
|
|
29
29
|
expect(record.reload.synchronized_at).to_not_be_nil
|
30
30
|
end
|
31
31
|
end
|
32
|
-
|
33
|
-
describe "#copy!" do
|
34
|
-
let(:text) { "Copied text" }
|
35
|
-
let(:copy_from) { Struct.new(:attributes).new(example: text) }
|
36
|
-
|
37
|
-
before do
|
38
|
-
instance.copy!(copy_from)
|
39
|
-
end
|
40
|
-
|
41
|
-
it "updates the record with the attributes from the copied object" do
|
42
|
-
expect(record.example).to_equal text
|
43
|
-
end
|
44
|
-
end
|
45
32
|
end
|
@@ -24,19 +24,6 @@ describe Restforce::DB::Instances::Salesforce do
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
describe "#copy!", :vcr do
|
28
|
-
let(:text) { "Copied text" }
|
29
|
-
let(:copy_from) { Struct.new(:attributes).new(example: text) }
|
30
|
-
|
31
|
-
before do
|
32
|
-
instance.copy!(copy_from)
|
33
|
-
end
|
34
|
-
|
35
|
-
it "updates the record with the attributes from the copied object" do
|
36
|
-
expect(instance.record.Example_Field__c).to_equal text
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
27
|
describe "#last_update" do
|
41
28
|
let(:timestamp) { "2015-03-18T20:28:24.000+0000" }
|
42
29
|
let(:record) { Struct.new(:SystemModstamp).new(timestamp) }
|
@@ -47,4 +34,24 @@ describe Restforce::DB::Instances::Salesforce do
|
|
47
34
|
end
|
48
35
|
end
|
49
36
|
|
37
|
+
describe "#synced?", :vcr do
|
38
|
+
|
39
|
+
describe "when no matching database record exists" do
|
40
|
+
|
41
|
+
it "returns false" do
|
42
|
+
expect(instance).to_not_be :synced?
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "when a matching database record exists" do
|
47
|
+
before do
|
48
|
+
database_model.create!(salesforce_id: id)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "returns true" do
|
52
|
+
expect(instance).to_be :synced?
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
50
57
|
end
|
@@ -35,6 +35,7 @@ describe Restforce::DB::Mapping do
|
|
35
35
|
|
36
36
|
it "adds the mapping to the global collection" do
|
37
37
|
expect(Restforce::DB::Mapping[database_model]).to_equal [mapping]
|
38
|
+
expect(Restforce::DB::Mapping[salesforce_model]).to_equal [mapping]
|
38
39
|
end
|
39
40
|
end
|
40
41
|
|
@@ -95,41 +96,4 @@ describe Restforce::DB::Mapping do
|
|
95
96
|
end
|
96
97
|
end
|
97
98
|
end
|
98
|
-
|
99
|
-
describe "#attributes" do
|
100
|
-
|
101
|
-
it "builds a normalized Hash of database attribute values" do
|
102
|
-
attributes = mapping.attributes(database_model) do |attribute|
|
103
|
-
expect(mapping.database_fields.include?(attribute)).to_equal true
|
104
|
-
attribute
|
105
|
-
end
|
106
|
-
|
107
|
-
expect(attributes.keys).to_equal(mapping.database_fields)
|
108
|
-
expect(attributes.values).to_equal(mapping.database_fields)
|
109
|
-
end
|
110
|
-
|
111
|
-
it "builds a normalized Hash of Salesforce field values" do
|
112
|
-
attributes = mapping.attributes(salesforce_model) do |attribute|
|
113
|
-
expect(mapping.salesforce_fields.include?(attribute)).to_equal true
|
114
|
-
attribute
|
115
|
-
end
|
116
|
-
|
117
|
-
expect(attributes.keys).to_equal(mapping.database_fields)
|
118
|
-
expect(attributes.values).to_equal(mapping.salesforce_fields)
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
describe "#convert" do
|
123
|
-
let(:attributes) { { column_one: "some value" } }
|
124
|
-
|
125
|
-
it "converts an attribute Hash to a Salesforce-compatible form" do
|
126
|
-
expect(mapping.convert(salesforce_model, attributes)).to_equal(
|
127
|
-
fields[attributes.keys.first] => attributes.values.first,
|
128
|
-
)
|
129
|
-
end
|
130
|
-
|
131
|
-
it "performs no special conversion for database columns" do
|
132
|
-
expect(mapping.convert(database_model, attributes)).to_equal(attributes)
|
133
|
-
end
|
134
|
-
end
|
135
99
|
end
|