restforce 4.2.2 → 5.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +9 -9
  3. data/.github/ISSUE_TEMPLATE/unhandled-salesforce-error.md +17 -0
  4. data/.github/dependabot.yml +19 -0
  5. data/.rubocop.yml +5 -4
  6. data/CHANGELOG.md +68 -0
  7. data/CONTRIBUTING.md +21 -1
  8. data/Dockerfile +31 -0
  9. data/Gemfile +10 -7
  10. data/README.md +46 -21
  11. data/UPGRADING.md +38 -0
  12. data/docker-compose.yml +7 -0
  13. data/lib/restforce/collection.rb +7 -2
  14. data/lib/restforce/concerns/api.rb +2 -2
  15. data/lib/restforce/concerns/base.rb +2 -2
  16. data/lib/restforce/concerns/caching.rb +7 -0
  17. data/lib/restforce/concerns/picklists.rb +2 -2
  18. data/lib/restforce/concerns/streaming.rb +1 -3
  19. data/lib/restforce/config.rb +4 -1
  20. data/lib/restforce/error_code.rb +638 -0
  21. data/lib/restforce/file_part.rb +24 -0
  22. data/lib/restforce/mash.rb +7 -2
  23. data/lib/restforce/middleware/caching.rb +1 -1
  24. data/lib/restforce/middleware/logger.rb +8 -7
  25. data/lib/restforce/middleware/raise_error.rb +3 -4
  26. data/lib/restforce/middleware.rb +2 -0
  27. data/lib/restforce/version.rb +1 -1
  28. data/lib/restforce.rb +4 -7
  29. data/restforce.gemspec +9 -19
  30. data/spec/integration/abstract_client_spec.rb +41 -32
  31. data/spec/integration/data/client_spec.rb +6 -2
  32. data/spec/spec_helper.rb +24 -1
  33. data/spec/support/client_integration.rb +7 -7
  34. data/spec/support/concerns.rb +1 -1
  35. data/spec/support/fixture_helpers.rb +1 -3
  36. data/spec/support/middleware.rb +1 -2
  37. data/spec/unit/collection_spec.rb +20 -2
  38. data/spec/unit/concerns/api_spec.rb +11 -11
  39. data/spec/unit/concerns/authentication_spec.rb +6 -6
  40. data/spec/unit/concerns/caching_spec.rb +26 -0
  41. data/spec/unit/concerns/connection_spec.rb +2 -2
  42. data/spec/unit/concerns/streaming_spec.rb +3 -3
  43. data/spec/unit/config_spec.rb +1 -1
  44. data/spec/unit/error_code_spec.rb +61 -0
  45. data/spec/unit/middleware/authentication/jwt_bearer_spec.rb +4 -4
  46. data/spec/unit/middleware/authentication/password_spec.rb +2 -2
  47. data/spec/unit/middleware/authentication/token_spec.rb +2 -2
  48. data/spec/unit/middleware/authentication_spec.rb +11 -5
  49. data/spec/unit/middleware/gzip_spec.rb +2 -2
  50. data/spec/unit/middleware/raise_error_spec.rb +29 -10
  51. data/spec/unit/signed_request_spec.rb +1 -1
  52. metadata +33 -123
  53. data/lib/restforce/upload_io.rb +0 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 414c3c4cb8ef46b5f943d190aa10d750c58c06d18ab280ba5dd34883cc684a80
4
- data.tar.gz: fa27e1d169c51af87ef5a2a10c80ffe9619f01f34efc54778a92361147b37e2a
3
+ metadata.gz: 68aba674731ec407d63a766c8bcf13a6a243e757e89b32c8bed07c07a2ee2a9e
4
+ data.tar.gz: 1529b415da1c3d34ff477aea87116d147d5e2bd3e74ebde236ef9292545fad54
5
5
  SHA512:
6
- metadata.gz: 227bb7793df6e71fda10d1c3d89b77c066525f0d5dee759a06900cec3bee8e7c2361cc395681a3cd0b0d547b16afb13bd19f707c750372357fd95da1697e4e12
7
- data.tar.gz: bfe499dc745c3f32d624cad78dbafc1c5b3777b4381d6ead38eeaae026d489ec22aa2719c0607b8923f0889744b87bf5a35694f201fd22d9418a5aefcf1f0a4d
6
+ metadata.gz: 5fc24ced1a9e38b622040d0b51ea3cd3aa2d4afc994ee41a8825ee2038c1f7379c56c2a32044a938102fe47030f02183549bdd91837ffab88320d99af13d27c5
7
+ data.tar.gz: 1a0be3c634cb0b9bcea1b38463b09e62e54ceee49b44e30e852e42c14c91761eff4cf8a6a786611682cb0ba309704d85243499c00358b6e411ded15e805f421e
data/.circleci/config.yml CHANGED
@@ -34,23 +34,23 @@ references:
34
34
  destination: test-results
35
35
 
36
36
  jobs:
37
- build-ruby265:
37
+ build-ruby30:
38
38
  docker:
39
- - image: circleci/ruby:2.6.5
39
+ - image: circleci/ruby:3.0
40
40
  steps: *steps
41
- build-ruby257:
41
+ build-ruby27:
42
42
  docker:
43
- - image: circleci/ruby:2.5.7
43
+ - image: circleci/ruby:2.7
44
44
  steps: *steps
45
- build-ruby249:
45
+ build-ruby26:
46
46
  docker:
47
- - image: circleci/ruby:2.4.9
47
+ - image: circleci/ruby:2.6
48
48
  steps: *steps
49
49
 
50
50
  workflows:
51
51
  version: 2
52
52
  tests:
53
53
  jobs:
54
- - build-ruby265
55
- - build-ruby257
56
- - build-ruby249
54
+ - build-ruby30
55
+ - build-ruby27
56
+ - build-ruby26
@@ -0,0 +1,17 @@
1
+ ---
2
+ name: Unhandled Salesforce error
3
+ about: We've recently changed the way we handle Salesforce errors to define them ahead
4
+ of time, rather than dynamically. This might mean we're missing some errors. Please
5
+ use this template to report them.
6
+ title: 'Unhandled Salesforce error: <insert error code here>'
7
+ labels: bug
8
+ assignees: timrogers
9
+
10
+ ---
11
+
12
+ Restforce doesn't have a definition for the error code `INSERT ERROR CODE HERE`.
13
+
14
+ I discovered this missing error code because:
15
+
16
+ - [ ] I tried to `rescue` it or refer to it in my code
17
+ - [ ] I got this error back from Salesforce
@@ -0,0 +1,19 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: bundler
4
+ directory: "/"
5
+ schedule:
6
+ interval: daily
7
+ open-pull-requests-limit: 10
8
+ ignore:
9
+ - dependency-name: rubocop
10
+ versions:
11
+ - 1.10.0
12
+ - 1.11.0
13
+ - 1.12.0
14
+ - 1.12.1
15
+ - 1.9.0
16
+ - dependency-name: webmock
17
+ versions:
18
+ - 3.12.0
19
+ - 3.12.1
data/.rubocop.yml CHANGED
@@ -7,10 +7,11 @@ AllCops:
7
7
  Exclude:
8
8
  - .*/**/*
9
9
  - vendor/**/*
10
- TargetRubyVersion: 2.4
10
+ NewCops: enable
11
+ TargetRubyVersion: 2.6
11
12
 
12
- # Limit lines to 80 characters.
13
- Metrics/LineLength:
13
+ # Limit lines to 90 characters.
14
+ Layout/LineLength:
14
15
  Max: 90
15
16
 
16
17
  Metrics/ClassLength:
@@ -70,4 +71,4 @@ Naming/FileName:
70
71
  - Guardfile
71
72
 
72
73
  Lint/UriEscapeUnescape:
73
- Enabled: false
74
+ Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,3 +1,71 @@
1
+ ## 5.1.1 (Oct 13, 2021)
2
+
3
+ * Handle the `INVALID_REPLICATION_DATE` error returned by Salesforce (@michaelwnyc)
4
+ * Handle the `BIG_OBJECT_UNSUPPORTED_OPERATION` error returned by Salesforce (@remon)
5
+
6
+ ## 5.1.0 (Aug 26, 2021)
7
+
8
+ * Add official support for Ruby 3.0 (@timrogers)
9
+ * Drop support for Ruby 2.5, which has reached end-of-life (@timrogers)
10
+ * Handle the `QUERY_TIMEOUT` error returned by Salesforce (@timrogers)
11
+ * Remove unnecessary development dependencies for the gem, which can just be in the project's `Gemfile` (@timrogers)
12
+
13
+ ## 5.0.6 (Jun 17, 2021)
14
+
15
+ * Handle the `API_DISABLED_FOR_ORG` error returned by Salesforce (@cmac)
16
+ * Handle the `METHOD_NOT_ALLOWED` error returned by Salesforce (@timrogers)
17
+ * Handle the `APEX_ERROR` error returned by Salesforce (@timrogers)
18
+
19
+ ## 5.0.5 (Feb 17, 2021)
20
+
21
+ * Handle the `CANNOT_EXECUTE_FLOW_TRIGGER` error returned by Salesforce (@almusavi, @timrogers)
22
+
23
+ ## 5.0.4 (Jan 18, 2021)
24
+
25
+ * Handle the `INVALID_QUERY_LOCATOR` error returned by Salesforce
26
+ * Handle the `INVALID_OPERATION_WITH_EXPIRED_PASSWORD` error returned by Salesforce
27
+ * Handle the `FIELD_INTEGRITY_EXCEPTION` error returned by Salesforce
28
+ * Handle the `FORBIDDEN` error returned by Salesforce
29
+ * Handle the `ILLEGAL_QUERY_PARAMETER_VALUE` error returned by Salesforce
30
+ * Handle the `JSON_PARSER_ERROR` error returned by Salesforce
31
+
32
+ ## 5.0.3 (Sep 8, 2020)
33
+
34
+ * Handle the undocumented `EXCEEDED_MAX_SEMIJOIN_SUBSELECTS` error returned by Salesforce (@embertel, @timrogers)
35
+
36
+ ## 5.0.2 (Sep 6, 2020)
37
+
38
+ * Handle the undocumented `REQUEST_LIMIT_EXCEEDED` error returned by Salesforce (@wkirkby, @timrogers)
39
+ * Handle the undocumented `SERVER_UNAVAILABLE` error returned by Salesforce (@wkirkby, @timrogers)
40
+ * Refactor the library to be compatible with Rubocop 0.90's cops (this shouldn't introduce any noticeable changes see #569 for detailed changes) (@timrogers)
41
+
42
+ ## 5.0.1 (Aug 13, 2020)
43
+
44
+ * Handle the undocumented `API_CURRENTLY_DISABLED` error returned by Salesforce (@ruipserra, @timrogers)
45
+ * Handle the undocumented `MALFORMED_QUERY` error returned by Salesforce (@scottserok, @timrogers)
46
+ * Handle the undocumented `INVALID_QUERY_FILTER_OPERATOR` error returned by Salesforce (@Dantemss, @timrogers)
47
+ * Add documentation and scripts for running the
48
+ library's tests using Docker (@ryansch)
49
+
50
+ ## 5.0.0 (Jul 10, 2020)
51
+
52
+ For instructions on upgrading from Restforce 4.x to 5.x, see our ["Upgrading from Restforce 4.x to 5.x"](https://github.com/restforce/restforce/blob/master/UPGRADING.md) guide.
53
+
54
+ ### Breaking changes
55
+
56
+ * __⚠️ Define exception classes for Salesforce errors up-front instead of dynamically at runtime__, *running the risk that we might miss some errors which should be defined*. If any errors are missed, they will be added in patch versions (e.g. `5.0.1`). For more details on this change, see the ["Upgrading from Restforce 4.x to 5.x"](https://github.com/restforce/restforce/blob/master/UPGRADING.md) guide (@presidentbeef, @timrogers).
57
+ * __⚠️ Deprecate support for Ruby 2.4__, since [Ruby 2.4 reached its end-of-life](https://www.ruby-lang.org/en/news/2020/04/05/support-of-ruby-2-4-has-ended/) in April 2020 (@timrogers)
58
+ * __⚠️ Change the ancestry of `Restforce::UnauthorizedError` so it inherits from `Faraday::ClientError`, not `Restforce::Error`__. This breaking change was required to expose the response body returned by the API as part of this error - see the non-breaking changes entry below for further details (@michaldbianchi).
59
+
60
+ ### Non-breaking changes
61
+
62
+ * Add support for `lostisland/faraday` v1.x, whilst maintaining support for v0.9.x (@ryansch)
63
+ * Add `#empty?` method to `Restforce::Collection`, returning whether they are any items in a collection (@bubaflub)
64
+ * Allow opting-in to caching on a per-call basis with `Restforce::Client#with_caching` (@swaincreates)
65
+ * Expose the response body from Salesforce on `Restforce::UnauthorizedError` and `Restforce::NotFoundError` (@michaeldbianchi)
66
+ * Remove the unnecessary depending on the `json` gem, which has been part of the Ruby standard library since v1.9 (@vonTronje)
67
+
68
+
1
69
  ## 4.2.2 (Jan 23, 2020)
2
70
 
3
71
  * Fix `NoMethodError: undefined method '[]' for nil:NilClass` error when generating objects to return (@apurkiss)
data/CONTRIBUTING.md CHANGED
@@ -34,4 +34,24 @@ Some things that will increase the chance that your pull request is accepted:
34
34
  * Write tests.
35
35
  * Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
36
36
 
37
- *Adapted from [factory_girl_rails's CONTRIBUTING.md](https://github.com/thoughtbot/factory_girl_rails/blob/master/CONTRIBUTING.md).*
37
+ *Adapted from [factory_bot_rails's CONTRIBUTING.md](https://github.com/thoughtbot/factory_bot_rails/blob/master/CONTRIBUTING.md).*
38
+
39
+ ## Docker
40
+
41
+ If you'd rather use a docker container to run the tests, you can use the following instructions.
42
+
43
+ To set up the container image:
44
+
45
+ `docker-compose build --pull`
46
+
47
+ To run specs:
48
+
49
+ `docker-compose run --rm restforce rspec`
50
+
51
+ To run rubocop:
52
+
53
+ `docker-compose run --rm restforce rubocop`
54
+
55
+ To reset the bundler cache:
56
+
57
+ `docker-compose down -v`
data/Dockerfile ADDED
@@ -0,0 +1,31 @@
1
+ FROM ruby:2.6.5-alpine
2
+
3
+ RUN apk add --no-cache \
4
+ ca-certificates \
5
+ wget \
6
+ openssl \
7
+ bash \
8
+ build-base \
9
+ git \
10
+ sqlite-dev \
11
+ tzdata \
12
+ tini
13
+
14
+ ENV LANG en_US.UTF-8
15
+ ENV LANGUAGE en_US:en
16
+ ENV LC_ALL en_US.UTF-8
17
+
18
+ ENV BUNDLER_VERSION 2.1.4
19
+ RUN gem install bundler -v ${BUNDLER_VERSION} -i /usr/local/lib/ruby/gems/$(ls /usr/local/lib/ruby/gems) --force
20
+
21
+ WORKDIR /srv
22
+
23
+ COPY Gemfile restforce.gemspec /srv/
24
+ COPY lib/restforce/version.rb /srv/lib/restforce/version.rb
25
+
26
+ RUN bundle install
27
+
28
+ COPY . /srv/
29
+
30
+ ENTRYPOINT ["/sbin/tini", "-g", "--", "bundle", "exec"]
31
+ CMD ["rspec"]
data/Gemfile CHANGED
@@ -3,12 +3,15 @@
3
3
  source 'https://rubygems.org'
4
4
  gemspec
5
5
 
6
- gem 'faraday', '~> 0.17.0'
6
+ gem 'faye' unless RUBY_PLATFORM == 'java'
7
+ gem 'guard-rspec'
8
+ gem 'guard-rubocop'
7
9
  gem 'jruby-openssl', platforms: :jruby
8
- gem 'jwt'
9
10
  gem 'rake'
10
-
11
- group :development do
12
- gem 'guard-rspec'
13
- gem 'guard-rubocop'
14
- end
11
+ gem 'rspec', '~> 3.10.0'
12
+ gem 'rspec-collection_matchers', '~> 1.2.0'
13
+ gem 'rspec-its', '~> 1.3.0'
14
+ gem 'rspec_junit_formatter', '~> 0.4.1'
15
+ gem 'rubocop', '~> 1.22.1'
16
+ gem 'simplecov', '~> 0.21.2'
17
+ gem 'webmock', '~> 3.14.0'
data/README.md CHANGED
@@ -8,7 +8,7 @@ Restforce is a ruby gem for the [Salesforce REST api](http://www.salesforce.com/
8
8
  Features include:
9
9
 
10
10
  * A clean and modular architecture using [Faraday middleware](https://github.com/technoweenie/faraday) and [Hashie::Mash](https://github.com/intridea/hashie/tree/v1.2.0)'d responses.
11
- * Support for interacting with multiple users from different orgs.
11
+ * Support for interacting with multiple users from different organizations.
12
12
  * Support for parent-to-child relationships.
13
13
  * Support for aggregate queries.
14
14
  * Support for the [Streaming API](#streaming)
@@ -19,13 +19,13 @@ Features include:
19
19
  * Support for dependent picklists.
20
20
  * Support for decoding [Force.com Canvas](http://www.salesforce.com/us/developer/docs/platform_connectpre/canvas_framework.pdf) signed requests. (NEW!)
21
21
 
22
- [Official Website](http://restforce.org/) | [Documentation](http://rubydoc.info/gems/restforce/frames) | [Changelog](https://github.com/restforce/restforce/tree/master/CHANGELOG.md)
22
+ [Official Website](https://restforce.github.io/) | [Documentation](http://rubydoc.info/gems/restforce/frames) | [Changelog](https://github.com/restforce/restforce/tree/master/CHANGELOG.md)
23
23
 
24
24
  ## Installation
25
25
 
26
26
  Add this line to your application's Gemfile:
27
27
 
28
- gem 'restforce', '~> 4.2.2'
28
+ gem 'restforce', '~> 5.1.1'
29
29
 
30
30
  And then execute:
31
31
 
@@ -35,7 +35,13 @@ Or install it yourself as:
35
35
 
36
36
  $ gem install restforce
37
37
 
38
- __As of [version 4.0.0](https://github.com/restforce/restforce/blob/master/CHANGELOG.md#400-oct-9-2019), this gem is only compatible with Ruby 2.4.0 and later.__ You'll need to use version 3.2.0 or earlier if you're running on Ruby 2.3. If you're running on Ruby 2.2, 2.1 or 2.0, use version 2.5.3 or earlier. For Ruby 1.9.3, you'll need to manually specify that you wish to use version 2.4.2.
38
+ __As of version 5.1.0, this gem is only compatible with Ruby 2.6.0 and later.__ If you're using an earlier Ruby version:
39
+
40
+ * for Ruby 2.5, use version 5.0.6 or earlier
41
+ * for Ruby 2.4, use version 4.3.0 or earlier
42
+ * for Ruby 2.3, use version 3.2.0 or earlier
43
+ * for Ruby versions 2.2, 2.1 and 2.0, use version 2.5.3 or earlier
44
+ * for Ruby 1.9.3, use version 2.4.2
39
45
 
40
46
  This gem is versioned using [Semantic Versioning](http://semver.org/), so you can be confident when updating that there will not be breaking changes outside of a major version (following format MAJOR.MINOR.PATCH, so for instance moving from 3.1.0 to 4.0.0 would be allowed to include incompatible API changes). See the [changelog](https://github.com/restforce/restforce/tree/master/CHANGELOG.md) for details on what has changed in each version.
41
47
 
@@ -48,7 +54,7 @@ so you can do things like `client.query('select Id, (select Name from Children__
48
54
  ### Initialization
49
55
 
50
56
  Which authentication method you use really depends on your use case. If you're
51
- building an application where many users from different orgs are authenticated
57
+ building an application where many users from different organizations are authenticated
52
58
  through oauth and you need to interact with data in their org on their behalf,
53
59
  you should use the OAuth token authentication method.
54
60
 
@@ -78,7 +84,7 @@ client = Restforce.new(oauth_token: 'access_token',
78
84
  api_version: '41.0')
79
85
  ```
80
86
 
81
- The middleware will use the `refresh_token` automatically to acquire a new `access_token` if the existing `access_token` is invalid.
87
+ The middleware will use the `refresh_token` automatically to acquire a new `access_token` if the existing `access_token` is invalid. The refresh process uses the `host` option so make sure that is set correctly for sandbox organizations.
82
88
 
83
89
  `authentication_callback` is a proc that handles the response from Salesforce when the `refresh_token` is used to obtain a new `access_token`. This allows the `access_token` to be saved for re-use later - otherwise subsequent API calls will continue the cycle of "auth failure/issue new access_token/auth success".
84
90
 
@@ -142,7 +148,17 @@ export SALESFORCE_API_VERSION="41.0"
142
148
  client = Restforce.new
143
149
  ```
144
150
 
145
- ### Proxy Support
151
+ #### Sandbox Organizations
152
+
153
+ You can connect to sandbox organizations by specifying a host. The default host is
154
+ 'login.salesforce.com':
155
+
156
+ ```ruby
157
+ client = Restforce.new(host: 'test.salesforce.com')
158
+ ```
159
+ The host can also be set with the environment variable `SALESFORCE_HOST`.
160
+
161
+ #### Proxy Support
146
162
 
147
163
  You can specify a HTTP proxy using the `proxy_uri` option, as follows, or by setting the `SALESFORCE_PROXY_URI` environment variable:
148
164
 
@@ -158,16 +174,6 @@ client = Restforce.new(username: 'foo',
158
174
 
159
175
  You may specify a username and password for the proxy with a URL along the lines of 'http://user:password@proxy.example.com:123'.
160
176
 
161
- #### Sandbox Orgs
162
-
163
- You can connect to sandbox orgs by specifying a host. The default host is
164
- 'login.salesforce.com':
165
-
166
- ```ruby
167
- client = Restforce.new(host: 'test.salesforce.com')
168
- ```
169
- The host can also be set with the environment variable `SALESFORCE_HOST`.
170
-
171
177
  #### Global configuration
172
178
 
173
179
  You can set any of the options passed into `Restforce.new` globally:
@@ -328,8 +334,11 @@ client.update('Account', Id: '0016000000MRatd', Name: 'Whizbang Corp')
328
334
  ```ruby
329
335
  # Update the record with external `External__c` external ID set to '12'
330
336
  client.upsert('Account', 'External__c', External__c: 12, Name: 'Foobar')
337
+ # => true or "RecordId"
331
338
  ```
332
339
 
340
+ The upsert method will return the record Id if included in the response body from the Salesforce API; otherwise, it returns true. Currently the Salesforce API only returns the Id for newly created records.
341
+
333
342
  ### destroy
334
343
 
335
344
  ```ruby
@@ -451,13 +460,13 @@ info.user_id
451
460
 
452
461
  ### File Uploads
453
462
 
454
- Using the new [Blob Data](http://www.salesforce.com/us/developer/docs/api_rest/Content/dome_sobject_insert_update_blob.htm) api feature (500mb limit):
463
+ Using the new [Blob Data](https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/dome_sobject_insert_update_blob.htm) api feature (500mb limit):
455
464
 
456
465
  ```ruby
457
466
  client.create('Document', FolderId: '00lE0000000FJ6H',
458
467
  Description: 'Document test',
459
468
  Name: 'My image',
460
- Body: Restforce::UploadIO.new(File.expand_path('image.jpg', __FILE__), 'image/jpeg')
469
+ Body: Restforce::FilePart.new(File.expand_path('image.jpg', __FILE__), 'image/jpeg')
461
470
  ```
462
471
 
463
472
  Using base64 encoded data (37.5mb limit):
@@ -469,7 +478,7 @@ client.create('Document', FolderId: '00lE0000000FJ6H',
469
478
  Body: Base64::encode64(File.read('image.jpg'))
470
479
  ```
471
480
 
472
- _See also: [Inserting or updating blob data](http://www.salesforce.com/us/developer/docs/api_rest/Content/dome_sobject_insert_update_blob.htm)_
481
+ _See also: [Inserting or updating blob data](https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/dome_sobject_insert_update_blob.htm)_
473
482
 
474
483
  * * *
475
484
 
@@ -688,7 +697,23 @@ client.without_caching do
688
697
  end
689
698
  ```
690
699
 
691
- Caching is done on based on your authentication credentials, so cached responses will not be shared between different Salesforce logins.
700
+ If you prefer to opt in to caching on a per-request, you can do so by using .with_caching and
701
+ setting the `use_cache` config option to false:
702
+
703
+ ```ruby
704
+ Restforce.configure do |config|
705
+ config.cache = Rails.cache
706
+ config.use_cache = false
707
+ end
708
+ ```
709
+
710
+ ```ruby
711
+ client.with_caching do
712
+ client.query('select Id from Account')
713
+ end
714
+ ```
715
+
716
+ Caching is done based on your authentication credentials, so cached responses will not be shared between different Salesforce logins.
692
717
 
693
718
  * * *
694
719
 
data/UPGRADING.md ADDED
@@ -0,0 +1,38 @@
1
+ # Upgrading from Restforce 4.x to 5.x
2
+
3
+ __There are three breaking changes introduced in Restforce 5.x__. In this guide, you'll learn about these changes and what you should check in your code to make sure that it will work with the latest version of the library.
4
+
5
+ ## Error classes are now defined up-front, rather than dynamically at runtime
6
+
7
+ __Likelyhood of impact__: Moderate
8
+
9
+ The Salesforce REST API can return a range of `errorCode`s representing different kinds of errors. To make these easy to
10
+ handle in your code, we want to turn these into individual, specific exception classes in the `Restforce::ErrorCode` namespace that inherit from `Restforce:: ResponseError`.
11
+
12
+ Up until now, these exception classes have been defined dynamically at runtime which has some disadvantages - see the [pull request](https://github.com/restforce/restforce/pull/551) for more details.
13
+
14
+ In this version, we switch to defining them up-front in the code based on a list in the Salesforce documentation. There is a risk that we might have missed some errors which should be defined. If any errors are missed, they will be added in patch versions (e.g. `5.0.1`).
15
+
16
+ If your application won't run because you are referring to an exception class that no longer exists, or you see warnings logged anywhere, please [create an issue](https://github.com/restforce/restforce/issues/new?template=unhandled-salesforce-error.md&title=Unhandled+Salesforce+error%3A+%3Cinsert+error+code+here%3E).
17
+
18
+ ## Ruby 2.4 is no longer supported
19
+
20
+ __Likelyhood of impact__: Moderate
21
+
22
+ As of [5th April 2020](https://www.ruby-lang.org/en/news/2020/04/05/support-of-ruby-2-4-has-ended/), Ruby 2.4 is no longer officially supported as an active version of the Ruby language. That means that it will not receive patches and security fixes.
23
+
24
+ Accordingly, we've dropped support for Ruby 2.4 and earlier in the Restforce library. It *may* be compatible, bu we don't guarantee this or enforce it with automated tests.
25
+
26
+ Before you update to Restforce 5.x, you'll need to switch to Ruby 2.5 or later. The current version of Ruby at the time of wriing is 2.7.
27
+
28
+ ## `Restforce::UnauthorizedError` no longer inherits from `Restforce::Error`
29
+
30
+ __Likelyhood of impact__: Low
31
+
32
+ Previously, the `Restforce::UnauthorizedError` returned when the library couldn't authenticate with the Salesforce API inherits from `Restforce::Error`. So, if you used `rescue Restforce::Error` in your code, you'd catch these exceptions.
33
+
34
+ We've now changed this exception class to inherit from `Faraday::ClientError` which allows the response body returned from the Salesforce API to be attached to the error.
35
+
36
+ If you refer to `Restforce::Error` anywhere in your code, you should check whether you also need to take into account `Restforce::UnauthorizedError`.
37
+
38
+ If you refer to `Faraday::ClientError` anywhere in your code, you should check that you want the case where Restforce can't authenticate to be included.
@@ -0,0 +1,7 @@
1
+ version: "3.6"
2
+ services:
3
+ restforce:
4
+ build: .
5
+ image: restforce:dev
6
+ volumes:
7
+ - .:/srv
@@ -12,12 +12,12 @@ module Restforce
12
12
  end
13
13
 
14
14
  # Yield each value on each page.
15
- def each
15
+ def each(&block)
16
16
  @raw_page['records'].each { |record| yield Restforce::Mash.build(record, @client) }
17
17
 
18
18
  np = next_page
19
19
  while np
20
- np.current_page.each { |record| yield record }
20
+ np.current_page.each(&block)
21
21
  np = np.next_page
22
22
  end
23
23
  end
@@ -33,6 +33,11 @@ module Restforce
33
33
  end
34
34
  alias length size
35
35
 
36
+ # Returns true if the size of the Collection is zero.
37
+ def empty?
38
+ size.zero?
39
+ end
40
+
36
41
  # Return array of the elements on the current page
37
42
  def current_page
38
43
  first(@raw_page['records'].size)
@@ -380,7 +380,7 @@ module Restforce
380
380
  end
381
381
  else
382
382
  api_patch "sobjects/#{sobject}/#{field}/" \
383
- "#{ERB::Util.url_encode(external_id)}", attrs
383
+ "#{ERB::Util.url_encode(external_id)}", attrs
384
384
  end
385
385
 
386
386
  response.body.respond_to?(:fetch) ? response.body.fetch('id', true) : true
@@ -510,7 +510,7 @@ module Restforce
510
510
 
511
511
  # Internal: Errors that should be rescued from in non-bang methods
512
512
  def exceptions
513
- [Faraday::ClientError]
513
+ [Faraday::Error]
514
514
  end
515
515
  end
516
516
  end
@@ -61,9 +61,9 @@ module Restforce
61
61
  def initialize(opts = {})
62
62
  raise ArgumentError, 'Please specify a hash of options' unless opts.is_a?(Hash)
63
63
 
64
- @options = Hash[Restforce.configuration.options.map do |option|
64
+ @options = Restforce.configuration.options.map do |option|
65
65
  [option, Restforce.configuration.send(option)]
66
- end]
66
+ end.to_h
67
67
 
68
68
  @options.merge! opts
69
69
  yield builder if block_given?
@@ -15,6 +15,13 @@ module Restforce
15
15
  options.delete(:use_cache)
16
16
  end
17
17
 
18
+ def with_caching
19
+ options[:use_cache] = true
20
+ yield
21
+ ensure
22
+ options[:use_cache] = false
23
+ end
24
+
18
25
  private
19
26
 
20
27
  # Internal: Cache to use for the caching middleware
@@ -35,7 +35,7 @@ module Restforce
35
35
  @valid_for = options.delete(:valid_for)
36
36
  raise "#{field} is not a dependent picklist" if @valid_for && !dependent?
37
37
 
38
- replace(picklist_values)
38
+ super(picklist_values)
39
39
  end
40
40
 
41
41
  private
@@ -85,7 +85,7 @@ module Restforce
85
85
  def valid?(picklist_entry)
86
86
  valid_for = picklist_entry['validFor'].ljust(16, 'A').unpack1('m').
87
87
  unpack('C*')
88
- (valid_for[index >> 3] & (0x80 >> index % 8)).positive?
88
+ (valid_for[index >> 3] & (0x80 >> (index % 8))).positive?
89
89
  end
90
90
  end
91
91
  end
@@ -95,9 +95,7 @@ module Restforce
95
95
 
96
96
  def replay_id(channel)
97
97
  handler = @replay_handlers[channel]
98
- if handler.is_a?(Integer)
99
- handler # treat it as a scalar
100
- elsif handler.respond_to?(:[])
98
+ if handler.respond_to?(:[]) && !handler.is_a?(Integer)
101
99
  # Ask for the latest replayId for this channel
102
100
  handler[channel]
103
101
  else
@@ -151,11 +151,14 @@ module Restforce
151
151
  option :request_headers
152
152
 
153
153
  # Set a logger for when Restforce.log is set to true, defaulting to STDOUT
154
- option :logger, default: ::Logger.new(STDOUT)
154
+ option :logger, default: ::Logger.new($stdout)
155
155
 
156
156
  # Set a log level for logging when Restforce.log is set to true, defaulting to :debug
157
157
  option :log_level, default: :debug
158
158
 
159
+ # Set use_cache to false to opt in to caching with client.with_caching
160
+ option :use_cache, default: true
161
+
159
162
  def options
160
163
  self.class.options
161
164
  end