restforce-db 0.4.0 → 0.5.0

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