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.
- checksums.yaml +4 -4
- data/README.md +38 -22
- data/lib/restforce/db/associations/base.rb +152 -0
- data/lib/restforce/db/associations/belongs_to.rb +70 -0
- data/lib/restforce/db/associations/foreign_key.rb +80 -0
- data/lib/restforce/db/associations/has_many.rb +37 -0
- data/lib/restforce/db/associations/has_one.rb +33 -0
- data/lib/restforce/db/dsl.rb +25 -13
- data/lib/restforce/db/mapping.rb +2 -3
- data/lib/restforce/db/record_types/active_record.rb +3 -8
- data/lib/restforce/db/record_types/salesforce.rb +23 -8
- data/lib/restforce/db/strategies/associated.rb +58 -0
- data/lib/restforce/db/version.rb +1 -1
- data/lib/restforce/db.rb +6 -1
- data/restforce-db.gemspec +0 -1
- data/test/cassettes/Restforce_DB_Associations_BelongsTo/with_an_inverse_mapping/_build/returns_an_associated_record_populated_with_the_Salesforce_attributes.yml +271 -0
- 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
- 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
- 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
- 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
- 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
- data/test/cassettes/Restforce_DB_Associations_HasOne/with_an_inverse_mapping/_build/returns_an_associated_record_populated_with_the_Salesforce_attributes.yml +271 -0
- 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
- 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
- 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
- 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
- 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
- data/test/lib/restforce/db/associations/belongs_to_test.rb +82 -0
- data/test/lib/restforce/db/associations/has_many_test.rb +96 -0
- data/test/lib/restforce/db/associations/has_one_test.rb +80 -0
- data/test/lib/restforce/db/dsl_test.rb +22 -3
- data/test/lib/restforce/db/mapping_test.rb +10 -8
- data/test/lib/restforce/db/record_types/active_record_test.rb +12 -5
- data/test/lib/restforce/db/runner_test.rb +2 -3
- data/test/lib/restforce/db/strategies/always_test.rb +2 -2
- data/test/lib/restforce/db/strategies/associated_test.rb +78 -0
- data/test/lib/restforce/db/strategies/passive_test.rb +1 -1
- data/test/lib/restforce/db/tracker_test.rb +0 -2
- data/test/support/active_record.rb +25 -2
- data/test/support/salesforce.rb +1 -1
- data/test/support/utilities.rb +5 -7
- data/test/test_helper.rb +0 -1
- metadata +24 -18
- data/lib/restforce/db/associations/active_record.rb +0 -68
- 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
|
-
|
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 "
|
65
|
-
|
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(:
|
17
|
-
let!(:mapping) do
|
15
|
+
let(:mapping) do
|
18
16
|
Restforce::DB::Mapping.new(database_model, salesforce_model).tap do |m|
|
19
|
-
m.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(:
|
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 +
|
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
|
47
|
-
|
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 <<
|
57
|
+
Restforce::DB::Registry << associated_mapping
|
51
58
|
|
52
|
-
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
|
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
|
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
|
@@ -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
|
-
|
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
|
data/test/support/salesforce.rb
CHANGED
@@ -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
|
data/test/support/utilities.rb
CHANGED
@@ -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(:
|
22
|
-
let!(:mapping) do
|
22
|
+
let(:mapping) do
|
23
23
|
Restforce::DB::Mapping.new(database_model, salesforce_model).tap do |m|
|
24
|
-
m.
|
25
|
-
m.
|
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
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
|
+
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-
|
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/
|
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/
|
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
|