restforce 5.0.5 → 5.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 38acae68870155f93e38df159915fc242a663d02a4dbb252bb294c51763842e5
4
- data.tar.gz: eeae1f3c32d469a435121baa0c9857b222cffea7055b4b3b50c84854191a5950
3
+ metadata.gz: f30c54c95fc530b6278faf751728b2793971c8aa0e43862f6719753a1d62d4fa
4
+ data.tar.gz: c7ac3a654170e2cb883325b12f4e6315d0c0423f9673142c93c87cf5de2003b8
5
5
  SHA512:
6
- metadata.gz: e75731e44bfb826364edd12410a159d59a20c16865c4e6134736ec0ca83b06266cf8f5455772c92628fd092be94e4efb042951bbd6456865fc24d8cd2f7e3b80
7
- data.tar.gz: af8a20544ea4f628a162d8038b8515ca2bd0333bd92f3796cbd19fcd713abfa46043395ee56a858ab5f2568b85e1961097269ac56fc29417633ead0dcbcd46f8
6
+ metadata.gz: 4a731ebfe6e755b66479f8e85434a017d50a81c084f048e1454f3714bb047c36f8362976c904a91890b8f62099a3238689fe93f200468670b8f4dafc51cb5aa5
7
+ data.tar.gz: f5e8cd87fc4eccd486828627dfa1c769107e5869f7cf60088d5c7ee2cde2207d9bf33794a4f1639b98cfccfee54734d583dcbdbea8d841442a7086ff00b9e315
data/.circleci/config.yml CHANGED
@@ -34,23 +34,23 @@ references:
34
34
  destination: test-results
35
35
 
36
36
  jobs:
37
- build-ruby271:
37
+ build-ruby30:
38
38
  docker:
39
- - image: circleci/ruby:2.7.1
39
+ - image: circleci/ruby:3.0
40
40
  steps: *steps
41
- build-ruby266:
41
+ build-ruby27:
42
42
  docker:
43
- - image: circleci/ruby:2.6.6
43
+ - image: circleci/ruby:2.7
44
44
  steps: *steps
45
- build-ruby258:
45
+ build-ruby26:
46
46
  docker:
47
- - image: circleci/ruby:2.5.8
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-ruby271
55
- - build-ruby266
56
- - build-ruby258
54
+ - build-ruby30
55
+ - build-ruby27
56
+ - build-ruby26
@@ -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
@@ -8,7 +8,7 @@ AllCops:
8
8
  - .*/**/*
9
9
  - vendor/**/*
10
10
  NewCops: enable
11
- TargetRubyVersion: 2.5
11
+ TargetRubyVersion: 2.6
12
12
 
13
13
  # Limit lines to 90 characters.
14
14
  Layout/LineLength:
@@ -71,4 +71,4 @@ Naming/FileName:
71
71
  - Guardfile
72
72
 
73
73
  Lint/UriEscapeUnescape:
74
- Enabled: false
74
+ Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,3 +1,26 @@
1
+ ## 5.2.0 (Oct 15, 2021)
2
+
3
+ * Add support for Salesforce's Composite API and Composite Batch API (@meenie, @amacdougall)
4
+ * Improve the performance of counting numbers of query results with `Restforce::Collection#count`, avoiding unnecessary API requests (@jhass)
5
+
6
+ ## 5.1.1 (Oct 13, 2021)
7
+
8
+ * Handle the `INVALID_REPLICATION_DATE` error returned by Salesforce (@michaelwnyc)
9
+ * Handle the `BIG_OBJECT_UNSUPPORTED_OPERATION` error returned by Salesforce (@remon)
10
+
11
+ ## 5.1.0 (Aug 26, 2021)
12
+
13
+ * Add official support for Ruby 3.0 (@timrogers)
14
+ * Drop support for Ruby 2.5, which has reached end-of-life (@timrogers)
15
+ * Handle the `QUERY_TIMEOUT` error returned by Salesforce (@timrogers)
16
+ * Remove unnecessary development dependencies for the gem, which can just be in the project's `Gemfile` (@timrogers)
17
+
18
+ ## 5.0.6 (Jun 17, 2021)
19
+
20
+ * Handle the `API_DISABLED_FOR_ORG` error returned by Salesforce (@cmac)
21
+ * Handle the `METHOD_NOT_ALLOWED` error returned by Salesforce (@timrogers)
22
+ * Handle the `APEX_ERROR` error returned by Salesforce (@timrogers)
23
+
1
24
  ## 5.0.5 (Feb 17, 2021)
2
25
 
3
26
  * Handle the `CANNOT_EXECUTE_FLOW_TRIGGER` error returned by Salesforce (@almusavi, @timrogers)
data/Gemfile CHANGED
@@ -3,11 +3,15 @@
3
3
  source 'https://rubygems.org'
4
4
  gemspec
5
5
 
6
+ gem 'faye' unless RUBY_PLATFORM == 'java'
7
+ gem 'guard-rspec'
8
+ gem 'guard-rubocop'
6
9
  gem 'jruby-openssl', platforms: :jruby
7
- gem 'jwt'
8
10
  gem 'rake'
9
-
10
- group :development do
11
- gem 'guard-rspec'
12
- gem 'guard-rubocop'
13
- 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
@@ -12,6 +12,8 @@ Features include:
12
12
  * Support for parent-to-child relationships.
13
13
  * Support for aggregate queries.
14
14
  * Support for the [Streaming API](#streaming)
15
+ * Support for the [Composite API](#composite-api)
16
+ * Support for the [Composite Batch API](#composite-batch-api)
15
17
  * Support for the GetUpdated API
16
18
  * Support for blob data types.
17
19
  * Support for GZIP compression.
@@ -25,7 +27,7 @@ Features include:
25
27
 
26
28
  Add this line to your application's Gemfile:
27
29
 
28
- gem 'restforce', '~> 5.0.5'
30
+ gem 'restforce', '~> 5.2.0'
29
31
 
30
32
  And then execute:
31
33
 
@@ -35,8 +37,9 @@ Or install it yourself as:
35
37
 
36
38
  $ gem install restforce
37
39
 
38
- __As of version 5.0.0, this gem is only compatible with Ruby 2.5.0 and later.__ If you're using an earlier Ruby version:
40
+ __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
41
 
42
+ * for Ruby 2.5, use version 5.0.6 or earlier
40
43
  * for Ruby 2.4, use version 4.3.0 or earlier
41
44
  * for Ruby 2.3, use version 3.2.0 or earlier
42
45
  * for Ruby versions 2.2, 2.1 and 2.0, use version 2.5.3 or earlier
@@ -459,7 +462,7 @@ info.user_id
459
462
 
460
463
  ### File Uploads
461
464
 
462
- 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):
465
+ 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):
463
466
 
464
467
  ```ruby
465
468
  client.create('Document', FolderId: '00lE0000000FJ6H',
@@ -477,7 +480,7 @@ client.create('Document', FolderId: '00lE0000000FJ6H',
477
480
  Body: Base64::encode64(File.read('image.jpg'))
478
481
  ```
479
482
 
480
- _See also: [Inserting or updating blob data](http://www.salesforce.com/us/developer/docs/api_rest/Content/dome_sobject_insert_update_blob.htm)_
483
+ _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)_
481
484
 
482
485
  * * *
483
486
 
@@ -572,6 +575,52 @@ end
572
575
  Boom, you're now receiving push notifications when Accounts are
573
576
  created/updated.
574
577
 
578
+ #### Composite API
579
+
580
+ Restforce supports the [Composite API](https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_composite_composite.htm).
581
+ This feature permits the user to send a composite object—that is, a complex
582
+ object with nested children—in a single API call. Up to 25 requests may be
583
+ included in a single composite.
584
+
585
+ Note that `GET` is not yet implemented for this API.
586
+
587
+ ```ruby
588
+ # build up an array of requests:
589
+ requests << {
590
+ method: :update,
591
+ sobject: sobject, # e.g. "Contact"
592
+ reference_id: reference_id,
593
+ data: data
594
+ }
595
+
596
+ # send every 25 requests as a subrequest in a single composite call
597
+ requests.each_slice(25).map do |req_slice|
598
+ client.composite do |subrequest|
599
+ req_slice.each do |r|
600
+ subrequest.send *r.values
601
+ end
602
+ end
603
+ end
604
+
605
+ # note that we're using `map` to return an array of each responses to each
606
+ # composite call; 100 requests will produce 4 responses
607
+ ```
608
+
609
+ #### Composite Batch API
610
+
611
+ Restforce supports the [Composite Batch API](https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_composite_batch.htm).
612
+ This feature permits up to 25 subrequests in a single request, though each
613
+ subrequest counts against the API limit. On the other hand, it has fewer
614
+ limitations than the Composite API.
615
+
616
+ ```
617
+ client.batch do |subrequests|
618
+ subrequests.create('Object', name: 'test')
619
+ subrequests.update('Object', id: '123', name: 'test')
620
+ subrequests.destroy('Object', '123')
621
+ end
622
+ ```
623
+
575
624
  #### Replaying Events
576
625
 
577
626
  Since API version 37.0, Salesforce stores events for 24 hours and they can be
@@ -8,5 +8,6 @@ module Restforce
8
8
  include Restforce::Concerns::Caching
9
9
  include Restforce::Concerns::API
10
10
  include Restforce::Concerns::BatchAPI
11
+ include Restforce::Concerns::CompositeAPI
11
12
  end
12
13
  end
@@ -27,12 +27,26 @@ module Restforce
27
27
  @raw_page['records'].size
28
28
  end
29
29
 
30
- # Return the size of the Collection without making any additional requests.
30
+ # Return the number of items in the Collection without making any additional
31
+ # requests and going through all of the pages of results, one by one. Instead,
32
+ # we can rely on the total count of results which Salesforce returns.
31
33
  def size
32
34
  @raw_page['totalSize']
33
35
  end
34
36
  alias length size
35
37
 
38
+ def count(*args)
39
+ # By default, `Enumerable`'s `#count` uses `#each`, which means going through all
40
+ # of the pages of results, one by one. Instead, we can use `#size` which we have
41
+ # already overridden to work in a smarter, more efficient way. This only works for
42
+ # the simple version of `#count` with no arguments. When called with an argument or
43
+ # a block, you need to know what the items in the collection actually are, so we
44
+ # call `super` and end up iterating through each item in the collection.
45
+ return size unless block_given? || !args.empty?
46
+
47
+ super
48
+ end
49
+
36
50
  # Returns true if the size of the Collection is zero.
37
51
  def empty?
38
52
  size.zero?
@@ -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
@@ -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?
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'restforce/concerns/verbs'
4
+
5
+ module Restforce
6
+ module Concerns
7
+ module CompositeAPI
8
+ extend Restforce::Concerns::Verbs
9
+
10
+ define_verbs :post
11
+
12
+ def composite(all_or_none: false, collate_subrequests: false)
13
+ subrequests = Subrequests.new(options)
14
+ yield(subrequests)
15
+
16
+ if subrequests.requests.length > 25
17
+ raise ArgumentError, 'Cannot have more than 25 subrequests.'
18
+ end
19
+
20
+ properties = {
21
+ compositeRequest: subrequests.requests,
22
+ allOrNone: all_or_none,
23
+ collateSubrequests: collate_subrequests
24
+ }
25
+ response = api_post('composite', properties.to_json)
26
+
27
+ results = response.body['CompositeResponse']
28
+ has_errors = results.any? { |result| result['HttpStatusCode'].digits.last == 4 }
29
+ if all_or_none && has_errors
30
+ last_error_index = results.rindex { |result| result['HttpStatusCode'] != 412 }
31
+ last_error = results[last_error_index]
32
+ raise CompositeAPIError, last_error['Body'][0]['errorCode']
33
+ end
34
+
35
+ results
36
+ end
37
+
38
+ def composite!(collate_subrequests: false, &block)
39
+ composite(all_or_none: true, collate_subrequests: collate_subrequests, &block)
40
+ end
41
+
42
+ class Subrequests
43
+ def initialize(options)
44
+ @options = options
45
+ @requests = []
46
+ end
47
+ attr_reader :options, :requests
48
+
49
+ def create(sobject, reference_id, attrs)
50
+ requests << {
51
+ method: 'POST',
52
+ url: composite_api_path(sobject),
53
+ body: attrs,
54
+ referenceId: reference_id
55
+ }
56
+ end
57
+
58
+ def update(sobject, reference_id, attrs)
59
+ id = attrs.fetch(attrs.keys.find { |k, _v| k.to_s.casecmp?('id') }, nil)
60
+ raise ArgumentError, 'Id field missing from attrs.' unless id
61
+
62
+ attrs_without_id = attrs.reject { |k, _v| k.to_s.casecmp?('id') }
63
+ requests << {
64
+ method: 'PATCH',
65
+ url: composite_api_path("#{sobject}/#{id}"),
66
+ body: attrs_without_id,
67
+ referenceId: reference_id
68
+ }
69
+ end
70
+
71
+ def destroy(sobject, reference_id, id)
72
+ requests << {
73
+ method: 'DELETE',
74
+ url: composite_api_path("#{sobject}/#{id}"),
75
+ referenceId: reference_id
76
+ }
77
+ end
78
+
79
+ def upsert(sobject, reference_id, ext_field, attrs)
80
+ raise ArgumentError, 'External id field missing.' unless ext_field
81
+
82
+ ext_id = attrs.fetch(attrs.keys.find do |k, _v|
83
+ k.to_s.casecmp?(ext_field.to_s)
84
+ end, nil)
85
+ raise ArgumentError, 'External id missing from attrs.' unless ext_id
86
+
87
+ attrs_without_ext_id = attrs.reject { |k, _v| k.to_s.casecmp?(ext_field) }
88
+ requests << {
89
+ method: 'PATCH',
90
+ url: composite_api_path("#{sobject}/#{ext_field}/#{ext_id}"),
91
+ body: attrs_without_ext_id,
92
+ referenceId: reference_id
93
+ }
94
+ end
95
+
96
+ private
97
+
98
+ def composite_api_path(path)
99
+ "/services/data/v#{options[:api_version]}/sobjects/#{path}"
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -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
@@ -3,8 +3,8 @@
3
3
  module Restforce
4
4
  module ErrorCode
5
5
  GITHUB_ISSUE_URL = "https://github.com/restforce/restforce/issues/new?template=" \
6
- "unhandled-salesforce-error.md&title=Unhandled+Salesforce+error%3A+%3Cinsert+" \
7
- "error+code+here%3E"
6
+ "unhandled-salesforce-error.md&title=Unhandled+Salesforce+error" \
7
+ "%3A+%3Cinsert+error+code+here%3E"
8
8
 
9
9
  # We define all of the known errors returned by Salesforce based on the
10
10
  # documentation at
@@ -17,8 +17,12 @@ module Restforce
17
17
 
18
18
  class AlreadyInProcess < ResponseError; end
19
19
 
20
+ class ApexError < ResponseError; end
21
+
20
22
  class ApiCurrentlyDisabled < ResponseError; end
21
23
 
24
+ class ApiDisabledForOrg < ResponseError; end
25
+
22
26
  class AssigneeTypeRequired < ResponseError; end
23
27
 
24
28
  class BadCustomEntityParentDomain < ResponseError; end
@@ -27,6 +31,8 @@ module Restforce
27
31
 
28
32
  class BccSelfNotAllowedIfBccComplianceEnabled < ResponseError; end
29
33
 
34
+ class BigObjectUnsupportedOperation < ResponseError; end
35
+
30
36
  class CannotCascadeProductActive < ResponseError; end
31
37
 
32
38
  class CannotChangeFieldTypeOfApexReferencedField < ResponseError; end
@@ -233,6 +239,8 @@ module Restforce
233
239
 
234
240
  class InvalidReadOnlyUserDml < ResponseError; end
235
241
 
242
+ class InvalidReplicationDate < ResponseError; end
243
+
236
244
  class InvalidSaveAsActivityFlag < ResponseError; end
237
245
 
238
246
  class InvalidSessionId < ResponseError; end
@@ -303,6 +311,8 @@ module Restforce
303
311
 
304
312
  class MergeFailed < ResponseError; end
305
313
 
314
+ class MethodNotAllowed < ResponseError; end
315
+
306
316
  class MissingArgument < ResponseError; end
307
317
 
308
318
  class NonuniqueShippingAddress < ResponseError; end
@@ -335,6 +345,8 @@ module Restforce
335
345
 
336
346
  class PrivateContactOnAsset < ResponseError; end
337
347
 
348
+ class QueryTimeout < ResponseError; end
349
+
338
350
  class RecordInUseByWorkflow < ResponseError; end
339
351
 
340
352
  class RequestLimitExceeded < ResponseError; end
@@ -396,13 +408,16 @@ module Restforce
396
408
  ERROR_EXCEPTION_CLASSES = {
397
409
  "ALL_OR_NONE_OPERATION_ROLLED_BACK" => AllOrNoneOperationRolledBack,
398
410
  "ALREADY_IN_PROCESS" => AlreadyInProcess,
411
+ "APEX_ERROR" => ApexError,
399
412
  "API_CURRENTLY_DISABLED" => ApiCurrentlyDisabled,
413
+ "API_DISABLED_FOR_ORG" => ApiDisabledForOrg,
400
414
  "ASSIGNEE_TYPE_REQUIRED" => AssigneeTypeRequired,
401
415
  "BAD_CUSTOM_ENTITY_PARENT_DOMAIN" => BadCustomEntityParentDomain,
402
416
  "BCC_NOT_ALLOWED_IF_BCC_COMPLIANCE_ENABLED" =>
403
417
  BccNotAllowedIfBccComplianceEnabled,
404
418
  "BCC_SELF_NOT_ALLOWED_IF_BCC_COMPLIANCE_ENABLED" =>
405
419
  BccSelfNotAllowedIfBccComplianceEnabled,
420
+ "BIG_OBJECT_UNSUPPORTED_OPERATION" => BigObjectUnsupportedOperation,
406
421
  "CANNOT_CASCADE_PRODUCT_ACTIVE" => CannotCascadeProductActive,
407
422
  "CANNOT_CHANGE_FIELD_TYPE_OF_APEX_REFERENCED_FIELD" =>
408
423
  CannotChangeFieldTypeOfApexReferencedField,
@@ -513,6 +528,7 @@ module Restforce
513
528
  "INVALID_PARTNER_NETWORK_STATUS" => InvalidPartnerNetworkStatus,
514
529
  "INVALID_PERSON_ACCOUNT_OPERATION" => InvalidPersonAccountOperation,
515
530
  "INVALID_READ_ONLY_USER_DML" => InvalidReadOnlyUserDml,
531
+ "INVALID_REPLICATION_DATE" => InvalidReplicationDate,
516
532
  "INVALID_SAVE_AS_ACTIVITY_FLAG" => InvalidSaveAsActivityFlag,
517
533
  "INVALID_SESSION_ID" => InvalidSessionId,
518
534
  "INVALID_STATUS" => InvalidStatus,
@@ -548,6 +564,7 @@ module Restforce
548
564
  "MAX_TM_RULES_EXCEEDED" => MaxTmRulesExceeded,
549
565
  "MAX_TM_RULE_ITEMS_EXCEEDED" => MaxTmRuleItemsExceeded,
550
566
  "MERGE_FAILED" => MergeFailed,
567
+ "METHOD_NOT_ALLOWED" => MethodNotAllowed,
551
568
  "MISSING_ARGUMENT" => MissingArgument,
552
569
  "NONUNIQUE_SHIPPING_ADDRESS" => NonuniqueShippingAddress,
553
570
  "NO_APPLICABLE_PROCESS" => NoApplicableProcess,
@@ -564,6 +581,7 @@ module Restforce
564
581
  "PLATFORM_EVENT_PUBLISH_FAILED" => PlatformEventPublishFailed,
565
582
  "PORTAL_USER_ALREADY_EXISTS_FOR_CONTACT" => PortalUserAlreadyExistsForContact,
566
583
  "PRIVATE_CONTACT_ON_ASSET" => PrivateContactOnAsset,
584
+ "QUERY_TIMEOUT" => QueryTimeout,
567
585
  "RECORD_IN_USE_BY_WORKFLOW" => RecordInUseByWorkflow,
568
586
  "REQUEST_LIMIT_EXCEEDED" => RequestLimitExceeded,
569
587
  "REQUEST_RUNNING_TOO_LONG" => RequestRunningTooLong,
@@ -597,9 +615,9 @@ module Restforce
597
615
  def self.get_exception_class(error_code)
598
616
  ERROR_EXCEPTION_CLASSES.fetch(error_code) do |_|
599
617
  warn "[restforce] An unrecognised error code, `#{error_code}` has been " \
600
- "received from Salesforce. Instead of raising an error-specific exception, " \
601
- "we'll raise a generic `ResponseError`. Please report this missing error code" \
602
- " on GitHub at <#{GITHUB_ISSUE_URL}>."
618
+ "received from Salesforce. Instead of raising an error-specific exception" \
619
+ ", we'll raise a generic `ResponseError`. Please report this missing " \
620
+ "error code on GitHub at <#{GITHUB_ISSUE_URL}>."
603
621
 
604
622
  # If we've received an unexpected error where we don't have a specific
605
623
  # class defined, we can return a generic ResponseError instead
@@ -609,10 +627,10 @@ module Restforce
609
627
 
610
628
  def self.const_missing(constant_name)
611
629
  warn "[restforce] You're referring to a Restforce error that isn't defined, " \
612
- "`#{name}::#{constant_name}` (for example by trying to `rescue` it). This might " \
613
- "be our fault - we've recently made some changes to how errors are defined. If " \
614
- "you're sure that this is a valid Salesforce error, then please create an " \
615
- "issue on GitHub at <#{GITHUB_ISSUE_URL}>."
630
+ "`#{name}::#{constant_name}` (for example by trying to `rescue` it). This " \
631
+ "might be our fault - we've recently made some changes to how errors are " \
632
+ "defined. If you're sure that this is a valid Salesforce error, then " \
633
+ "please create an issue on GitHub at <#{GITHUB_ISSUE_URL}>."
616
634
 
617
635
  super(constant_name)
618
636
  end
@@ -20,9 +20,9 @@ module Restforce
20
20
  def call(env)
21
21
  debug('request') do
22
22
  dump url: env[:url].to_s,
23
- method: env[:method],
24
- headers: env[:request_headers],
25
- body: env[:body]
23
+ method: env[:method],
24
+ headers: env[:request_headers],
25
+ body: env[:body]
26
26
  end
27
27
  super
28
28
  end
@@ -30,8 +30,8 @@ module Restforce
30
30
  def on_complete(env)
31
31
  debug('response') do
32
32
  dump status: env[:status].to_s,
33
- headers: env[:response_headers],
34
- body: env[:body]
33
+ headers: env[:response_headers],
34
+ body: env[:body]
35
35
  end
36
36
  end
37
37
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Restforce
4
- VERSION = '5.0.5'
4
+ VERSION = '5.2.0'
5
5
  end
data/lib/restforce.rb CHANGED
@@ -32,6 +32,7 @@ module Restforce
32
32
  autoload :Base, 'restforce/concerns/base'
33
33
  autoload :API, 'restforce/concerns/api'
34
34
  autoload :BatchAPI, 'restforce/concerns/batch_api'
35
+ autoload :CompositeAPI, 'restforce/concerns/composite_api'
35
36
  end
36
37
 
37
38
  module Data
@@ -48,6 +49,7 @@ module Restforce
48
49
  UnauthorizedError = Class.new(Faraday::ClientError)
49
50
  APIVersionError = Class.new(Error)
50
51
  BatchAPIError = Class.new(Error)
52
+ CompositeAPIError = Class.new(Error)
51
53
 
52
54
  # Inherit from Faraday::ResourceNotFound for backwards-compatibility
53
55
  # Consumers of this library that rescue and handle Faraday::ResourceNotFound
data/restforce.gemspec CHANGED
@@ -22,20 +22,10 @@ Gem::Specification.new do |gem|
22
22
  'changelog_uri' => 'https://github.com/restforce/restforce/blob/master/CHANGELOG.md'
23
23
  }
24
24
 
25
- gem.required_ruby_version = '>= 2.5'
25
+ gem.required_ruby_version = '>= 2.6'
26
26
 
27
27
  gem.add_dependency 'faraday', '<= 2.0', '>= 0.9.0'
28
28
  gem.add_dependency 'faraday_middleware', ['>= 0.8.8', '<= 2.0']
29
-
30
- gem.add_dependency 'jwt', ['>= 1.5.6']
31
-
32
29
  gem.add_dependency 'hashie', '>= 1.2.0', '< 5.0'
33
-
34
- gem.add_development_dependency 'faye' unless RUBY_PLATFORM == 'java'
35
- gem.add_development_dependency 'rspec', '~> 2.14.0'
36
- gem.add_development_dependency 'rspec_junit_formatter', '~> 0.4.1'
37
-
38
- gem.add_development_dependency 'rubocop', '~> 1.9.1'
39
- gem.add_development_dependency 'simplecov', '~> 0.21.2'
40
- gem.add_development_dependency 'webmock', '~> 3.11.1'
30
+ gem.add_dependency 'jwt', ['>= 1.5.6']
41
31
  end