restforce-db 1.3.0 → 2.0.0

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