restforce-db 1.0.4 → 1.1.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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +38 -22
  3. data/lib/restforce/db/associations/base.rb +152 -0
  4. data/lib/restforce/db/associations/belongs_to.rb +70 -0
  5. data/lib/restforce/db/associations/foreign_key.rb +80 -0
  6. data/lib/restforce/db/associations/has_many.rb +37 -0
  7. data/lib/restforce/db/associations/has_one.rb +33 -0
  8. data/lib/restforce/db/dsl.rb +25 -13
  9. data/lib/restforce/db/mapping.rb +2 -3
  10. data/lib/restforce/db/record_types/active_record.rb +3 -8
  11. data/lib/restforce/db/record_types/salesforce.rb +23 -8
  12. data/lib/restforce/db/strategies/associated.rb +58 -0
  13. data/lib/restforce/db/version.rb +1 -1
  14. data/lib/restforce/db.rb +6 -1
  15. data/restforce-db.gemspec +0 -1
  16. data/test/cassettes/Restforce_DB_Associations_BelongsTo/with_an_inverse_mapping/_build/returns_an_associated_record_populated_with_the_Salesforce_attributes.yml +271 -0
  17. data/test/cassettes/Restforce_DB_Associations_BelongsTo/with_an_inverse_mapping/_synced_for_/when_a_matching_associated_record_has_been_synchronized/returns_true.yml +271 -0
  18. data/test/cassettes/Restforce_DB_Associations_BelongsTo/with_an_inverse_mapping/_synced_for_/when_no_matching_associated_record_has_been_synchronized/returns_false.yml +271 -0
  19. data/test/cassettes/Restforce_DB_Associations_HasMany/with_an_inverse_mapping/_build/builds_a_number_of_associated_records_from_the_data_in_Salesforce.yml +439 -0
  20. data/test/cassettes/Restforce_DB_Associations_HasMany/with_an_inverse_mapping/_synced_for_/when_a_matching_associated_record_has_been_synchronized/returns_true.yml +439 -0
  21. data/test/cassettes/Restforce_DB_Associations_HasMany/with_an_inverse_mapping/_synced_for_/when_no_matching_associated_record_has_been_synchronized/returns_false.yml +196 -0
  22. data/test/cassettes/Restforce_DB_Associations_HasOne/with_an_inverse_mapping/_build/returns_an_associated_record_populated_with_the_Salesforce_attributes.yml +271 -0
  23. data/test/cassettes/Restforce_DB_Associations_HasOne/with_an_inverse_mapping/_synced_for_/when_a_matching_associated_record_has_been_synchronized/returns_true.yml +271 -0
  24. data/test/cassettes/Restforce_DB_Associations_HasOne/with_an_inverse_mapping/_synced_for_/when_no_matching_associated_record_has_been_synchronized/returns_false.yml +271 -0
  25. data/test/cassettes/Restforce_DB_Strategies_Associated/_build_/given_an_inverse_mapping/with_a_synchronized_association_record/wants_to_build_a_new_record.yml +275 -0
  26. data/test/cassettes/Restforce_DB_Strategies_Associated/_build_/given_an_inverse_mapping/with_an_existing_database_record/does_not_want_to_build_a_new_record.yml +237 -0
  27. data/test/cassettes/Restforce_DB_Strategies_Associated/_build_/given_an_inverse_mapping/with_no_synchronized_association_record/does_not_want_to_build_a_new_record.yml +275 -0
  28. data/test/lib/restforce/db/associations/belongs_to_test.rb +82 -0
  29. data/test/lib/restforce/db/associations/has_many_test.rb +96 -0
  30. data/test/lib/restforce/db/associations/has_one_test.rb +80 -0
  31. data/test/lib/restforce/db/dsl_test.rb +22 -3
  32. data/test/lib/restforce/db/mapping_test.rb +10 -8
  33. data/test/lib/restforce/db/record_types/active_record_test.rb +12 -5
  34. data/test/lib/restforce/db/runner_test.rb +2 -3
  35. data/test/lib/restforce/db/strategies/always_test.rb +2 -2
  36. data/test/lib/restforce/db/strategies/associated_test.rb +78 -0
  37. data/test/lib/restforce/db/strategies/passive_test.rb +1 -1
  38. data/test/lib/restforce/db/tracker_test.rb +0 -2
  39. data/test/support/active_record.rb +25 -2
  40. data/test/support/salesforce.rb +1 -1
  41. data/test/support/utilities.rb +5 -7
  42. data/test/test_helper.rb +0 -1
  43. metadata +24 -18
  44. data/lib/restforce/db/associations/active_record.rb +0 -68
  45. data/test/lib/restforce/db/associations/active_record_test.rb +0 -43
@@ -0,0 +1,80 @@
1
+ require_relative "../../../../test_helper"
2
+
3
+ describe Restforce::DB::Associations::HasOne do
4
+
5
+ configure!
6
+ mappings!
7
+
8
+ let(:association) { Restforce::DB::Associations::HasOne.new(:custom_object, through: "Friend__c") }
9
+
10
+ it "sets the lookup field" do
11
+ expect(association.lookup).to_equal "Friend__c"
12
+ end
13
+
14
+ describe "#fields" do
15
+
16
+ it "returns nothing (since the lookup field is external)" do
17
+ expect(association.fields).to_equal []
18
+ end
19
+ end
20
+
21
+ describe "with an inverse mapping", :vcr do
22
+ let(:inverse_mapping) do
23
+ Restforce::DB::Mapping.new(User, "Contact").tap do |m|
24
+ m.fields = { email: "Email" }
25
+ m.associations << association
26
+ end
27
+ end
28
+ let(:user_salesforce_id) do
29
+ Salesforce.create!(
30
+ inverse_mapping.salesforce_model,
31
+ "Email" => "somebody@example.com",
32
+ "LastName" => "Somebody",
33
+ )
34
+ end
35
+ let(:object_salesforce_id) do
36
+ Salesforce.create!(mapping.salesforce_model, "Friend__c" => user_salesforce_id)
37
+ end
38
+
39
+ before do
40
+ Restforce::DB::Registry << mapping
41
+ Restforce::DB::Registry << inverse_mapping
42
+ mapping.associations << Restforce::DB::Associations::BelongsTo.new(:user, through: "Friend__c")
43
+
44
+ object_salesforce_id
45
+ end
46
+
47
+ describe "#synced_for?" do
48
+ let(:salesforce_instance) { inverse_mapping.salesforce_record_type.find(user_salesforce_id) }
49
+
50
+ describe "when no matching associated record has been synchronized" do
51
+
52
+ it "returns false" do
53
+ expect(association).to_not_be :synced_for?, salesforce_instance
54
+ end
55
+ end
56
+
57
+ describe "when a matching associated record has been synchronized" do
58
+ before do
59
+ mapping.database_model.create!(salesforce_id: object_salesforce_id)
60
+ end
61
+
62
+ it "returns true" do
63
+ expect(association).to_be :synced_for?, salesforce_instance
64
+ end
65
+ end
66
+ end
67
+
68
+ describe "#build" do
69
+ let(:database_record) { User.new }
70
+ let(:salesforce_record) { inverse_mapping.salesforce_record_type.find(user_salesforce_id).record }
71
+ let(:associated) { association.build(database_record, salesforce_record) }
72
+
73
+ it "returns an associated record, populated with the Salesforce attributes" do
74
+ expect(associated.user).to_equal database_record
75
+ expect(associated.salesforce_id).to_equal object_salesforce_id
76
+ end
77
+ end
78
+ end
79
+
80
+ end
@@ -52,7 +52,10 @@ describe Restforce::DB::DSL do
52
52
  end
53
53
 
54
54
  it "adds an association to the created mapping" do
55
- expect(mapping.associations).to_equal some_association: "Some_Field__c"
55
+ association = mapping.associations.first
56
+ expect(association).to_be_instance_of Restforce::DB::Associations::BelongsTo
57
+ expect(association.name).to_equal :some_association
58
+ expect(association.lookup).to_equal "Some_Field__c"
56
59
  end
57
60
  end
58
61
 
@@ -61,8 +64,24 @@ describe Restforce::DB::DSL do
61
64
  dsl.has_one :other_association, through: "Other_Field__c"
62
65
  end
63
66
 
64
- it "sets the `through` attribute for the created mapping" do
65
- expect(mapping.through).to_equal "Other_Field__c"
67
+ it "adds an association to the created mapping" do
68
+ association = mapping.associations.first
69
+ expect(association).to_be_instance_of Restforce::DB::Associations::HasOne
70
+ expect(association.name).to_equal :other_association
71
+ expect(association.lookup).to_equal "Other_Field__c"
72
+ end
73
+ end
74
+
75
+ describe "#has_many" do
76
+ before do
77
+ dsl.has_many :multiple_associations, through: "External_Field__c"
78
+ end
79
+
80
+ it "adds an association to the created mapping" do
81
+ association = mapping.associations.first
82
+ expect(association).to_be_instance_of Restforce::DB::Associations::HasMany
83
+ expect(association.name).to_equal :multiple_associations
84
+ expect(association.lookup).to_equal "External_Field__c"
66
85
  end
67
86
  end
68
87
 
@@ -6,19 +6,15 @@ describe Restforce::DB::Mapping do
6
6
 
7
7
  let(:database_model) { CustomObject }
8
8
  let(:salesforce_model) { "CustomObject__c" }
9
- let(:associations) { {} }
10
9
  let(:fields) do
11
10
  {
12
11
  column_one: "SF_Field_One__c",
13
12
  column_two: "SF_Field_Two__c",
14
13
  }
15
14
  end
16
- let(:through) { nil }
17
- let!(:mapping) do
15
+ let(:mapping) do
18
16
  Restforce::DB::Mapping.new(database_model, salesforce_model).tap do |m|
19
- m.fields = fields
20
- m.associations = associations
21
- m.through = through
17
+ m.fields = fields
22
18
  end
23
19
  end
24
20
 
@@ -39,10 +35,16 @@ describe Restforce::DB::Mapping do
39
35
  end
40
36
 
41
37
  describe "given a set of associations" do
42
- let(:associations) { { user: "Owner" } }
38
+ let(:association) do
39
+ Restforce::DB::Associations::BelongsTo.new(:user, through: "Owner")
40
+ end
41
+
42
+ before do
43
+ mapping.associations << association
44
+ end
43
45
 
44
46
  it "lists the field and association lookups" do
45
- expect(mapping.salesforce_fields).to_equal(fields.values + associations.values)
47
+ expect(mapping.salesforce_fields).to_equal(fields.values + association.fields)
46
48
  end
47
49
  end
48
50
  end
@@ -40,16 +40,23 @@ describe Restforce::DB::RecordTypes::ActiveRecord do
40
40
  describe "given a mapped association" do
41
41
  let(:record) { Struct.new(:Friend__c).new(association_id) }
42
42
  let(:association_id) { "a001a000001EFRIEND" }
43
- let(:associations) { { user: "Friend__c" } }
44
43
 
45
44
  before do
46
- mapping = Restforce::DB::Mapping.new(User, "Contact").tap do |m|
47
- m.through = "Friend__c"
45
+ mapping.associations << Restforce::DB::Associations::BelongsTo.new(
46
+ :user,
47
+ through: "Friend__c",
48
+ )
49
+
50
+ associated_mapping = Restforce::DB::Mapping.new(User, "Contact").tap do |m|
48
51
  m.fields = { email: "Email" }
52
+ m.associations << Restforce::DB::Associations::HasOne.new(
53
+ :custom_object,
54
+ through: "Friend__c",
55
+ )
49
56
  end
50
- Restforce::DB::Registry << mapping
57
+ Restforce::DB::Registry << associated_mapping
51
58
 
52
- salesforce_record_type = mapping.salesforce_record_type
59
+ salesforce_record_type = associated_mapping.salesforce_record_type
53
60
 
54
61
  # Stub out the `#find` method on the record type
55
62
  def salesforce_record_type.find(id)
@@ -1,12 +1,10 @@
1
1
  require_relative "../../../test_helper"
2
2
 
3
3
  describe Restforce::DB::Runner do
4
- before { Restforce::DB.last_run = Time.now }
5
- after { Restforce::DB.last_run = nil }
6
-
7
4
  let(:runner) { Restforce::DB::Runner.new }
8
5
 
9
6
  describe "#initialize" do
7
+ before { Restforce::DB.last_run = Time.now }
10
8
 
11
9
  it "prefills the Collector's last_run timestamp with the global configuration" do
12
10
  expect(runner.last_run).to_equal Restforce::DB.last_run
@@ -14,6 +12,7 @@ describe Restforce::DB::Runner do
14
12
  end
15
13
 
16
14
  describe "#tick!" do
15
+ before { Restforce::DB.last_run = Time.now }
17
16
 
18
17
  it "updates the run timestamps" do
19
18
  prior_run = runner.last_run
@@ -18,7 +18,7 @@ describe Restforce::DB::Strategies::Always do
18
18
  let(:record) { mapping.salesforce_record_type.find(salesforce_id) }
19
19
 
20
20
  it "wants to build a new matching record" do
21
- expect(strategy.build?(record)).to_equal true
21
+ expect(strategy).to_be :build?, record
22
22
  end
23
23
 
24
24
  describe "with a corresponding database record" do
@@ -30,7 +30,7 @@ describe Restforce::DB::Strategies::Always do
30
30
  end
31
31
 
32
32
  it "does not want to build a new record" do
33
- expect(strategy.build?(record)).to_equal false
33
+ expect(strategy).to_not_be :build?, record
34
34
  end
35
35
  end
36
36
  end
@@ -0,0 +1,78 @@
1
+ require_relative "../../../../test_helper"
2
+
3
+ describe Restforce::DB::Strategies::Associated do
4
+
5
+ configure!
6
+ mappings!
7
+
8
+ let(:strategy) { Restforce::DB::Strategies::Associated.new(with: :custom_object) }
9
+
10
+ it "is not a passive strategy" do
11
+ expect(strategy).to_not_be :passive?
12
+ end
13
+
14
+ describe "#build?", :vcr do
15
+
16
+ describe "given an inverse mapping" do
17
+ let(:inverse_mapping) do
18
+ Restforce::DB::Mapping.new(Detail, "CustomObjectDetail__c").tap do |m|
19
+ m.fields = { name: "Name" }
20
+ m.associations << Restforce::DB::Associations::BelongsTo.new(
21
+ :custom_object,
22
+ through: "CustomObject__c",
23
+ )
24
+ end
25
+ end
26
+ let(:object_salesforce_id) { Salesforce.create!(mapping.salesforce_model) }
27
+ let(:detail_salesforce_id) do
28
+ Salesforce.create!(
29
+ inverse_mapping.salesforce_model,
30
+ "CustomObject__c" => object_salesforce_id,
31
+ )
32
+ end
33
+ let(:record) { inverse_mapping.salesforce_record_type.find(detail_salesforce_id) }
34
+
35
+ before do
36
+ Restforce::DB::Registry << mapping
37
+ Restforce::DB::Registry << inverse_mapping
38
+ mapping.associations << Restforce::DB::Associations::HasMany.new(
39
+ :details,
40
+ through: "CustomObject__c",
41
+ )
42
+ end
43
+
44
+ describe "with no synchronized association record" do
45
+
46
+ it "does not want to build a new record" do
47
+ expect(strategy).to_not_be :build?, record
48
+ end
49
+ end
50
+
51
+ describe "with an existing database record" do
52
+ before do
53
+ Detail.create!(
54
+ salesforce_id: detail_salesforce_id,
55
+ synchronized_at: Time.now,
56
+ )
57
+ end
58
+
59
+ it "does not want to build a new record" do
60
+ expect(strategy).to_not_be :build?, record
61
+ end
62
+ end
63
+
64
+ describe "with a synchronized association record" do
65
+ before do
66
+ CustomObject.create!(
67
+ salesforce_id: object_salesforce_id,
68
+ synchronized_at: Time.now,
69
+ )
70
+ end
71
+
72
+ it "wants to build a new record" do
73
+ expect(strategy).to_be :build?, record
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -11,7 +11,7 @@ describe Restforce::DB::Strategies::Passive do
11
11
 
12
12
  it "returns false for any record" do
13
13
  record = Object.new
14
- expect(strategy.build?(record)).to_equal false
14
+ expect(strategy).to_not_be :build?, record
15
15
  end
16
16
  end
17
17
  end
@@ -5,8 +5,6 @@ describe Restforce::DB::Tracker do
5
5
  let(:tracker) { Restforce::DB::Tracker.new(file.path) }
6
6
  let(:runtime) { Time.now }
7
7
 
8
- after { Restforce::DB.last_run = nil }
9
-
10
8
  describe "#initialize" do
11
9
 
12
10
  describe "when no timestamp has been recorded" do
@@ -19,6 +19,16 @@ ActiveRecord::Schema.define do
19
19
 
20
20
  add_index :custom_objects, :salesforce_id
21
21
 
22
+ create_table :details do |table|
23
+ table.column :name, :string
24
+ table.column :custom_object_id, :integer
25
+ table.column :salesforce_id, :string
26
+ table.column :synchronized_at, :datetime
27
+ table.timestamps null: false
28
+ end
29
+
30
+ add_index :details, :salesforce_id
31
+
22
32
  create_table :users do |table|
23
33
  table.column :email, :string
24
34
  table.column :salesforce_id, :string
@@ -33,8 +43,21 @@ end
33
43
  # :nodoc:
34
44
  class CustomObject < ActiveRecord::Base
35
45
 
36
- belongs_to :user
46
+ belongs_to :user, inverse_of: :custom_object, autosave: true
47
+ has_many :details, inverse_of: :custom_object
37
48
 
38
49
  end
39
50
 
40
- class User < ActiveRecord::Base; end
51
+ # :nodoc:
52
+ class Detail < ActiveRecord::Base
53
+
54
+ belongs_to :custom_object, inverse_of: :details
55
+
56
+ end
57
+
58
+ # :nodoc:
59
+ class User < ActiveRecord::Base
60
+
61
+ has_one :custom_object, inverse_of: :user
62
+
63
+ end
@@ -24,7 +24,7 @@ class Salesforce
24
24
  # Returns a Salesforce record ID.
25
25
  def self.create!(salesforce_model, attributes = nil)
26
26
  attributes ||= { "Name" => "Sample object" }
27
- salesforce_id = Restforce::DB.client.create(salesforce_model, attributes)
27
+ salesforce_id = Restforce::DB.client.create!(salesforce_model, attributes)
28
28
  Salesforce.records << [salesforce_model, salesforce_id]
29
29
 
30
30
  salesforce_id
@@ -6,6 +6,8 @@ def configure!
6
6
 
7
7
  after do
8
8
  Restforce::DB::Registry.clean!
9
+ Restforce::DB.last_run = nil
10
+
9
11
  DatabaseCleaner.clean
10
12
  Salesforce.clean!
11
13
  end
@@ -16,15 +18,11 @@ def mappings!
16
18
  let(:database_model) { CustomObject }
17
19
  let(:salesforce_model) { "CustomObject__c" }
18
20
  let(:fields) { { name: "Name", example: "Example_Field__c" } }
19
- let(:associations) { {} }
20
21
  let(:conditions) { [] }
21
- let(:through) { nil }
22
- let!(:mapping) do
22
+ let(:mapping) do
23
23
  Restforce::DB::Mapping.new(database_model, salesforce_model).tap do |m|
24
- m.through = through
25
- m.conditions = conditions
26
- m.fields = fields
27
- m.associations = associations
24
+ m.conditions = conditions
25
+ m.fields = fields
28
26
  end
29
27
  end
30
28
  end
data/test/test_helper.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  require "cgi"
2
2
  require "minitest/autorun"
3
- require "minitest/bang"
4
3
  require "minitest/spec/expect"
5
4
  require "yaml"
6
5
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: restforce-db
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Horner
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-04-10 00:00:00.000000000 Z
11
+ date: 2015-04-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -94,20 +94,6 @@ dependencies:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
- - !ruby/object:Gem::Dependency
98
- name: minitest-bang
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
97
  - !ruby/object:Gem::Dependency
112
98
  name: minitest-spec-expect
113
99
  requirement: !ruby/object:Gem::Requirement
@@ -222,7 +208,11 @@ files:
222
208
  - lib/generators/templates/script
223
209
  - lib/restforce/db.rb
224
210
  - lib/restforce/db/accumulator.rb
225
- - lib/restforce/db/associations/active_record.rb
211
+ - lib/restforce/db/associations/base.rb
212
+ - lib/restforce/db/associations/belongs_to.rb
213
+ - lib/restforce/db/associations/foreign_key.rb
214
+ - lib/restforce/db/associations/has_many.rb
215
+ - lib/restforce/db/associations/has_one.rb
226
216
  - lib/restforce/db/attribute_map.rb
227
217
  - lib/restforce/db/collector.rb
228
218
  - lib/restforce/db/command.rb
@@ -240,6 +230,7 @@ files:
240
230
  - lib/restforce/db/registry.rb
241
231
  - lib/restforce/db/runner.rb
242
232
  - lib/restforce/db/strategies/always.rb
233
+ - lib/restforce/db/strategies/associated.rb
243
234
  - lib/restforce/db/strategies/passive.rb
244
235
  - lib/restforce/db/strategy.rb
245
236
  - lib/restforce/db/synchronizer.rb
@@ -249,6 +240,15 @@ files:
249
240
  - lib/restforce/extensions.rb
250
241
  - restforce-db.gemspec
251
242
  - test/cassettes/Restforce_DB/accessing_Salesforce/uses_the_configured_credentials.yml
243
+ - test/cassettes/Restforce_DB_Associations_BelongsTo/with_an_inverse_mapping/_build/returns_an_associated_record_populated_with_the_Salesforce_attributes.yml
244
+ - test/cassettes/Restforce_DB_Associations_BelongsTo/with_an_inverse_mapping/_synced_for_/when_a_matching_associated_record_has_been_synchronized/returns_true.yml
245
+ - test/cassettes/Restforce_DB_Associations_BelongsTo/with_an_inverse_mapping/_synced_for_/when_no_matching_associated_record_has_been_synchronized/returns_false.yml
246
+ - test/cassettes/Restforce_DB_Associations_HasMany/with_an_inverse_mapping/_build/builds_a_number_of_associated_records_from_the_data_in_Salesforce.yml
247
+ - test/cassettes/Restforce_DB_Associations_HasMany/with_an_inverse_mapping/_synced_for_/when_a_matching_associated_record_has_been_synchronized/returns_true.yml
248
+ - test/cassettes/Restforce_DB_Associations_HasMany/with_an_inverse_mapping/_synced_for_/when_no_matching_associated_record_has_been_synchronized/returns_false.yml
249
+ - test/cassettes/Restforce_DB_Associations_HasOne/with_an_inverse_mapping/_build/returns_an_associated_record_populated_with_the_Salesforce_attributes.yml
250
+ - test/cassettes/Restforce_DB_Associations_HasOne/with_an_inverse_mapping/_synced_for_/when_a_matching_associated_record_has_been_synchronized/returns_true.yml
251
+ - test/cassettes/Restforce_DB_Associations_HasOne/with_an_inverse_mapping/_synced_for_/when_no_matching_associated_record_has_been_synchronized/returns_false.yml
252
252
  - test/cassettes/Restforce_DB_Collector/_run/given_a_Salesforce_record_with_an_associated_database_record/returns_the_attributes_from_both_records.yml
253
253
  - test/cassettes/Restforce_DB_Collector/_run/given_an_existing_Salesforce_record/returns_the_attributes_from_the_Salesforce_record.yml
254
254
  - test/cassettes/Restforce_DB_Collector/_run/given_an_existing_database_record/returns_the_attributes_from_the_database_record.yml
@@ -269,11 +269,16 @@ files:
269
269
  - test/cassettes/Restforce_DB_RecordTypes_Salesforce/_find/returns_nil_when_no_matching_record_exists.yml
270
270
  - test/cassettes/Restforce_DB_Strategies_Always/_build_/given_a_Salesforce_record/wants_to_build_a_new_matching_record.yml
271
271
  - test/cassettes/Restforce_DB_Strategies_Always/_build_/given_a_Salesforce_record/with_a_corresponding_database_record/does_not_want_to_build_a_new_record.yml
272
+ - test/cassettes/Restforce_DB_Strategies_Associated/_build_/given_an_inverse_mapping/with_a_synchronized_association_record/wants_to_build_a_new_record.yml
273
+ - test/cassettes/Restforce_DB_Strategies_Associated/_build_/given_an_inverse_mapping/with_an_existing_database_record/does_not_want_to_build_a_new_record.yml
274
+ - test/cassettes/Restforce_DB_Strategies_Associated/_build_/given_an_inverse_mapping/with_no_synchronized_association_record/does_not_want_to_build_a_new_record.yml
272
275
  - test/cassettes/Restforce_DB_Synchronizer/_run/given_a_Salesforce_record_with_an_associated_database_record/updates_the_database_record.yml
273
276
  - test/cassettes/Restforce_DB_Synchronizer/_run/given_a_Salesforce_record_with_an_associated_database_record/updates_the_salesforce_record.yml
274
277
  - test/cassettes/Restforce_DB_Synchronizer/_run/given_a_Salesforce_record_with_no_associated_database_record/does_nothing_for_this_specific_mapping.yml
275
278
  - test/lib/restforce/db/accumulator_test.rb
276
- - test/lib/restforce/db/associations/active_record_test.rb
279
+ - test/lib/restforce/db/associations/belongs_to_test.rb
280
+ - test/lib/restforce/db/associations/has_many_test.rb
281
+ - test/lib/restforce/db/associations/has_one_test.rb
277
282
  - test/lib/restforce/db/attribute_map_test.rb
278
283
  - test/lib/restforce/db/collector_test.rb
279
284
  - test/lib/restforce/db/configuration_test.rb
@@ -288,6 +293,7 @@ files:
288
293
  - test/lib/restforce/db/registry_test.rb
289
294
  - test/lib/restforce/db/runner_test.rb
290
295
  - test/lib/restforce/db/strategies/always_test.rb
296
+ - test/lib/restforce/db/strategies/associated_test.rb
291
297
  - test/lib/restforce/db/strategies/passive_test.rb
292
298
  - test/lib/restforce/db/strategy_test.rb
293
299
  - test/lib/restforce/db/synchronizer_test.rb
@@ -1,68 +0,0 @@
1
- module Restforce
2
-
3
- module DB
4
-
5
- module Associations
6
-
7
- # Restforce::DB::Associations::ActiveRecord is a utility class which
8
- # encapsulates the logic for creating/populating a one-to-one association
9
- #
10
- class ActiveRecord
11
-
12
- attr_reader :associated
13
-
14
- # Public: Initialize a new Restforce::DB::Associations::ActiveRecord.
15
- #
16
- # record - The base ActiveRecord::Base instance for which the
17
- # association should be built.
18
- # association - The name of the association which should be built.
19
- def initialize(record, association)
20
- @record = record
21
- @associated = record.association(association).build
22
- end
23
-
24
- # Public: Build the associated record from the attributes found on the
25
- # passed Salesforce record's lookups.
26
- #
27
- # from_record - A Hashie::Mash representing a base Salesforce record.
28
- #
29
- # Returns the constructed associated record.
30
- def build(from_record)
31
- Registry[associated.class].each do |mapping|
32
- lookup_id = from_record[mapping.through]
33
- apply(mapping, lookup_id)
34
- end
35
-
36
- associated
37
- end
38
-
39
- private
40
-
41
- # Internal: Assemble the associated record, using the data from the
42
- # Salesforce record corresponding to a specific lookup ID.
43
- #
44
- # TODO: With some refactoring, this should be possible to handle as a
45
- # recursive call to the configured Mapping's database record type. Right
46
- # now, nested associations are unhandled.
47
- #
48
- # mapping - A Restforce::DB::Mapping.
49
- # lookup_id - A Salesforce ID corresponding to the record type in the
50
- # passed Mapping.
51
- #
52
- # Returns nothing.
53
- def apply(mapping, lookup_id)
54
- return if lookup_id.nil?
55
-
56
- salesforce_instance = mapping.salesforce_record_type.find(lookup_id)
57
- attributes = mapping.convert(associated.class, salesforce_instance.attributes)
58
-
59
- associated.assign_attributes(attributes.merge(mapping.lookup_column => lookup_id))
60
- end
61
-
62
- end
63
-
64
- end
65
-
66
- end
67
-
68
- end
@@ -1,43 +0,0 @@
1
- require_relative "../../../../test_helper"
2
-
3
- describe Restforce::DB::Associations::ActiveRecord do
4
-
5
- configure!
6
- mappings!
7
-
8
- let(:associations) { { user: "Friend__c" } }
9
- let(:record) { CustomObject.new }
10
- let(:association) { Restforce::DB::Associations::ActiveRecord.new(record, :user) }
11
-
12
- describe "#build" do
13
- let(:association_id) { "a001a000001EFRIEND" }
14
- let(:salesforce_record) { Hashie::Mash.new("Friend__c" => association_id) }
15
- let(:associated_record) { association.build(salesforce_record) }
16
-
17
- before do
18
- mapping = Restforce::DB::Mapping.new(User, "Contact").tap do |m|
19
- m.through = "Friend__c"
20
- m.fields = { email: "Email" }
21
- end
22
- Restforce::DB::Registry << mapping
23
-
24
- salesforce_record_type = mapping.salesforce_record_type
25
-
26
- # Stub out the `#find` method on the record type
27
- def salesforce_record_type.find(id)
28
- Struct.new(:id, :last_update, :attributes).new(
29
- id,
30
- Time.now,
31
- email: "somebody@example.com",
32
- )
33
- end
34
- end
35
-
36
- it "creates the associated record from the related Salesforce record's attributes" do
37
- expect(associated_record).to_not_be_nil
38
- expect(associated_record.email).to_equal("somebody@example.com")
39
- expect(associated_record.salesforce_id).to_equal(association_id)
40
- expect(associated_record).to_equal record.user
41
- end
42
- end
43
- end