public BatchSubRequest Update(string objectName, string recordId, object record)
        {
            if (string.IsNullOrEmpty(objectName))
            {
                throw new ArgumentNullException(nameof(objectName));
            }
            if (string.IsNullOrEmpty(recordId))
            {
                throw new ArgumentNullException(nameof(recordId));
            }
            if (record == null)
            {
                throw new ArgumentNullException(nameof(record));
            }

            var richInput = Dnf.UnFlatten(JObject.FromObject(record));
            var request   = new BatchSubRequest
            {
                RichInput = Dnf.Omit(richInput, "Id"),
                Method    = "PATCH",
                Url       = $"sobjects/{objectName}/{recordId}"
            };

            BatchRequests.Add(request);
            return(request);
        }
        public BatchSubRequest UpsertExternal(string objectName, string externalFieldName, string externalId, object record)
        {
            if (string.IsNullOrEmpty(objectName))
            {
                throw new ArgumentNullException(nameof(objectName));
            }
            if (string.IsNullOrEmpty(externalId))
            {
                throw new ArgumentNullException(nameof(externalId));
            }
            if (record == null)
            {
                throw new ArgumentNullException(nameof(record));
            }

            var richInput = Dnf.UnFlatten(JObject.FromObject(record));
            var request   = new BatchSubRequest
            {
                RichInput = Dnf.Omit(richInput, externalFieldName),
                Method    = "PATCH",
                Url       = $"sobjects/{objectName}/{externalFieldName}/{Uri.EscapeDataString(externalId)}"
            };

            BatchRequests.Add(request);
            return(request);
        }
        public async Task <SaveResponse> CreateTreeAsync <T>(string objectName, IList <T> objectTree)
        {
            if (string.IsNullOrEmpty(objectName))
            {
                throw new ArgumentNullException(nameof(objectName));
            }

            if (objectTree == null || !objectTree.Any())
            {
                throw new ArgumentNullException(nameof(objectTree));
            }

            if (typeof(IAttributedObject).IsAssignableFrom(typeof(T)))
            {
                return(await Dnf.TryDeserializeObjectAsync(
                           JsonHttp.HttpPostAsync <SaveResponse>(
                               new CreateRequest {
                    Records = objectTree.Cast <IAttributedObject>().ToList()
                },
                               $"composite/tree/{objectName}"))
                       .ConfigureAwait(false) ?? new SaveResponse());
            }
            return(await Dnf.TryDeserializeObjectAsync(
                       JsonHttp.HttpPostAsync <SaveResponse>(
                           new JObject {
                ["records"] = JToken.FromObject(objectTree)
            },
                           $"composite/tree/{objectName}"))
                   .ConfigureAwait(false) ?? new SaveResponse());
        }
        public CompositeSubRequest Update(string referenceId, string objectName, string recordId, object record)
        {
            if (string.IsNullOrEmpty(referenceId))
            {
                throw new ArgumentNullException(nameof(referenceId));
            }
            if (string.IsNullOrEmpty(objectName))
            {
                throw new ArgumentNullException(nameof(objectName));
            }
            if (string.IsNullOrEmpty(recordId))
            {
                throw new ArgumentNullException(nameof(recordId));
            }
            if (record == null)
            {
                throw new ArgumentNullException(nameof(record));
            }

            var body    = Dnf.UnFlatten(JObject.FromObject(record));
            var request = new CompositeSubRequest
            {
                Body        = Dnf.Omit(body, "Id"),
                Method      = "PATCH",
                ReferenceId = referenceId,
                Url         = $"sobjects/{objectName}{recordId}"
            };

            CompositeRequests.Add(request);
            return(request);
        }
        public BatchSubRequest Search(string query)
        {
            if (string.IsNullOrEmpty(query))
            {
                throw new ArgumentNullException(nameof(query));
            }
            if (!query.Contains("FIND"))
            {
                throw new ArgumentException("query does not contain FIND");
            }
            if (!query.Contains("{") || !query.Contains("}"))
            {
                throw new ArgumentException("search term must be wrapped in braces");
            }

            var request = new BatchSubRequest
            {
                ResponseType = "query",
                Method       = "GET",
                Url          = $"search?q={Dnf.EscapeDataString(query)}"
            };

            BatchRequests.Add(request);
            return(request);
        }
        public CompositeSubRequest UpsertExternal(string referenceId, string objectName, string externalFieldName, string externalId, object record)
        {
            if (string.IsNullOrEmpty(referenceId))
            {
                throw new ArgumentNullException(nameof(referenceId));
            }
            if (string.IsNullOrEmpty(objectName))
            {
                throw new ArgumentNullException(nameof(objectName));
            }
            if (string.IsNullOrEmpty(externalId))
            {
                throw new ArgumentNullException(nameof(externalId));
            }
            if (record == null)
            {
                throw new ArgumentNullException(nameof(record));
            }

            var body    = Dnf.UnFlatten(JObject.FromObject(record));
            var request = new CompositeSubRequest
            {
                Body        = Dnf.Omit(body, externalFieldName),
                Method      = "PATCH",
                ReferenceId = referenceId,
                Url         = $"sobjects/{objectName}/{externalFieldName}/{Uri.EscapeDataString(externalId)}"
            };

            CompositeRequests.Add(request);
            return(request);
        }
        public BatchSubRequest Update(string objectName, object record)
        {
            if (string.IsNullOrEmpty(objectName))
            {
                throw new ArgumentNullException(nameof(objectName));
            }
            if (record == null)
            {
                throw new ArgumentNullException(nameof(record));
            }

            var richInput = Dnf.UnFlatten(JObject.FromObject(record));

            return(Update(objectName, richInput["Id"]?.ToString() ?? string.Empty, Dnf.Omit(richInput, "Id")));
        }
        public BatchSubRequest UpsertExternal(string objectName, string externalFieldName, object record)
        {
            if (string.IsNullOrEmpty(objectName))
            {
                throw new ArgumentNullException(nameof(objectName));
            }
            if (record == null)
            {
                throw new ArgumentNullException(nameof(record));
            }

            var richInput = Dnf.UnFlatten(JObject.FromObject(record));

            return(UpsertExternal(objectName, externalFieldName, richInput[externalFieldName]?.ToString() ?? string.Empty, Dnf.Omit(richInput, externalFieldName)));
        }
        public BatchSubRequest ExplainAll(string query)
        {
            if (string.IsNullOrEmpty(query))
            {
                throw new ArgumentNullException(nameof(query));
            }

            var request = new BatchSubRequest
            {
                Method = "GET",
                Url    = $"queryAll?explain={Dnf.EscapeDataString(query)}"
            };

            BatchRequests.Add(request);
            return(request);
        }
Exemple #10
0
        public BatchSubRequest Query(string query)
        {
            if (string.IsNullOrEmpty(query))
            {
                throw new ArgumentNullException(nameof(query));
            }

            var request = new BatchSubRequest
            {
                ResponseType = "query",
                Method       = "GET",
                Url          = $"query?q={Dnf.EscapeDataString(query)}"
            };

            BatchRequests.Add(request);
            return(request);
        }
        public async IAsyncEnumerable <QueryResult <T> > SearchAsync <T>(string q)
        {
            if (string.IsNullOrEmpty(q))
            {
                throw new ArgumentNullException(nameof(q));
            }

            var resourceName = $"tooling/search?q={Dnf.EscapeDataString(q)}";
            var result       = await JsonHttp.HttpGetAsync <QueryResult <T> >(resourceName)
                               .ConfigureAwait(false);

            await foreach (var nextResult in QueryByLocatorAsync(result)
                           .ConfigureAwait(false))
            {
                yield return(nextResult);
            }
        }
        public CompositeSubRequest UpsertExternal(string referenceId, string objectName, string externalFieldName, object record)
        {
            if (string.IsNullOrEmpty(referenceId))
            {
                throw new ArgumentNullException(nameof(referenceId));
            }
            if (string.IsNullOrEmpty(objectName))
            {
                throw new ArgumentNullException(nameof(objectName));
            }
            if (record == null)
            {
                throw new ArgumentNullException(nameof(record));
            }

            var body = Dnf.UnFlatten(JObject.FromObject(record));

            return(UpsertExternal(referenceId, objectName, externalFieldName, body[externalFieldName]?.ToString() ?? string.Empty, Dnf.Omit(body, externalFieldName)));
        }
Exemple #13
0
        public BatchSubRequest Create(string objectName, object record)
        {
            if (string.IsNullOrEmpty(objectName))
            {
                throw new ArgumentNullException(nameof(objectName));
            }
            if (record == null)
            {
                throw new ArgumentNullException(nameof(record));
            }

            var request = new BatchSubRequest
            {
                RichInput = Dnf.UnFlatten(JObject.FromObject(record)),
                Url       = $"sobjects/{objectName}"
            };

            BatchRequests.Add(request);
            return(request);
        }
Exemple #14
0
        public CompositeSubRequest Explain(string referenceId, string query)
        {
            if (string.IsNullOrEmpty(referenceId))
            {
                throw new ArgumentNullException(nameof(referenceId));
            }
            if (string.IsNullOrEmpty(query))
            {
                throw new ArgumentNullException(nameof(query));
            }

            var request = new CompositeSubRequest
            {
                Method      = "GET",
                ReferenceId = referenceId,
                Url         = $@"query?explain={Dnf.EscapeDataString(query)}"
            };

            CompositeRequests.Add(request);
            return(request);
        }
        public async Task <BatchResult> BatchAsync(IBatchRequest request)
        {
            if (request == null || request.BatchRequests.Count <= 0)
            {
                throw new ArgumentNullException(nameof(request));
            }

            try
            {
                var resourceName = $"{request.Prefix}composite/batch";

                if (request.HaltOnError)
                {
                    if (request.BatchRequests.Count > Dnf.BatchLimit)
                    {
                        throw new ArgumentOutOfRangeException(nameof(request));
                    }

                    var inputObject = new JObject
                    {
                        ["batchRequests"] = JToken.FromObject(request.BatchRequests.Select(req => Dnf.Assign(JObject.FromObject(req), new JObject
                        {
                            ["url"] = DecodeReference($"/services/data/{ApiVersion}/{request.Prefix}{req.Url?.TrimStart('/')}")
                        }))),
                        ["haltOnError"] = true
                    };

                    var result = await JsonHttp.HttpPostAsync <BatchResultBody>(inputObject, resourceName)
                                 .ConfigureAwait(false);

                    var results = new BatchResult(request.BatchRequests, result?.Results ?? new List <BatchSubRequestResult>());
                    return(results);
                }
                else
                {
                    var throttler = new SemaphoreSlim(Dnf.DefaultConcurrentLimit, Dnf.DefaultConcurrentLimit);
                    var results   = new BatchResult();

                    var chunks = new List <IList <BatchSubRequest> >();
                    IList <BatchSubRequest>?chunk = null;

                    foreach (var req in request.BatchRequests)
                    {
                        var added = false;

                        if (chunk?.Count < Dnf.BatchLimit)
                        {
                            chunk.Add(req);
                            added = true;
                        }

                        if (added)
                        {
                            continue;
                        }
                        chunk = new List <BatchSubRequest> {
                            req
                        };
                        chunks.Add(chunk);
                    }

                    var tasks = new List <Task>();

                    foreach (var requests in chunks)
                    {
                        await throttler.WaitAsync()
                        .ConfigureAwait(false);

                        tasks.Add(Task.Run(async() =>
                        {
                            try
                            {
                                var inputObject = new JObject
                                {
                                    ["batchRequests"] = JToken.FromObject(requests.Select(req => Dnf.Assign(JObject.FromObject(req), new JObject
                                    {
                                        ["url"] = DecodeReference($"/services/data/{ApiVersion}/{request.Prefix}{req.Url?.TrimStart('/')}")
                                    })))
                                };


                                var result = await JsonHttp.HttpPostAsync <BatchResultBody>(inputObject, resourceName)
                                             .ConfigureAwait(false);
                                results.Add(requests, result?.Results ?? new List <BatchSubRequestResult>());
                            }
                            catch (Exception ex)
                            {
                                var body = new JArray {
                                    ex.Message
                                };
                                var responses = requests.Select(req => new BatchSubRequestResult
                                {
                                    Result     = body,
                                    StatusCode = 500
                                }).ToList();
                                results.Add(requests, responses);
                            }
                            finally
                            {
                                throttler.Release();
                            }
                        }));
                    }
                    await Task.WhenAll(tasks)
                    .ConfigureAwait(false);

                    return(results);
                }
            }
            catch (Exception ex)
            {
                var body = new JArray {
                    ex.Message
                };
                var responses = request.BatchRequests.Select(req => new BatchSubRequestResult
                {
                    Result     = body,
                    StatusCode = 500
                }).ToList();
                var results = new BatchResult(request.BatchRequests, responses);
                return(results);
            }
        }
        public async Task <CompositeResult> PostAsync(ICompositeRequest request)
        {
            if (request == null || request.CompositeRequests.Count <= 0)
            {
                throw new ArgumentNullException(nameof(request));
            }

            try
            {
                var resourceName = $"{request.Prefix}composite";

                if (request.AllOrNone)
                {
                    var requests = request.CompositeRequests;

                    if (requests.Count > Dnf.CompositeLimit)
                    {
                        throw new ArgumentOutOfRangeException(nameof(request));
                    }
                    if (requests.Count(c => IsQuery(c.ResponseType)) > Dnf.CompositeQueryLimit)
                    {
                        throw new ArgumentOutOfRangeException(nameof(request));
                    }

                    var inputObject = new JObject
                    {
                        ["allOrNone"]        = true,
                        ["compositeRequest"] = JToken.FromObject(requests.Select(req => Dnf.Assign(JObject.FromObject(req), new JObject
                        {
                            ["url"] = DecodeReference($"/services/data/{ApiVersion}/{request.Prefix}{req.Url?.TrimStart('/')}")
                        })))
                    };

                    var result = await JsonHttp.HttpPostAsync <CompositeResultBody>(inputObject, resourceName)
                                 .ConfigureAwait(false);

                    var results = new CompositeResult(request.CompositeRequests, result?.CompositeResponse ?? new List <CompositeSubRequestResult>());
                    return(results);
                }
                else
                {
                    var throttler = new SemaphoreSlim(Dnf.DefaultConcurrentLimit, Dnf.DefaultConcurrentLimit);
                    var results   = new CompositeResult();

                    var chunks = new List <IList <CompositeSubRequest> >();
                    IList <CompositeSubRequest>?chunk = null;

                    foreach (var req in request.CompositeRequests)
                    {
                        var added = false;

                        if (IsQuery(req.ResponseType))
                        {
                            if (chunk != null && chunk.Count(c => IsQuery(c.ResponseType)) < Dnf.CompositeQueryLimit)
                            {
                                chunk.Add(req);
                                added = true;
                            }
                        }
                        else if (chunk?.Count < Dnf.CompositeLimit)
                        {
                            chunk.Add(req);
                            added = true;
                        }

                        if (added)
                        {
                            continue;
                        }
                        chunk = new List <CompositeSubRequest> {
                            req
                        };
                        chunks.Add(chunk);
                    }

                    var tasks = new List <Task>();

                    foreach (var requests in chunks)
                    {
                        await throttler.WaitAsync()
                        .ConfigureAwait(false);

                        tasks.Add(Task.Run(async() =>
                        {
                            try
                            {
                                var inputObject = new JObject
                                {
                                    ["compositeRequest"] = JToken.FromObject(requests.Select(req => Dnf.Assign(JObject.FromObject(req), new JObject
                                    {
                                        ["url"] = DecodeReference($"/services/data/{ApiVersion}/{request.Prefix}{req.Url?.TrimStart('/')}")
                                    })))
                                };

                                var result = await JsonHttp.HttpPostAsync <CompositeResultBody>(inputObject, resourceName)
                                             .ConfigureAwait(false);
                                results.Add(requests, result?.CompositeResponse ?? new List <CompositeSubRequestResult>());
                            }
                            catch (Exception ex)
                            {
                                var body = new JArray {
                                    ex.Message
                                };
                                var responses = requests.Select(req => new CompositeSubRequestResult
                                {
                                    Body           = body,
                                    ReferenceId    = req.ReferenceId,
                                    HttpStatusCode = 500
                                }).ToList();
                                results.Add(requests, responses);
                            }
                            finally
                            {
                                throttler.Release();
                            }
                        }));
                    }
                    await Task.WhenAll(tasks)
                    .ConfigureAwait(false);

                    return(results);
                }
            }
            catch (Exception ex)
            {
                var body = new JArray {
                    ex.Message
                };
                var responses = request.CompositeRequests.Select(req => new CompositeSubRequestResult
                {
                    Body           = body,
                    ReferenceId    = req.ReferenceId,
                    HttpStatusCode = 500
                }).ToList();
                var results = new CompositeResult(request.CompositeRequests, responses);
                return(results);
            }

            bool IsQuery(string responseType)
            {
                return(responseType == "query" || responseType == "collections");
            }
        }
Exemple #17
0
        public IList <CompositeSubRequest> Update <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      = "PATCH",
                    ReferenceId = $"{referenceId}_{chunkIdx}",
                    Url         = "composite/sobjects"
                };
                CompositeRequests.Add(request);
                result.Add(request);
            }
            return(result);
        }