//public IList<CompositeSubRequest> UpsertExternal<T>(string referenceId, string objectName, string externalFieldName, IList<T> records) //{ // return UpsertExternal(referenceId, false, externalFieldName, records); //} //public IList<CompositeSubRequest> UpsertExternal<T>(string referenceId, bool allOrNone, string externalFieldName, IList<T> records) //{ // if (string.IsNullOrEmpty(referenceId)) throw new ArgumentNullException("referenceId"); // if (records == null || !records.Any()) throw new ArgumentNullException("records"); // var result = new List<CompositeSubRequest>(); // if (allOrNone && records.Count() > 200) throw new ArgumentOutOfRangeException("records"); // foreach (var (chunk, chunkIdx) in EnumerableChunk.Create(records, 200).Select((chunk, chunkIdx) => (chunk, chunkIdx))) // { // var bodyRecords = JToken.FromObject(chunk.Select(record => Dnf.UnFlatten(JObject.FromObject(record)))); // var request = new CompositeSubRequest // { // ResponseType = "collections", // Body = new JObject // { // ["allOrNone"] = allOrNone, // ["records"] = bodyRecords // }, // Method = "PATCH", // ReferenceId = $"{referenceId}_{chunkIdx}", // Url = "composite/sobjects" // }; // CompositeRequests.Add(request); // result.Add(request); // } // return result; //} public IList <CompositeSubRequest> Delete(string referenceId, bool allOrNone, params string[] ids) { if (string.IsNullOrEmpty(referenceId)) { throw new ArgumentNullException(nameof(referenceId)); } if (ids == null || ids.Length == 0) { throw new ArgumentNullException(nameof(ids)); } if (allOrNone && ids.Length > 200) { throw new ArgumentOutOfRangeException(nameof(ids)); } var result = new List <CompositeSubRequest>(); foreach (var(chunk, chunkIdx) in EnumerableChunk.Create(ids, 200).Select((chunk, chunkIdx) => (chunk, chunkIdx))) { var request = new CompositeSubRequest { ResponseType = "collections", Method = "DELETE", ReferenceId = $"{referenceId}_{chunkIdx}", Url = $"composite/sobjects?ids={string.Join(",", chunk.Select(Uri.EscapeDataString))}{(allOrNone ? "&allOrNone=" : "")}" }; CompositeRequests.Add(request); result.Add(request); } return(result); }
public static IEnumerable <string> ChunkIds(IEnumerable <string> source, string soql, string template) { soql = soql.Trim().Replace("\r\n", "\n"); // var soqlMaxLen = 20000; var nonTemplateLength = soql.Replace(template, "").Length; // var idsTextLen = soqlMaxLen - nonTemplateLength; var idsTextLen = SoqlMaxLength - nonTemplateLength; var numOfTemplate = (int)Math.Ceiling((soql.Length - nonTemplateLength) / (double)template.Length); var numOfId = (int)Math.Max(1, Math.Floor(idsTextLen / (18.0 * numOfTemplate))); return(EnumerableChunk.Create(source, numOfId) .Select(l => soql.Replace(template, string.Join(",", l.Select(id => SoqlString(ToId15(id))))))); }
public async IAsyncEnumerable <QueryResult <T> > QueryByLocatorAsync <T>(QueryResult <T>?queryResult, int compositeLimit) { if (queryResult == null) { yield break; } yield return(queryResult); // batch size can be changed via Sforce-Query-Options header // i.e. request.Query(referenceId, query).HttpHeaders = new HttpHeaders().QueryOptions(200); // https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/headers_queryoptions.htm // The default is 2,000; the minimum is 200, and the maximum is 2,000. // There is no guarantee that the requested batch size is the actual batch size. // Changes are made as necessary to maximize performance. if (compositeLimit > Dnf.CompositeQueryLimit) { compositeLimit = Dnf.CompositeQueryLimit; } var batchSize = GetBatchSizeByUrl(queryResult.NextRecordsUrl); var batches = PredictQueryLocators(queryResult.NextRecordsUrl, queryResult.Records?.Count ?? 0, queryResult.TotalSize - (queryResult.Records?.Count ?? 0), batchSize); var chunks = EnumerableChunk.Create(batches, compositeLimit); foreach (var(batch, _) in chunks.Select((batch, batchIdx) => (batch, batchIdx))) { //await Dnf.QueryCursorThrottler.WaitAsync().ConfigureAwait(true); //try //{ await foreach (var chunkResult in QueryByChunkAsync <T>(batch) .ConfigureAwait(false)) { // if (batchIdx > 0 && recordIdx == 0) // await tasks[batchIdx - 1].ConfigureAwait(false); //queryResult.Records.Add(record); //queryResult.Done = queryResult.Records.Count >= queryResult.TotalSize; yield return(chunkResult); } //} //finally //{ // Dnf.QueryCursorThrottler.Release(); //} } }
public IList <CompositeSubRequest> RetrieveExternal(string referenceId, string objectName, string externalFieldName, IList <string> externalIds, params string[] fields) { if (string.IsNullOrEmpty(referenceId)) { throw new ArgumentNullException(nameof(referenceId)); } if (string.IsNullOrEmpty(objectName)) { throw new ArgumentNullException(nameof(objectName)); } if (string.IsNullOrEmpty(externalFieldName)) { throw new ArgumentNullException(nameof(externalFieldName)); } if (externalIds == null || !externalIds.Any()) { throw new ArgumentNullException(nameof(externalIds)); } if (fields == null || fields.Length == 0) { throw new ArgumentNullException(nameof(fields)); } var result = new List <CompositeSubRequest>(); foreach (var(chunk, chunkIdx) in EnumerableChunk.Create(externalIds, 2000).Select((chunk, chunkIdx) => (chunk, chunkIdx))) { var request = new CompositeSubRequest { ResponseType = "collections", Body = new JObject { ["ids"] = JToken.FromObject(chunk.Select(id => id)), ["fields"] = JToken.FromObject(fields) }, Method = "POST", ReferenceId = $"{referenceId}_{chunkIdx}", Url = $"composite/sobjects/{objectName}/{externalFieldName}" }; CompositeRequests.Add(request); result.Add(request); } return(result); }
public IList <CompositeSubRequest> Create <T>(string referenceId, bool allOrNone, IList <T> records) { if (string.IsNullOrEmpty(referenceId)) { throw new ArgumentNullException(nameof(referenceId)); } if (records == null || !records.Any()) { throw new ArgumentNullException(nameof(records)); } if (allOrNone && records.Count > 200) { throw new ArgumentOutOfRangeException(nameof(records)); } var result = new List <CompositeSubRequest>(); foreach (var(chunk, chunkIdx) in EnumerableChunk.Create(records, 200).Select((chunk, chunkIdx) => (chunk, chunkIdx))) { var bodyRecords = JToken.FromObject(chunk.Select(record => record == null ? new JObject() : Dnf.UnFlatten(JObject.FromObject(record)))); var request = new CompositeSubRequest { ResponseType = "collections", Body = new JObject { ["allOrNone"] = allOrNone, ["records"] = bodyRecords }, Method = "POST", ReferenceId = $"{referenceId}_{chunkIdx}", Url = "composite/sobjects" }; CompositeRequests.Add(request); result.Add(request); } return(result); }
public static string?EscapeDataString(string?uri) { return(uri == null ? null : string.Join("", EnumerableChunk.Create(uri, 65519).Select(c => Uri.EscapeDataString(new string(c.ToArray()))))); }