/// <inheritdoc /> public IUriComponents GetUriComponents(string uriString, Context context) { var uriMatch = Regex.Match(uriString, @"(?<entityset>/[^/\?]*)?(?<options>\?[^/]*)?"); if (!uriMatch.Success) { throw new InvalidODataSyntax(InvalidUriSyntax, "Check URI syntax"); } var entitySet = uriMatch.Groups["entityset"].Value.TrimStart('/'); var options = uriMatch.Groups["options"].Value.TrimStart('?'); var uri = new ODataUriComponents(this); switch (entitySet) { case "": uri.ResourceSpecifier = Resource <ServiceDocument> .ResourceSpecifier; break; case "$metadata": uri.ResourceSpecifier = Resource <MetadataDocument> .ResourceSpecifier; break; default: uri.ResourceSpecifier = entitySet; break; } if (options.Length != 0) { PopulateFromOptions(uri, options); } return(uri); }
private static void PopulateFromOptions(ODataUriComponents args, string options) { foreach (var(optionKey, optionValue) in options.Split('&').Select(option => option.TSplit('='))) { if (string.IsNullOrWhiteSpace(optionKey)) { throw new InvalidODataSyntax(InvalidConditionSyntax, "An OData query option key was null or whitespace"); } if (string.IsNullOrWhiteSpace(optionValue)) { throw new InvalidODataSyntax(InvalidConditionSyntax, $"The OData query option value for '{optionKey}' was invalid"); } var decodedValue = HttpUtility.UrlDecode(optionValue); switch (optionKey) { case var system when optionKey[0] == '$': if (!Enum.TryParse(system.Substring(1), out QueryOptions option) || option == none) { throw new FeatureNotImplemented($"Unknown or not implemented query option '{system}'"); } switch (option) { case filter: if (Regex.Match(decodedValue, @"(/| has | not | cast\(.*\)| mul | div | mod | add | sub | isof | or )") is Match m && m.Success) { throw new FeatureNotImplemented($"Not implemented operator '{m.Value}' in $filter"); } decodedValue .Replace("(", "") .Replace(")", "") .Split(" and ") .Select(c => { var parts = c.Split(' '); if (parts.Length != 3) { throw new InvalidODataSyntax(InvalidConditionSyntax, "Invalid syntax in $filter query option"); } return(new UriCondition(parts[0], GetOperator(parts[1]), parts[2], TypeCode.String)); }) .ForEach(cond => args.Conditions.Add(cond)); break; case orderby: if (decodedValue.Contains(",")) { throw new FeatureNotImplemented("Multiple expressions not implemented for $orderby"); } var(term, order) = decodedValue.TSplit(' '); switch (order) { case null: case "": case "asc": args.MetaConditions.Add(new UriCondition(Order_asc, term)); break; case "desc": args.MetaConditions.Add(new UriCondition(Order_desc, term)); break; default: throw new InvalidODataSyntax(InvalidConditionSyntax, "The OData query option value for $orderby was invalid"); } break; case select: args.MetaConditions.Add(new UriCondition(Select, decodedValue)); break; case skip: args.MetaConditions.Add(new UriCondition(Offset, decodedValue)); break; case top: args.MetaConditions.Add(new UriCondition(Limit, decodedValue)); break; case search: args.MetaConditions.Add(new UriCondition(Search, decodedValue)); break; default: throw new ArgumentOutOfRangeException(); } break; default: args.MetaConditions.Add(new UriCondition(optionKey, Operators.EQUALS, optionValue, TypeCode.String)); break; } } }