restforce-db 3.0.0 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/lib/restforce/db.rb +2 -0
  3. data/lib/restforce/db/associator.rb +2 -11
  4. data/lib/restforce/db/attacher.rb +91 -0
  5. data/lib/restforce/db/cleaner.rb +3 -13
  6. data/lib/restforce/db/collector.rb +1 -10
  7. data/lib/restforce/db/field_processor.rb +53 -17
  8. data/lib/restforce/db/initializer.rb +6 -14
  9. data/lib/restforce/db/instances/salesforce.rb +2 -1
  10. data/lib/restforce/db/record_types/salesforce.rb +47 -20
  11. data/lib/restforce/db/synchronizer.rb +1 -9
  12. data/lib/restforce/db/task.rb +32 -0
  13. data/lib/restforce/db/version.rb +1 -1
  14. data/lib/restforce/db/worker.rb +21 -59
  15. data/test/cassettes/Restforce_DB/accessing_Salesforce/uses_the_configured_credentials.yml +6 -6
  16. data/test/cassettes/Restforce_DB_Associations_BelongsTo/with_an_inverse_mapping/_build/returns_an_associated_record_populated_with_the_Salesforce_attributes.yml +203 -52
  17. data/test/cassettes/Restforce_DB_Associations_BelongsTo/with_an_inverse_mapping/_build/when_no_salesforce_record_is_found_for_the_association/proceeds_without_constructing_any_records.yml +185 -34
  18. data/test/cassettes/Restforce_DB_Associations_BelongsTo/with_an_inverse_mapping/_build/when_the_associated_record_has_already_been_persisted/assigns_the_existing_record.yml +203 -52
  19. data/test/cassettes/Restforce_DB_Associations_BelongsTo/with_an_inverse_mapping/_build/when_the_associated_record_has_been_cached/uses_the_cached_record.yml +203 -52
  20. data/test/cassettes/Restforce_DB_Associations_BelongsTo/with_an_inverse_mapping/_build/when_the_association_is_non-building/proceeds_without_constructing_any_records.yml +97 -44
  21. data/test/cassettes/Restforce_DB_Associations_BelongsTo/with_an_inverse_mapping/_build/with_an_unrelated_association_mapping/proceeds_without_raising_an_error.yml +203 -52
  22. data/test/cassettes/Restforce_DB_Associations_BelongsTo/with_an_inverse_mapping/_lookups/returns_a_hash_of_the_associated_records_lookup_IDs.yml +36 -36
  23. data/test/cassettes/Restforce_DB_Associations_BelongsTo/with_an_inverse_mapping/_lookups/when_there_is_currently_no_associated_record/and_the_underlying_association_is_one-to-many/still_returns_a_nil_lookup_value_in_the_hash.yml +20 -20
  24. data/test/cassettes/Restforce_DB_Associations_BelongsTo/with_an_inverse_mapping/_lookups/when_there_is_currently_no_associated_record/returns_a_nil_lookup_value_in_the_hash.yml +20 -20
  25. data/test/cassettes/Restforce_DB_Associations_BelongsTo/with_an_inverse_mapping/_synced_for_/when_a_matching_associated_record_has_been_synchronized/returns_true.yml +105 -52
  26. data/test/cassettes/Restforce_DB_Associations_BelongsTo/with_an_inverse_mapping/_synced_for_/when_no_matching_associated_record_has_been_synchronized/returns_false.yml +105 -52
  27. data/test/cassettes/Restforce_DB_Associations_HasMany/with_an_inverse_mapping/_build/builds_a_number_of_associated_records_from_the_data_in_Salesforce.yml +191 -87
  28. data/test/cassettes/Restforce_DB_Associations_HasMany/with_an_inverse_mapping/_build/when_no_salesforce_record_is_found_for_the_association/proceeds_without_constructing_any_records.yml +139 -35
  29. data/test/cassettes/Restforce_DB_Associations_HasMany/with_an_inverse_mapping/_build/when_the_associated_records_have_alrady_been_persisted/constructs_the_association_from_the_existing_records.yml +191 -87
  30. data/test/cassettes/Restforce_DB_Associations_HasMany/with_an_inverse_mapping/_build/when_the_associated_records_have_been_cached/uses_the_cached_records.yml +191 -87
  31. data/test/cassettes/Restforce_DB_Associations_HasMany/with_an_inverse_mapping/_build/when_the_association_is_non-building/proceeds_without_constructing_any_records.yml +81 -28
  32. data/test/cassettes/Restforce_DB_Associations_HasMany/with_an_inverse_mapping/_synced_for_/when_a_matching_associated_record_has_been_synchronized/returns_true.yml +191 -87
  33. data/test/cassettes/Restforce_DB_Associations_HasMany/with_an_inverse_mapping/_synced_for_/when_no_matching_associated_record_has_been_synchronized/returns_false.yml +139 -35
  34. data/test/cassettes/Restforce_DB_Associations_HasOne/with_an_inverse_mapping/_build/and_a_nested_association_on_the_associated_mapping/recursively_builds_all_associations.yml +278 -76
  35. data/test/cassettes/Restforce_DB_Associations_HasOne/with_an_inverse_mapping/_build/returns_an_associated_record_populated_with_the_Salesforce_attributes.yml +203 -52
  36. data/test/cassettes/Restforce_DB_Associations_HasOne/with_an_inverse_mapping/_build/when_no_salesforce_record_is_found_for_the_association/proceeds_without_constructing_any_records.yml +186 -35
  37. data/test/cassettes/Restforce_DB_Associations_HasOne/with_an_inverse_mapping/_build/when_the_associated_record_has_already_been_persisted/assigns_the_existing_record.yml +203 -52
  38. data/test/cassettes/Restforce_DB_Associations_HasOne/with_an_inverse_mapping/_build/when_the_associated_record_has_been_cached/uses_the_cached_record.yml +203 -52
  39. data/test/cassettes/Restforce_DB_Associations_HasOne/with_an_inverse_mapping/_build/when_the_association_is_non-building/proceeds_without_constructing_any_records.yml +142 -44
  40. data/test/cassettes/Restforce_DB_Associations_HasOne/with_an_inverse_mapping/_synced_for_/when_a_matching_associated_record_has_been_synchronized/returns_true.yml +203 -52
  41. data/test/cassettes/Restforce_DB_Associations_HasOne/with_an_inverse_mapping/_synced_for_/when_no_matching_associated_record_has_been_synchronized/returns_false.yml +203 -52
  42. data/test/cassettes/Restforce_DB_Associator/_run/given_a_BelongsTo_association/given_another_record_for_association/when_the_Salesforce_association_is_out_of_date/updates_the_association_ID_in_Salesforce.yml +124 -124
  43. data/test/cassettes/Restforce_DB_Associator/_run/given_a_BelongsTo_association/given_another_record_for_association/when_the_database_association_is_out_of_date/updates_the_associated_record_in_the_database.yml +224 -126
  44. data/test/cassettes/Restforce_DB_Attacher/_run/given_a_Salesforce_record_with_an_upsert_ID/for_a_Passive_strategy/does_nothing.yml +119 -0
  45. data/test/cassettes/Restforce_DB_Attacher/_run/given_a_Salesforce_record_with_an_upsert_ID/for_an_Always_strategy/links_the_Salesforce_record_to_the_matching_database_record.yml +246 -0
  46. data/test/cassettes/Restforce_DB_Attacher/_run/given_a_Salesforce_record_with_an_upsert_ID/for_an_Always_strategy/when_no_matching_database_record_can_be_found/wipes_the_SynchronizationID__c_on_the_Salesforce_record.yml +284 -0
  47. data/test/cassettes/Restforce_DB_Attacher/_run/given_a_Salesforce_record_with_an_upsert_ID/for_an_Always_strategy/when_the_matching_database_record_has_a_salesforce_id/does_not_change_the_current_Salesforce_ID.yml +246 -0
  48. data/test/cassettes/Restforce_DB_Attacher/_run/given_a_Salesforce_record_with_an_upsert_ID/for_an_Always_strategy/when_the_matching_database_record_has_a_salesforce_id/wipes_the_SynchronizationId__c.yml +284 -0
  49. data/test/cassettes/{Restforce_DB_Synchronizer/_run/given_a_Salesforce_record_with_an_associated_database_record/updates_the_salesforce_record.yml → Restforce_DB_Attacher/_run/given_a_Salesforce_record_with_an_upsert_ID/for_an_Always_strategy/when_the_upsert_ID_is_for_another_database_model/does_not_wipe_the_SynchronizationId__c.yml} +57 -95
  50. data/test/cassettes/{Restforce_DB_Synchronizer/_run/given_a_Salesforce_record_with_an_associated_database_record/updates_the_database_record.yml → Restforce_DB_Attacher/_run/given_a_Salesforce_record_with_an_upsert_ID/for_an_Always_strategy/wipes_the_SynchronizationId__c.yml} +77 -116
  51. data/test/cassettes/Restforce_DB_Cleaner/_run/given_a_synchronized_Salesforce_record/when_the_mapping_has_no_conditions/does_not_drop_the_synchronized_database_record.yml +20 -20
  52. data/test/cassettes/Restforce_DB_Cleaner/_run/given_a_synchronized_Salesforce_record/when_the_record_does_not_meet_the_mapping_conditions/but_meets_conditions_for_a_parallel_mapping/does_not_drop_the_synchronized_database_record.yml +98 -45
  53. data/test/cassettes/Restforce_DB_Cleaner/_run/given_a_synchronized_Salesforce_record/when_the_record_does_not_meet_the_mapping_conditions/drops_the_synchronized_database_record.yml +90 -37
  54. data/test/cassettes/Restforce_DB_Cleaner/_run/given_a_synchronized_Salesforce_record/when_the_record_has_been_deleted_in_Salesforce/drops_the_synchronized_database_record.yml +20 -20
  55. data/test/cassettes/Restforce_DB_Cleaner/_run/given_a_synchronized_Salesforce_record/when_the_record_meets_the_mapping_conditions/does_not_drop_the_synchronized_database_record.yml +89 -36
  56. data/test/cassettes/Restforce_DB_Collector/_run/given_a_Salesforce_record_with_an_associated_database_record/returns_the_attributes_from_both_records.yml +103 -50
  57. data/test/cassettes/Restforce_DB_Collector/_run/given_an_existing_Salesforce_record/which_has_been_synchronized/returns_the_attributes_from_the_Salesforce_record.yml +102 -73
  58. data/test/cassettes/Restforce_DB_Collector/_run/given_an_existing_Salesforce_record/which_has_not_been_synchronized/does_not_store_any_attributes.yml +81 -40
  59. data/test/cassettes/Restforce_DB_Collector/_run/given_an_existing_database_record/returns_the_attributes_from_the_database_record.yml +66 -13
  60. data/test/cassettes/Restforce_DB_Collector/_run/when_the_record_has_not_been_updated_outside_of_the_system/does_not_collect_any_changes.yml +82 -29
  61. data/test/cassettes/Restforce_DB_Initializer/_run/given_an_existing_Salesforce_record/for_a_Passive_strategy/does_not_create_a_database_record.yml +20 -20
  62. data/test/cassettes/Restforce_DB_Initializer/_run/given_an_existing_Salesforce_record/for_an_Always_strategy/creates_a_matching_database_record.yml +81 -28
  63. data/test/cassettes/Restforce_DB_Initializer/_run/given_an_existing_database_record/for_an_Always_strategy/populates_Salesforce_with_the_new_record.yml +103 -67
  64. data/test/cassettes/Restforce_DB_Instances_Salesforce/_synced_/when_a_matching_database_record_exists/returns_true.yml +81 -28
  65. data/test/cassettes/Restforce_DB_Instances_Salesforce/_synced_/when_no_matching_database_record_exists/returns_false.yml +81 -28
  66. data/test/cassettes/Restforce_DB_Instances_Salesforce/_update_/updates_the_local_record_with_the_passed_attributes.yml +59 -59
  67. data/test/cassettes/Restforce_DB_Instances_Salesforce/_update_/updates_the_record_in_Salesforce_with_the_passed_attributes.yml +67 -67
  68. data/test/cassettes/Restforce_DB_Instances_Salesforce/_updated_internally_/when_another_user_made_the_last_change/returns_false.yml +18 -18
  69. data/test/cassettes/Restforce_DB_Instances_Salesforce/_updated_internally_/when_our_client_made_the_last_change/returns_true.yml +101 -48
  70. data/test/cassettes/Restforce_DB_Model/given_a_database_model_which_includes_the_module/_force_sync_/given_a_previously-synchronized_record_for_a_mapped_model/force-updates_both_synchronized_records.yml +67 -67
  71. data/test/cassettes/Restforce_DB_Model/given_a_database_model_which_includes_the_module/_force_sync_/given_an_unsynchronized_record_for_a_mapped_model/creates_a_matching_record_in_Salesforce.yml +78 -42
  72. data/test/cassettes/Restforce_DB_RecordTypes_Salesforce/_all/returns_a_list_of_the_existing_records_in_Salesforce.yml +82 -29
  73. data/test/cassettes/Restforce_DB_RecordTypes_Salesforce/_create_/creates_a_record_in_Salesforce_from_the_passed_database_record_s_attributes.yml +70 -34
  74. data/test/cassettes/Restforce_DB_RecordTypes_Salesforce/_create_/updates_the_database_record_with_the_Salesforce_record_s_ID.yml +70 -34
  75. data/test/cassettes/Restforce_DB_RecordTypes_Salesforce/_create_/when_a_Salesforce_record_already_exists_for_the_database_instance/uses_the_existing_record.yml +76 -40
  76. data/test/cassettes/Restforce_DB_RecordTypes_Salesforce/_create_/wipes_the_temporary_SynchronizationId__c_value_used_for_upsert.yml +247 -0
  77. data/test/cassettes/Restforce_DB_RecordTypes_Salesforce/_find/finds_existing_records_in_Salesforce.yml +81 -28
  78. data/test/cassettes/Restforce_DB_RecordTypes_Salesforce/_find/given_a_set_of_mapping_conditions/when_a_record_does_not_meet_the_conditions/does_not_find_the_record.yml +80 -27
  79. data/test/cassettes/Restforce_DB_RecordTypes_Salesforce/_find/given_a_set_of_mapping_conditions/when_a_record_meets_the_conditions/finds_the_record.yml +81 -28
  80. data/test/cassettes/Restforce_DB_RecordTypes_Salesforce/_find/returns_nil_when_no_matching_record_exists.yml +65 -12
  81. data/test/cassettes/Restforce_DB_Strategies_Always/_build_/given_a_Salesforce_record/wants_to_build_a_new_matching_record.yml +81 -28
  82. data/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 +81 -28
  83. data/test/cassettes/Restforce_DB_Strategies_Associated/_build_/given_an_inverse_mapping/with_a_synchronized_association_record/wants_to_build_a_new_record.yml +103 -52
  84. 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 +95 -44
  85. 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 +103 -52
  86. data/test/cassettes/Restforce_DB_Synchronizer/_run/given_a_Salesforce_record_with_an_associated_database_record/when_the_change_timestamp_is_stale/does_not_update_the_database_record.yml +60 -96
  87. data/test/cassettes/Restforce_DB_Synchronizer/_run/given_a_Salesforce_record_with_an_associated_database_record/when_the_change_timestamp_is_stale/does_not_update_the_salesforce_record.yml +97 -44
  88. data/test/cassettes/Restforce_DB_Synchronizer/_run/given_a_Salesforce_record_with_an_associated_database_record/when_the_changes_are_current/updates_the_database_record.yml +77 -77
  89. data/test/cassettes/Restforce_DB_Synchronizer/_run/given_a_Salesforce_record_with_an_associated_database_record/when_the_changes_are_current/updates_the_salesforce_record.yml +85 -85
  90. data/test/cassettes/Restforce_DB_Synchronizer/_run/given_a_Salesforce_record_with_no_associated_database_record/does_nothing_for_this_specific_mapping.yml +89 -36
  91. data/test/cassettes/Restforce_DB_Worker/a_race_condition_during_synchronization/does_not_change_the_user-entered_name_on_the_database_record.yml +153 -116
  92. data/test/cassettes/Restforce_DB_Worker/a_race_condition_during_synchronization/overrides_the_stale-but-more-recent_name_on_the_Salesforce.yml +161 -124
  93. data/test/lib/restforce/db/attacher_test.rb +93 -0
  94. data/test/lib/restforce/db/field_processor_test.rb +62 -23
  95. data/test/lib/restforce/db/record_types/salesforce_test.rb +5 -0
  96. data/test/lib/restforce/db/worker_test.rb +4 -3
  97. metadata +13 -4
@@ -0,0 +1,93 @@
1
+ require_relative "../../../test_helper"
2
+
3
+ describe Restforce::DB::Attacher do
4
+
5
+ configure!
6
+ mappings!
7
+
8
+ let(:attacher) { Restforce::DB::Attacher.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
+ "SynchronizationId__c" => "CustomObject::#{database_record.id}",
14
+ }
15
+ end
16
+ let(:database_record) { database_model.create! }
17
+ let(:salesforce_id) { Salesforce.create!(salesforce_model, attributes) }
18
+
19
+ describe "given a Salesforce record with an upsert ID" do
20
+ before do
21
+ salesforce_id
22
+ end
23
+
24
+ describe "for a Passive strategy" do
25
+ before do
26
+ mapping.strategy = Restforce::DB::Strategies::Passive.new
27
+ attacher.run
28
+ end
29
+
30
+ it "does nothing" do
31
+ expect(database_record.reload).to_not_be :salesforce_id?
32
+ end
33
+ end
34
+
35
+ describe "for an Always strategy" do
36
+ before do
37
+ mapping.strategy = Restforce::DB::Strategies::Always.new
38
+ attacher.run
39
+ end
40
+
41
+ it "links the Salesforce record to the matching database record" do
42
+ expect(database_record.reload).to_be :salesforce_id?
43
+ end
44
+
45
+ it "wipes the SynchronizationId__c" do
46
+ salesforce_record = mapping.salesforce_record_type.find(salesforce_id).record
47
+ expect(salesforce_record.SynchronizationId__c).to_be_nil
48
+ end
49
+
50
+ describe "when the matching database record has a salesforce_id" do
51
+ let(:old_id) { "a001a000001E1vFAKE" }
52
+ let(:database_record) { database_model.create!(salesforce_id: old_id) }
53
+
54
+ it "does not change the current Salesforce ID" do
55
+ expect(database_record.reload.salesforce_id).to_equal old_id
56
+ end
57
+
58
+ it "wipes the SynchronizationId__c" do
59
+ salesforce_record = mapping.salesforce_record_type.find(salesforce_id).record
60
+ expect(salesforce_record.SynchronizationId__c).to_be_nil
61
+ end
62
+ end
63
+
64
+ describe "when no matching database record can be found" do
65
+ let(:database_record) { nil }
66
+ let(:attributes) do
67
+ {
68
+ "SynchronizationId__c" => "CustomObject::1",
69
+ }
70
+ end
71
+
72
+ it "wipes the SynchronizationId__c" do
73
+ salesforce_record = mapping.salesforce_record_type.find(salesforce_id).record
74
+ expect(salesforce_record.SynchronizationId__c).to_be_nil
75
+ end
76
+ end
77
+
78
+ describe "when the upsert ID is for another database model" do
79
+ let(:attributes) do
80
+ {
81
+ "SynchronizationId__c" => "User::1",
82
+ }
83
+ end
84
+
85
+ it "does not wipe the SynchronizationId__c" do
86
+ salesforce_record = mapping.salesforce_record_type.find(salesforce_id).record
87
+ expect(salesforce_record.SynchronizationId__c).to_not_be_nil
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -5,42 +5,81 @@ describe Restforce::DB::FieldProcessor do
5
5
  configure!
6
6
 
7
7
  let(:processor) { Restforce::DB::FieldProcessor.new }
8
+ let(:dummy_client) do
9
+ Object.new.tap do |client|
10
+
11
+ def client.describe(_)
12
+ raise "This has already been invoked!" if @already_run
13
+ @already_run = true
14
+
15
+ Struct.new(:fields).new([
16
+ { "name" => "Createable", "createable" => true, "updateable" => false },
17
+ { "name" => "Updateable", "createable" => false, "updateable" => true },
18
+ { "name" => "Both", "createable" => true, "updateable" => true },
19
+ { "name" => "Neither", "createable" => false, "updateable" => false },
20
+ ])
21
+ end
22
+
23
+ end
24
+ end
25
+
26
+ describe "#available_fields" do
27
+ let(:fields) do
28
+ %w(
29
+ Createable
30
+ Updateable
31
+ Both
32
+ Neither
33
+ Relationship__r.Relateable
34
+ )
35
+ end
36
+
37
+ it "filters the passed fields to only existing fields for an object" do
38
+ Restforce::DB.stub(:client, dummy_client) do
39
+ excessive_fields = fields + ["NonExistent"]
40
+ expect(processor.available_fields("CustomObject__c", excessive_fields)).to_equal(fields)
41
+ end
42
+ end
43
+
44
+ it "filters the passed fields to only createable fields" do
45
+ Restforce::DB.stub(:client, dummy_client) do
46
+ expect(processor.available_fields("CustomObject__c", fields, :create)).to_equal(%w(
47
+ Createable
48
+ Both
49
+ ))
50
+ end
51
+ end
52
+
53
+ it "filters the passed fields to only updateable fields" do
54
+ Restforce::DB.stub(:client, dummy_client) do
55
+ expect(processor.available_fields("CustomObject__c", fields, :update)).to_equal(%w(
56
+ Updateable
57
+ Both
58
+ ))
59
+ end
60
+ end
61
+ end
8
62
 
9
63
  describe "#process" do
10
64
  let(:attributes) do
11
65
  {
12
- "Creatable" => "This field is create-only!",
66
+ "Createable" => "This field is create-only!",
13
67
  "Updateable" => "And... this field is update-only!",
14
68
  "Both" => "But... this field allows both!",
69
+ "Neither" => "Unfortunately, this field allows neither.",
15
70
  }
16
71
  end
17
- let(:dummy_client) do
18
- Object.new.tap do |client|
19
72
 
20
- def client.describe(_)
21
- raise "This has already been invoked!" if @already_run
22
- @already_run = true
23
-
24
- Struct.new(:fields).new([
25
- { "name" => "Creatable", "createable" => true, "updateable" => false },
26
- { "name" => "Updateable", "createable" => false, "updateable" => true },
27
- { "name" => "Both", "createable" => true, "updateable" => true },
28
- ])
29
- end
30
-
31
- end
32
- end
33
-
34
- it "removes the read-only fields from the passed attribute Hash on :create" do
73
+ it "removes the non-creatable fields from the passed attribute Hash on :create" do
35
74
  Restforce::DB.stub(:client, dummy_client) do
36
75
  expect(processor.process("CustomObject__c", attributes, :create)).to_equal(
37
- "Creatable" => attributes["Creatable"],
38
- "Both" => attributes["Both"],
76
+ "Createable" => attributes["Createable"],
77
+ "Both" => attributes["Both"],
39
78
  )
40
79
  end
41
80
  end
42
81
 
43
- it "removes the read-only fields from the passed attribute Hash on :update" do
82
+ it "removes the non-updateable fields from the passed attribute Hash on :update" do
44
83
  Restforce::DB.stub(:client, dummy_client) do
45
84
  expect(processor.process("CustomObject__c", attributes, :update)).to_equal(
46
85
  "Updateable" => attributes["Updateable"],
@@ -51,11 +90,11 @@ describe Restforce::DB::FieldProcessor do
51
90
 
52
91
  it "invokes the client only once for a single SObject Type" do
53
92
  Restforce::DB.stub(:client, dummy_client) do
54
- processor.process("CustomObject__c", attributes)
93
+ processor.process("CustomObject__c", attributes, :update)
55
94
 
56
95
  # Our dummy client is configured to raise an error if `#describe` is
57
96
  # invoked more than once. There is no "wont_raise" in Minitest.
58
- processor.process("CustomObject__c", attributes)
97
+ processor.process("CustomObject__c", attributes, :create)
59
98
  end
60
99
  end
61
100
  end
@@ -28,6 +28,11 @@ describe Restforce::DB::RecordTypes::Salesforce do
28
28
  expect(sync_from.synced?).to_equal(true)
29
29
  end
30
30
 
31
+ it "wipes the temporary SynchronizationId__c value used for upsert" do
32
+ Salesforce.records << [salesforce_model, instance.Id]
33
+ expect(instance.SynchronizationId__c).to_be_nil
34
+ end
35
+
31
36
  describe "when a Salesforce record already exists for the database instance" do
32
37
 
33
38
  it "uses the existing record" do
@@ -20,7 +20,8 @@ describe Restforce::DB::Worker do
20
20
 
21
21
  ## 1b. The record is synced to Salesforce.
22
22
  worker.send :reset!
23
- worker.send :propagate, mapping
23
+ worker.send :task, Restforce::DB::Initializer, mapping
24
+
24
25
  expect(database_record.reload).to_be :salesforce_id?
25
26
  Salesforce.records << [salesforce_model, database_record.salesforce_id]
26
27
 
@@ -43,8 +44,8 @@ describe Restforce::DB::Worker do
43
44
  # We sleep here to ensure we pick up our manual changes.
44
45
  sleep 1 if VCR.current_cassette.recording?
45
46
  worker.send :reset!
46
- worker.send :collect, mapping
47
- worker.send :synchronize, mapping
47
+ worker.send :task, Restforce::DB::Collector, mapping
48
+ worker.send :task, Restforce::DB::Synchronizer, mapping
48
49
  end
49
50
  end
50
51
 
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: 3.0.0
4
+ version: 3.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-06-25 00:00:00.000000000 Z
11
+ date: 2015-06-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -216,6 +216,7 @@ files:
216
216
  - lib/restforce/db/associations/has_many.rb
217
217
  - lib/restforce/db/associations/has_one.rb
218
218
  - lib/restforce/db/associator.rb
219
+ - lib/restforce/db/attacher.rb
219
220
  - lib/restforce/db/attribute_map.rb
220
221
  - lib/restforce/db/cleaner.rb
221
222
  - lib/restforce/db/client.rb
@@ -243,6 +244,7 @@ files:
243
244
  - lib/restforce/db/strategy.rb
244
245
  - lib/restforce/db/synchronization_error.rb
245
246
  - lib/restforce/db/synchronizer.rb
247
+ - lib/restforce/db/task.rb
246
248
  - lib/restforce/db/timestamp_cache.rb
247
249
  - lib/restforce/db/tracker.rb
248
250
  - lib/restforce/db/version.rb
@@ -279,6 +281,13 @@ files:
279
281
  - test/cassettes/Restforce_DB_Associations_HasOne/with_an_inverse_mapping/_synced_for_/when_no_matching_associated_record_has_been_synchronized/returns_false.yml
280
282
  - test/cassettes/Restforce_DB_Associator/_run/given_a_BelongsTo_association/given_another_record_for_association/when_the_Salesforce_association_is_out_of_date/updates_the_association_ID_in_Salesforce.yml
281
283
  - test/cassettes/Restforce_DB_Associator/_run/given_a_BelongsTo_association/given_another_record_for_association/when_the_database_association_is_out_of_date/updates_the_associated_record_in_the_database.yml
284
+ - test/cassettes/Restforce_DB_Attacher/_run/given_a_Salesforce_record_with_an_upsert_ID/for_a_Passive_strategy/does_nothing.yml
285
+ - test/cassettes/Restforce_DB_Attacher/_run/given_a_Salesforce_record_with_an_upsert_ID/for_an_Always_strategy/links_the_Salesforce_record_to_the_matching_database_record.yml
286
+ - test/cassettes/Restforce_DB_Attacher/_run/given_a_Salesforce_record_with_an_upsert_ID/for_an_Always_strategy/when_no_matching_database_record_can_be_found/wipes_the_SynchronizationID__c_on_the_Salesforce_record.yml
287
+ - test/cassettes/Restforce_DB_Attacher/_run/given_a_Salesforce_record_with_an_upsert_ID/for_an_Always_strategy/when_the_matching_database_record_has_a_salesforce_id/does_not_change_the_current_Salesforce_ID.yml
288
+ - test/cassettes/Restforce_DB_Attacher/_run/given_a_Salesforce_record_with_an_upsert_ID/for_an_Always_strategy/when_the_matching_database_record_has_a_salesforce_id/wipes_the_SynchronizationId__c.yml
289
+ - test/cassettes/Restforce_DB_Attacher/_run/given_a_Salesforce_record_with_an_upsert_ID/for_an_Always_strategy/when_the_upsert_ID_is_for_another_database_model/does_not_wipe_the_SynchronizationId__c.yml
290
+ - test/cassettes/Restforce_DB_Attacher/_run/given_a_Salesforce_record_with_an_upsert_ID/for_an_Always_strategy/wipes_the_SynchronizationId__c.yml
282
291
  - test/cassettes/Restforce_DB_Cleaner/_run/given_a_synchronized_Salesforce_record/when_the_mapping_has_no_conditions/does_not_drop_the_synchronized_database_record.yml
283
292
  - test/cassettes/Restforce_DB_Cleaner/_run/given_a_synchronized_Salesforce_record/when_the_record_does_not_meet_the_mapping_conditions/but_meets_conditions_for_a_parallel_mapping/does_not_drop_the_synchronized_database_record.yml
284
293
  - test/cassettes/Restforce_DB_Cleaner/_run/given_a_synchronized_Salesforce_record/when_the_record_does_not_meet_the_mapping_conditions/drops_the_synchronized_database_record.yml
@@ -304,6 +313,7 @@ files:
304
313
  - test/cassettes/Restforce_DB_RecordTypes_Salesforce/_create_/creates_a_record_in_Salesforce_from_the_passed_database_record_s_attributes.yml
305
314
  - test/cassettes/Restforce_DB_RecordTypes_Salesforce/_create_/updates_the_database_record_with_the_Salesforce_record_s_ID.yml
306
315
  - test/cassettes/Restforce_DB_RecordTypes_Salesforce/_create_/when_a_Salesforce_record_already_exists_for_the_database_instance/uses_the_existing_record.yml
316
+ - test/cassettes/Restforce_DB_RecordTypes_Salesforce/_create_/wipes_the_temporary_SynchronizationId__c_value_used_for_upsert.yml
307
317
  - test/cassettes/Restforce_DB_RecordTypes_Salesforce/_find/finds_existing_records_in_Salesforce.yml
308
318
  - test/cassettes/Restforce_DB_RecordTypes_Salesforce/_find/given_a_set_of_mapping_conditions/when_a_record_does_not_meet_the_conditions/does_not_find_the_record.yml
309
319
  - test/cassettes/Restforce_DB_RecordTypes_Salesforce/_find/given_a_set_of_mapping_conditions/when_a_record_meets_the_conditions/finds_the_record.yml
@@ -313,8 +323,6 @@ files:
313
323
  - test/cassettes/Restforce_DB_Strategies_Associated/_build_/given_an_inverse_mapping/with_a_synchronized_association_record/wants_to_build_a_new_record.yml
314
324
  - 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
315
325
  - 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
316
- - test/cassettes/Restforce_DB_Synchronizer/_run/given_a_Salesforce_record_with_an_associated_database_record/updates_the_database_record.yml
317
- - test/cassettes/Restforce_DB_Synchronizer/_run/given_a_Salesforce_record_with_an_associated_database_record/updates_the_salesforce_record.yml
318
326
  - test/cassettes/Restforce_DB_Synchronizer/_run/given_a_Salesforce_record_with_an_associated_database_record/when_the_change_timestamp_is_stale/does_not_update_the_database_record.yml
319
327
  - test/cassettes/Restforce_DB_Synchronizer/_run/given_a_Salesforce_record_with_an_associated_database_record/when_the_change_timestamp_is_stale/does_not_update_the_salesforce_record.yml
320
328
  - test/cassettes/Restforce_DB_Synchronizer/_run/given_a_Salesforce_record_with_an_associated_database_record/when_the_changes_are_current/updates_the_database_record.yml
@@ -329,6 +337,7 @@ files:
329
337
  - test/lib/restforce/db/associations/has_many_test.rb
330
338
  - test/lib/restforce/db/associations/has_one_test.rb
331
339
  - test/lib/restforce/db/associator_test.rb
340
+ - test/lib/restforce/db/attacher_test.rb
332
341
  - test/lib/restforce/db/attribute_map_test.rb
333
342
  - test/lib/restforce/db/cleaner_test.rb
334
343
  - test/lib/restforce/db/collector_test.rb