From 9e26343e3373e48b19f1d5507804cf0bc837feb3 Mon Sep 17 00:00:00 2001 From: JefWight Date: Thu, 5 Mar 2015 11:29:32 -0800 Subject: [PATCH 1/4] Expose additional Preference Headers Adds the odata.track-changes, odata.maxpagesize, and odata.continue-on-error preference headers. --- .../ODataPreferenceHeader.cs | 117 ++++++++++++++++++ .../Common/ODataPreferenceHeaderTests.cs | 62 ++++++++++ 2 files changed, 179 insertions(+) diff --git a/src/Microsoft.OData.Core/ODataPreferenceHeader.cs b/src/Microsoft.OData.Core/ODataPreferenceHeader.cs index 5e8bd02db9..60ab702345 100644 --- a/src/Microsoft.OData.Core/ODataPreferenceHeader.cs +++ b/src/Microsoft.OData.Core/ODataPreferenceHeader.cs @@ -46,6 +46,21 @@ public sealed class ODataPreferenceHeader /// private const string WaitPreferenceTokenName = "wait"; + /// + /// The odata.continue-on-error preference token. + /// + private const string ODataContinueOnErrorPreferenceToken = "odata.continue-on-error"; + + /// + /// The odata.maxpagesize=# preference token. + /// + private const string ODataMaxPageSizePreferenceToken = "odata.maxpagesize"; + + /// + /// The odata.track-changes preference token. + /// + private const string ODataTrackChangesPreferenceToken = "odata.track-changes"; + /// /// The Prefer header name. /// @@ -61,6 +76,11 @@ public sealed class ODataPreferenceHeader /// private static readonly KeyValuePair[] EmptyParameters = new KeyValuePair[0]; + /// + /// The respond-async preference. + /// + private static readonly HttpHeaderValueElement ContinueOnErrorPreference = new HttpHeaderValueElement(ODataContinueOnErrorPreferenceToken, null, EmptyParameters); + /// /// The return=minimal preference. /// @@ -76,6 +96,11 @@ public sealed class ODataPreferenceHeader /// private static readonly HttpHeaderValueElement RespondAsyncPreference = new HttpHeaderValueElement(RespondAsyncPreferenceToken, null, EmptyParameters); + /// + /// The respond-async preference. + /// + private static readonly HttpHeaderValueElement TrackChangesPreference = new HttpHeaderValueElement(ODataTrackChangesPreferenceToken, null, EmptyParameters); + /// /// The message to set the preference header to and to get the preference header from. /// @@ -288,6 +313,98 @@ private HttpHeaderValue Preferences get { return this.preferences ?? (this.preferences = this.ParsePreferences()); } } + /// + /// Property to get and set the "odata.continue-on-error" preference to the "Prefer" header on the underlying IODataRequestMessage or + /// the "Preference-Applied" header on the underlying IODataResponseMessage. + /// Setting true sets the "odata.continue-on-error" preference. + /// Setting false clears the "odata.continue-on-error" preference. + /// Returns true of the "odata.continue-on-error" preference is on the header. Otherwise returns false if the "odata.continue-on-error" is not on the header. + /// + public bool ContinueOnError + { + get + { + return this.Get(ODataContinueOnErrorPreferenceToken) != null; + } + + set + { + if (value) + { + this.Set(ContinueOnErrorPreference); + } + else + { + this.Clear(ODataContinueOnErrorPreferenceToken); + } + } + } + + /// + /// Property to get and set the "odata.maxpagesize" preference to the "Prefer" header on the underlying IODataRequestMessage or + /// the "Preference-Applied" header on the underlying IODataResponseMessage. + /// Setting N sets the "odata.maxpagesize=N" preference. + /// Setting null clears the "odata.maxpagesize" preference. + /// Returns N if the "odata.maxpagesize=N" preference is on the header. + /// Returning null indicates that "odata.maxpagesize" is not on the header. + /// + public int? MaxPageSize + { + get + { + var maxPageSizeHttpHeaderValueElement = this.Get(ODataMaxPageSizePreferenceToken); + + // Should check maxPageSizeHttpHeaderValueElement.Value != null. + // Should do int.TryParse. + // If either of the above fail, should throw an ODataException for parsing, not a System.Exception (such as FormatException, etc.). + if (maxPageSizeHttpHeaderValueElement != null) + { + return int.Parse(maxPageSizeHttpHeaderValueElement.Value, CultureInfo.InvariantCulture); + } + + return null; + } + + set + { + if (value.HasValue) + { + this.Set(new HttpHeaderValueElement(ODataMaxPageSizePreferenceToken, string.Format(CultureInfo.InvariantCulture, "{0}", value.Value), EmptyParameters)); + } + else + { + this.Clear(ODataMaxPageSizePreferenceToken); + } + } + } + + /// + /// Property to get and set the "odata.track-changes" preference to the "Prefer" header on the underlying IODataRequestMessage or + /// the "Preference-Applied" header on the underlying IODataResponseMessage. + /// Setting true sets the "odata.track-changes" preference. + /// Setting false clears the "odata.track-changes" preference. + /// Returns true of the "odata.track-changes" preference is on the header. Otherwise returns false if the "odata.track-changes" is not on the header. + /// + public bool TrackChanges + { + get + { + return this.Get(ODataTrackChangesPreferenceToken) != null; + } + + set + { + if (value) + { + this.Set(TrackChangesPreference); + } + else + { + this.Clear(ODataTrackChangesPreferenceToken); + } + } + } + /// /// Adds quotes around the given text value. /// diff --git a/test/FunctionalTests/Tests/DataOData/Tests/OData.TDD.Tests/Common/ODataPreferenceHeaderTests.cs b/test/FunctionalTests/Tests/DataOData/Tests/OData.TDD.Tests/Common/ODataPreferenceHeaderTests.cs index e1b726c129..995eb99838 100644 --- a/test/FunctionalTests/Tests/DataOData/Tests/OData.TDD.Tests/Common/ODataPreferenceHeaderTests.cs +++ b/test/FunctionalTests/Tests/DataOData/Tests/OData.TDD.Tests/Common/ODataPreferenceHeaderTests.cs @@ -30,6 +30,9 @@ public class ODataPreferenceHeaderTests private const string RespondAyncPreference = "respond-async"; private const string RespondAsyncAndWaitPreference = "respond-async,wait=10"; private const string WaitPreference = "wait=10"; + private const string MaxPageSizePreference = "odata.maxpagesize"; + private const string TrackChangesPreference = "odata.track-changes"; + private const string ContinueOnErrorPreference = "odata.continue-on-error"; [TestInitialize] public void TestInit() @@ -250,5 +253,64 @@ public void ReturnWaitOfBadIntergerFormatShouldThrow() Action test = () => wait = this.preferHeader.Wait; test.ShouldThrow().WithMessage("Input string was not in a correct format."); } + + [TestMethod] + public void SetContinueOnErrorToTrueShouldAppendHeader() + { + this.preferHeader.ContinueOnError = true; + this.preferHeader.ContinueOnError.Should().BeTrue(); + this.requestMessage.GetHeader(PreferHeaderName).Should().Be(ContinueOnErrorPreference); + } + + [TestMethod] + public void SetContinueOnErrorToFalseShouldClearHeader() + { + this.preferHeader.ContinueOnError = false; + this.preferHeader.ContinueOnError.Should().BeFalse(); + this.requestMessage.GetHeader(PreferHeaderName).Should().BeNull(); + } + + [TestMethod] + public void SetMaxPageSizeShouldAppendHeader() + { + const int MaxPageSize = 10; + this.preferHeader.MaxPageSize = MaxPageSize; + this.preferHeader.MaxPageSize.Should().Be(MaxPageSize); + this.requestMessage.GetHeader(PreferHeaderName).Should().Be(string.Format("{0}={1}", MaxPageSizePreference, MaxPageSize)); + } + + [TestMethod] + public void SetMaxPageSizeToNullShouldClearHeader() + { + this.preferHeader.MaxPageSize = null; + this.preferHeader.MaxPageSize.Should().Be(null); + this.requestMessage.GetHeader(PreferHeaderName).Should().BeNull(); + } + + [TestMethod] + public void ReturnMaxPageSizeOfBadIntergerFormatShouldThrow() + { + this.requestMessage.SetHeader(PreferHeaderName, string.Format("{0}=abc", MaxPageSizePreference)); + this.preferHeader = new ODataPreferenceHeader(this.requestMessage); + int? maxPageSize; + Action test = () => maxPageSize = this.preferHeader.MaxPageSize; + test.ShouldThrow().WithMessage("Input string was not in a correct format."); + } + + [TestMethod] + public void SetTrackChangesToTrueShouldAppendHeader() + { + this.preferHeader.TrackChanges = true; + this.preferHeader.TrackChanges.Should().BeTrue(); + this.requestMessage.GetHeader(PreferHeaderName).Should().Be(TrackChangesPreference); + } + + [TestMethod] + public void SetTrackChangesToFalseShouldClearHeader() + { + this.preferHeader.TrackChanges = false; + this.preferHeader.TrackChanges.Should().BeFalse(); + this.requestMessage.GetHeader(PreferHeaderName).Should().BeNull(); + } } } From 6955b762627fc5495308182325a1856f398cdee3 Mon Sep 17 00:00:00 2001 From: JefWight Date: Mon, 9 Mar 2015 17:00:57 -0700 Subject: [PATCH 2/4] Parse $skipToken, $deltaToken, and $format in ODataUri This adds support for parsing $skipToken, $deltaToken, and $format from the URI, and exposes them on ODataUri. --- src/Microsoft.OData.Core/ODataUri.cs | 20 ++++++++++- .../UriParser/ODataQueryOptionParser.cs | 30 ++++++++++++++++ .../UriParser/ODataUriParser.cs | 36 +++++++++++++++++++ .../UriParser/UriQueryConstants.cs | 6 ++++ ...seInsensitiveBuiltinIdentifierUnitTests.cs | 33 +++++++++++++++++ .../ODataUriParserUnitTests.cs | 29 +++++++++++++-- 6 files changed, 150 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.OData.Core/ODataUri.cs b/src/Microsoft.OData.Core/ODataUri.cs index 68c883d861..c7a690e843 100644 --- a/src/Microsoft.OData.Core/ODataUri.cs +++ b/src/Microsoft.OData.Core/ODataUri.cs @@ -171,6 +171,21 @@ public IDictionary ParameterAliasNodes /// public bool? QueryCount { get; set; } + /// + /// Gets or sets any $skipToken option for this uri. + /// + public string SkipToken { get; set; } + + /// + /// Gets or sets any $deltaToken option for this uri. + /// + public string DeltaToken { get; set; } + + /// + /// Gets or sets any $format option for this uri. + /// + public IEnumerable> Format { get; set; } + /// /// Get or sets the MetadataDocumentUri, which is always ServiceRoot + $metadata /// @@ -201,7 +216,10 @@ public ODataUri Clone() Search = Search, Skip = Skip, Top = Top, - QueryCount = QueryCount + QueryCount = QueryCount, + SkipToken = SkipToken, + DeltaToken = DeltaToken, + Format = Format, }; } } diff --git a/src/Microsoft.OData.Core/UriParser/ODataQueryOptionParser.cs b/src/Microsoft.OData.Core/UriParser/ODataQueryOptionParser.cs index 8a02352dec..ccefce9756 100644 --- a/src/Microsoft.OData.Core/UriParser/ODataQueryOptionParser.cs +++ b/src/Microsoft.OData.Core/UriParser/ODataQueryOptionParser.cs @@ -231,6 +231,36 @@ public SearchClause ParseSearch() this.searchClause = ParseSearchImplementation(searchQuery, this.Configuration); return searchClause; } + + /// + /// Parses a $skipToken query option + /// + /// A value representing that skip token option, null if $skipToken query does not exist. + public string ParseSkipToken() + { + string skipTokenQuery; + return this.TryGetQueryOption(UriQueryConstants.SkipTokenQueryOption, out skipTokenQuery) ? skipTokenQuery : null; + } + + /// + /// Parses a $deltaToken query option + /// + /// A value representing that delta token option, null if $deltaToken query does not exist. + public string ParseDeltaToken() + { + string deltaTokenQuery; + return this.TryGetQueryOption(UriQueryConstants.DeltaTokenQueryOption, out deltaTokenQuery) ? deltaTokenQuery : null; + } + + /// + /// Parses a $format query option + /// + /// A value representing that format option, null if $format query does not exist. + public IEnumerable> ParseFormat() + { + string formatQuery; + return this.TryGetQueryOption(UriQueryConstants.FormatQueryOption, out formatQuery) ? HttpUtils.MediaTypesFromString(formatQuery) : null; + } #endregion public methods #region private methods diff --git a/src/Microsoft.OData.Core/UriParser/ODataUriParser.cs b/src/Microsoft.OData.Core/UriParser/ODataUriParser.cs index 3da8fddec3..da4bba3600 100644 --- a/src/Microsoft.OData.Core/UriParser/ODataUriParser.cs +++ b/src/Microsoft.OData.Core/UriParser/ODataUriParser.cs @@ -331,6 +331,36 @@ public SearchClause ParseSearch() return this.queryOptionParser.ParseSearch(); } + /// + /// Parses a $skipToken query option + /// + /// A value representing that skip token option, null if $skipToken query does not exist. + public string ParseSkipToken() + { + this.Initialize(); + return this.queryOptionParser.ParseSkipToken(); + } + + /// + /// Parses a $deltaToken query option + /// + /// A value representing that delta token option, null if $deltaToken query does not exist. + public string ParseDeltaToken() + { + this.Initialize(); + return this.queryOptionParser.ParseDeltaToken(); + } + + /// + /// Parses a $format query option + /// + /// A value representing that format option, null if $format query does not exist. + public IEnumerable> ParseFormat() + { + this.Initialize(); + return this.queryOptionParser.ParseFormat(); + } + /// /// Parse a full Uri into its contingent parts with semantic meaning attached to each part. /// See . @@ -349,12 +379,18 @@ public ODataUri ParseUri() long? top = this.ParseTop(); long? skip = this.ParseSkip(); bool? count = this.ParseCount(); + string skipToken = this.ParseSkipToken(); + string deltaToken = this.ParseDeltaToken(); + IEnumerable> format = this.ParseFormat(); // TODO: check it shouldn't be empty List boundQueryOptions = new List(); ODataUri odataUri = new ODataUri(this.ParameterAliasValueAccessor, path, boundQueryOptions, selectExpand, filter, orderBy, search, skip, top, count); odataUri.ServiceRoot = this.serviceRoot; + odataUri.SkipToken = skipToken; + odataUri.DeltaToken = deltaToken; + odataUri.Format = format; return odataUri; } diff --git a/src/Microsoft.OData.Core/UriParser/UriQueryConstants.cs b/src/Microsoft.OData.Core/UriParser/UriQueryConstants.cs index 8deee046a6..4d24e370bf 100644 --- a/src/Microsoft.OData.Core/UriParser/UriQueryConstants.cs +++ b/src/Microsoft.OData.Core/UriParser/UriQueryConstants.cs @@ -41,6 +41,12 @@ internal static class UriQueryConstants /// A skip query option name. internal const string SkipQueryOption = "$skip"; + /// A skip token query option name. + internal const string SkipTokenQueryOption = "$skipToken"; + + /// A delta token query option name. + internal const string DeltaTokenQueryOption = "$deltaToken"; + /// An entity id query option name. internal const string IdQueryOption = "$id"; diff --git a/test/FunctionalTests/Tests/DataOData/Tests/OData.Query.TDD.Tests/Metadata/CaseInsensitiveBuiltinIdentifierUnitTests.cs b/test/FunctionalTests/Tests/DataOData/Tests/OData.Query.TDD.Tests/Metadata/CaseInsensitiveBuiltinIdentifierUnitTests.cs index b1a524cf24..e9f42daa22 100644 --- a/test/FunctionalTests/Tests/DataOData/Tests/OData.Query.TDD.Tests/Metadata/CaseInsensitiveBuiltinIdentifierUnitTests.cs +++ b/test/FunctionalTests/Tests/DataOData/Tests/OData.Query.TDD.Tests/Metadata/CaseInsensitiveBuiltinIdentifierUnitTests.cs @@ -273,6 +273,39 @@ public void CaseInsensitiveSelectExpandConflicts() HardCodedTestModel.TestModel, new ODataUriResolver() { EnableCaseInsensitive = true }); } + + [TestMethod] + public void CaseInsensitiveSkipTokenShouldWork() + { + this.TestCaseInsensitiveBuiltIn( + "People?$skipToken=foo", + "People?$SKIPTOKEN=foo", + uriParser => uriParser.ParseSkipToken(), + val => val.Should().Be("foo"), + /*errorMessage*/ null); + } + + [TestMethod] + public void CaseInsensitiveDeltaTokenShouldWork() + { + this.TestCaseInsensitiveBuiltIn( + "People?$deltaToken=foo", + "People?$DELTATOKEN=foo", + uriParser => uriParser.ParseDeltaToken(), + val => val.Should().Be("foo"), + /*errorMessage*/ null); + } + + [TestMethod] + public void CaseInsensitiveFormatShouldWork() + { + this.TestCaseInsensitiveBuiltIn( + "People?$format=application/json", + "People?$FORMAT=application/json", + uriParser => uriParser.ParseFormat(), + format => format.Should().NotBeNull(), + /*errorMessage*/ null); + } #endregion #region builtin functions Tests diff --git a/test/FunctionalTests/Tests/DataOData/Tests/OData.Query.TDD.Tests/ODataUriParserUnitTests.cs b/test/FunctionalTests/Tests/DataOData/Tests/OData.Query.TDD.Tests/ODataUriParserUnitTests.cs index 1931604808..e1b9d84244 100644 --- a/test/FunctionalTests/Tests/DataOData/Tests/OData.Query.TDD.Tests/ODataUriParserUnitTests.cs +++ b/test/FunctionalTests/Tests/DataOData/Tests/OData.Query.TDD.Tests/ODataUriParserUnitTests.cs @@ -11,7 +11,6 @@ namespace Microsoft.Test.OData.Query.TDD.Tests using System.Linq; using FluentAssertions; using Microsoft.OData.Edm; - using Microsoft.OData.Edm.Library; using Microsoft.OData.Core; using Microsoft.OData.Core.UriParser; using Microsoft.OData.Core.UriParser.Semantic; @@ -42,12 +41,15 @@ public void NoneQueryOptionShouldWork() uriParser.ParseSkip().Should().Be(null); uriParser.ParseCount().Should().Be(null); uriParser.ParseSearch().Should().BeNull(); + uriParser.ParseSkipToken().Should().BeNull(); + uriParser.ParseDeltaToken().Should().BeNull(); + uriParser.ParseFormat().Should().BeNull(); } [TestMethod] public void EmptyValueQueryOptionShouldWork() { - var uriParser = new ODataUriParser(HardCodedTestModel.TestModel, ServiceRoot, new Uri(FullUri, "?$filter=&$select=&$expand=&$orderby=&$top=&$skip=&$count=&$search=&$unknow=&$unknowvalue")); + var uriParser = new ODataUriParser(HardCodedTestModel.TestModel, ServiceRoot, new Uri(FullUri, "?$filter=&$select=&$expand=&$orderby=&$top=&$skip=&$count=&$search=&$unknow=&$unknowvalue&$skipToken=&$deltaToken=&$format=")); var path = uriParser.ParsePath(); path.Should().HaveCount(1); path.LastSegment.ShouldBeEntitySetSegment(HardCodedTestModel.GetPeopleSet()); @@ -64,6 +66,9 @@ public void EmptyValueQueryOptionShouldWork() action.ShouldThrow().WithMessage(Strings.ODataUriParser_InvalidCount("")); action = () => uriParser.ParseSearch(); action.ShouldThrow().WithMessage(Strings.UriQueryExpressionParser_ExpressionExpected(0, "")); + uriParser.ParseSkipToken().Should().BeEmpty(); + uriParser.ParseDeltaToken().Should().BeEmpty(); + uriParser.ParseFormat().Should().BeNull(); } [TestMethod] @@ -550,6 +555,21 @@ public void ErrorKeyTemplateInputShouldThrow() } } + [TestMethod] + public void ParseFormat() + { + var uriParser = new ODataUriParser(HardCodedTestModel.TestModel, ServiceRoot, new Uri(FullUri, "?$format=invalid")); + Action action = () => uriParser.ParseFormat(); + action.ShouldThrow().WithMessage(Strings.HttpUtils_MediaTypeUnspecified("invalid")); + + uriParser = new ODataUriParser(HardCodedTestModel.TestModel, ServiceRoot, new Uri(FullUri, "?$format=type/subtype")); + var format = uriParser.ParseFormat(); + format.Should().OnlyContain(pair => pair.Key.Type == "type" && pair.Key.SubType == "subtype" && pair.Key.Parameters == null && pair.Value == null); + + uriParser = new ODataUriParser(HardCodedTestModel.TestModel, ServiceRoot, new Uri(FullUri, "?$format=type1/subtype1;odata.metadata=full,type2/subtype2")); + uriParser.ParseFormat().Should().HaveCount(2); + } + #region Relative full path smoke test [TestMethod] public void AbsoluteUriInConstructorShouldThrow() @@ -569,7 +589,7 @@ public void ParsePathShouldWork() [TestMethod] public void ParseQueryOptionsShouldWork() { - var parser = new ODataUriParser(HardCodedTestModel.TestModel, new Uri("People?$filter=MyDog/Color eq 'Brown'&$select=ID&$expand=MyDog&$orderby=ID&$top=1&$skip=2&$count=true&$search=FA&$unknow=&$unknowvalue", UriKind.Relative)); + var parser = new ODataUriParser(HardCodedTestModel.TestModel, new Uri("People?$filter=MyDog/Color eq 'Brown'&$select=ID&$expand=MyDog&$orderby=ID&$top=1&$skip=2&$count=true&$search=FA&$unknow=&$unknowvalue&$skipToken=abc&$deltaToken=def&$format=application/json;odata.metadata=full", UriKind.Relative)); parser.ParseSelectAndExpand().Should().NotBeNull(); parser.ParseFilter().Should().NotBeNull(); parser.ParseOrderBy().Should().NotBeNull(); @@ -577,6 +597,9 @@ public void ParseQueryOptionsShouldWork() parser.ParseSkip().Should().Be(2); parser.ParseCount().Should().Be(true); parser.ParseSearch().Should().NotBeNull(); + parser.ParseSkipToken().Should().Be("abc"); + parser.ParseDeltaToken().Should().Be("def"); + parser.ParseFormat().Should().NotBeNull(); } #endregion From 32942ca331f9e3100c91a3da8c4dc6de8724e1d3 Mon Sep 17 00:00:00 2001 From: JefWight Date: Thu, 12 Mar 2015 12:38:05 -0700 Subject: [PATCH 3/4] Revert "Parse $skipToken, $deltaToken, and $format in ODataUri" This reverts commit 6955b762627fc5495308182325a1856f398cdee3. --- src/Microsoft.OData.Core/ODataUri.cs | 20 +---------- .../UriParser/ODataQueryOptionParser.cs | 30 ---------------- .../UriParser/ODataUriParser.cs | 36 ------------------- .../UriParser/UriQueryConstants.cs | 6 ---- ...seInsensitiveBuiltinIdentifierUnitTests.cs | 33 ----------------- .../ODataUriParserUnitTests.cs | 29 ++------------- 6 files changed, 4 insertions(+), 150 deletions(-) diff --git a/src/Microsoft.OData.Core/ODataUri.cs b/src/Microsoft.OData.Core/ODataUri.cs index c7a690e843..68c883d861 100644 --- a/src/Microsoft.OData.Core/ODataUri.cs +++ b/src/Microsoft.OData.Core/ODataUri.cs @@ -171,21 +171,6 @@ public IDictionary ParameterAliasNodes /// public bool? QueryCount { get; set; } - /// - /// Gets or sets any $skipToken option for this uri. - /// - public string SkipToken { get; set; } - - /// - /// Gets or sets any $deltaToken option for this uri. - /// - public string DeltaToken { get; set; } - - /// - /// Gets or sets any $format option for this uri. - /// - public IEnumerable> Format { get; set; } - /// /// Get or sets the MetadataDocumentUri, which is always ServiceRoot + $metadata /// @@ -216,10 +201,7 @@ public ODataUri Clone() Search = Search, Skip = Skip, Top = Top, - QueryCount = QueryCount, - SkipToken = SkipToken, - DeltaToken = DeltaToken, - Format = Format, + QueryCount = QueryCount }; } } diff --git a/src/Microsoft.OData.Core/UriParser/ODataQueryOptionParser.cs b/src/Microsoft.OData.Core/UriParser/ODataQueryOptionParser.cs index ccefce9756..8a02352dec 100644 --- a/src/Microsoft.OData.Core/UriParser/ODataQueryOptionParser.cs +++ b/src/Microsoft.OData.Core/UriParser/ODataQueryOptionParser.cs @@ -231,36 +231,6 @@ public SearchClause ParseSearch() this.searchClause = ParseSearchImplementation(searchQuery, this.Configuration); return searchClause; } - - /// - /// Parses a $skipToken query option - /// - /// A value representing that skip token option, null if $skipToken query does not exist. - public string ParseSkipToken() - { - string skipTokenQuery; - return this.TryGetQueryOption(UriQueryConstants.SkipTokenQueryOption, out skipTokenQuery) ? skipTokenQuery : null; - } - - /// - /// Parses a $deltaToken query option - /// - /// A value representing that delta token option, null if $deltaToken query does not exist. - public string ParseDeltaToken() - { - string deltaTokenQuery; - return this.TryGetQueryOption(UriQueryConstants.DeltaTokenQueryOption, out deltaTokenQuery) ? deltaTokenQuery : null; - } - - /// - /// Parses a $format query option - /// - /// A value representing that format option, null if $format query does not exist. - public IEnumerable> ParseFormat() - { - string formatQuery; - return this.TryGetQueryOption(UriQueryConstants.FormatQueryOption, out formatQuery) ? HttpUtils.MediaTypesFromString(formatQuery) : null; - } #endregion public methods #region private methods diff --git a/src/Microsoft.OData.Core/UriParser/ODataUriParser.cs b/src/Microsoft.OData.Core/UriParser/ODataUriParser.cs index da4bba3600..3da8fddec3 100644 --- a/src/Microsoft.OData.Core/UriParser/ODataUriParser.cs +++ b/src/Microsoft.OData.Core/UriParser/ODataUriParser.cs @@ -331,36 +331,6 @@ public SearchClause ParseSearch() return this.queryOptionParser.ParseSearch(); } - /// - /// Parses a $skipToken query option - /// - /// A value representing that skip token option, null if $skipToken query does not exist. - public string ParseSkipToken() - { - this.Initialize(); - return this.queryOptionParser.ParseSkipToken(); - } - - /// - /// Parses a $deltaToken query option - /// - /// A value representing that delta token option, null if $deltaToken query does not exist. - public string ParseDeltaToken() - { - this.Initialize(); - return this.queryOptionParser.ParseDeltaToken(); - } - - /// - /// Parses a $format query option - /// - /// A value representing that format option, null if $format query does not exist. - public IEnumerable> ParseFormat() - { - this.Initialize(); - return this.queryOptionParser.ParseFormat(); - } - /// /// Parse a full Uri into its contingent parts with semantic meaning attached to each part. /// See . @@ -379,18 +349,12 @@ public ODataUri ParseUri() long? top = this.ParseTop(); long? skip = this.ParseSkip(); bool? count = this.ParseCount(); - string skipToken = this.ParseSkipToken(); - string deltaToken = this.ParseDeltaToken(); - IEnumerable> format = this.ParseFormat(); // TODO: check it shouldn't be empty List boundQueryOptions = new List(); ODataUri odataUri = new ODataUri(this.ParameterAliasValueAccessor, path, boundQueryOptions, selectExpand, filter, orderBy, search, skip, top, count); odataUri.ServiceRoot = this.serviceRoot; - odataUri.SkipToken = skipToken; - odataUri.DeltaToken = deltaToken; - odataUri.Format = format; return odataUri; } diff --git a/src/Microsoft.OData.Core/UriParser/UriQueryConstants.cs b/src/Microsoft.OData.Core/UriParser/UriQueryConstants.cs index 4d24e370bf..8deee046a6 100644 --- a/src/Microsoft.OData.Core/UriParser/UriQueryConstants.cs +++ b/src/Microsoft.OData.Core/UriParser/UriQueryConstants.cs @@ -41,12 +41,6 @@ internal static class UriQueryConstants /// A skip query option name. internal const string SkipQueryOption = "$skip"; - /// A skip token query option name. - internal const string SkipTokenQueryOption = "$skipToken"; - - /// A delta token query option name. - internal const string DeltaTokenQueryOption = "$deltaToken"; - /// An entity id query option name. internal const string IdQueryOption = "$id"; diff --git a/test/FunctionalTests/Tests/DataOData/Tests/OData.Query.TDD.Tests/Metadata/CaseInsensitiveBuiltinIdentifierUnitTests.cs b/test/FunctionalTests/Tests/DataOData/Tests/OData.Query.TDD.Tests/Metadata/CaseInsensitiveBuiltinIdentifierUnitTests.cs index e9f42daa22..b1a524cf24 100644 --- a/test/FunctionalTests/Tests/DataOData/Tests/OData.Query.TDD.Tests/Metadata/CaseInsensitiveBuiltinIdentifierUnitTests.cs +++ b/test/FunctionalTests/Tests/DataOData/Tests/OData.Query.TDD.Tests/Metadata/CaseInsensitiveBuiltinIdentifierUnitTests.cs @@ -273,39 +273,6 @@ public void CaseInsensitiveSelectExpandConflicts() HardCodedTestModel.TestModel, new ODataUriResolver() { EnableCaseInsensitive = true }); } - - [TestMethod] - public void CaseInsensitiveSkipTokenShouldWork() - { - this.TestCaseInsensitiveBuiltIn( - "People?$skipToken=foo", - "People?$SKIPTOKEN=foo", - uriParser => uriParser.ParseSkipToken(), - val => val.Should().Be("foo"), - /*errorMessage*/ null); - } - - [TestMethod] - public void CaseInsensitiveDeltaTokenShouldWork() - { - this.TestCaseInsensitiveBuiltIn( - "People?$deltaToken=foo", - "People?$DELTATOKEN=foo", - uriParser => uriParser.ParseDeltaToken(), - val => val.Should().Be("foo"), - /*errorMessage*/ null); - } - - [TestMethod] - public void CaseInsensitiveFormatShouldWork() - { - this.TestCaseInsensitiveBuiltIn( - "People?$format=application/json", - "People?$FORMAT=application/json", - uriParser => uriParser.ParseFormat(), - format => format.Should().NotBeNull(), - /*errorMessage*/ null); - } #endregion #region builtin functions Tests diff --git a/test/FunctionalTests/Tests/DataOData/Tests/OData.Query.TDD.Tests/ODataUriParserUnitTests.cs b/test/FunctionalTests/Tests/DataOData/Tests/OData.Query.TDD.Tests/ODataUriParserUnitTests.cs index e1b9d84244..1931604808 100644 --- a/test/FunctionalTests/Tests/DataOData/Tests/OData.Query.TDD.Tests/ODataUriParserUnitTests.cs +++ b/test/FunctionalTests/Tests/DataOData/Tests/OData.Query.TDD.Tests/ODataUriParserUnitTests.cs @@ -11,6 +11,7 @@ namespace Microsoft.Test.OData.Query.TDD.Tests using System.Linq; using FluentAssertions; using Microsoft.OData.Edm; + using Microsoft.OData.Edm.Library; using Microsoft.OData.Core; using Microsoft.OData.Core.UriParser; using Microsoft.OData.Core.UriParser.Semantic; @@ -41,15 +42,12 @@ public void NoneQueryOptionShouldWork() uriParser.ParseSkip().Should().Be(null); uriParser.ParseCount().Should().Be(null); uriParser.ParseSearch().Should().BeNull(); - uriParser.ParseSkipToken().Should().BeNull(); - uriParser.ParseDeltaToken().Should().BeNull(); - uriParser.ParseFormat().Should().BeNull(); } [TestMethod] public void EmptyValueQueryOptionShouldWork() { - var uriParser = new ODataUriParser(HardCodedTestModel.TestModel, ServiceRoot, new Uri(FullUri, "?$filter=&$select=&$expand=&$orderby=&$top=&$skip=&$count=&$search=&$unknow=&$unknowvalue&$skipToken=&$deltaToken=&$format=")); + var uriParser = new ODataUriParser(HardCodedTestModel.TestModel, ServiceRoot, new Uri(FullUri, "?$filter=&$select=&$expand=&$orderby=&$top=&$skip=&$count=&$search=&$unknow=&$unknowvalue")); var path = uriParser.ParsePath(); path.Should().HaveCount(1); path.LastSegment.ShouldBeEntitySetSegment(HardCodedTestModel.GetPeopleSet()); @@ -66,9 +64,6 @@ public void EmptyValueQueryOptionShouldWork() action.ShouldThrow().WithMessage(Strings.ODataUriParser_InvalidCount("")); action = () => uriParser.ParseSearch(); action.ShouldThrow().WithMessage(Strings.UriQueryExpressionParser_ExpressionExpected(0, "")); - uriParser.ParseSkipToken().Should().BeEmpty(); - uriParser.ParseDeltaToken().Should().BeEmpty(); - uriParser.ParseFormat().Should().BeNull(); } [TestMethod] @@ -555,21 +550,6 @@ public void ErrorKeyTemplateInputShouldThrow() } } - [TestMethod] - public void ParseFormat() - { - var uriParser = new ODataUriParser(HardCodedTestModel.TestModel, ServiceRoot, new Uri(FullUri, "?$format=invalid")); - Action action = () => uriParser.ParseFormat(); - action.ShouldThrow().WithMessage(Strings.HttpUtils_MediaTypeUnspecified("invalid")); - - uriParser = new ODataUriParser(HardCodedTestModel.TestModel, ServiceRoot, new Uri(FullUri, "?$format=type/subtype")); - var format = uriParser.ParseFormat(); - format.Should().OnlyContain(pair => pair.Key.Type == "type" && pair.Key.SubType == "subtype" && pair.Key.Parameters == null && pair.Value == null); - - uriParser = new ODataUriParser(HardCodedTestModel.TestModel, ServiceRoot, new Uri(FullUri, "?$format=type1/subtype1;odata.metadata=full,type2/subtype2")); - uriParser.ParseFormat().Should().HaveCount(2); - } - #region Relative full path smoke test [TestMethod] public void AbsoluteUriInConstructorShouldThrow() @@ -589,7 +569,7 @@ public void ParsePathShouldWork() [TestMethod] public void ParseQueryOptionsShouldWork() { - var parser = new ODataUriParser(HardCodedTestModel.TestModel, new Uri("People?$filter=MyDog/Color eq 'Brown'&$select=ID&$expand=MyDog&$orderby=ID&$top=1&$skip=2&$count=true&$search=FA&$unknow=&$unknowvalue&$skipToken=abc&$deltaToken=def&$format=application/json;odata.metadata=full", UriKind.Relative)); + var parser = new ODataUriParser(HardCodedTestModel.TestModel, new Uri("People?$filter=MyDog/Color eq 'Brown'&$select=ID&$expand=MyDog&$orderby=ID&$top=1&$skip=2&$count=true&$search=FA&$unknow=&$unknowvalue", UriKind.Relative)); parser.ParseSelectAndExpand().Should().NotBeNull(); parser.ParseFilter().Should().NotBeNull(); parser.ParseOrderBy().Should().NotBeNull(); @@ -597,9 +577,6 @@ public void ParseQueryOptionsShouldWork() parser.ParseSkip().Should().Be(2); parser.ParseCount().Should().Be(true); parser.ParseSearch().Should().NotBeNull(); - parser.ParseSkipToken().Should().Be("abc"); - parser.ParseDeltaToken().Should().Be("def"); - parser.ParseFormat().Should().NotBeNull(); } #endregion From a2556bc02f091c031900ffe34a13a6e9d9e64c0a Mon Sep 17 00:00:00 2001 From: JefWight Date: Thu, 12 Mar 2015 12:41:06 -0700 Subject: [PATCH 4/4] Update header xml. Update header xml. --- src/Microsoft.OData.Core/ODataPreferenceHeader.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.OData.Core/ODataPreferenceHeader.cs b/src/Microsoft.OData.Core/ODataPreferenceHeader.cs index 60ab702345..42c05f007e 100644 --- a/src/Microsoft.OData.Core/ODataPreferenceHeader.cs +++ b/src/Microsoft.OData.Core/ODataPreferenceHeader.cs @@ -77,7 +77,7 @@ public sealed class ODataPreferenceHeader private static readonly KeyValuePair[] EmptyParameters = new KeyValuePair[0]; /// - /// The respond-async preference. + /// The odata.continue-on-error preference. /// private static readonly HttpHeaderValueElement ContinueOnErrorPreference = new HttpHeaderValueElement(ODataContinueOnErrorPreferenceToken, null, EmptyParameters); @@ -97,7 +97,7 @@ public sealed class ODataPreferenceHeader private static readonly HttpHeaderValueElement RespondAsyncPreference = new HttpHeaderValueElement(RespondAsyncPreferenceToken, null, EmptyParameters); /// - /// The respond-async preference. + /// The odata.track-changes preference. /// private static readonly HttpHeaderValueElement TrackChangesPreference = new HttpHeaderValueElement(ODataTrackChangesPreferenceToken, null, EmptyParameters);