public static ODataQueryOptions RemoveOptions(ODataQueryOptions queryOptions, List <String> optionNames, List <KeyValuePair <string, string> > newQueryOptions = null)
        {
            var request = queryOptions.Request;
            //var oldUri = new Uri(queryOptions.Request.QueryString.ToString());
            var oldUri = new Uri($"{request.Scheme}://{request.Host}{request.Path.ToString().TrimEnd('/')}/{request.QueryString}");

            var map = Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(oldUri.Query).Where(d => (d.Key.Trim().Length > 0) && !optionNames.Contains(d.Key.Trim()))
                      .Select(d => new KeyValuePair <string, string>(d.Key, d.Value)).ToList();

            if (newQueryOptions != null)
            {
                newQueryOptions?.ForEach(newQueryOption =>
                {
                    map.Add(new KeyValuePair <string, string>(newQueryOption.Key, newQueryOption.Value));
                });
            }

            var qb     = new Microsoft.AspNetCore.Http.Extensions.QueryBuilder(map);
            var newUrl = oldUri.Scheme + "://" + oldUri.Authority + oldUri.AbsolutePath.TrimEnd('/') + "/" + qb.ToQueryString();

            //var newUri = new Uri(newUrl);

            //request.Path = new PathString(newUrl);
            request.QueryString = qb.ToQueryString();
            var newQo = new ODataQueryOptions(queryOptions.Context, request);

            return(newQo);
            //return queryOptions;
        }
        public static ODataQueryOptions FixupExpand(ODataQueryOptions queryOptions)
        {
            var expandQueryString = queryOptions.RawValues.Expand;

            if (string.IsNullOrEmpty(expandQueryString))
            {
                return(queryOptions);
            }
            var request = queryOptions.Request;
            var oldUri  = new Uri($"{request.Scheme}://{request.Host}{request.Path.ToString().TrimEnd('/')}/{request.QueryString}");

            var map = Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(oldUri.Query).Where(d => (d.Key.Trim().Length > 0))
                      .Select(d => new KeyValuePair <string, string>(d.Key, d.Value)).ToList();
            bool foundExpand = false;

            for (int i = 0; i < map.Count; i++)
            {
                var mapItem = map[i];
                if (mapItem.Key == "$expand")
                {
                    var expandItems = mapItem.Value.Split(',').ToList();
                    if (expandItems.Count <= 0)
                    {
                        continue;
                    }
                    foundExpand = true;
                    var result = String.Empty;
                    expandItems.ForEach(expandItem =>
                    {
                        var orderByItems = expandItem.Split('/');
                        var thisResult   = orderByItems[0];
                        for (int j = 1; j < orderByItems.Length; j++)
                        {
                            thisResult += "($expand=" + orderByItems[j];
                        }
                        thisResult += String.Empty.PadLeft(orderByItems.Length - 1, ')');
                        result     += thisResult + ",";
                    });
                    result = result.TrimEnd(',');

                    map[i] = new KeyValuePair <string, string>(mapItem.Key, result);
                }
            }
            if (!foundExpand)
            {
                return(queryOptions);
            }
            var qb     = new Microsoft.AspNetCore.Http.Extensions.QueryBuilder(map);
            var newUrl = oldUri.Scheme + "://" + oldUri.Authority + oldUri.AbsolutePath.TrimEnd('/') + "/" + qb.ToQueryString();

            request.QueryString = qb.ToQueryString();
            var newQo = new ODataQueryOptions(queryOptions.Context, request);

            return(newQo);
        }
        public static ODataQueryOptions FixupOrderBy(ODataQueryOptions queryOptions)
        {
            return(queryOptions);

            var expandQueryString = queryOptions.RawValues.OrderBy;

            if (string.IsNullOrEmpty(expandQueryString))
            {
                return(queryOptions);
            }
            var request = queryOptions.Request;
            var oldUri  = new Uri($"{request.Scheme}://{request.Host}{request.Path.ToString().TrimEnd('/')}/{request.QueryString}");

            var map = Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(oldUri.Query).Where(d => (d.Key.Trim().Length > 0))
                      .Select(d => new KeyValuePair <string, string>(d.Key, d.Value)).ToList();
            bool foundOrderBy = false;

            for (int i = 0; i < map.Count; i++)
            {
                var mapItem = map[i];
                if (mapItem.Key == "$orderby")
                {
                    var expandItems = mapItem.Value.Split(',').ToList();
                    if (expandItems.Count <= 1)
                    {
                        continue;
                    }
                    foundOrderBy = true;
                    //map[i] = new KeyValuePair<string, string>(mapItem.Key, "OrderView,OrderItem,OrderItem($expand=OrderItemType),OrderItem($expand=OrderItemActivity),OrderNotes,OrderType,Circuit,OwnerUser,Circuit($expand=ALocation),Circuit($expand=ZLocation),BusinessEntity");
                }
            }
            if (!foundOrderBy)
            {
                return(queryOptions);
            }
            var qb     = new Microsoft.AspNetCore.Http.Extensions.QueryBuilder(map);
            var newUrl = oldUri.Scheme + "://" + oldUri.Authority + oldUri.AbsolutePath.TrimEnd('/') + "/" + qb.ToQueryString();

            request.QueryString = qb.ToQueryString();
            var newQo = new ODataQueryOptions(queryOptions.Context, request);

            return(newQo);
        }
        public static ODataQueryOptions FixupFilter(ODataQueryOptions queryOptions)
        {
            var filterQueryString = queryOptions.RawValues.Filter;

            if (string.IsNullOrEmpty(filterQueryString))
            {
                return(queryOptions);
            }
            var request = queryOptions.Request;
            var oldUri  = new Uri($"{request.Scheme}://{request.Host}{request.Path.ToString().TrimEnd('/')}/{request.QueryString}");

            var map = Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(oldUri.Query).Where(d => (d.Key.Trim().Length > 0))
                      .Select(d => new KeyValuePair <string, string>(d.Key, d.Value)).ToList();
            bool filterChanged = false;

            for (int i = 0; i < map.Count; i++)
            {
                var mapItem = map[i];
                if (mapItem.Key.ToLower() == "$filter")
                {
                    // swap "substringof" with "contains" and swap parm values
                    if (mapItem.Value.ToLower().Contains("substringof"))
                    {
                        var r      = new System.Text.RegularExpressions.Regex(@"substringof\s*?\(\s*?('[^']+?'|[^,]+?)\s*?,\s*?('[^']+?'|[^,]+?)\s*?\)", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                        var result = r.Replace(mapItem.Value, m => $"contains({m.Groups[2].Value},{m.Groups[1].Value})");
                        if (result != mapItem.Value)
                        {
                            filterChanged = true;
                            mapItem       = map[i] = new KeyValuePair <string, string>(mapItem.Key, result);
                        }
                    }
                    // OData 4 does not support DateTime.  Substitute "datetime('yyyy-mmm-ddThh:mm:ss')" values with "cast(yyyy-mmm-ddThh:mm:ssTZ,Edm.DateTimeOffset)"
                    if (mapItem.Value.ToLower().Contains("datetime'"))
                    {
                        var r      = new System.Text.RegularExpressions.Regex(@"datetime\s*?'([^']+?)'", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                        var result = r.Replace(mapItem.Value, m =>
                        {
                            var origVal      = m.Groups[1].Value;
                            var containsT    = origVal.ToUpper().IndexOf('T') > -1;
                            var containsTZ   = (origVal.Count(s => s == '-') > 2) || origVal.IndexOf('+') > -1 || origVal.ToUpper().IndexOf('Z') > -1;
                            var curUTCoffset = System.TimeZoneInfo.Local.BaseUtcOffset.ToString().Substring(0, 6);
                            // if has TimeZone, return as is
                            if (containsTZ)
                            {
                                return($"cast({origVal},Edm.DateTimeOffset)");
                            }
                            // if no TimeZone, add TZ
                            if (containsT && !containsTZ)
                            {
                                return($"cast({origVal}{curUTCoffset},Edm.DateTimeOffset)");
                            }
                            // if no TimeZone, add TZ
                            if (!containsT || !containsTZ)
                            {
                                return($"cast({origVal}{curUTCoffset},Edm.DateTimeOffset)");
                            }
                            throw new Exception($"Unable to parse {origVal} as DateTimeOffset value.");
                        });
                        if (result != mapItem.Value)
                        {
                            filterChanged = true;
                            mapItem       = map[i] = new KeyValuePair <string, string>(mapItem.Key, result);
                        }
                    }
                }
            }
            if (!filterChanged)
            {
                return(queryOptions);
            }
            var qb     = new Microsoft.AspNetCore.Http.Extensions.QueryBuilder(map);
            var newUrl = oldUri.Scheme + "://" + oldUri.Authority + oldUri.AbsolutePath.TrimEnd('/') + "/" + qb.ToQueryString();

            request.QueryString = qb.ToQueryString();
            var newQo = new ODataQueryOptions(queryOptions.Context, request);

            return(newQo);
        }