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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/lib/file_daemon.rb +42 -0
  3. data/lib/restforce/db/accumulator.rb +41 -0
  4. data/lib/restforce/db/attribute_map.rb +132 -0
  5. data/lib/restforce/db/collector.rb +79 -0
  6. data/lib/restforce/db/initializer.rb +62 -0
  7. data/lib/restforce/db/instances/base.rb +1 -14
  8. data/lib/restforce/db/instances/salesforce.rb +7 -0
  9. data/lib/restforce/db/mapping.rb +33 -79
  10. data/lib/restforce/db/record_types/base.rb +0 -30
  11. data/lib/restforce/db/runner.rb +80 -0
  12. data/lib/restforce/db/synchronizer.rb +29 -37
  13. data/lib/restforce/db/version.rb +1 -1
  14. data/lib/restforce/db/worker.rb +53 -40
  15. data/lib/restforce/db.rb +6 -0
  16. 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
  17. data/test/cassettes/Restforce_DB_Collector/_run/given_an_existing_Salesforce_record/returns_the_attributes_from_the_Salesforce_record.yml +197 -0
  18. data/test/cassettes/Restforce_DB_Collector/_run/given_an_existing_database_record/returns_the_attributes_from_the_database_record.yml +81 -0
  19. 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
  20. 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
  21. 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
  22. 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
  23. 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
  24. data/test/cassettes/Restforce_DB_Synchronizer/_run/given_a_Salesforce_record_with_an_associated_database_record/updates_the_database_record.yml +194 -0
  25. data/test/cassettes/Restforce_DB_Synchronizer/_run/given_a_Salesforce_record_with_an_associated_database_record/updates_the_salesforce_record.yml +233 -0
  26. data/test/lib/restforce/db/accumulator_test.rb +71 -0
  27. data/test/lib/restforce/db/attribute_map_test.rb +70 -0
  28. data/test/lib/restforce/db/collector_test.rb +91 -0
  29. data/test/lib/restforce/db/initializer_test.rb +92 -0
  30. data/test/lib/restforce/db/instances/active_record_test.rb +0 -13
  31. data/test/lib/restforce/db/instances/salesforce_test.rb +20 -13
  32. data/test/lib/restforce/db/mapping_test.rb +1 -37
  33. data/test/lib/restforce/db/record_types/active_record_test.rb +0 -40
  34. data/test/lib/restforce/db/runner_test.rb +40 -0
  35. data/test/lib/restforce/db/synchronizer_test.rb +26 -86
  36. 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