restforce-db 2.0.0 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/lib/restforce/db/accumulator.rb +13 -0
  3. data/lib/restforce/db/field_processor.rb +70 -0
  4. data/lib/restforce/db/instances/salesforce.rb +10 -0
  5. data/lib/restforce/db/record_types/salesforce.rb +2 -2
  6. data/lib/restforce/db/synchronizer.rb +2 -1
  7. data/lib/restforce/db/version.rb +1 -1
  8. data/lib/restforce/db.rb +1 -0
  9. 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 +135 -82
  10. 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 +152 -99
  11. 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 +120 -0
  12. data/test/cassettes/Restforce_DB_Cleaner/_run/given_a_synchronized_Salesforce_record/when_the_record_does_not_meet_the_mapping_conditions/for_a_non-Passive_strategy/drops_the_synchronized_database_record.yml +34 -36
  13. 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 +35 -37
  14. data/test/cassettes/Restforce_DB_Initializer/_run/given_an_existing_database_record/for_an_Always_strategy/populates_Salesforce_with_the_new_record.yml +96 -44
  15. data/test/cassettes/Restforce_DB_Instances_Salesforce/_update_/updates_the_local_record_with_the_passed_attributes.yml +88 -35
  16. data/test/cassettes/Restforce_DB_Instances_Salesforce/_update_/updates_the_record_in_Salesforce_with_the_passed_attributes.yml +96 -43
  17. data/test/cassettes/Restforce_DB_RecordTypes_Salesforce/_create_/creates_a_record_in_Salesforce_from_the_passed_database_record_s_attributes.yml +81 -28
  18. data/test/cassettes/Restforce_DB_RecordTypes_Salesforce/_create_/updates_the_database_record_with_the_Salesforce_record_s_ID.yml +81 -28
  19. data/test/cassettes/Restforce_DB_Synchronizer/_run/given_a_Salesforce_record_with_an_associated_database_record/updates_the_database_record.yml +88 -35
  20. data/test/cassettes/Restforce_DB_Synchronizer/_run/given_a_Salesforce_record_with_an_associated_database_record/updates_the_salesforce_record.yml +96 -43
  21. data/test/lib/restforce/db/accumulator_test.rb +16 -0
  22. data/test/lib/restforce/db/cleaner_test.rb +15 -9
  23. data/test/lib/restforce/db/collector_test.rb +13 -15
  24. data/test/lib/restforce/db/field_processor_test.rb +51 -0
  25. data/test/lib/restforce/db/initializer_test.rb +10 -13
  26. data/test/lib/restforce/db/runner_cache_test.rb +1 -0
  27. data/test/support/utilities.rb +1 -0
  28. metadata +5 -3
  29. data/test/cassettes/Restforce_DB_Instances_Salesforce/_copy_/updates_the_record_with_the_attributes_from_the_copied_object.yml +0 -194
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e92a8e2216150a27646cdd8525a951100055ad99
4
- data.tar.gz: 07ade758ff323cd721daede50850a724562df0b1
3
+ metadata.gz: bd30e064e5e85ed7a3324e54e08797f34df84c84
4
+ data.tar.gz: 43bf5c31a7517094be1fbb875c701d9b580a4121
5
5
  SHA512:
6
- metadata.gz: be4a146095c1555becbb048bd0944b56d37fe8c14231cc2e27355f30c372526ced00f8767ed486d14117af61dc47c8b4d55c28d95b99d74723a4f6ec83993c4e
7
- data.tar.gz: d5a0929ca903969593e9037961a9ba2874329fa9f3f30e58fee67fa993c1b6d3bdc9bec2a84b06ccd0dee6c0a210261b95b2a9ff0212b80e6f65dc472068c8ca
6
+ metadata.gz: 9c8c3b7f0ce2cd131c643f2d33f7c15c719b820522e67696bb6d6a4eeb9ef80a77d4a841d8a7d0bf7a8a66fd9caf252357e29cd245f4257823a9d85c55cb9e63
7
+ data.tar.gz: e75e5b35ed86a07426eea1926ae642d7176167a7de858934a3e251399efe0f85af30fca97e1ea12f93ff9fbcddf7bf925bd08221bb1158e9520987da5ea16d46
@@ -44,6 +44,19 @@ module Restforce
44
44
  end
45
45
  end
46
46
 
47
+ # Public: Do the canonical attributes stored in this Accumulator differ
48
+ # from those in the passed comparison Hash?
49
+ #
50
+ # comparison - A Hash mapping of attributes to values.
51
+ #
52
+ # Returns a Boolean.
53
+ def changed?(comparison)
54
+ attributes.any? do |attribute, value|
55
+ next unless comparison.key?(attribute)
56
+ comparison[attribute] != value
57
+ end
58
+ end
59
+
47
60
  end
48
61
 
49
62
  end
@@ -0,0 +1,70 @@
1
+ module Restforce
2
+
3
+ module DB
4
+
5
+ # Restforce::DB::FieldProcessor encapsulates logic for preventing
6
+ # information for unwriteable fields from being submitted to Salesforce.
7
+ class FieldProcessor
8
+
9
+ # Internal: Get a global cache with which to store/fetch the writable
10
+ # fields for each Salesforce SObject Type.
11
+ #
12
+ # Returns a Hash.
13
+ def self.field_cache
14
+ @field_cache ||= {}
15
+ end
16
+
17
+ # Internal: Clear out the global field cache.
18
+ #
19
+ # Returns nothing.
20
+ def self.reset
21
+ @field_cache = {}
22
+ end
23
+
24
+ # Public: Get a restricted version of the passed attributes Hash, with
25
+ # unwritable fields stripped out.
26
+ #
27
+ # sobject_type - A String name of an SObject Type in Salesforce.
28
+ # attributes - A Hash with keys corresponding to Salesforce field names.
29
+ #
30
+ # Returns a Hash.
31
+ def process(sobject_type, attributes)
32
+ attributes.each_with_object({}) do |(field, value), processed|
33
+ next unless writable?(sobject_type, field)
34
+ processed[field] = value
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ # Internal: Is the passed attribute writable for the passed SObject Type?
41
+ #
42
+ # sobject_type - A String name of an SObject Type in Salesforce.
43
+ # field - A String Salesforce field API name.
44
+ #
45
+ # Returns a Boolean.
46
+ def writable?(sobject_type, field)
47
+ field_statuses(sobject_type)[field]
48
+ end
49
+
50
+ # Internal: Get a collection of all fields for the passed Salesforce
51
+ # SObject Type, with an indication of whether or not they are writable.
52
+ #
53
+ # sobject_type - A String name of an SObject Type in Salesforce.
54
+ #
55
+ # Returns a Hash.
56
+ def field_statuses(sobject_type)
57
+ self.class.field_cache[sobject_type] ||= begin
58
+ fields = Restforce::DB.client.describe(sobject_type).fields
59
+
60
+ fields.each_with_object({}) do |field, output|
61
+ output[field["name"]] = field["updateable"]
62
+ end
63
+ end
64
+ end
65
+
66
+ end
67
+
68
+ end
69
+
70
+ end
@@ -21,6 +21,16 @@ module Restforce
21
21
  @record.Id
22
22
  end
23
23
 
24
+ # Public: Update the instance with the passed attributes.
25
+ #
26
+ # attributes - A Hash mapping attribute names to values.
27
+ #
28
+ # Returns self.
29
+ # Raises if the update fails for any reason.
30
+ def update!(attributes)
31
+ super FieldProcessor.new.process(@record_type, attributes)
32
+ end
33
+
24
34
  # Public: Get the time of the last update to this record.
25
35
  #
26
36
  # Returns a Time-compatible object.
@@ -17,8 +17,8 @@ module Restforce
17
17
  # Returns a Restforce::DB::Instances::Salesforce instance.
18
18
  # Raises on any error from Salesforce.
19
19
  def create!(from_record)
20
- attributes = @mapping.convert(@record_type, from_record.attributes)
21
- record_id = DB.client.create!(@record_type, attributes)
20
+ from_attributes = FieldProcessor.new.process(@record_type, from_record.attributes)
21
+ record_id = DB.client.create!(@record_type, from_attributes)
22
22
 
23
23
  from_record.update!(@mapping.lookup_column => record_id).after_sync
24
24
 
@@ -49,10 +49,11 @@ module Restforce
49
49
  #
50
50
  # Returns nothing.
51
51
  def update(instance, accumulator)
52
+ return unless accumulator.changed?(instance.attributes)
53
+
52
54
  current_attributes = accumulator.current(instance.attributes)
53
55
  attributes = @mapping.convert(instance.record_type, current_attributes)
54
56
 
55
- return if attributes.empty?
56
57
  instance.update!(attributes)
57
58
  end
58
59
 
@@ -3,7 +3,7 @@ module Restforce
3
3
  # :nodoc:
4
4
  module DB
5
5
 
6
- VERSION = "2.0.0"
6
+ VERSION = "2.0.1"
7
7
 
8
8
  end
9
9
 
data/lib/restforce/db.rb CHANGED
@@ -16,6 +16,7 @@ require "restforce/db/associations/foreign_key"
16
16
  require "restforce/db/associations/has_many"
17
17
  require "restforce/db/associations/has_one"
18
18
 
19
+ require "restforce/db/field_processor"
19
20
  require "restforce/db/instances/base"
20
21
  require "restforce/db/instances/active_record"
21
22
  require "restforce/db/instances/salesforce"