restforce-db 1.3.0 → 2.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7d8819030ad19f9cf66c0f4f0e8a8f619a75a207
4
- data.tar.gz: 239e7983d8a2f382f02616635d2d96882eae3a44
3
+ metadata.gz: e92a8e2216150a27646cdd8525a951100055ad99
4
+ data.tar.gz: 07ade758ff323cd721daede50850a724562df0b1
5
5
  SHA512:
6
- metadata.gz: dac325298c30890ac75800f246863b3e831c25e2c66c108f3835f091271f49cd2c69ddc9fa165620c8c650f507d22db44346435c3c062deac0fd251728918c64
7
- data.tar.gz: 0d95128ded0b74be19e399e2350d9a0f34889c1a0fd0f69703dd5dc475f2f1684e32ff1be9b4f030c8d1ed41385b9e487e40cc4d8d5a14f96e20bd5df2fec80c
6
+ metadata.gz: be4a146095c1555becbb048bd0944b56d37fe8c14231cc2e27355f30c372526ced00f8767ed486d14117af61dc47c8b4d55c28d95b99d74723a4f6ec83993c4e
7
+ data.tar.gz: d5a0929ca903969593e9037961a9ba2874329fa9f3f30e58fee67fa993c1b6d3bdc9bec2a84b06ccd0dee6c0a210261b95b2a9ff0212b80e6f65dc472068c8ca
data/README.md CHANGED
@@ -44,12 +44,16 @@ class Restaurant < ActiveRecord::Base
44
44
 
45
45
  module StyleAdapter
46
46
 
47
- def self.to_salesforce(value)
48
- "#{value} in Salesforce"
47
+ def self.to_database(attributes)
48
+ attributes.each_with_object({}) do |(key, value), final|
49
+ final[key] = value.chomp(" in Salesforce")
50
+ end
49
51
  end
50
52
 
51
- def self.to_database(value)
52
- value.chomp(" in Salesforce")
53
+ def self.from_database(attributes)
54
+ attributes.each_with_object({}) do |(key, value), final|
55
+ final[key] = "#{value} in Salesforce"
56
+ end
53
57
  end
54
58
 
55
59
  end
@@ -59,14 +63,12 @@ class Restaurant < ActiveRecord::Base
59
63
  has_many :dishes, through: "Restaurant__c"
60
64
  belongs_to :chef, through: %w(Chef__c Cuisine__c)
61
65
 
66
+ converts_with StyleAdapter
67
+
62
68
  maps(
63
69
  name: "Name",
64
70
  style: "Style__c",
65
71
  )
66
-
67
- converts(
68
- style: StyleAdapter,
69
- )
70
72
  end
71
73
 
72
74
  end
@@ -135,9 +137,17 @@ Individual conditions supplied to `where` will be appended together with `AND` c
135
137
 
136
138
  `maps` defines a set of direct field-to-field mappings. It takes a Hash as an argument; the keys should line up with your ActiveRecord attribute names, while the values should line up with the matching field names in Salesforce.
137
139
 
140
+ Your ActiveRecord class _must_ expose readers for each attribute in the mapping, and generally _should_ expose matching writers, though you can use an adapter object (see "Field Conversions" below) to obviate the need for the latter.
141
+
138
142
  #### Field Conversions
139
143
 
140
- `converts` defines a set of value adapters. It takes a Hash as an argument; the keys should line up with the ActiveRecord attribute names defined in your `maps` clause, while the values should be the corresponding adapter objects. The only requirement for an adapter is that it respond to the methods `#to_database` and `#to_salesforce`.
144
+ `converts_with` defines a mapping conversion adapter. The only requirement for an adapter is that it respond to the methods `#to_database` and `#from_database`.
145
+
146
+ - `#to_database` will be handed a "normalized" Hash, with the standard Symbol mapped attributes as keys, and the values as they are stored in Salesforce. It should return a modified version of the Hash which can be passed to `assign_attributes` for a record.
147
+
148
+ - `#from_database` will be handed a Hash with the standard Symbol mapped attributes as keys, and the values for those attributes as they are returned by the ActiveRecord object. It should return a modified version of the Hash with values suitable for storage in Salesforce.
149
+
150
+ By default, `Restforce::DB::Adapter` will be used, which simply converts times into String ISO-8601 timestamps before passing them off to Salesforce.
141
151
 
142
152
  #### Associations
143
153
 
data/circle.yml ADDED
@@ -0,0 +1,20 @@
1
+ checkout:
2
+ post:
3
+ - mkdir -p test/config
4
+ - cp lib/generators/templates/config.yml test/config/secrets.yml
5
+ machine:
6
+ ruby:
7
+ version: 2.2.2
8
+ dependencies:
9
+ pre:
10
+ # Get the most recent bundler
11
+ - gem install bundler
12
+ database:
13
+ override:
14
+ # Do nothing; we don't need any database setup.
15
+ - echo "SKIPPING"
16
+ test:
17
+ override:
18
+ - bundle exec rubocop
19
+ - bundle exec rake test
20
+
@@ -31,19 +31,16 @@ module Restforce
31
31
  end
32
32
  end
33
33
 
34
- # Public: Get a Hash representing the changes that would need to be
35
- # applied to make a passed Hash a subset of this Accumulator's derived
36
- # attributes Hash.
34
+ # Public: Get a Hash representing the current values for the items in the
35
+ # passed Hash, as a subset of this Accumulator's attributes Hash.
37
36
  #
38
37
  # comparison - A Hash mapping of attributes to values.
39
38
  #
40
39
  # Returns a Hash.
41
- def diff(comparison)
42
- attributes.each_with_object({}) do |(attribute, value), diff|
40
+ def current(comparison)
41
+ attributes.each_with_object({}) do |(attribute, value), final|
43
42
  next unless comparison.key?(attribute)
44
- next if comparison[attribute] == value
45
-
46
- diff[attribute] = value
43
+ final[attribute] = value
47
44
  end
48
45
  end
49
46
 
@@ -0,0 +1,39 @@
1
+ module Restforce
2
+
3
+ module DB
4
+
5
+ # Restforce::DB::Adapter defines the default data conversions between
6
+ # database and Salesforce formats. It translates Dates and Times to ISO-8601
7
+ # format for storage in Salesforce.
8
+ class Adapter
9
+
10
+ # Public: Convert the passed attribute hash to a format consumable by
11
+ # the ActiveRecord model. By default, performs no conversions.
12
+ #
13
+ # attributes - A Hash of attributes, with keys corresponding to a Mapping.
14
+ #
15
+ # Returns a Hash.
16
+ def to_database(attributes)
17
+ attributes.dup
18
+ end
19
+
20
+ # Public: Convert the passed attribute hash to a format consumable by
21
+ # Salesforce.
22
+ #
23
+ # attributes - A Hash of attributes, with keys corresponding to a Mapping.
24
+ #
25
+ # Returns a Hash.
26
+ def from_database(attributes)
27
+ attributes.each_with_object({}) do |(key, value), final|
28
+ value = value.utc if value.respond_to?(:utc)
29
+ value = value.iso8601 if value.respond_to?(:iso8601)
30
+
31
+ final[key] = value
32
+ end
33
+ end
34
+
35
+ end
36
+
37
+ end
38
+
39
+ end
@@ -4,40 +4,25 @@ module Restforce
4
4
 
5
5
  # Restforce::DB::AttributeMap encapsulates the logic for converting between
6
6
  # various representations of attribute hashes.
7
+ #
8
+ # For the purposes of our mappings, a "normalized" attribute Hash maps the
9
+ # Salesforce field names to Salesforce-compatible values. Value conversion
10
+ # into and out of the database occurs through a lightweight Adapter object.
7
11
  class AttributeMap
8
12
 
9
- # DefaultAdapter defines the default data conversions between database and
10
- # Salesforce formats. It translates Dates and Times to ISO-8601 format for
11
- # storage in Salesforce.
12
- module DefaultAdapter
13
-
14
- # :nodoc:
15
- def self.to_database(value)
16
- value
17
- end
18
-
19
- # :nodoc:
20
- def self.to_salesforce(value)
21
- value = value.respond_to?(:utc) ? value.utc : value
22
- value.respond_to?(:iso8601) ? value.iso8601 : value
23
- end
24
-
25
- end
26
-
27
13
  # Public: Initialize a Restforce::DB::AttributeMap.
28
14
  #
29
15
  # database_model - A Class compatible with ActiveRecord::Base.
30
16
  # salesforce_model - A String name of an object type in Salesforce.
31
17
  # fields - A Hash of mappings between database columns and
32
18
  # fields in Salesforce.
33
- # conversions - A Hash of mappings between database columns and the
34
- # corresponding adapter objects which should be used to
35
- # convert between data formats.
36
- def initialize(database_model, salesforce_model, fields = {}, conversions = {})
19
+ # adapter - An adapter object which should be used to convert
20
+ # between data formats.
21
+ def initialize(database_model, salesforce_model, fields = {}, adapter = Adapter.new)
37
22
  @database_model = database_model
38
23
  @salesforce_model = salesforce_model
39
24
  @fields = fields
40
- @conversions = conversions
25
+ @adapter = adapter
41
26
 
42
27
  @types = {
43
28
  database_model => :database,
@@ -47,7 +32,7 @@ module Restforce
47
32
 
48
33
  # Public: Build a normalized Hash of attributes from the appropriate set
49
34
  # of mappings. The keys of the resulting mapping Hash will correspond to
50
- # the database column names.
35
+ # the Salesforce field names.
51
36
  #
52
37
  # from_format - A String or Class reflecting the record type from which
53
38
  # the attribute Hash is being compiled.
@@ -57,13 +42,18 @@ module Restforce
57
42
  def attributes(from_format)
58
43
  case @types[from_format]
59
44
  when :salesforce
60
- @fields.each_with_object({}) do |(attribute, mapping), values|
61
- values[attribute] = adapter(attribute).to_database(yield(mapping))
45
+ @fields.values.each_with_object({}) do |mapping, values|
46
+ values[mapping] = yield(mapping)
62
47
  end
63
48
  when :database
64
- @fields.keys.each_with_object({}) do |attribute, values|
49
+ attributes = @fields.keys.each_with_object({}) do |attribute, values|
65
50
  values[attribute] = yield(attribute)
66
51
  end
52
+ attributes = @adapter.from_database(attributes)
53
+
54
+ @fields.each_with_object({}) do |(attribute, mapping), final|
55
+ final[mapping] = attributes[attribute]
56
+ end
67
57
  else
68
58
  raise ArgumentError
69
59
  end
@@ -85,65 +75,22 @@ module Restforce
85
75
  # some_key: "SomeField__c",
86
76
  # )
87
77
  #
88
- # mapping.convert("Object__c", some_key: "some value")
89
- # # => { "Some_Field__c" => "some value" }
78
+ # mapping.convert(MyClass, "Some_Field__c" => "some value")
79
+ # # => { some_key: "some value" }
90
80
  #
91
- # mapping.convert(MyClass, some_key: "some other value")
92
- # # => { some_key: "some other value" }
81
+ # mapping.convert("Object__c", "Some_Field__c" => "some other value")
82
+ # # => { "Some_Field__c" => "some other value" }
93
83
  #
94
84
  # Returns a Hash.
95
85
  def convert(to_format, attributes)
96
86
  case @types[to_format]
97
87
  when :database
98
- attributes.dup
99
- when :salesforce
100
- @fields.each_with_object({}) do |(attribute, mapping), converted|
101
- next unless attributes.key?(attribute)
102
- value = adapter(attribute).to_salesforce(attributes[attribute])
103
- converted[mapping] = value
104
- end
105
- else
106
- raise ArgumentError
107
- end
108
- end
109
-
110
- # Public: Convert a Hash of Salesforce attributes to a format compatible
111
- # with a specific platform.
112
- #
113
- # to_format - A String or Class reflecting the record type for which the
114
- # attribute Hash is being compiled.
115
- # attributes - A Hash of attributes, with keys corresponding to the
116
- # Salesforce attribute names.
117
- #
118
- # Examples
119
- #
120
- # map = AttributeMap.new(
121
- # MyClass,
122
- # "Object__c",
123
- # some_key: "SomeField__c",
124
- # )
125
- #
126
- # map.convert_from_salesforce(
127
- # "Object__c",
128
- # "Some_Field__c" => "some value",
129
- # )
130
- # # => { "Some_Field__c" => "some value" }
131
- #
132
- # map.convert_from_salesforce(
133
- # MyClass,
134
- # "Some_Field__c" => "some other value",
135
- # )
136
- # # => { some_key: "some other value" }
137
- #
138
- # Returns a Hash.
139
- def convert_from_salesforce(to_format, attributes)
140
- case @types[to_format]
141
- when :database
142
- @fields.each_with_object({}) do |(attribute, mapping), converted|
88
+ attributes = @fields.each_with_object({}) do |(attribute, mapping), converted|
143
89
  next unless attributes.key?(mapping)
144
- value = adapter(attribute).to_database(attributes[mapping])
145
- converted[attribute] = value
90
+ converted[attribute] = attributes[mapping]
146
91
  end
92
+
93
+ @adapter.to_database(attributes)
147
94
  when :salesforce
148
95
  attributes.dup
149
96
  else
@@ -151,15 +98,6 @@ module Restforce
151
98
  end
152
99
  end
153
100
 
154
- # Internal: Get the data format adapter for the passed attribute. Defaults
155
- # to DefaultAdapter if no adapter has been explicitly assigned for the
156
- # attribute.
157
- #
158
- # Returns an Object.
159
- def adapter(attribute)
160
- @conversions[attribute] || DefaultAdapter
161
- end
162
-
163
101
  end
164
102
 
165
103
  end
@@ -47,27 +47,27 @@ module Restforce
47
47
  @accumulated_changes ||= Hash.new { |h, k| h[k] = {} }
48
48
  end
49
49
 
50
- # Internal: Append the passed record's attributes to its accumulated list
50
+ # Internal: Append the passed instance's attributes to its accumulated list
51
51
  # of changesets.
52
52
  #
53
- # record - A Restforce::DB::Instances::Base.
53
+ # instance - A Restforce::DB::Instances::Base.
54
54
  #
55
55
  # Returns nothing.
56
- def accumulate(record)
57
- accumulated_changes[key_for(record)].store(
58
- record.last_update,
59
- @mapping.convert(@mapping.salesforce_model, record.attributes),
56
+ def accumulate(instance)
57
+ accumulated_changes[key_for(instance)].store(
58
+ instance.last_update,
59
+ instance.attributes,
60
60
  )
61
61
  end
62
62
 
63
63
  # Internal: Get a unique key with enough information to look up the passed
64
- # record in Salesforce.
64
+ # instance in Salesforce.
65
65
  #
66
- # record - A Restforce::DB::Instances::Base.
66
+ # instance - A Restforce::DB::Instances::Base.
67
67
  #
68
68
  # Returns an Object.
69
- def key_for(record)
70
- [record.id, record.mapping.salesforce_model]
69
+ def key_for(instance)
70
+ [instance.id, instance.mapping.salesforce_model]
71
71
  end
72
72
 
73
73
  end
@@ -97,17 +97,17 @@ module Restforce
97
97
  # Public: Define a set of adapters which should be used to translate data
98
98
  # between the database and Salesforce.
99
99
  #
100
- # fields - A Hash, with keys corresponding to attributes of the database
101
- # record, and adapter objects as values.
100
+ # adapter - An adapter object, which converts an attribute Hash between
101
+ # normalized and database-ready formats.
102
102
  #
103
- # Raises ArgumentError if any adapter object has an incomplete interface.
103
+ # Raises ArgumentError if the adapter object has an incomplete interface.
104
104
  # Returns nothing.
105
- def converts(conversions)
106
- unless conversions.values.all? { |c| c.respond_to?(:to_database) && c.respond_to?(:to_salesforce) }
107
- raise ArgumentError, "All adapters must implement `to_database` and `to_salesforce` methods"
105
+ def converts_with(adapter)
106
+ unless adapter.respond_to?(:to_database) && adapter.respond_to?(:from_database)
107
+ raise ArgumentError, "Your adapter must implement `to_database` and `from_database` methods"
108
108
  end
109
109
 
110
- @mapping.conversions = conversions
110
+ @mapping.adapter = adapter
111
111
  end
112
112
 
113
113
  end
@@ -14,7 +14,6 @@ module Restforce
14
14
  :attribute_map,
15
15
  :attributes,
16
16
  :convert,
17
- :convert_from_salesforce,
18
17
  )
19
18
 
20
19
  attr_reader(
@@ -25,8 +24,8 @@ module Restforce
25
24
  )
26
25
 
27
26
  attr_accessor(
27
+ :adapter,
28
28
  :fields,
29
- :conversions,
30
29
  :associations,
31
30
  :conditions,
32
31
  :strategy,
@@ -44,8 +43,8 @@ module Restforce
44
43
  @database_record_type = RecordTypes::ActiveRecord.new(database_model, self)
45
44
  @salesforce_record_type = RecordTypes::Salesforce.new(salesforce_model, self)
46
45
 
46
+ self.adapter = Adapter.new
47
47
  self.fields = {}
48
- self.conversions = {}
49
48
  self.associations = []
50
49
  self.conditions = []
51
50
  self.strategy = strategy
@@ -109,7 +108,7 @@ module Restforce
109
108
  #
110
109
  # Returns a Restforce::DB::AttributeMap.
111
110
  def attribute_map
112
- @attribute_map ||= AttributeMap.new(database_model, salesforce_model, fields, conversions)
111
+ @attribute_map ||= AttributeMap.new(database_model, salesforce_model, fields, adapter)
113
112
  end
114
113
 
115
114
  end
@@ -49,8 +49,8 @@ module Restforce
49
49
  #
50
50
  # Returns nothing.
51
51
  def update(instance, accumulator)
52
- diff = accumulator.diff(@mapping.convert(@mapping.salesforce_model, instance.attributes))
53
- attributes = @mapping.convert_from_salesforce(instance.record_type, diff)
52
+ current_attributes = accumulator.current(instance.attributes)
53
+ attributes = @mapping.convert(instance.record_type, current_attributes)
54
54
 
55
55
  return if attributes.empty?
56
56
  instance.update!(attributes)
@@ -3,7 +3,7 @@ module Restforce
3
3
  # :nodoc:
4
4
  module DB
5
5
 
6
- VERSION = "1.3.0"
6
+ VERSION = "2.0.0"
7
7
 
8
8
  end
9
9
 
data/lib/restforce/db.rb CHANGED
@@ -32,6 +32,7 @@ require "restforce/db/runner_cache"
32
32
  require "restforce/db/runner"
33
33
 
34
34
  require "restforce/db/accumulator"
35
+ require "restforce/db/adapter"
35
36
  require "restforce/db/associator"
36
37
  require "restforce/db/attribute_map"
37
38
  require "restforce/db/cleaner"
data/restforce-db.gemspec CHANGED
@@ -28,7 +28,7 @@ Gem::Specification.new do |spec|
28
28
  spec.add_dependency "daemons"
29
29
  spec.add_dependency "restforce"
30
30
 
31
- spec.add_development_dependency "bundler", "~> 1.8"
31
+ spec.add_development_dependency "bundler"
32
32
  spec.add_development_dependency "database_cleaner"
33
33
  spec.add_development_dependency "minitest", "5.5.1"
34
34
  spec.add_development_dependency "minitest-spec-expect"
@@ -65,22 +65,19 @@ describe Restforce::DB::Accumulator do
65
65
  end
66
66
  end
67
67
 
68
- describe "#diff" do
68
+ describe "#current" do
69
69
  let(:attributes) { { wocket: "Pocket", jertain: "Curtain", zelf: "Shelf" } }
70
70
 
71
71
  before do
72
72
  accumulator.store(Time.now, attributes)
73
73
  end
74
74
 
75
- it "returns the differences from the attributes hash" do
76
- expect(accumulator.diff(wocket: "Locket", zelf: "Belfrey")).to_equal(
77
- wocket: "Pocket",
75
+ it "returns the current values for all attributes in the passed hash" do
76
+ expect(accumulator.current(wocket: "Locket")).to_equal(wocket: "Pocket")
77
+ expect(accumulator.current(jertain: "Curtain", zelf: "Belfrey")).to_equal(
78
+ jertain: "Curtain",
78
79
  zelf: "Shelf",
79
80
  )
80
81
  end
81
-
82
- it "ignores attributes not set in the Accumulator" do
83
- expect(accumulator.diff(yottle: "Bottle")).to_be :empty?
84
- end
85
82
  end
86
83
  end
@@ -0,0 +1,29 @@
1
+ require_relative "../../../test_helper"
2
+
3
+ describe Restforce::DB::Adapter do
4
+
5
+ configure!
6
+
7
+ let(:adapter) { Restforce::DB::Adapter.new }
8
+ let(:attributes) { { where: "Here", when: Time.now } }
9
+
10
+ describe "#to_database" do
11
+ let(:results) { adapter.to_database(attributes) }
12
+
13
+ it "returns the passed attributes, unchanged" do
14
+ expect(results).to_equal attributes
15
+ end
16
+ end
17
+
18
+ describe "#from_database" do
19
+ let(:results) { adapter.from_database(attributes) }
20
+
21
+ it "converts times to ISO-8601 timestamps" do
22
+ expect(results[:when]).to_equal attributes[:when].utc.iso8601
23
+ end
24
+
25
+ it "leaves other attributes unchanged" do
26
+ expect(results[:where]).to_equal attributes[:where]
27
+ end
28
+ end
29
+ end
@@ -12,8 +12,8 @@ describe Restforce::DB::AttributeMap do
12
12
  column_two: "SF_Field_Two__c",
13
13
  }
14
14
  end
15
- let(:conversions) { {} }
16
- let(:attribute_map) { Restforce::DB::AttributeMap.new(database_model, salesforce_model, fields, conversions) }
15
+ let(:adapter) { Restforce::DB::Adapter.new }
16
+ let(:attribute_map) { Restforce::DB::AttributeMap.new(database_model, salesforce_model, fields, adapter) }
17
17
 
18
18
  describe "#attributes" do
19
19
  let(:mapping) do
@@ -28,7 +28,7 @@ describe Restforce::DB::AttributeMap do
28
28
  attribute
29
29
  end
30
30
 
31
- expect(attributes.keys).to_equal(mapping.database_fields)
31
+ expect(attributes.keys).to_equal(mapping.salesforce_fields)
32
32
  expect(attributes.values).to_equal(mapping.database_fields)
33
33
  end
34
34
 
@@ -38,82 +38,32 @@ describe Restforce::DB::AttributeMap do
38
38
  attribute
39
39
  end
40
40
 
41
- expect(attributes.keys).to_equal(mapping.database_fields)
41
+ expect(attributes.keys).to_equal(mapping.salesforce_fields)
42
42
  expect(attributes.values).to_equal(mapping.salesforce_fields)
43
43
  end
44
-
45
- describe "when an adapter has been defined for an attribute" do
46
- let(:conversions) { { column_one: boolean_adapter } }
47
-
48
- it "uses the adapter to convert the value returned by the block" do
49
- attributes = attribute_map.attributes(salesforce_model) { |_| "Yes" }
50
- expect(attributes).to_equal(
51
- column_one: true,
52
- column_two: "Yes",
53
- )
54
- end
55
- end
56
44
  end
57
45
 
58
46
  describe "#convert" do
59
- let(:attributes) { { column_one: "some value" } }
47
+ let(:attributes) { { "SF_Field_One__c" => "some value" } }
60
48
 
61
49
  it "converts an attribute Hash to a Salesforce-compatible form" do
62
- expect(attribute_map.convert(salesforce_model, attributes)).to_equal(
63
- fields[attributes.keys.first] => attributes.values.first,
64
- )
65
- end
66
-
67
- it "performs no special conversion for database columns" do
68
- expect(attribute_map.convert(database_model, attributes)).to_equal(attributes)
69
- end
70
-
71
- describe "when one of the attributes is a Date or Time" do
72
- let(:timestamp) { Time.now }
73
- let(:attributes) { { column_one: timestamp } }
74
-
75
- it "converts the attribute to an ISO-8601 string for Salesforce" do
76
- expect(attribute_map.convert(salesforce_model, attributes)).to_equal(
77
- fields[attributes.keys.first] => timestamp.iso8601,
78
- )
79
- end
50
+ expect(attribute_map.convert(salesforce_model, attributes)).to_equal(attributes)
80
51
  end
81
52
 
82
- describe "when an adapter has been defined for an attribute" do
83
- let(:conversions) { { column_one: boolean_adapter } }
84
-
85
- it "uses the adapter to convert that attribute to a Salesforce-compatible form" do
86
- expect(attribute_map.convert(salesforce_model, column_one: true)).to_equal(
87
- "SF_Field_One__c" => "Yes",
88
- )
89
- expect(attribute_map.convert(salesforce_model, column_one: false)).to_equal(
90
- "SF_Field_One__c" => "No",
91
- )
92
- end
93
- end
94
- end
95
-
96
- describe "#convert_from_salesforce" do
97
- let(:attributes) { { "SF_Field_One__c" => "some value" } }
98
-
99
53
  it "converts an attribute Hash to a database-compatible form" do
100
- expect(attribute_map.convert_from_salesforce(database_model, attributes)).to_equal(
54
+ expect(attribute_map.convert(database_model, attributes)).to_equal(
101
55
  fields.key(attributes.keys.first) => attributes.values.first,
102
56
  )
103
57
  end
104
58
 
105
- it "performs no special conversion for Salesforce fields" do
106
- expect(attribute_map.convert_from_salesforce(salesforce_model, attributes)).to_equal(attributes)
107
- end
108
-
109
- describe "when an adapter has been defined for an attribute" do
110
- let(:conversions) { { column_one: boolean_adapter } }
59
+ describe "when an adapter has been specified" do
60
+ let(:adapter) { boolean_adapter }
111
61
 
112
- it "uses the adapter to convert that attribute to a database-compatible form" do
113
- expect(attribute_map.convert_from_salesforce(database_model, "SF_Field_One__c" => "Yes")).to_equal(
62
+ it "uses the adapter to convert attributes to a database-compatible form" do
63
+ expect(attribute_map.convert(database_model, "SF_Field_One__c" => "Yes")).to_equal(
114
64
  column_one: true,
115
65
  )
116
- expect(attribute_map.convert_from_salesforce(database_model, "SF_Field_One__c" => "No")).to_equal(
66
+ expect(attribute_map.convert(database_model, "SF_Field_One__c" => "No")).to_equal(
117
67
  column_one: false,
118
68
  )
119
69
  end
@@ -99,20 +99,19 @@ describe Restforce::DB::DSL do
99
99
  end
100
100
  end
101
101
 
102
- describe "#converts" do
102
+ describe "#converts_with" do
103
103
  let(:adapter) { boolean_adapter }
104
- let(:conversions) { { some: adapter } }
105
104
 
106
105
  it "sets the conversions for the created mapping" do
107
- dsl.converts conversions
108
- expect(mapping.conversions).to_equal conversions
106
+ dsl.converts_with adapter
107
+ expect(mapping.adapter).to_equal adapter
109
108
  end
110
109
 
111
110
  describe "when the adapter does not define the expected methods" do
112
111
  let(:adapter) { Object.new }
113
112
 
114
113
  it "raises an ArgumentError" do
115
- expect(-> { dsl.converts conversions }).to_raise ArgumentError
114
+ expect(-> { dsl.converts_with adapter }).to_raise ArgumentError
116
115
  end
117
116
  end
118
117
  end
@@ -11,8 +11,8 @@ describe Restforce::DB::RecordTypes::ActiveRecord do
11
11
  describe "#create!" do
12
12
  let(:attributes) do
13
13
  {
14
- name: "Some name",
15
- example: "Some text",
14
+ "Name" => "Some name",
15
+ "Example_Field__c" => "Some text",
16
16
  }
17
17
  end
18
18
  let(:record) { nil }
@@ -32,8 +32,8 @@ describe Restforce::DB::RecordTypes::ActiveRecord do
32
32
 
33
33
  it "creates a record in the database from the passed Salesforce record's attributes" do
34
34
  expect(instance.salesforce_id).to_equal salesforce_id
35
- expect(instance.name).to_equal attributes[:name]
36
- expect(instance.example).to_equal attributes[:example]
35
+ expect(instance.name).to_equal attributes["Name"]
36
+ expect(instance.example).to_equal attributes["Example_Field__c"]
37
37
  expect(instance.synchronized_at).to_not_be_nil
38
38
  end
39
39
 
@@ -64,7 +64,7 @@ describe Restforce::DB::RecordTypes::ActiveRecord do
64
64
  id,
65
65
  Time.now,
66
66
  Restforce::DB::Registry[User].first,
67
- email: "somebody@example.com",
67
+ "Email" => "somebody@example.com",
68
68
  )
69
69
  end
70
70
  end
@@ -10,20 +10,15 @@ describe Restforce::DB::Synchronizer do
10
10
  describe "#run", vcr: { match_requests_on: [:method, VCR.request_matchers.uri_without_param(:q)] } do
11
11
  let(:attributes) do
12
12
  {
13
- name: "Custom object",
14
- example: "Some sample text",
13
+ "Name" => "Custom object",
14
+ "Example_Field__c" => "Some sample text",
15
15
  }
16
16
  end
17
- let(:salesforce_id) do
18
- Salesforce.create!(
19
- salesforce_model,
20
- mapping.convert(salesforce_model, attributes),
21
- )
22
- end
17
+ let(:salesforce_id) { Salesforce.create!(salesforce_model, attributes) }
23
18
  let(:changes) { { [salesforce_id, salesforce_model] => accumulator } }
24
19
  let(:new_attributes) do
25
20
  {
26
- "Name" => "Some new name",
21
+ "Name" => "Some new name",
27
22
  "Example_Field__c" => "New sample text",
28
23
  }
29
24
  end
@@ -31,12 +31,16 @@ end
31
31
  def boolean_adapter
32
32
  Object.new.tap do |object|
33
33
 
34
- def object.to_database(value)
35
- value == "Yes"
34
+ def object.to_database(attributes)
35
+ attributes.each_with_object({}) do |(k, v), final|
36
+ final[k] = (v == "Yes")
37
+ end
36
38
  end
37
39
 
38
- def object.to_salesforce(value)
39
- value ? "Yes" : "No"
40
+ def object.from_database(attributes)
41
+ attributes.each_with_object({}) do |(k, v), final|
42
+ final[k] = v ? "Yes" : "No"
43
+ end
40
44
  end
41
45
 
42
46
  end
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.3.0
4
+ version: 2.0.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-05-12 00:00:00.000000000 Z
11
+ date: 2015-05-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -56,16 +56,16 @@ dependencies:
56
56
  name: bundler
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: '1.8'
61
+ version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: '1.8'
68
+ version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: database_cleaner
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -200,6 +200,7 @@ files:
200
200
  - Rakefile
201
201
  - bin/console
202
202
  - bin/setup
203
+ - circle.yml
203
204
  - lib/file_daemon.rb
204
205
  - lib/generators/restforce/install_generator.rb
205
206
  - lib/generators/restforce/migration_generator.rb
@@ -208,6 +209,7 @@ files:
208
209
  - lib/generators/templates/script
209
210
  - lib/restforce/db.rb
210
211
  - lib/restforce/db/accumulator.rb
212
+ - lib/restforce/db/adapter.rb
211
213
  - lib/restforce/db/association_cache.rb
212
214
  - lib/restforce/db/associations/base.rb
213
215
  - lib/restforce/db/associations/belongs_to.rb
@@ -302,6 +304,7 @@ files:
302
304
  - test/cassettes/Restforce_DB_Synchronizer/_run/given_a_Salesforce_record_with_an_associated_database_record/updates_the_salesforce_record.yml
303
305
  - test/cassettes/Restforce_DB_Synchronizer/_run/given_a_Salesforce_record_with_no_associated_database_record/does_nothing_for_this_specific_mapping.yml
304
306
  - test/lib/restforce/db/accumulator_test.rb
307
+ - test/lib/restforce/db/adapter_test.rb
305
308
  - test/lib/restforce/db/association_cache_test.rb
306
309
  - test/lib/restforce/db/associations/belongs_to_test.rb
307
310
  - test/lib/restforce/db/associations/has_many_test.rb