|
1 | | -using System; |
| 1 | +using NetCoreForce.Client.Enumerations; |
| 2 | +using NetCoreForce.Client.Models; |
| 3 | +using System; |
2 | 4 | using System.Collections.Generic; |
3 | 5 | using System.Diagnostics; |
4 | 6 | using System.IO; |
| 7 | +using System.Linq; |
5 | 8 | using System.Net.Http; |
6 | 9 | using System.Runtime.CompilerServices; |
7 | 10 | using System.Text.RegularExpressions; |
8 | 11 | using System.Threading; |
9 | 12 | using System.Threading.Tasks; |
10 | | -using NetCoreForce.Client.Models; |
11 | 13 |
|
12 | 14 | namespace NetCoreForce.Client |
13 | 15 | { |
@@ -521,7 +523,7 @@ public async Task UpdateRecord<T>( |
521 | 523 | } |
522 | 524 |
|
523 | 525 | /// <summary> |
524 | | - /// Update multiple reocrds. |
| 526 | + /// Update multiple records. |
525 | 527 | /// The list can contain up to 200 objects. |
526 | 528 | /// The list can contain objects of different types, including custom objects. |
527 | 529 | /// Each object must contain an attributes map. The map must contain a value for type. |
@@ -636,6 +638,110 @@ public async Task DeleteRecord(string sObjectTypeName, string objectId) |
636 | 638 | return; |
637 | 639 | } |
638 | 640 |
|
| 641 | + /// <summary> |
| 642 | + /// Execute multiple composite records. |
| 643 | + /// The list can contain up to 200 objects. |
| 644 | + /// The list can contain objects of different types, including custom objects. |
| 645 | + /// Each object must contain an attributes map. The map must contain a value for type. |
| 646 | + /// </summary> |
| 647 | + /// <param name="sObjects">Objects to update</param> |
| 648 | + /// <param name="allOrNone">Optional. Indicates whether to roll back the entire request when the update of any object fails (true) or to continue with the independent update of other objects in the request. The default is false.</param> |
| 649 | + /// <param name="collateSubrequests">Optional. Controls whether the API collates unrelated subrequests to bulkify them (true) or not (false). When subrequests are collated, the processing speed is faster, but the order of execution is not guaranteed (unless there is an explicit dependency between the subrequests).If collation is disabled, then the subrequests are executed in the order in which they are received. The default is true.</param> |
| 650 | + /// <param name="customHeaders">Custom headers to include in request (Optional). await The HeaderFormatter helper class can be used to generate the custom header as needed.</param> |
| 651 | + /// <returns>List of UpdateMultipleResponse objects, includes response for each object (id, success, errors)</returns> |
| 652 | + /// <exception cref="ArgumentException">Thrown when missing required information</exception> |
| 653 | + /// <exception cref="ForceApiException">Thrown when update fails</exception> |
| 654 | + public async Task<CompositeRequestResponse> ExecuteCompositeRecords( |
| 655 | + List<CompositeSObject> sObjects, |
| 656 | + bool allOrNone = false, |
| 657 | + bool collateSubrequests = true, |
| 658 | + Dictionary<string, string> customHeaders = null) |
| 659 | + { |
| 660 | + if (sObjects == null) |
| 661 | + { |
| 662 | + throw new ArgumentNullException("sObjects"); |
| 663 | + } |
| 664 | + |
| 665 | + foreach (CompositeSObject s in sObjects) |
| 666 | + { |
| 667 | + if (s == null || (string.IsNullOrEmpty(s.Type) && s.CompositeType == CompositeType.SObject)) |
| 668 | + { |
| 669 | + throw new ForceApiException("Objects are missing Type property in Attributes map"); |
| 670 | + } |
| 671 | + } |
| 672 | + |
| 673 | + Dictionary<string, string> headers = new Dictionary<string, string>(); |
| 674 | + |
| 675 | + //Add call options |
| 676 | + Dictionary<string, string> callOptions = HeaderFormatter.SforceCallOptions(ClientName); |
| 677 | + headers.AddRange(callOptions); |
| 678 | + |
| 679 | + //Add custom headers if specified |
| 680 | + if (customHeaders != null) |
| 681 | + { |
| 682 | + headers.AddRange(customHeaders); |
| 683 | + } |
| 684 | + |
| 685 | + var uri = UriFormatter.CompositeRequest(InstanceUrl, ApiVersion); |
| 686 | + |
| 687 | + JsonClient client = new JsonClient(AccessToken, _httpClient); |
| 688 | + |
| 689 | + List<CompositeSubRequest> subRequests = sObjects.Select(s => |
| 690 | + { |
| 691 | + return new CompositeSubRequest( |
| 692 | + s.SObject, |
| 693 | + s.Method == CompositeMethod.Write ? string.IsNullOrWhiteSpace(s.Id) ? "POST" : "PATCH" : s.Method == CompositeMethod.Delete ? "DELETE" : "GET", |
| 694 | + s.ReferenceId, |
| 695 | + s.CompositeType == CompositeType.SObject ? UriFormatter.CompositeSubRequest(ApiVersion, s.Type, s.Id) : UriFormatter.CompositeSObjectCollectionsSubRequest(ApiVersion) |
| 696 | + ); |
| 697 | + }).ToList(); |
| 698 | + |
| 699 | + CompositeRequest createMultipleRequest = new CompositeRequest(subRequests, allOrNone, collateSubrequests); |
| 700 | + |
| 701 | + return await client.HttpPostAsync<CompositeRequestResponse>(createMultipleRequest, uri, headers); |
| 702 | + |
| 703 | + } |
| 704 | + |
| 705 | + /// <summary> |
| 706 | + /// Execute request against ApexRest custom endpoints. |
| 707 | + /// </summary> |
| 708 | + /// <param name="apexResourceUrl">The URL of the apex resource. Ex: /services/apexrest/DuplicateCheck should provide "DuplicateCheck"</param> |
| 709 | + /// <param name="request">The custom object to include in the request</param> |
| 710 | + /// <param name="customHeaders">Custom headers to include in request (Optional). await The HeaderFormatter helper class can be used to generate the custom header as needed.</param> |
| 711 | + /// <returns>List of UpdateMultipleResponse objects, includes response for each object (id, success, errors)</returns> |
| 712 | + /// <exception cref="ArgumentException">Thrown when missing required information</exception> |
| 713 | + /// <exception cref="ForceApiException">Thrown when update fails</exception> |
| 714 | + public async Task<T> ExecuteApexPost<Request, T>(string apexResourceUrl, Request request, Dictionary<string, string> customHeaders = null) |
| 715 | + { |
| 716 | + if (request == null) |
| 717 | + { |
| 718 | + throw new ArgumentNullException(nameof(request)); |
| 719 | + } |
| 720 | + if (string.IsNullOrWhiteSpace(apexResourceUrl)) |
| 721 | + { |
| 722 | + throw new ArgumentNullException(nameof(apexResourceUrl)); |
| 723 | + } |
| 724 | + |
| 725 | + Dictionary<string, string> headers = new Dictionary<string, string>(); |
| 726 | + |
| 727 | + //Add call options |
| 728 | + Dictionary<string, string> callOptions = HeaderFormatter.SforceCallOptions(ClientName); |
| 729 | + headers.AddRange(callOptions); |
| 730 | + |
| 731 | + //Add custom headers if specified |
| 732 | + if (customHeaders != null) |
| 733 | + { |
| 734 | + headers.AddRange(customHeaders); |
| 735 | + } |
| 736 | + |
| 737 | + var uri = UriFormatter.ApexUri(InstanceUrl, apexResourceUrl); |
| 738 | + |
| 739 | + JsonClient client = new JsonClient(AccessToken, _httpClient); |
| 740 | + |
| 741 | + return await client.HttpPostAsync<T>(request, uri, headers); |
| 742 | + |
| 743 | + } |
| 744 | + |
639 | 745 | const string blobUrlRegexString = @"^.+sobjects\/(\w+)\/(\w+)\/(\w+)$"; |
640 | 746 | /// <summary> |
641 | 747 | /// Retrieve blob data at the specified URL. |
@@ -739,7 +845,7 @@ public async Task<OrganizationLimits> GetOrganizationLimits() |
739 | 845 |
|
740 | 846 | /// <summary> |
741 | 847 | /// List summary information about each REST API version currently available, including the version, label, and a link to each version's root. |
742 | | - /// You do not need authentication to retrieve the list of versions. |
| 848 | + /// You do not need authentication to retrieve the list of versions. |
743 | 849 | /// </summary> |
744 | 850 | /// <param name="currentInstanceUrl">Current instance URL. If the client has been initialized, the parameter is optional and the client's current instance URL will be used</param> |
745 | 851 | /// <returns>List of SalesforceVersion objects</returns> |
|
0 commit comments