restforce 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of restforce might be problematic. Click here for more details.
- data/CHANGELOG.md +8 -0
- data/README.md +9 -6
- data/lib/restforce/client.rb +1 -5
- data/lib/restforce/collection.rb +31 -9
- data/lib/restforce/config.rb +41 -56
- data/lib/restforce/version.rb +1 -1
- data/spec/lib/client_spec.rb +3 -3
- data/spec/lib/collection_spec.rb +20 -15
- metadata +4 -4
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
## 1.3.0 (Apr 6, 2013)
|
2
|
+
|
3
|
+
* Added support for lazily traversing paginated collections #61 by @nahiluhmot.
|
4
|
+
|
5
|
+
## 1.2.0 (Mar 30, 2013)
|
6
|
+
|
7
|
+
* Added support for proxies #60 by @wazoo.
|
8
|
+
|
1
9
|
## 1.1.0 (Mar 3, 2013)
|
2
10
|
|
3
11
|
* Added ability to download attachments easily.
|
data/README.md
CHANGED
@@ -395,7 +395,7 @@ end
|
|
395
395
|
|
396
396
|
* * *
|
397
397
|
|
398
|
-
### Logging/Debugging
|
398
|
+
### Logging/Debugging/Instrumenting
|
399
399
|
|
400
400
|
You can easily inspect what Restforce is sending/receiving by setting
|
401
401
|
`Restforce.log = true`.
|
@@ -407,16 +407,19 @@ client = Restforce.new.query('select Id, Name from Account')
|
|
407
407
|
|
408
408
|
Another awesome feature about restforce is that, because it is based on
|
409
409
|
Faraday, you can insert your own middleware. For example, if you were using
|
410
|
-
Restforce in a rails app, you can setup custom
|
411
|
-
ActiveSupport::Notifications:
|
410
|
+
Restforce in a rails app, you can setup custom reporting to
|
411
|
+
[Librato](https://github.com/librato/librato-rails) using ActiveSupport::Notifications:
|
412
412
|
|
413
413
|
```ruby
|
414
414
|
client = Restforce.new
|
415
|
-
client.middleware.insert_after Restforce::Middleware::InstanceURL,
|
415
|
+
client.middleware.insert_after Restforce::Middleware::InstanceURL,
|
416
|
+
FaradayMiddleware::Instrumentation, name: 'request.salesforce'
|
416
417
|
|
417
418
|
# config/initializers/notifications.rb
|
418
|
-
ActiveSupport::Notifications.subscribe('request.
|
419
|
-
|
419
|
+
ActiveSupport::Notifications.subscribe('request.salesforce') do |*args|
|
420
|
+
event = ActiveSupport::Notifications::Event.new(*args)
|
421
|
+
Librato.increment 'api.salesforce.request.total'
|
422
|
+
Librato.timing 'api.salesforce.request.time', event.duration
|
420
423
|
end
|
421
424
|
```
|
422
425
|
|
data/lib/restforce/client.rb
CHANGED
@@ -16,10 +16,6 @@ module Restforce
|
|
16
16
|
include Restforce::Client::Canvas
|
17
17
|
include Restforce::Client::API
|
18
18
|
|
19
|
-
OPTIONS = [:username, :password, :security_token, :client_id, :client_secret, :host, :compress,
|
20
|
-
:api_version, :oauth_token, :refresh_token, :instance_url, :cache, :authentication_retries,
|
21
|
-
:timeout, :proxy_uri]
|
22
|
-
|
23
19
|
# Public: Creates a new client instance
|
24
20
|
#
|
25
21
|
# opts - A hash of options to be passed in (default: {}).
|
@@ -76,7 +72,7 @@ module Restforce
|
|
76
72
|
#
|
77
73
|
def initialize(opts = {})
|
78
74
|
raise 'Please specify a hash of options' unless opts.is_a?(Hash)
|
79
|
-
@options = Hash[
|
75
|
+
@options = Hash[Restforce.configuration.options.map { |option| [option, Restforce.configuration.send(option)] }]
|
80
76
|
@options.merge! opts
|
81
77
|
end
|
82
78
|
|
data/lib/restforce/collection.rb
CHANGED
@@ -1,18 +1,40 @@
|
|
1
1
|
module Restforce
|
2
|
-
class Collection
|
3
|
-
|
2
|
+
class Collection
|
3
|
+
include Enumerable
|
4
4
|
|
5
|
+
# Given a hash and client, will create an Enumerator that will lazily
|
6
|
+
# request Salesforce for the next page of results.
|
5
7
|
def initialize(hash, client)
|
6
|
-
@client
|
7
|
-
@
|
8
|
-
@next_page_url = hash['nextRecordsUrl']
|
9
|
-
super(Restforce::Mash.build(hash['records'], @client))
|
8
|
+
@client = client
|
9
|
+
@raw_page = hash
|
10
10
|
end
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
# Yield each value on each page.
|
13
|
+
def each
|
14
|
+
@raw_page['records'].each { |record| yield Restforce::Mash.build(record, @client) }
|
15
|
+
|
16
|
+
next_page.each { |record| yield record } if has_next_page?
|
17
|
+
end
|
18
|
+
|
19
|
+
# Return the size of the Collection without making any additional requests.
|
20
|
+
def size
|
21
|
+
@raw_page['totalSize']
|
22
|
+
end
|
23
|
+
alias_method :length, :size
|
24
|
+
|
25
|
+
# Return the current and all of the following pages.
|
26
|
+
def pages
|
27
|
+
[self] + (has_next_page? ? next_page.pages : [])
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns true if there is a pointer to the next page.
|
31
|
+
def has_next_page?
|
32
|
+
!@raw_page['nextRecordsUrl'].nil?
|
15
33
|
end
|
16
34
|
|
35
|
+
# Returns the next page as a Restforce::Collection if it's available, nil otherwise.
|
36
|
+
def next_page
|
37
|
+
@next_page ||= @client.get(@raw_page['nextRecordsUrl']).body if has_next_page?
|
38
|
+
end
|
17
39
|
end
|
18
40
|
end
|
data/lib/restforce/config.rb
CHANGED
@@ -37,85 +37,70 @@ module Restforce
|
|
37
37
|
end
|
38
38
|
|
39
39
|
class Configuration
|
40
|
-
|
40
|
+
class << self
|
41
|
+
attr_accessor :options
|
42
|
+
|
43
|
+
def option(name, options = {})
|
44
|
+
default = options.fetch(:default, nil)
|
45
|
+
attr_accessor name
|
46
|
+
define_method name do
|
47
|
+
instance_variable_get(:"@#{name}") ||
|
48
|
+
instance_variable_set(:"@#{name}", default.respond_to?(:call) ? default.call : default)
|
49
|
+
end if default
|
50
|
+
self.options ||= []
|
51
|
+
self.options << name
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
option :api_version, :default => '26.0'
|
56
|
+
|
41
57
|
# The username to use during login.
|
42
|
-
|
58
|
+
option :username, :default => lambda { ENV['SALESFORCE_USERNAME'] }
|
59
|
+
|
43
60
|
# The password to use during login.
|
44
|
-
|
61
|
+
option :password, :default => lambda { ENV['SALESFORCE_PASSWORD'] }
|
62
|
+
|
45
63
|
# The security token to use during login.
|
46
|
-
|
64
|
+
option :security_token, :default => lambda { ENV['SALESFORCE_SECURITY_TOKEN'] }
|
65
|
+
|
47
66
|
# The OAuth client id
|
48
|
-
|
67
|
+
option :client_id, :default => lambda { ENV['SALESFORCE_CLIENT_ID'] }
|
68
|
+
|
49
69
|
# The OAuth client secret
|
50
|
-
|
70
|
+
option :client_secret, :default => lambda { ENV['SALESFORCE_CLIENT_SECRET'] }
|
71
|
+
|
51
72
|
# Set this to true if you're authenticating with a Sandbox instance.
|
52
73
|
# Defaults to false.
|
53
|
-
|
74
|
+
option :host, :default => 'login.salesforce.com'
|
54
75
|
|
55
|
-
|
56
|
-
|
57
|
-
|
76
|
+
option :oauth_token
|
77
|
+
option :refresh_token
|
78
|
+
option :instance_url
|
58
79
|
|
59
80
|
# Set this to an object that responds to read, write and fetch and all GET
|
60
81
|
# requests will be cached.
|
61
|
-
|
82
|
+
option :cache
|
62
83
|
|
63
84
|
# The number of times reauthentication should be tried before failing.
|
64
|
-
|
85
|
+
option :authentication_retries, :default => 3
|
65
86
|
|
66
87
|
# Set to true if you want responses from Salesforce to be gzip compressed.
|
67
|
-
|
88
|
+
option :compress
|
68
89
|
|
69
90
|
# Faraday request read/open timeout.
|
70
|
-
|
91
|
+
option :timeout
|
71
92
|
|
72
93
|
# Faraday adapter to use. Defaults to Faraday.default_adapter.
|
73
|
-
|
74
|
-
|
75
|
-
attr_accessor :proxy_uri
|
76
|
-
|
77
|
-
def api_version
|
78
|
-
@api_version ||= '26.0'
|
79
|
-
end
|
80
|
-
|
81
|
-
def username
|
82
|
-
@username ||= ENV['SALESFORCE_USERNAME']
|
83
|
-
end
|
84
|
-
|
85
|
-
def password
|
86
|
-
@password ||= ENV['SALESFORCE_PASSWORD']
|
87
|
-
end
|
94
|
+
option :adapter, :default => lambda { Faraday.default_adapter }
|
88
95
|
|
89
|
-
|
90
|
-
@security_token ||= ENV['SALESFORCE_SECURITY_TOKEN']
|
91
|
-
end
|
92
|
-
|
93
|
-
def client_id
|
94
|
-
@client_id ||= ENV['SALESFORCE_CLIENT_ID']
|
95
|
-
end
|
96
|
-
|
97
|
-
def client_secret
|
98
|
-
@client_secret ||= ENV['SALESFORCE_CLIENT_SECRET']
|
99
|
-
end
|
100
|
-
|
101
|
-
def proxy_uri
|
102
|
-
@proxy_uri ||= ENV['PROXY_URI']
|
103
|
-
end
|
104
|
-
|
105
|
-
def host
|
106
|
-
@host ||= 'login.salesforce.com'
|
107
|
-
end
|
108
|
-
|
109
|
-
def authentication_retries
|
110
|
-
@authentication_retries ||= 3
|
111
|
-
end
|
112
|
-
|
113
|
-
def adapter
|
114
|
-
@adapter ||= Faraday.default_adapter
|
115
|
-
end
|
96
|
+
option :proxy_uri, :default => lambda { ENV['PROXY_URI'] }
|
116
97
|
|
117
98
|
def logger
|
118
99
|
@logger ||= ::Logger.new STDOUT
|
119
100
|
end
|
101
|
+
|
102
|
+
def options
|
103
|
+
self.class.options
|
104
|
+
end
|
120
105
|
end
|
121
106
|
end
|
data/lib/restforce/version.rb
CHANGED
data/spec/lib/client_spec.rb
CHANGED
@@ -97,7 +97,7 @@ shared_examples_for 'methods' do
|
|
97
97
|
requests 'query\?q=SELECT%20some,%20fields%20FROM%20object', :fixture => 'sobject/query_success_response'
|
98
98
|
|
99
99
|
subject { client.query('SELECT some, fields FROM object') }
|
100
|
-
it { should be_an
|
100
|
+
it { should be_an Enumerable }
|
101
101
|
end
|
102
102
|
|
103
103
|
describe '.search' do
|
@@ -364,7 +364,7 @@ shared_examples_for 'methods' do
|
|
364
364
|
|
365
365
|
let(:cache) { MockCache.new }
|
366
366
|
subject { client.without_caching { client.query('SELECT some, fields FROM object') } }
|
367
|
-
it { should be_an
|
367
|
+
it { should be_an Enumerable }
|
368
368
|
end
|
369
369
|
|
370
370
|
unless RUBY_PLATFORM == 'java'
|
@@ -453,7 +453,7 @@ shared_examples_for 'methods' do
|
|
453
453
|
end
|
454
454
|
|
455
455
|
subject { client.query('SELECT some, fields FROM object') }
|
456
|
-
it { should be_an
|
456
|
+
it { should be_an Enumerable }
|
457
457
|
end
|
458
458
|
end
|
459
459
|
|
data/spec/lib/collection_spec.rb
CHANGED
@@ -11,10 +11,9 @@ describe Restforce::Collection do
|
|
11
11
|
described_class.new(JSON.parse(fixture('sobject/query_success_response')), client)
|
12
12
|
end
|
13
13
|
|
14
|
-
it
|
15
|
-
its(:size)
|
16
|
-
its(:
|
17
|
-
its(:next_page_url) { should be_nil }
|
14
|
+
it { should respond_to :each }
|
15
|
+
its(:size) { should eq 1 }
|
16
|
+
its(:has_next_page?) { should be_false }
|
18
17
|
specify { expect(subject.instance_variable_get(:@client)).to eq client }
|
19
18
|
|
20
19
|
describe 'each record' do
|
@@ -24,23 +23,29 @@ describe Restforce::Collection do
|
|
24
23
|
end
|
25
24
|
|
26
25
|
context 'with pagination' do
|
27
|
-
let(:
|
28
|
-
|
29
|
-
|
26
|
+
let(:first_page) { JSON.parse(fixture('sobject/query_paginated_first_page_response')) }
|
27
|
+
let(:next_page) { JSON.parse(fixture('sobject/query_paginated_last_page_response')) }
|
28
|
+
let(:records) { described_class.new(first_page, client) }
|
30
29
|
|
31
|
-
it
|
32
|
-
its(:size) { should eq 1 }
|
33
|
-
its(:total_size) { should eq 2 }
|
34
|
-
its(:next_page_url) { should eq "/services/data/v#{Restforce.configuration.api_version}/query/01gD" }
|
30
|
+
it { should respond_to :each }
|
35
31
|
specify { expect(subject.instance_variable_get(:@client)).to eq client }
|
36
32
|
|
37
|
-
|
33
|
+
context 'when only values from the first page are being requested' do
|
34
|
+
before { client.should_not_receive(:get) }
|
35
|
+
|
36
|
+
its(:size) { should eq 2 }
|
37
|
+
its(:first) { should be_an_instance_of Restforce::SObject }
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'when all of the values are being requested' do
|
38
41
|
before do
|
39
|
-
client.
|
42
|
+
client.stub(:get).and_return(Faraday::Response.new(:body => Restforce::Collection.new(next_page, client)))
|
40
43
|
end
|
41
44
|
|
42
|
-
|
43
|
-
|
45
|
+
its(:pages) { should be_all { |page| expect(page).to be_a Restforce::Collection } }
|
46
|
+
its(:has_next_page?) { should be_true }
|
47
|
+
it { should be_all { |record| expect(record).to be_a Restforce::SObject } }
|
48
|
+
specify { subject.next_page.should be_a Restforce::Collection }
|
44
49
|
end
|
45
50
|
end
|
46
51
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: restforce
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-04-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: faraday
|
@@ -252,7 +252,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
252
252
|
version: '0'
|
253
253
|
segments:
|
254
254
|
- 0
|
255
|
-
hash:
|
255
|
+
hash: 2514062890750763667
|
256
256
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
257
257
|
none: false
|
258
258
|
requirements:
|
@@ -261,7 +261,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
261
261
|
version: '0'
|
262
262
|
segments:
|
263
263
|
- 0
|
264
|
-
hash:
|
264
|
+
hash: 2514062890750763667
|
265
265
|
requirements: []
|
266
266
|
rubyforge_project:
|
267
267
|
rubygems_version: 1.8.23
|