/// <summary>
        /// Parse json data of a Dataverse row into Activity/Opportunities/Leads instance
        /// </summary>
        /// <returns>
        /// Tuple of Id column for the parsed table, An instance of parsed Activity, Opportunities or Leads class
        /// </returns>
        public (string, dynamic) ParseDataRowFromJson(string dataRowJson, string tableType)
        {
            // Set member variables and parse dataRowJson
            switch (tableType)
            {
            case Constant.TableNameActivities:
                return(Constant.TableIdColumnActivities, Activities.FromJson(dataRowJson));

            case Constant.TableNameOpportunities:
                return(Constant.TableIdColumnOpportunities, Opportunities.FromJson(dataRowJson));

            case Constant.TableNameLeads:
                return(Constant.TableIdColumnLeads, Leads.FromJson(dataRowJson));

            default:
                throw new DataverseException(Constant.InvalidTable);
            }
        }
        /// <summary>
        /// Generates a new Id in the given table if does not exist already
        ///	Inserts a new row when given row does not exist and returns the Id of the newly inserted row
        ///	https://docs.microsoft.com/en-us/powerapps/developer/common-data-service/webapi/retrieve-table-using-web-api#retrieve-using-an-alternate-key
        /// </summary>
        /// <returns>
        /// Returns Id of given queryColumnValue parameter
        /// </returns>
        public async Task <string> GetOrGenerateId(string queryTableName, string queryColumnName, string queryColumnValue, string selectIdColumnName, string getIdColumnName)
        {
            var values = await GetValues(queryTableName, new string[] { selectIdColumnName }, $"{queryColumnName} eq '{queryColumnValue}'");

            // Check if columnValue already exists in table
            if (values != null && values.Count > 0)
            {
                // Return the id of first match
                return(Convert.ToString(values[0][getIdColumnName], cultureInfo));
            }

            // An existing row not found, insert new row

            // New row's data
            // Note: We are creating a JObject as queryColumnName is dynamic
            var insertObject = new JObject();

            insertObject[queryColumnName] = queryColumnValue;

            // Add row creation date property
            insertObject[Constant.RowCreationDateColumnName] = DateTime.UtcNow.ToString(Constant.DataverseDateFormat);

            var insertObjectJson = JsonConvert.SerializeObject(insertObject);
            var reqContent       = new StringContent(insertObjectJson, Encoding.UTF8, "application/json");

            // Add "Prefer" header to return the inserted row
            dataverseClient.DefaultRequestHeaders.Add("Prefer", "return=representation");

            UriBuilder requestUri = new UriBuilder("https", dataverseConfig.Value.ApiBaseUrl);

            requestUri.Path = queryTableName;

            var response = await dataverseClient.PostAsync(requestUri.Uri, reqContent);

            if (!response.IsSuccessStatusCode)
            {
                throw new DataverseException(Constant.InvalidInsertDataColumns);
            }

            // Parse response
            var responseString = await response.Content.ReadAsStringAsync();

            // Return id column's value of inserted row
            switch (queryTableName)
            {
            case Constant.TableNameActivities:
                return(Activities.FromJson(responseString).Id);

            case Constant.TableNameOpportunities:
                return(Opportunities.FromJson(responseString).Id);

            case Constant.TableNameLeads:
                return(Leads.FromJson(responseString).Id);

            case Constant.TableNameAccounts:
                return(Accounts.FromJson(responseString).Id);

            default:
                throw new DataverseException(Constant.InvalidTable);
            }
        }
        /// <summary>
        /// Insert new row and set baseId and isLatest
        /// </summary>
        /// <returns>
        /// Task
        /// </returns>
        public async Task AddNewRow(dynamic newData, string tableName, string idColumn)
        {
            // Get account id for insert Lead
            if (tableName == Constant.TableNameLeads)
            {
                // Get id for the given account name, or create new account and get its id
                string accountId = await GetOrGenerateId(Constant.TableNameAccounts, "name", newData.ParentAccountName, "parentaccountid", Constant.TableIdColumnAccounts);

                if (accountId is null)
                {
                    throw new DataverseException(Constant.InvalidInsertDataColumns);
                }

                // remove name and add id
                newData.ParentAccountName    = null;
                newData.ParentAccountforlead = $"{Constant.TableNameAccounts}({accountId})";
            }

            newData.Baseid   = null;
            newData.Islatest = Constant.IsLatestTrue;               // Mark latest row as "1"

            var jsonTable = JsonConvert.SerializeObject(newData);
            var content   = new StringContent(jsonTable, Encoding.UTF8, "application/json");

            // Add "Prefer" header to return the inserted row
            dataverseClient.DefaultRequestHeaders.Add("Prefer", "return=representation");

            UriBuilder requestUri = new UriBuilder("https", dataverseConfig.Value.ApiBaseUrl);

            requestUri.Path = tableName;

            var response = await dataverseClient.PostAsync(requestUri.Uri, content);

            if (!response.IsSuccessStatusCode)
            {
                throw new DataverseException(Constant.InvalidInsertDataColumns);
            }

            // Parse row guid from insert response
            var responseString = await response.Content.ReadAsStringAsync();

            // Create JSON for update baseid operation i.e. set baseId = rowGuid of inserted row
            var table = new DataverseTable();

            // Set baseid with id column's value of inserted row
            switch (tableName)
            {
            case Constant.TableNameActivities:
                table.Baseid = Activities.FromJson(responseString).Id;
                break;

            case Constant.TableNameOpportunities:
                table.Baseid = Opportunities.FromJson(responseString).Id;
                break;

            case Constant.TableNameLeads:
                table.Baseid = Leads.FromJson(responseString).Id;
                break;

            case Constant.TableNameAccounts:
                table.Baseid = Accounts.FromJson(responseString).Id;
                break;

            default:
                throw new DataverseException(Constant.InvalidTable);
            }

            jsonTable = JsonConvert.SerializeObject(table);
            content   = new StringContent(jsonTable, Encoding.UTF8, "application/json");

            // Update operation
            requestUri      = new UriBuilder("https", dataverseConfig.Value.ApiBaseUrl);
            requestUri.Path = $"{tableName}({table.Baseid})";

            response = await dataverseClient.PatchAsync(requestUri.Uri, content);

            if (!response.IsSuccessStatusCode)
            {
                throw new DataverseException(Constant.InvalidInsertDataColumns);
            }
        }