restforce-db 1.0.4 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|