restforce-db 0.4.0 → 0.5.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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/lib/file_daemon.rb +42 -0
  3. data/lib/restforce/db/accumulator.rb +41 -0
  4. data/lib/restforce/db/attribute_map.rb +132 -0
  5. data/lib/restforce/db/collector.rb +79 -0
  6. data/lib/restforce/db/initializer.rb +62 -0
  7. data/lib/restforce/db/instances/base.rb +1 -14
  8. data/lib/restforce/db/instances/salesforce.rb +7 -0
  9. data/lib/restforce/db/mapping.rb +33 -79
  10. data/lib/restforce/db/record_types/base.rb +0 -30
  11. data/lib/restforce/db/runner.rb +80 -0
  12. data/lib/restforce/db/synchronizer.rb +29 -37
  13. data/lib/restforce/db/version.rb +1 -1
  14. data/lib/restforce/db/worker.rb +53 -40
  15. data/lib/restforce/db.rb +6 -0
  16. data/test/cassettes/{Restforce_DB_Synchronizer/_run/given_a_Salesforce_record_with_an_associated_database_record/when_synchronization_is_stale/updates_the_database_record.yml → Restforce_DB_Collector/_run/given_a_Salesforce_record_with_an_associated_database_record/returns_the_attributes_from_both_records.yml} +36 -36
  17. data/test/cassettes/Restforce_DB_Collector/_run/given_an_existing_Salesforce_record/returns_the_attributes_from_the_Salesforce_record.yml +197 -0
  18. data/test/cassettes/Restforce_DB_Collector/_run/given_an_existing_database_record/returns_the_attributes_from_the_database_record.yml +81 -0
  19. data/test/cassettes/Restforce_DB_Initializer/_run/given_an_existing_Salesforce_record/for_a_non-root_mapping/does_not_create_a_database_record.yml +119 -0
  20. data/test/cassettes/{Restforce_DB_Synchronizer/_run/given_a_Salesforce_record_with_an_associated_database_record/when_synchronization_is_up-to-date/does_not_update_the_database_record.yml → Restforce_DB_Initializer/_run/given_an_existing_Salesforce_record/for_a_root_mapping/creates_a_matching_database_record.yml} +28 -28
  21. data/test/cassettes/{Restforce_DB_Synchronizer/_run/given_an_existing_database_record → Restforce_DB_Initializer/_run/given_an_existing_database_record/for_a_root_mapping}/populates_Salesforce_with_the_new_record.yml +44 -44
  22. data/test/cassettes/{Restforce_DB_Synchronizer/_run/given_an_existing_Salesforce_record/for_a_non-root_mapping/does_not_create_a_database_record.yml → Restforce_DB_Instances_Salesforce/_synced_/when_a_matching_database_record_exists/returns_true.yml} +30 -30
  23. data/test/cassettes/{Restforce_DB_Synchronizer/_run/given_an_existing_Salesforce_record/for_a_root_mapping/creates_a_matching_database_record.yml → Restforce_DB_Instances_Salesforce/_synced_/when_no_matching_database_record_exists/returns_false.yml} +30 -30
  24. data/test/cassettes/Restforce_DB_Synchronizer/_run/given_a_Salesforce_record_with_an_associated_database_record/updates_the_database_record.yml +194 -0
  25. data/test/cassettes/Restforce_DB_Synchronizer/_run/given_a_Salesforce_record_with_an_associated_database_record/updates_the_salesforce_record.yml +233 -0
  26. data/test/lib/restforce/db/accumulator_test.rb +71 -0
  27. data/test/lib/restforce/db/attribute_map_test.rb +70 -0
  28. data/test/lib/restforce/db/collector_test.rb +91 -0
  29. data/test/lib/restforce/db/initializer_test.rb +92 -0
  30. data/test/lib/restforce/db/instances/active_record_test.rb +0 -13
  31. data/test/lib/restforce/db/instances/salesforce_test.rb +20 -13
  32. data/test/lib/restforce/db/mapping_test.rb +1 -37
  33. data/test/lib/restforce/db/record_types/active_record_test.rb +0 -40
  34. data/test/lib/restforce/db/runner_test.rb +40 -0
  35. data/test/lib/restforce/db/synchronizer_test.rb +26 -86
  36. metadata +23 -7
@@ -8,52 +8,44 @@ module Restforce
8
8
  # update records with the appropriate values.
9
9
  class Synchronizer
10
10
 
11
- attr_reader :last_run
12
-
13
11
  # Public: Initialize a new Restforce::DB::Synchronizer.
14
12
  #
15
- # database_record_type - A Restforce::DB::RecordTypes::ActiveRecord
16
- # instance.
17
- # salesforce_record_type - A Restforce::DB::RecordTypes::Salesforce
18
- # instance.
19
- # last_run_time - A Time object reflecting the time of the most
20
- # recent synchronization run. Runs will only
21
- # synchronize data more recent than this stamp.
22
- def initialize(database_record_type, salesforce_record_type, last_run_time = DB.last_run)
23
- @database_record_type = database_record_type
24
- @salesforce_record_type = salesforce_record_type
25
- @last_run = last_run_time
13
+ # mapping - A Restforce::DB::Mapping.
14
+ def initialize(mapping)
15
+ @mapping = mapping
26
16
  end
27
17
 
28
- # Public: Run the synchronize process, pulling in records from Salesforce
29
- # and the database to determine which records need to be created and/or
30
- # updated.
31
- #
32
- # NOTE: We bootstrap our record lookups to the exact same timespan, and
33
- # run the Salesforce sync into the database first. This has the effect of
34
- # overwriting recent changes to the database, in the event that Salesforce
35
- # has also been updated since the last sync.
18
+ # Public: Synchronize records for the current mapping from a Hash of
19
+ # record descriptors to attributes.
36
20
  #
37
- # options - A Hash of options for configuring the run. Valid keys are:
38
- # :delay - An offset to apply to the time filters. Allows the
39
- # synchronization to account for server time drift.
21
+ # changes - A Hash, with keys composed of a Salesforce ID and model name,
22
+ # with Restforce::DB::Accumulator objects as values.
40
23
  #
41
- # Returns the Time the run was performed.
42
- def run(options = {})
43
- run_time = Time.now
44
-
45
- delay = options.fetch(:delay) { 0 }
46
- before = run_time - delay
47
- after = last_run - delay if last_run
24
+ # Returns nothing.
25
+ def run(changes)
26
+ changes.each do |(id, salesforce_model), accumulator|
27
+ next unless salesforce_model == @mapping.salesforce_model
48
28
 
49
- @salesforce_record_type.each(after: after, before: before) do |record|
50
- @database_record_type.sync!(record)
51
- end
52
- @database_record_type.each(after: after, before: before) do |record|
53
- @salesforce_record_type.sync!(record)
29
+ update(@mapping.database_record_type.find(id), accumulator)
30
+ update(@mapping.salesforce_record_type.find(id), accumulator)
54
31
  end
32
+ end
33
+
34
+ private
35
+
36
+ # Internal: Update the passed instance with the accumulated attributes
37
+ # from a synchronization run.
38
+ #
39
+ # instance - An instance of Restforce::DB::Instances::Base.
40
+ # accumulator - A Restforce::DB::Accumulator.
41
+ #
42
+ # Returns nothing.
43
+ def update(instance, accumulator)
44
+ diff = accumulator.diff(@mapping.convert(@mapping.salesforce_model, instance.attributes))
45
+ attributes = @mapping.convert_from_salesforce(instance.record_type, diff)
55
46
 
56
- @last_run = run_time
47
+ return if attributes.empty?
48
+ instance.update!(attributes)
57
49
  end
58
50
 
59
51
  end
@@ -3,7 +3,7 @@ module Restforce
3
3
  # :nodoc:
4
4
  module DB
5
5
 
6
- VERSION = "0.4.0"
6
+ VERSION = "0.5.0"
7
7
 
8
8
  end
9
9
 
@@ -1,3 +1,5 @@
1
+ require "file_daemon"
2
+
1
3
  module Restforce
2
4
 
3
5
  module DB
@@ -6,40 +8,11 @@ module Restforce
6
8
  # all record synchronization occurs.
7
9
  class Worker
8
10
 
11
+ include FileDaemon
12
+
9
13
  DEFAULT_INTERVAL = 5
10
14
  DEFAULT_DELAY = 1
11
15
 
12
- class << self
13
-
14
- # Public: Store the list of currently open file descriptors so that they
15
- # may be reopened when a new process is spawned.
16
- #
17
- # Returns nothing.
18
- def before_fork
19
- return if @files_to_reopen
20
-
21
- @files_to_reopen = []
22
- ObjectSpace.each_object(File) do |file|
23
- @files_to_reopen << file unless file.closed?
24
- end
25
- end
26
-
27
- # Public: Reopen all file descriptors that have been stored through the
28
- # before_fork hook.
29
- #
30
- # Returns nothing.
31
- def after_fork
32
- @files_to_reopen.each do |file|
33
- begin
34
- file.reopen file.path, "a+"
35
- file.sync = true
36
- rescue ::Exception # rubocop:disable HandleExceptions, RescueException
37
- end
38
- end
39
- end
40
-
41
- end
42
-
43
16
  attr_accessor :logger, :tracker
44
17
 
45
18
  # Public: Initialize a new Restforce::DB::Worker.
@@ -52,10 +25,10 @@ module Restforce
52
25
  def initialize(options = {})
53
26
  @verbose = options.fetch(:verbose) { false }
54
27
  @interval = options.fetch(:interval) { DEFAULT_INTERVAL }
55
- @delay = options.fetch(:delay) { DEFAULT_DELAY }
28
+ @runner = Runner.new(options.fetch(:delay) { DEFAULT_DELAY })
56
29
 
57
- Restforce::DB.reset
58
- Restforce::DB.configure { |config| config.parse(options[:config]) }
30
+ DB.reset
31
+ DB.configure { |config| config.parse(options[:config]) }
59
32
  end
60
33
 
61
34
  # Public: Start the polling loop for this Worker. Synchronizes all
@@ -98,9 +71,19 @@ module Restforce
98
71
  #
99
72
  # Returns nothing.
100
73
  def perform
74
+ @runner.tick!
75
+ @changes = Hash.new { |h, k| h[k] = Accumulator.new }
76
+
101
77
  track do
102
78
  Restforce::DB::Mapping.each do |mapping|
103
- synchronize mapping
79
+ task("PROPAGATING RECORDS", mapping) { propagate mapping }
80
+ task("COLLECTING CHANGES", mapping) { collect mapping }
81
+ end
82
+
83
+ # NOTE: We can only perform the synchronization after all record
84
+ # changes have been aggregated, so this second loop is necessary.
85
+ Restforce::DB::Mapping.each do |mapping|
86
+ task("APPLYING CHANGES", mapping) { synchronize mapping }
104
87
  end
105
88
  end
106
89
  end
@@ -129,15 +112,45 @@ module Restforce
129
112
  end
130
113
  end
131
114
 
132
- # Internal: Synchronize the objects in the database and Salesforce
133
- # corresponding to the passed record type.
115
+ # Internal: Propagate unsynchronized records between the two systems for
116
+ # the passed mapping.
134
117
  #
135
118
  # mapping - A Restforce::DB::Mapping.
136
119
  #
137
- # Returns a Boolean.
120
+ # Returns nothing.
121
+ def propagate(mapping)
122
+ Initializer.new(mapping, @runner).run
123
+ end
124
+
125
+ # Internal: Collect a list of changes from recently-updated records for
126
+ # the passed mapping.
127
+ #
128
+ # mapping - A Restforce::DB::Mapping.
129
+ #
130
+ # Returns nothing.
131
+ def collect(mapping)
132
+ Collector.new(mapping, @runner).run(@changes)
133
+ end
134
+
135
+ # Internal: Apply the aggregated changes to the objects in both systems,
136
+ # according to the defined mappings.
137
+ #
138
+ # mapping - A Restforce::DB::Mapping.
139
+ #
140
+ # Returns nothing.
138
141
  def synchronize(mapping)
139
- log " SYNCHRONIZE #{mapping.database_model.name} with #{mapping.salesforce_model}"
140
- runtime = Benchmark.realtime { mapping.synchronizer.run(delay: @delay) }
142
+ Synchronizer.new(mapping).run(@changes)
143
+ end
144
+
145
+ # Internal: Log a description and response time for a specific named task.
146
+ #
147
+ # name - A String task name.
148
+ # mapping - A Restforce::DB::Mapping.
149
+ #
150
+ # Returns a Boolean.
151
+ def task(name, mapping)
152
+ log " #{name} between #{mapping.database_model.name} and #{mapping.salesforce_model}"
153
+ runtime = Benchmark.realtime { yield }
141
154
  log format(" COMPLETE after %.4f", runtime)
142
155
 
143
156
  return true
data/lib/restforce/db.rb CHANGED
@@ -16,6 +16,12 @@ require "restforce/db/record_types/base"
16
16
  require "restforce/db/record_types/active_record"
17
17
  require "restforce/db/record_types/salesforce"
18
18
 
19
+ require "restforce/db/runner"
20
+
21
+ require "restforce/db/accumulator"
22
+ require "restforce/db/attribute_map"
23
+ require "restforce/db/collector"
24
+ require "restforce/db/initializer"
19
25
  require "restforce/db/mapping"
20
26
  require "restforce/db/model"
21
27
  require "restforce/db/synchronizer"
@@ -21,10 +21,10 @@ http_interactions:
21
21
  message: OK
22
22
  headers:
23
23
  Date:
24
- - Thu, 26 Mar 2015 10:20:45 GMT
24
+ - Mon, 06 Apr 2015 09:47:04 GMT
25
25
  Set-Cookie:
26
- - BrowserId=MByA7KJ3QdSiXfyMNJrEYA;Path=/;Domain=.salesforce.com;Expires=Mon,
27
- 25-May-2015 10:20:45 GMT
26
+ - BrowserId=1-W-oxIGS2WOOLOo6wzW2A;Path=/;Domain=.salesforce.com;Expires=Fri,
27
+ 05-Jun-2015 09:47:04 GMT
28
28
  Expires:
29
29
  - Thu, 01 Jan 1970 00:00:00 GMT
30
30
  Pragma:
@@ -37,9 +37,9 @@ http_interactions:
37
37
  - chunked
38
38
  body:
39
39
  encoding: ASCII-8BIT
40
- string: '{"id":"https://login.salesforce.com/id/00D1a000000H3O9EAK/0051a000000UGT8AAO","issued_at":"1427365245359","token_type":"Bearer","instance_url":"https://<host>","signature":"1PndvYoRn++HWkykAeAFgL4jxoWO5WvXwmJS45YgAEE=","access_token":"00D1a000000H3O9!AQ4AQFqDs34WtnS6RDwxyGdLSPYE_cFTuNjjnDvX2HbNhGMu917m6JyqchGFbdiOruyd5Z.w7uN.ogsJF4_8TMMzdt2fw7OZ"}'
40
+ string: '{"id":"https://login.salesforce.com/id/00D1a000000H3O9EAK/0051a000000UGT8AAO","issued_at":"1428313624267","token_type":"Bearer","instance_url":"https://<host>","signature":"ABLounL9O5kFDJ9y/g/l4dLcm/HQOU8UIF9L3wpVmng=","access_token":"00D1a000000H3O9!AQ4AQIEcyaEa1EiezSuMSEJm73cIL8I5CDJ_vnqlgzm7mAXRhbGBSo3xF6_EdmNqSa42nDRyl2szOaP4ybHrIHxo.G4YonU_"}'
41
41
  http_version:
42
- recorded_at: Thu, 26 Mar 2015 10:20:45 GMT
42
+ recorded_at: Mon, 06 Apr 2015 09:47:04 GMT
43
43
  - request:
44
44
  method: post
45
45
  uri: https://<host>/services/data/v26.0/sobjects/CustomObject__c
@@ -52,7 +52,7 @@ http_interactions:
52
52
  Content-Type:
53
53
  - application/json
54
54
  Authorization:
55
- - OAuth 00D1a000000H3O9!AQ4AQFqDs34WtnS6RDwxyGdLSPYE_cFTuNjjnDvX2HbNhGMu917m6JyqchGFbdiOruyd5Z.w7uN.ogsJF4_8TMMzdt2fw7OZ
55
+ - OAuth 00D1a000000H3O9!AQ4AQIEcyaEa1EiezSuMSEJm73cIL8I5CDJ_vnqlgzm7mAXRhbGBSo3xF6_EdmNqSa42nDRyl2szOaP4ybHrIHxo.G4YonU_
56
56
  Accept-Encoding:
57
57
  - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
58
58
  Accept:
@@ -63,28 +63,28 @@ http_interactions:
63
63
  message: Created
64
64
  headers:
65
65
  Date:
66
- - Thu, 26 Mar 2015 10:20:47 GMT
66
+ - Mon, 06 Apr 2015 09:47:05 GMT
67
67
  Set-Cookie:
68
- - BrowserId=0HamoaRdQlutLKddwYnR3Q;Path=/;Domain=.salesforce.com;Expires=Mon,
69
- 25-May-2015 10:20:47 GMT
68
+ - BrowserId=dE26sxE8Rl-Rumx82ekC0Q;Path=/;Domain=.salesforce.com;Expires=Fri,
69
+ 05-Jun-2015 09:47:05 GMT
70
70
  Expires:
71
71
  - Thu, 01 Jan 1970 00:00:00 GMT
72
72
  Sforce-Limit-Info:
73
- - api-usage=8/15000
73
+ - api-usage=15/15000
74
74
  Location:
75
- - "/services/data/v26.0/sobjects/CustomObject__c/a001a000001J1B5AAK"
75
+ - "/services/data/v26.0/sobjects/CustomObject__c/a001a000001LGf9AAG"
76
76
  Content-Type:
77
77
  - application/json;charset=UTF-8
78
78
  Transfer-Encoding:
79
79
  - chunked
80
80
  body:
81
81
  encoding: ASCII-8BIT
82
- string: '{"id":"a001a000001J1B5AAK","success":true,"errors":[]}'
82
+ string: '{"id":"a001a000001LGf9AAG","success":true,"errors":[]}'
83
83
  http_version:
84
- recorded_at: Thu, 26 Mar 2015 10:20:47 GMT
84
+ recorded_at: Mon, 06 Apr 2015 09:47:05 GMT
85
85
  - request:
86
86
  method: get
87
- uri: https://<host>/services/data/v26.0/query?q=select%20Id,%20SystemModstamp,%20Name,%20Example_Field__c%20from%20CustomObject__c%20where%20Id%20=%20%27a001a000001J1B5AAK%27
87
+ uri: https://<host>/services/data/v26.0/query?q=select%20Id,%20SystemModstamp,%20Name,%20Example_Field__c%20from%20CustomObject__c%20where%20Id%20=%20%27a001a000001LGf9AAG%27
88
88
  body:
89
89
  encoding: US-ASCII
90
90
  string: ''
@@ -92,7 +92,7 @@ http_interactions:
92
92
  User-Agent:
93
93
  - Faraday v0.9.1
94
94
  Authorization:
95
- - OAuth 00D1a000000H3O9!AQ4AQFqDs34WtnS6RDwxyGdLSPYE_cFTuNjjnDvX2HbNhGMu917m6JyqchGFbdiOruyd5Z.w7uN.ogsJF4_8TMMzdt2fw7OZ
95
+ - OAuth 00D1a000000H3O9!AQ4AQIEcyaEa1EiezSuMSEJm73cIL8I5CDJ_vnqlgzm7mAXRhbGBSo3xF6_EdmNqSa42nDRyl2szOaP4ybHrIHxo.G4YonU_
96
96
  Accept-Encoding:
97
97
  - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
98
98
  Accept:
@@ -103,27 +103,27 @@ http_interactions:
103
103
  message: OK
104
104
  headers:
105
105
  Date:
106
- - Thu, 26 Mar 2015 10:20:48 GMT
106
+ - Mon, 06 Apr 2015 09:47:06 GMT
107
107
  Set-Cookie:
108
- - BrowserId=qy1ZzoKPTf2uberfpTqRqw;Path=/;Domain=.salesforce.com;Expires=Mon,
109
- 25-May-2015 10:20:48 GMT
108
+ - BrowserId=t7abvz2zRKWKmlx5GTtwMw;Path=/;Domain=.salesforce.com;Expires=Fri,
109
+ 05-Jun-2015 09:47:06 GMT
110
110
  Expires:
111
111
  - Thu, 01 Jan 1970 00:00:00 GMT
112
112
  Sforce-Limit-Info:
113
- - api-usage=14/15000
113
+ - api-usage=15/15000
114
114
  Content-Type:
115
115
  - application/json;charset=UTF-8
116
116
  Transfer-Encoding:
117
117
  - chunked
118
118
  body:
119
119
  encoding: ASCII-8BIT
120
- string: '{"totalSize":1,"done":true,"records":[{"attributes":{"type":"CustomObject__c","url":"/services/data/v26.0/sobjects/CustomObject__c/a001a000001J1B5AAK"},"Id":"a001a000001J1B5AAK","SystemModstamp":"2015-03-26T10:20:47.000+0000","Name":"Custom
120
+ string: '{"totalSize":1,"done":true,"records":[{"attributes":{"type":"CustomObject__c","url":"/services/data/v26.0/sobjects/CustomObject__c/a001a000001LGf9AAG"},"Id":"a001a000001LGf9AAG","SystemModstamp":"2015-04-06T09:47:05.000+0000","Name":"Custom
121
121
  object","Example_Field__c":"Some sample text"}]}'
122
122
  http_version:
123
- recorded_at: Thu, 26 Mar 2015 10:20:48 GMT
123
+ recorded_at: Mon, 06 Apr 2015 09:47:06 GMT
124
124
  - request:
125
125
  method: get
126
- uri: https://<host>/services/data/v26.0/query?q=select%20Id,%20SystemModstamp,%20Name,%20Example_Field__c%20from%20CustomObject__c%20where%20SystemModstamp%20%3C=%202015-03-26T10:20:48Z
126
+ uri: https://<host>/services/data/v26.0/query?q=select%20Id,%20SystemModstamp,%20Name,%20Example_Field__c%20from%20CustomObject__c%20where%20SystemModstamp%20%3C%202015-04-06T09:47:06Z
127
127
  body:
128
128
  encoding: US-ASCII
129
129
  string: ''
@@ -131,7 +131,7 @@ http_interactions:
131
131
  User-Agent:
132
132
  - Faraday v0.9.1
133
133
  Authorization:
134
- - OAuth 00D1a000000H3O9!AQ4AQFqDs34WtnS6RDwxyGdLSPYE_cFTuNjjnDvX2HbNhGMu917m6JyqchGFbdiOruyd5Z.w7uN.ogsJF4_8TMMzdt2fw7OZ
134
+ - OAuth 00D1a000000H3O9!AQ4AQIEcyaEa1EiezSuMSEJm73cIL8I5CDJ_vnqlgzm7mAXRhbGBSo3xF6_EdmNqSa42nDRyl2szOaP4ybHrIHxo.G4YonU_
135
135
  Accept-Encoding:
136
136
  - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
137
137
  Accept:
@@ -142,27 +142,27 @@ http_interactions:
142
142
  message: OK
143
143
  headers:
144
144
  Date:
145
- - Thu, 26 Mar 2015 10:20:49 GMT
145
+ - Mon, 06 Apr 2015 09:47:07 GMT
146
146
  Set-Cookie:
147
- - BrowserId=iGFn-JlOR8OfeocU65FnbA;Path=/;Domain=.salesforce.com;Expires=Mon,
148
- 25-May-2015 10:20:49 GMT
147
+ - BrowserId=RphmGcW7T66OthKLT_v52w;Path=/;Domain=.salesforce.com;Expires=Fri,
148
+ 05-Jun-2015 09:47:07 GMT
149
149
  Expires:
150
150
  - Thu, 01 Jan 1970 00:00:00 GMT
151
151
  Sforce-Limit-Info:
152
- - api-usage=11/15000
152
+ - api-usage=15/15000
153
153
  Content-Type:
154
154
  - application/json;charset=UTF-8
155
155
  Transfer-Encoding:
156
156
  - chunked
157
157
  body:
158
158
  encoding: ASCII-8BIT
159
- string: '{"totalSize":3,"done":true,"records":[{"attributes":{"type":"CustomObject__c","url":"/services/data/v26.0/sobjects/CustomObject__c/a001a000001IjCFAA0"},"Id":"a001a000001IjCFAA0","SystemModstamp":"2015-03-24T08:25:04.000+0000","Name":"andrew@tablexi.com","Example_Field__c":null},{"attributes":{"type":"CustomObject__c","url":"/services/data/v26.0/sobjects/CustomObject__c/a001a000001IjP2AAK"},"Id":"a001a000001IjP2AAK","SystemModstamp":"2015-03-24T08:27:33.000+0000","Name":"somebody+new@example.com","Example_Field__c":null},{"attributes":{"type":"CustomObject__c","url":"/services/data/v26.0/sobjects/CustomObject__c/a001a000001J1B5AAK"},"Id":"a001a000001J1B5AAK","SystemModstamp":"2015-03-26T10:20:47.000+0000","Name":"Custom
159
+ string: '{"totalSize":1,"done":true,"records":[{"attributes":{"type":"CustomObject__c","url":"/services/data/v26.0/sobjects/CustomObject__c/a001a000001LGf9AAG"},"Id":"a001a000001LGf9AAG","SystemModstamp":"2015-04-06T09:47:05.000+0000","Name":"Custom
160
160
  object","Example_Field__c":"Some sample text"}]}'
161
161
  http_version:
162
- recorded_at: Thu, 26 Mar 2015 10:20:49 GMT
162
+ recorded_at: Mon, 06 Apr 2015 09:47:07 GMT
163
163
  - request:
164
164
  method: delete
165
- uri: https://<host>/services/data/v26.0/sobjects/CustomObject__c/a001a000001J1B5AAK
165
+ uri: https://<host>/services/data/v26.0/sobjects/CustomObject__c/a001a000001LGf9AAG
166
166
  body:
167
167
  encoding: US-ASCII
168
168
  string: ''
@@ -170,7 +170,7 @@ http_interactions:
170
170
  User-Agent:
171
171
  - Faraday v0.9.1
172
172
  Authorization:
173
- - OAuth 00D1a000000H3O9!AQ4AQFqDs34WtnS6RDwxyGdLSPYE_cFTuNjjnDvX2HbNhGMu917m6JyqchGFbdiOruyd5Z.w7uN.ogsJF4_8TMMzdt2fw7OZ
173
+ - OAuth 00D1a000000H3O9!AQ4AQIEcyaEa1EiezSuMSEJm73cIL8I5CDJ_vnqlgzm7mAXRhbGBSo3xF6_EdmNqSa42nDRyl2szOaP4ybHrIHxo.G4YonU_
174
174
  Accept-Encoding:
175
175
  - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
176
176
  Accept:
@@ -181,17 +181,17 @@ http_interactions:
181
181
  message: No Content
182
182
  headers:
183
183
  Date:
184
- - Thu, 26 Mar 2015 10:20:50 GMT
184
+ - Mon, 06 Apr 2015 09:47:08 GMT
185
185
  Set-Cookie:
186
- - BrowserId=HBXMV64BTRO-Utd9-FareA;Path=/;Domain=.salesforce.com;Expires=Mon,
187
- 25-May-2015 10:20:50 GMT
186
+ - BrowserId=oPwfk9OFQpKhvzl0QDNZ1Q;Path=/;Domain=.salesforce.com;Expires=Fri,
187
+ 05-Jun-2015 09:47:08 GMT
188
188
  Expires:
189
189
  - Thu, 01 Jan 1970 00:00:00 GMT
190
190
  Sforce-Limit-Info:
191
- - api-usage=12/15000
191
+ - api-usage=15/15000
192
192
  body:
193
193
  encoding: UTF-8
194
194
  string: ''
195
195
  http_version:
196
- recorded_at: Thu, 26 Mar 2015 10:20:50 GMT
196
+ recorded_at: Mon, 06 Apr 2015 09:47:09 GMT
197
197
  recorded_with: VCR 2.9.3
@@ -0,0 +1,197 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://<host>/services/oauth2/token
6
+ body:
7
+ encoding: US-ASCII
8
+ string: grant_type=password&client_id=<client_id>&client_secret=<client_secret>&username=<username>&password=<password><security_token>
9
+ headers:
10
+ User-Agent:
11
+ - Faraday v0.9.1
12
+ Content-Type:
13
+ - application/x-www-form-urlencoded
14
+ Accept-Encoding:
15
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
16
+ Accept:
17
+ - "*/*"
18
+ response:
19
+ status:
20
+ code: 200
21
+ message: OK
22
+ headers:
23
+ Date:
24
+ - Mon, 06 Apr 2015 09:47:10 GMT
25
+ Set-Cookie:
26
+ - BrowserId=GYwnKzDZSXW2pS0fi86B-Q;Path=/;Domain=.salesforce.com;Expires=Fri,
27
+ 05-Jun-2015 09:47:10 GMT
28
+ Expires:
29
+ - Thu, 01 Jan 1970 00:00:00 GMT
30
+ Pragma:
31
+ - no-cache
32
+ Cache-Control:
33
+ - no-cache, no-store
34
+ Content-Type:
35
+ - application/json;charset=UTF-8
36
+ Transfer-Encoding:
37
+ - chunked
38
+ body:
39
+ encoding: ASCII-8BIT
40
+ string: '{"id":"https://login.salesforce.com/id/00D1a000000H3O9EAK/0051a000000UGT8AAO","issued_at":"1428313630193","token_type":"Bearer","instance_url":"https://<host>","signature":"ApVLPX1o4/XFwiO/5YCw9BePXEF1eqtQcn5fdHsn9cI=","access_token":"00D1a000000H3O9!AQ4AQIEcyaEa1EiezSuMSEJm73cIL8I5CDJ_vnqlgzm7mAXRhbGBSo3xF6_EdmNqSa42nDRyl2szOaP4ybHrIHxo.G4YonU_"}'
41
+ http_version:
42
+ recorded_at: Mon, 06 Apr 2015 09:47:10 GMT
43
+ - request:
44
+ method: post
45
+ uri: https://<host>/services/data/v26.0/sobjects/CustomObject__c
46
+ body:
47
+ encoding: UTF-8
48
+ string: '{"Name":"Custom object","Example_Field__c":"Some sample text"}'
49
+ headers:
50
+ User-Agent:
51
+ - Faraday v0.9.1
52
+ Content-Type:
53
+ - application/json
54
+ Authorization:
55
+ - OAuth 00D1a000000H3O9!AQ4AQIEcyaEa1EiezSuMSEJm73cIL8I5CDJ_vnqlgzm7mAXRhbGBSo3xF6_EdmNqSa42nDRyl2szOaP4ybHrIHxo.G4YonU_
56
+ Accept-Encoding:
57
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
58
+ Accept:
59
+ - "*/*"
60
+ response:
61
+ status:
62
+ code: 201
63
+ message: Created
64
+ headers:
65
+ Date:
66
+ - Mon, 06 Apr 2015 09:47:11 GMT
67
+ Set-Cookie:
68
+ - BrowserId=f3N4KWB3TCCtg_ZNr1YUOA;Path=/;Domain=.salesforce.com;Expires=Fri,
69
+ 05-Jun-2015 09:47:11 GMT
70
+ Expires:
71
+ - Thu, 01 Jan 1970 00:00:00 GMT
72
+ Sforce-Limit-Info:
73
+ - api-usage=15/15000
74
+ Location:
75
+ - "/services/data/v26.0/sobjects/CustomObject__c/a001a000001LGfEAAW"
76
+ Content-Type:
77
+ - application/json;charset=UTF-8
78
+ Transfer-Encoding:
79
+ - chunked
80
+ body:
81
+ encoding: ASCII-8BIT
82
+ string: '{"id":"a001a000001LGfEAAW","success":true,"errors":[]}'
83
+ http_version:
84
+ recorded_at: Mon, 06 Apr 2015 09:47:11 GMT
85
+ - request:
86
+ method: get
87
+ uri: https://<host>/services/data/v26.0/query?q=select%20Id,%20SystemModstamp,%20Name,%20Example_Field__c%20from%20CustomObject__c%20where%20Id%20=%20%27a001a000001LGfEAAW%27
88
+ body:
89
+ encoding: US-ASCII
90
+ string: ''
91
+ headers:
92
+ User-Agent:
93
+ - Faraday v0.9.1
94
+ Authorization:
95
+ - OAuth 00D1a000000H3O9!AQ4AQIEcyaEa1EiezSuMSEJm73cIL8I5CDJ_vnqlgzm7mAXRhbGBSo3xF6_EdmNqSa42nDRyl2szOaP4ybHrIHxo.G4YonU_
96
+ Accept-Encoding:
97
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
98
+ Accept:
99
+ - "*/*"
100
+ response:
101
+ status:
102
+ code: 200
103
+ message: OK
104
+ headers:
105
+ Date:
106
+ - Mon, 06 Apr 2015 09:47:12 GMT
107
+ Set-Cookie:
108
+ - BrowserId=O5AXigkwScCVCQ_O3JaAiQ;Path=/;Domain=.salesforce.com;Expires=Fri,
109
+ 05-Jun-2015 09:47:12 GMT
110
+ Expires:
111
+ - Thu, 01 Jan 1970 00:00:00 GMT
112
+ Sforce-Limit-Info:
113
+ - api-usage=15/15000
114
+ Content-Type:
115
+ - application/json;charset=UTF-8
116
+ Transfer-Encoding:
117
+ - chunked
118
+ body:
119
+ encoding: ASCII-8BIT
120
+ string: '{"totalSize":1,"done":true,"records":[{"attributes":{"type":"CustomObject__c","url":"/services/data/v26.0/sobjects/CustomObject__c/a001a000001LGfEAAW"},"Id":"a001a000001LGfEAAW","SystemModstamp":"2015-04-06T09:47:11.000+0000","Name":"Custom
121
+ object","Example_Field__c":"Some sample text"}]}'
122
+ http_version:
123
+ recorded_at: Mon, 06 Apr 2015 09:47:12 GMT
124
+ - request:
125
+ method: get
126
+ uri: https://<host>/services/data/v26.0/query?q=select%20Id,%20SystemModstamp,%20Name,%20Example_Field__c%20from%20CustomObject__c%20where%20SystemModstamp%20%3C%202015-04-06T09:47:12Z
127
+ body:
128
+ encoding: US-ASCII
129
+ string: ''
130
+ headers:
131
+ User-Agent:
132
+ - Faraday v0.9.1
133
+ Authorization:
134
+ - OAuth 00D1a000000H3O9!AQ4AQIEcyaEa1EiezSuMSEJm73cIL8I5CDJ_vnqlgzm7mAXRhbGBSo3xF6_EdmNqSa42nDRyl2szOaP4ybHrIHxo.G4YonU_
135
+ Accept-Encoding:
136
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
137
+ Accept:
138
+ - "*/*"
139
+ response:
140
+ status:
141
+ code: 200
142
+ message: OK
143
+ headers:
144
+ Date:
145
+ - Mon, 06 Apr 2015 09:47:13 GMT
146
+ Set-Cookie:
147
+ - BrowserId=g-5Hn4m0RYqtYjdU8FhUfw;Path=/;Domain=.salesforce.com;Expires=Fri,
148
+ 05-Jun-2015 09:47:13 GMT
149
+ Expires:
150
+ - Thu, 01 Jan 1970 00:00:00 GMT
151
+ Sforce-Limit-Info:
152
+ - api-usage=15/15000
153
+ Content-Type:
154
+ - application/json;charset=UTF-8
155
+ Transfer-Encoding:
156
+ - chunked
157
+ body:
158
+ encoding: ASCII-8BIT
159
+ string: '{"totalSize":1,"done":true,"records":[{"attributes":{"type":"CustomObject__c","url":"/services/data/v26.0/sobjects/CustomObject__c/a001a000001LGfEAAW"},"Id":"a001a000001LGfEAAW","SystemModstamp":"2015-04-06T09:47:11.000+0000","Name":"Custom
160
+ object","Example_Field__c":"Some sample text"}]}'
161
+ http_version:
162
+ recorded_at: Mon, 06 Apr 2015 09:47:13 GMT
163
+ - request:
164
+ method: delete
165
+ uri: https://<host>/services/data/v26.0/sobjects/CustomObject__c/a001a000001LGfEAAW
166
+ body:
167
+ encoding: US-ASCII
168
+ string: ''
169
+ headers:
170
+ User-Agent:
171
+ - Faraday v0.9.1
172
+ Authorization:
173
+ - OAuth 00D1a000000H3O9!AQ4AQIEcyaEa1EiezSuMSEJm73cIL8I5CDJ_vnqlgzm7mAXRhbGBSo3xF6_EdmNqSa42nDRyl2szOaP4ybHrIHxo.G4YonU_
174
+ Accept-Encoding:
175
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
176
+ Accept:
177
+ - "*/*"
178
+ response:
179
+ status:
180
+ code: 204
181
+ message: No Content
182
+ headers:
183
+ Date:
184
+ - Mon, 06 Apr 2015 09:47:14 GMT
185
+ Set-Cookie:
186
+ - BrowserId=NB2Kj_8CSFy1w02HjcWRfQ;Path=/;Domain=.salesforce.com;Expires=Fri,
187
+ 05-Jun-2015 09:47:14 GMT
188
+ Expires:
189
+ - Thu, 01 Jan 1970 00:00:00 GMT
190
+ Sforce-Limit-Info:
191
+ - api-usage=16/15000
192
+ body:
193
+ encoding: UTF-8
194
+ string: ''
195
+ http_version:
196
+ recorded_at: Mon, 06 Apr 2015 09:47:14 GMT
197
+ recorded_with: VCR 2.9.3