diff --git a/.vscode/launch.json b/.vscode/launch.json index f4ebc69..ce76f36 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,6 +1,16 @@ { "version": "0.2.0", "configurations": [ + { + "name": "Launch Update Docs", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + "program": "${workspaceFolder}/tool/UpdateDocs/bin/Debug/net6.0/UpdateDocs.dll", + "cwd": "${workspaceFolder}/tool/UpdateDocs/bin/Debug/net6.0", + "console": "internalConsole", + "stopAtEntry": false + }, { "name": ".NET Core Attach", "type": "coreclr", diff --git a/Microsoft.OpenApi.OData.sln b/Microsoft.OpenApi.OData.sln index 7c8c29f..900a13d 100644 --- a/Microsoft.OpenApi.OData.sln +++ b/Microsoft.OpenApi.OData.sln @@ -16,6 +16,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution .editorconfig = .editorconfig EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tool", "tool", "{DE8F8E75-A119-4CF3-AFDD-4132B55DAE76}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UpdateDocs", "tool\UpdateDocs\UpdateDocs.csproj", "{AAC31ECB-05F9-444A-9B86-42ECD50AA468}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -38,6 +42,10 @@ Global {79B190E8-EDB0-4C03-8FD8-EB48E4807CFB}.Debug|Any CPU.Build.0 = Debug|Any CPU {79B190E8-EDB0-4C03-8FD8-EB48E4807CFB}.Release|Any CPU.ActiveCfg = Release|Any CPU {79B190E8-EDB0-4C03-8FD8-EB48E4807CFB}.Release|Any CPU.Build.0 = Release|Any CPU + {AAC31ECB-05F9-444A-9B86-42ECD50AA468}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AAC31ECB-05F9-444A-9B86-42ECD50AA468}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AAC31ECB-05F9-444A-9B86-42ECD50AA468}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AAC31ECB-05F9-444A-9B86-42ECD50AA468}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -45,4 +53,7 @@ Global GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {9AE22713-F94E-45CA-81F4-0806CA195B69} EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {AAC31ECB-05F9-444A-9B86-42ECD50AA468} = {DE8F8E75-A119-4CF3-AFDD-4132B55DAE76} + EndGlobalSection EndGlobal diff --git a/src/Microsoft.OpenApi.OData.Reader/Common/Constants.cs b/src/Microsoft.OpenApi.OData.Reader/Common/Constants.cs index d332dbe..b116bb0 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Common/Constants.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Common/Constants.cs @@ -79,5 +79,10 @@ namespace Microsoft.OpenApi.OData.Common /// extension for discriminator value support /// public static string xMsDiscriminatorValue = "x-ms-discriminator-value"; + + /// + /// Name used for the OpenAPI referenced schema for OData Count operations responses. + /// + public static string DollarCountSchemaName = "ODataCountResponse"; } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataDollarCountSegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataDollarCountSegment.cs index 2109dad..23f93ce 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataDollarCountSegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataDollarCountSegment.cs @@ -12,6 +12,11 @@ namespace Microsoft.OpenApi.OData.Edm /// public class ODataDollarCountSegment : ODataSegment { + /// + /// Get the static instance of $count segment. + /// + internal static ODataDollarCountSegment Instance = new(); + /// public override ODataSegmentKind Kind => ODataSegmentKind.DollarCount; diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPath.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPath.cs index 7c2d9cc..bd07491 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPath.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPath.cs @@ -146,8 +146,8 @@ namespace Microsoft.OpenApi.OData.Edm // From Open API spec, parameter name is case sensitive, so don't use the IgnoreCase HashSet. // HashSet parameters = new HashSet(StringComparer.OrdinalIgnoreCase); - HashSet parameters = new HashSet(); - StringBuilder sb = new StringBuilder(); + HashSet parameters = new(); + StringBuilder sb = new(); if (!string.IsNullOrWhiteSpace(settings.PathPrefix)) { diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs index 580d27a..3427d02 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs @@ -57,7 +57,7 @@ namespace Microsoft.OpenApi.OData.Edm { if (CanFilter(entitySet)) { - RetrieveNavigationSourcePaths(entitySet); + RetrieveNavigationSourcePaths(entitySet, settings); } } @@ -66,7 +66,7 @@ namespace Microsoft.OpenApi.OData.Edm { if (CanFilter(singleton)) { - RetrieveNavigationSourcePaths(singleton); + RetrieveNavigationSourcePaths(singleton, settings); } } @@ -102,7 +102,7 @@ namespace Microsoft.OpenApi.OData.Edm private IEnumerable MergePaths() { - List allODataPaths = new List(); + List allODataPaths = new(); foreach (var item in _allNavigationSourcePaths.Values) { allODataPaths.AddRange(item); @@ -127,6 +127,7 @@ namespace Microsoft.OpenApi.OData.Edm ODataPathKind kind = path.Kind; switch(kind) { + case ODataPathKind.DollarCount: case ODataPathKind.Entity: case ODataPathKind.EntitySet: case ODataPathKind.Singleton: @@ -143,8 +144,7 @@ namespace Microsoft.OpenApi.OData.Edm case ODataPathKind.NavigationProperty: case ODataPathKind.Ref: - ODataNavigationPropertySegment navigationPropertySegment = path.Last(p => p is ODataNavigationPropertySegment) - as ODataNavigationPropertySegment; + ODataNavigationPropertySegment navigationPropertySegment = path.OfType().Last(); if (!_allNavigationPropertyPaths.TryGetValue(navigationPropertySegment.EntityType, out IList npList)) { @@ -169,20 +169,26 @@ namespace Microsoft.OpenApi.OData.Edm /// Retrieve the paths for . /// /// The navigation source. - private void RetrieveNavigationSourcePaths(IEdmNavigationSource navigationSource) + /// The settings for the current conversion. + private void RetrieveNavigationSourcePaths(IEdmNavigationSource navigationSource, OpenApiConvertSettings convertSettings) { Debug.Assert(navigationSource != null); // navigation source itself - ODataPath path = new ODataPath(new ODataNavigationSourceSegment(navigationSource)); + ODataPath path = new(new ODataNavigationSourceSegment(navigationSource)); AppendPath(path.Clone()); IEdmEntitySet entitySet = navigationSource as IEdmEntitySet; IEdmEntityType entityType = navigationSource.EntityType(); + CountRestrictionsType count = null; - // for entity set, create a path with key + // for entity set, create a path with key and a $count path if (entitySet != null) { + count = _model.GetRecord(entitySet, CapabilitiesConstants.CountRestrictions); + if(count?.Countable ?? true) + CreateCountPath(path, convertSettings); + path.Push(new ODataKeySegment(entityType)); AppendPath(path.Clone()); } @@ -195,7 +201,7 @@ namespace Microsoft.OpenApi.OData.Edm { if (CanFilter(np)) { - RetrieveNavigationPropertyPaths(np, path); + RetrieveNavigationPropertyPaths(np, count, path, convertSettings); } } @@ -249,8 +255,10 @@ namespace Microsoft.OpenApi.OData.Edm /// Retrieve the path for . /// /// The navigation property. + /// The count restrictions. /// The current OData path. - private void RetrieveNavigationPropertyPaths(IEdmNavigationProperty navigationProperty, ODataPath currentPath) + /// The settings for the current conversion. + private void RetrieveNavigationPropertyPaths(IEdmNavigationProperty navigationProperty, CountRestrictionsType count, ODataPath currentPath, OpenApiConvertSettings convertSettings) { Debug.Assert(navigationProperty != null); Debug.Assert(currentPath != null); @@ -275,6 +283,15 @@ namespace Microsoft.OpenApi.OData.Edm if (restriction == null || restriction.IndexableByKey == true) { IEdmEntityType navEntityType = navigationProperty.ToEntityType(); + var targetsMany = navigationProperty.TargetMultiplicity() == EdmMultiplicity.Many; + var propertyPath = navigationProperty.GetPartnerPath()?.Path; + + if (targetsMany && (string.IsNullOrEmpty(propertyPath) || + (count?.IsNonCountableNavigationProperty(propertyPath) ?? true))) + { + // ~/entityset/{key}/collection-valued-Nav/$count + CreateCountPath(currentPath, convertSettings); + } if (!navigationProperty.ContainsTarget) { @@ -283,7 +300,7 @@ namespace Microsoft.OpenApi.OData.Edm // Collection-valued: ~/entityset/{key}/collection-valued-Nav/$ref?$id ={navKey} CreateRefPath(currentPath); - if (navigationProperty.TargetMultiplicity() == EdmMultiplicity.Many) + if (targetsMany) { // Collection-valued: DELETE ~/entityset/{key}/collection-valued-Nav/{key}/$ref currentPath.Push(new ODataKeySegment(navEntityType)); @@ -296,7 +313,7 @@ namespace Microsoft.OpenApi.OData.Edm else { // append a navigation property key. - if (navigationProperty.TargetMultiplicity() == EdmMultiplicity.Many) + if (targetsMany) { currentPath.Push(new ODataKeySegment(navEntityType)); AppendPath(currentPath.Clone()); @@ -312,13 +329,13 @@ namespace Microsoft.OpenApi.OData.Edm { if (CanFilter(subNavProperty)) { - RetrieveNavigationPropertyPaths(subNavProperty, currentPath); + RetrieveNavigationPropertyPaths(subNavProperty, count, currentPath, convertSettings); } } } } - if (navigationProperty.TargetMultiplicity() == EdmMultiplicity.Many) + if (targetsMany) { currentPath.Pop(); } @@ -361,6 +378,21 @@ namespace Microsoft.OpenApi.OData.Edm AppendPath(newPath); } + /// + /// Create $count paths. + /// + /// The current OData path. + /// The settings for the current conversion. + private void CreateCountPath(ODataPath currentPath, OpenApiConvertSettings convertSettings) + { + if(currentPath == null) throw new ArgumentNullException(nameof(currentPath)); + if(convertSettings == null) throw new ArgumentNullException(nameof(convertSettings)); + if(!convertSettings.EnableDollarCountPath) return; + var countPath = currentPath.Clone(); + countPath.Push(ODataDollarCountSegment.Instance); + AppendPath(countPath); + } + /// /// Retrieve all bounding . /// @@ -436,7 +468,11 @@ namespace Microsoft.OpenApi.OData.Edm } } } - + private static readonly HashSet _oDataPathKindsToSkipForOperations = new HashSet() { + ODataPathKind.EntitySet, + ODataPathKind.MediaEntity, + ODataPathKind.DollarCount + }; private bool AppendBoundOperationOnNavigationSourcePath(IEdmOperation edmOperation, bool isCollection, IEdmEntityType bindingEntityType) { bool found = false; @@ -448,8 +484,7 @@ namespace Microsoft.OpenApi.OData.Edm foreach (var subPath in value) { if ((isCollection && subPath.Kind == ODataPathKind.EntitySet) || - (!isCollection && subPath.Kind != ODataPathKind.EntitySet && - subPath.Kind != ODataPathKind.MediaEntity)) + (!isCollection && !_oDataPathKindsToSkipForOperations.Contains(subPath.Kind))) { ODataPath newPath = subPath.Clone(); newPath.Push(new ODataOperationSegment(edmOperation, isEscapedFunction)); @@ -461,7 +496,9 @@ namespace Microsoft.OpenApi.OData.Edm return found; } - + private static readonly HashSet _pathKindToSkipForNavigationProperties = new () { + ODataPathKind.Ref, + }; private bool AppendBoundOperationOnNavigationPropertyPath(IEdmOperation edmOperation, bool isCollection, IEdmEntityType bindingEntityType) { bool found = false; @@ -469,13 +506,8 @@ namespace Microsoft.OpenApi.OData.Edm if (_allNavigationPropertyPaths.TryGetValue(bindingEntityType, out IList value)) { - foreach (var path in value) + foreach (var path in value.Where(x => !_pathKindToSkipForNavigationProperties.Contains(x.Kind))) { - if (path.Kind == ODataPathKind.Ref) - { - continue; - } - ODataNavigationPropertySegment npSegment = path.Segments.Last(s => s is ODataNavigationPropertySegment) as ODataNavigationPropertySegment; if (!npSegment.NavigationProperty.ContainsTarget) @@ -596,15 +628,9 @@ namespace Microsoft.OpenApi.OData.Edm { if (_allNavigationPropertyPaths.TryGetValue(baseType, out IList paths)) { - foreach (var path in paths) + foreach (var path in paths.Where(x => !_pathKindToSkipForNavigationProperties.Contains(x.Kind))) { - if (path.Kind == ODataPathKind.Ref) - { - continue; - } - - var npSegment = path.Segments.Last(s => s is ODataNavigationPropertySegment) - as ODataNavigationPropertySegment; + var npSegment = path.Segments.OfType().LastOrDefault(); if (npSegment == null) { continue; diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/RecordExpressionExtensions.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/RecordExpressionExtensions.cs index ab37ba6..d205c27 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/RecordExpressionExtensions.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/RecordExpressionExtensions.cs @@ -29,20 +29,10 @@ namespace Microsoft.OpenApi.OData.Edm Utils.CheckArgumentNull(record, nameof(record)); Utils.CheckArgumentNull(propertyName, nameof(propertyName)); - if (record.Properties != null) - { - IEdmPropertyConstructor property = record.Properties.FirstOrDefault(e => e.Name == propertyName); - if (property != null) - { - IEdmIntegerConstantExpression value = property.Value as IEdmIntegerConstantExpression; - if (value != null) - { - return value.Value; - } - } - } - - return null; + return (record.Properties?.FirstOrDefault(e => e.Name == propertyName) is IEdmPropertyConstructor property && + property.Value is IEdmIntegerConstantExpression value) ? + value.Value : + null; } /// @@ -56,20 +46,10 @@ namespace Microsoft.OpenApi.OData.Edm Utils.CheckArgumentNull(record, nameof(record)); Utils.CheckArgumentNull(propertyName, nameof(propertyName)); - if (record.Properties != null) - { - IEdmPropertyConstructor property = record.Properties.FirstOrDefault(e => e.Name == propertyName); - if (property != null) - { - IEdmStringConstantExpression value = property.Value as IEdmStringConstantExpression; - if (value != null) - { - return value.Value; - } - } - } - - return null; + return (record.Properties?.FirstOrDefault(e => e.Name == propertyName) is IEdmPropertyConstructor property && + property.Value is IEdmStringConstantExpression value) ? + value.Value : + null; } /// @@ -83,20 +63,10 @@ namespace Microsoft.OpenApi.OData.Edm Utils.CheckArgumentNull(record, nameof(record)); Utils.CheckArgumentNull(propertyName, nameof(propertyName)); - if (record.Properties != null) - { - IEdmPropertyConstructor property = record.Properties.FirstOrDefault(e => e.Name == propertyName); - if (property != null) - { - IEdmBooleanConstantExpression value = property.Value as IEdmBooleanConstantExpression; - if (value != null) - { - return value.Value; - } - } - } - - return null; + return (record.Properties?.FirstOrDefault(e => e.Name == propertyName) is IEdmPropertyConstructor property && + property.Value is IEdmBooleanConstantExpression value) ? + value.Value : + null; } /// @@ -112,25 +82,13 @@ namespace Microsoft.OpenApi.OData.Edm Utils.CheckArgumentNull(record, nameof(record)); Utils.CheckArgumentNull(propertyName, nameof(propertyName)); - if (record.Properties != null) - { - IEdmPropertyConstructor property = record.Properties.FirstOrDefault(e => e.Name == propertyName); - if (property != null) - { - IEdmEnumMemberExpression value = property.Value as IEdmEnumMemberExpression; - if (value != null && value.EnumMembers != null && value.EnumMembers.Any()) - { - IEdmEnumMember member = value.EnumMembers.First(); - T result; - if (Enum.TryParse(member.Name, out result)) - { - return result; - } - } - } - } - - return null; + return (record.Properties?.FirstOrDefault(e => e.Name == propertyName) is IEdmPropertyConstructor property && + property.Value is IEdmEnumMemberExpression value && + value.EnumMembers != null && + value.EnumMembers.Any() && + Enum.TryParse(value.EnumMembers.First().Name, out T result)) ? + result : + null; } /// @@ -146,16 +104,12 @@ namespace Microsoft.OpenApi.OData.Edm Utils.CheckArgumentNull(record, nameof(record)); Utils.CheckArgumentNull(propertyName, nameof(propertyName)); - IEdmPropertyConstructor property = record.Properties.FirstOrDefault(e => e.Name == propertyName); - if (property != null) + if (record.Properties?.FirstOrDefault(e => e.Name == propertyName) is IEdmPropertyConstructor property && + property.Value is IEdmRecordExpression recordValue) { - IEdmRecordExpression recordValue = property.Value as IEdmRecordExpression; - if (recordValue != null) - { - T a = new T(); - a.Initialize(recordValue); - return a; - } + T a = new(); + a.Initialize(recordValue); + return a; } return default; @@ -172,20 +126,10 @@ namespace Microsoft.OpenApi.OData.Edm Utils.CheckArgumentNull(record, nameof(record)); Utils.CheckArgumentNull(propertyName, nameof(propertyName)); - if (record.Properties != null) - { - IEdmPropertyConstructor property = record.Properties.FirstOrDefault(e => e.Name == propertyName); - if (property != null) - { - IEdmPathExpression value = property.Value as IEdmPathExpression; - if (value != null) - { - return value.Path; - } - } - } - - return null; + return (record.Properties?.FirstOrDefault(e => e.Name == propertyName) is IEdmPropertyConstructor property && + property.Value is IEdmPathExpression value) ? + value.Path : + null; } /// @@ -199,25 +143,18 @@ namespace Microsoft.OpenApi.OData.Edm Utils.CheckArgumentNull(record, nameof(record)); Utils.CheckArgumentNull(propertyName, nameof(propertyName)); - if (record.Properties != null) + if (record.Properties?.FirstOrDefault(e => e.Name == propertyName) is IEdmPropertyConstructor property && + property.Value is IEdmCollectionExpression value && value.Elements != null) { - IEdmPropertyConstructor property = record.Properties.FirstOrDefault(e => e.Name == propertyName); - if (property != null) - { - IEdmCollectionExpression value = property.Value as IEdmCollectionExpression; - if (value != null && value.Elements != null) - { - IList properties = new List(); - foreach (var path in value.Elements.Select(e => e as IEdmPathExpression)) - { - properties.Add(path.Path); - } + IList properties = + value.Elements + .OfType() + .Select(x => x.Path) + .ToList(); - if (properties.Any()) - { - return properties; - } - } + if (properties.Any()) + { + return properties; } } @@ -235,21 +172,14 @@ namespace Microsoft.OpenApi.OData.Edm Utils.CheckArgumentNull(record, nameof(record)); Utils.CheckArgumentNull(propertyName, nameof(propertyName)); - IEdmPropertyConstructor property = record.Properties.FirstOrDefault(e => e.Name == propertyName); - if (property != null) + if (record.Properties?.FirstOrDefault(e => e.Name == propertyName) is IEdmPropertyConstructor property && + property.Value is IEdmCollectionExpression collection && collection.Elements != null) { - IEdmCollectionExpression collection = property.Value as IEdmCollectionExpression; - if (collection != null && collection.Elements != null) - { - IList items = new List(); - foreach (var item in collection.Elements) - { - IEdmStringConstantExpression itemRecord = item as IEdmStringConstantExpression; - items.Add(itemRecord.Value); - } - - return items; - } + IList items = collection.Elements + .OfType() + .Select(x => x.Value) + .ToList(); + return items; } return null; @@ -268,22 +198,18 @@ namespace Microsoft.OpenApi.OData.Edm Utils.CheckArgumentNull(record, nameof(record)); Utils.CheckArgumentNull(propertyName, nameof(propertyName)); - IEdmPropertyConstructor property = record.Properties.FirstOrDefault(e => e.Name == propertyName); - if (property != null) + if (record.Properties?.FirstOrDefault(e => e.Name == propertyName) is IEdmPropertyConstructor property && + property.Value is IEdmCollectionExpression collection && collection.Elements != null) { - IEdmCollectionExpression collection = property.Value as IEdmCollectionExpression; - if (collection != null && collection.Elements != null) + IList items = new List(); + foreach (IEdmRecordExpression item in collection.Elements.OfType()) { - IList items = new List(); - foreach (IEdmRecordExpression item in collection.Elements.OfType()) - { - T a = new T(); - a.Initialize(item); - items.Add(a); - } - - return items; + T a = new(); + a.Initialize(item); + items.Add(a); } + + return items; } return null; diff --git a/src/Microsoft.OpenApi.OData.Reader/EdmModelOpenApiExtensions.cs b/src/Microsoft.OpenApi.OData.Reader/EdmModelOpenApiExtensions.cs index 5043276..60fab5c 100644 --- a/src/Microsoft.OpenApi.OData.Reader/EdmModelOpenApiExtensions.cs +++ b/src/Microsoft.OpenApi.OData.Reader/EdmModelOpenApiExtensions.cs @@ -42,21 +42,20 @@ namespace Microsoft.OpenApi.OData if (settings.VerifyEdmModel) { - IEnumerable errors; - if (!model.Validate(out errors)) - { - OpenApiDocument document = new OpenApiDocument(); - int index = 1; - foreach (var error in errors) - { - document.Extensions.Add(Constants.xMsEdmModelError + index++, new OpenApiString(error.ToString())); - } + if (!model.Validate(out var errors)) + { + OpenApiDocument document = new(); + int index = 1; + foreach (var error in errors) + { + document.Extensions.Add(Constants.xMsEdmModelError + index++, new OpenApiString(error.ToString())); + } - return document; - } - } + return document; + } + } - ODataContext context = new ODataContext(model, settings); + ODataContext context = new(model, settings); return context.CreateDocument(); } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiPathItemGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiPathItemGenerator.cs index 13832d7..db276fd 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiPathItemGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiPathItemGenerator.cs @@ -54,7 +54,7 @@ namespace Microsoft.OpenApi.OData.Generator if (settings.ShowRootPath) { - OpenApiPathItem rootPath = new OpenApiPathItem() + OpenApiPathItem rootPath = new() { Operations = new Dictionary { { diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSchemaGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSchemaGenerator.cs index c989b15..67a9e29 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSchemaGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSchemaGenerator.cs @@ -67,6 +67,12 @@ namespace Microsoft.OpenApi.OData.Generator schemas[schema.Key] = schema.Value; } + if(context.Settings.EnableDollarCountPath) + schemas[Constants.DollarCountSchemaName] = new OpenApiSchema { + Type = "integer", + Format = "int32" + }; + return schemas; } diff --git a/src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs b/src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs index 5fdc97d..be319c3 100644 --- a/src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs +++ b/src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs @@ -183,6 +183,11 @@ namespace Microsoft.OpenApi.OData /// public IODataPathProvider PathProvider { get; set; } + /// + /// Gets/sets a value indicating whether or not add OData $count segments in the description for collections. + /// + public bool EnableDollarCountPath { get; set; } = true; + internal OpenApiConvertSettings Clone() { var newSettings = new OpenApiConvertSettings @@ -212,7 +217,8 @@ namespace Microsoft.OpenApi.OData RequireDerivedTypesConstraintForBoundOperations = this.RequireDerivedTypesConstraintForBoundOperations, ShowSchemaExamples = this.ShowSchemaExamples, ShowRootPath = this.ShowRootPath, - PathProvider = this.PathProvider + PathProvider = this.PathProvider, + EnableDollarCountPath = this.EnableDollarCountPath, }; return newSettings; diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/DollarCountGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/DollarCountGetOperationHandler.cs index 62673b0..9cfcb74 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/DollarCountGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/DollarCountGetOperationHandler.cs @@ -25,7 +25,7 @@ namespace Microsoft.OpenApi.OData.Operation /// this segment could be "entity set", "Collection property", "Composable function whose return is collection",etc. /// internal ODataSegment LastSecondSegment { get; set; } - + private const int SecondLastSegmentIndex = 2; /// protected override void Initialize(ODataContext context, ODataPath path) { @@ -33,7 +33,8 @@ namespace Microsoft.OpenApi.OData.Operation // get the last second segment int count = path.Segments.Count; - LastSecondSegment = path.Segments.ElementAt(count - 1); + if(count >= SecondLastSegmentIndex) + LastSecondSegment = path.Segments.ElementAt(count - SecondLastSegmentIndex); } /// @@ -54,10 +55,12 @@ namespace Microsoft.OpenApi.OData.Operation /// protected override void SetResponses(OpenApiOperation operation) { - OpenApiSchema schema = new OpenApiSchema - { - Type = "integer", - Format = "int32" + OpenApiSchema schema = new() + { + Reference = new() { + Type = ReferenceType.Schema, + Id = Constants.DollarCountSchemaName + } }; operation.Responses = new OpenApiResponses diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandlerProvider.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandlerProvider.cs index e3a7c74..1291505 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandlerProvider.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandlerProvider.cs @@ -14,88 +14,82 @@ namespace Microsoft.OpenApi.OData.Operation /// internal class OperationHandlerProvider : IOperationHandlerProvider { - private IDictionary> _handlers; - - /// - /// Initializes a new instance of class. - /// - public OperationHandlerProvider() - { - _handlers = new Dictionary>(); + private readonly IDictionary> _handlers + = new Dictionary>{ // entity set (Get/Post) - _handlers[ODataPathKind.EntitySet] = new Dictionary + {ODataPathKind.EntitySet, new Dictionary { {OperationType.Get, new EntitySetGetOperationHandler() }, {OperationType.Post, new EntitySetPostOperationHandler() } - }; + }}, // entity (Get/Patch/Delete) - _handlers[ODataPathKind.Entity] = new Dictionary + {ODataPathKind.Entity, new Dictionary { {OperationType.Get, new EntityGetOperationHandler() }, {OperationType.Patch, new EntityPatchOperationHandler() }, {OperationType.Delete, new EntityDeleteOperationHandler() } - }; + }}, // singleton (Get/Patch) - _handlers[ODataPathKind.Singleton] = new Dictionary + {ODataPathKind.Singleton, new Dictionary { {OperationType.Get, new SingletonGetOperationHandler() }, {OperationType.Patch, new SingletonPatchOperationHandler() } - }; + }}, // edm operation (Get|Post) - _handlers[ODataPathKind.Operation] = new Dictionary + {ODataPathKind.Operation, new Dictionary { {OperationType.Get, new EdmFunctionOperationHandler() }, {OperationType.Post, new EdmActionOperationHandler() } - }; + }}, // edm operation import (Get|Post) - _handlers[ODataPathKind.OperationImport] = new Dictionary + {ODataPathKind.OperationImport, new Dictionary { {OperationType.Get, new EdmFunctionImportOperationHandler() }, {OperationType.Post, new EdmActionImportOperationHandler() } - }; + }}, // navigation property (Get/Patch/Post/Delete) - _handlers[ODataPathKind.NavigationProperty] = new Dictionary + {ODataPathKind.NavigationProperty, new Dictionary { {OperationType.Get, new NavigationPropertyGetOperationHandler() }, {OperationType.Patch, new NavigationPropertyPatchOperationHandler() }, {OperationType.Post, new NavigationPropertyPostOperationHandler() }, {OperationType.Delete, new NavigationPropertyDeleteOperationHandler() } - }; + }}, // navigation property ref (Get/Post/Put/Delete) - _handlers[ODataPathKind.Ref] = new Dictionary + {ODataPathKind.Ref, new Dictionary { {OperationType.Get, new RefGetOperationHandler() }, {OperationType.Put, new RefPutOperationHandler() }, {OperationType.Post, new RefPostOperationHandler() }, {OperationType.Delete, new RefDeleteOperationHandler() } - }; + }}, // media entity operation (Get|Put) - _handlers[ODataPathKind.MediaEntity] = new Dictionary + {ODataPathKind.MediaEntity, new Dictionary { {OperationType.Get, new MediaEntityGetOperationHandler() }, {OperationType.Put, new MediaEntityPutOperationHandler() } - }; + }}, // $metadata operation (Get) - _handlers[ODataPathKind.Metadata] = new Dictionary + {ODataPathKind.Metadata, new Dictionary { {OperationType.Get, new MetadataGetOperationHandler() } - }; + }}, // $count operation (Get) - _handlers[ODataPathKind.DollarCount] = new Dictionary + {ODataPathKind.DollarCount, new Dictionary { {OperationType.Get, new DollarCountGetOperationHandler() } - }; - } + }}, + }; /// public IOperationHandler GetHandler(ODataPathKind pathKind, OperationType operationType) diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs index 6334325..132c59a 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs @@ -14,7 +14,6 @@ using Microsoft.OpenApi.OData.Edm; using Microsoft.OpenApi.Any; using Microsoft.OData.Edm.Vocabularies; using Microsoft.OpenApi.OData.Vocabulary.Capabilities; -using System.Drawing; namespace Microsoft.OpenApi.OData.PathItem { @@ -46,8 +45,8 @@ namespace Microsoft.OpenApi.OData.PathItem /// protected bool LastSegmentIsRefSegment { get; private set; } - /// - protected override void SetOperations(OpenApiPathItem item) + /// + protected override void SetOperations(OpenApiPathItem item) { IEdmEntitySet entitySet = NavigationSource as IEdmEntitySet; IEdmVocabularyAnnotatable target = entitySet; @@ -79,7 +78,7 @@ namespace Microsoft.OpenApi.OData.PathItem } } - // contaiment: Get / (Post - Collection | Patch - Single) + // containment: Get / (Post - Collection | Patch - Single) // non-containment: Get AddGetOperation(item, restriction); @@ -216,18 +215,17 @@ namespace Microsoft.OpenApi.OData.PathItem continue; } - ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment; - if (NavigationSource != navigationSourceSegment.NavigationSource) + if (path.FirstSegment is ODataNavigationSourceSegment navigationSourceSegment && + NavigationSource != navigationSourceSegment.NavigationSource) { continue; } - ODataNavigationPropertySegment npSegment = path.LastSegment as ODataNavigationPropertySegment; - if (npSegment == null) - { - npSegment = path.Segments[path.Count - 2] as ODataNavigationPropertySegment; - } - if (NavigationProperty != npSegment.NavigationProperty) + if (path.LastSegment is not ODataNavigationPropertySegment npSegment) + { + npSegment = path.Segments[path.Count - 2] as ODataNavigationPropertySegment; + } + if (NavigationProperty != npSegment.NavigationProperty) { continue; } @@ -237,7 +235,7 @@ namespace Microsoft.OpenApi.OData.PathItem if (samePaths.Any()) { - OpenApiArray array = new OpenApiArray(); + OpenApiArray array = new(); OpenApiConvertSettings settings = Context.Settings.Clone(); settings.EnableKeyAsSegment = Context.KeyAsSegment; foreach (var p in samePaths) diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/PathItemHandlerProvider.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/PathItemHandlerProvider.cs index 00eac42..ae81bc3 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/PathItemHandlerProvider.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/PathItemHandlerProvider.cs @@ -13,7 +13,7 @@ namespace Microsoft.OpenApi.OData.PathItem /// internal class PathItemHandlerProvider : IPathItemHandlerProvider { - private IDictionary _handlers = new Dictionary + private readonly IDictionary _handlers = new Dictionary { // EntitySet { ODataPathKind.EntitySet, new EntitySetPathItemHandler() }, diff --git a/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt b/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt index 3aa5997..97ec543 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt +++ b/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt @@ -128,6 +128,8 @@ Microsoft.OpenApi.OData.OpenApiConvertSettings.PathPrefix.get -> string Microsoft.OpenApi.OData.OpenApiConvertSettings.PathPrefix.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.PathProvider.get -> Microsoft.OpenApi.OData.Edm.IODataPathProvider Microsoft.OpenApi.OData.OpenApiConvertSettings.PathProvider.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableDollarCountPath.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableDollarCountPath.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.PrefixEntityTypeNameBeforeKey.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.PrefixEntityTypeNameBeforeKey.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.RequireDerivedTypesConstraintForBoundOperations.get -> bool diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/CountRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/CountRestrictionsType.cs index fcb5d1f..17447ca 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/CountRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/CountRestrictionsType.cs @@ -36,7 +36,7 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities /// Test the target supports count. /// /// True/false. - public bool IsCountable => Countable == null || Countable.Value; + public bool IsCountable => !Countable.HasValue || Countable.Value; /// /// Test the input property path which do not allow /$count segments. @@ -45,7 +45,7 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities /// True/False. public bool IsNonCountableProperty(string propertyPath) { - return NonCountableProperties != null ? NonCountableProperties.Any(a => a == propertyPath) : false; + return NonCountableProperties != null && NonCountableProperties.Any(a => a == propertyPath); } /// @@ -55,9 +55,7 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities /// True/False. public bool IsNonCountableNavigationProperty(string navigationPropertyPath) { - return NonCountableNavigationProperties != null ? - NonCountableNavigationProperties.Any(a => a == navigationPropertyPath) : - false; + return NonCountableNavigationProperties != null && NonCountableNavigationProperties.Any(a => a == navigationPropertyPath); } /// diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Edm/ODataPathProviderTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Edm/ODataPathProviderTests.cs index fa4f3b6..2daaa80 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Edm/ODataPathProviderTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Edm/ODataPathProviderTests.cs @@ -48,7 +48,7 @@ namespace Microsoft.OpenApi.OData.Edm.Tests // Assert Assert.NotNull(paths); - Assert.Equal(13727, paths.Count()); + Assert.Equal(17178, paths.Count()); } [Fact] @@ -67,7 +67,7 @@ namespace Microsoft.OpenApi.OData.Edm.Tests // Assert Assert.NotNull(paths); - Assert.Equal(13712, paths.Count()); + Assert.Equal(17163, paths.Count()); } [Fact] @@ -81,6 +81,24 @@ namespace Microsoft.OpenApi.OData.Edm.Tests // Act var paths = provider.GetPaths(model, settings); + // Assert + Assert.NotNull(paths); + Assert.Equal(4, paths.Count()); + } + + [Fact] + public void GetPathsDoesntReturnPathsForCountWhenDisabled() + { + // Arrange + IEdmModel model = GetInheritanceModel(string.Empty); + ODataPathProvider provider = new ODataPathProvider(); + var settings = new OpenApiConvertSettings { + EnableDollarCountPath = false, + }; + + // Act + var paths = provider.GetPaths(model, settings); + // Assert Assert.NotNull(paths); Assert.Equal(3, paths.Count()); @@ -102,7 +120,7 @@ namespace Microsoft.OpenApi.OData.Edm.Tests // Assert Assert.NotNull(paths); - Assert.Equal(2, paths.Count()); + Assert.Equal(3, paths.Count()); } [Fact] @@ -126,7 +144,7 @@ namespace Microsoft.OpenApi.OData.Edm.Tests var paths = provider.GetPaths(model, settings); // Assert - Assert.Equal(3, paths.Count()); + Assert.Equal(4, paths.Count()); } #if DEBUG @@ -151,7 +169,7 @@ namespace Microsoft.OpenApi.OData.Edm.Tests // Assert Assert.NotNull(paths); - Assert.Equal(4, paths.Count()); + Assert.Equal(5, paths.Count()); } [Fact] @@ -170,7 +188,7 @@ namespace Microsoft.OpenApi.OData.Edm.Tests // Assert Assert.NotNull(paths); - Assert.Equal(3, paths.Count()); + Assert.Equal(4, paths.Count()); } [Fact] @@ -195,7 +213,7 @@ namespace Microsoft.OpenApi.OData.Edm.Tests // Assert Assert.NotNull(paths); - Assert.Equal(4, paths.Count()); + Assert.Equal(5, paths.Count()); } [Fact] @@ -211,8 +229,8 @@ namespace Microsoft.OpenApi.OData.Edm.Tests // Assert Assert.NotNull(paths); - Assert.Equal(2, paths.Count()); - Assert.Equal(new[] { "/Customers", "/Customers({ID})" }, paths.Select(p => p.GetPathItemName())); + Assert.Equal(3, paths.Count()); + Assert.Equal(new[] { "/Customers", "/Customers({ID})", "/Customers/$count" }, paths.Select(p => p.GetPathItemName())); } [Fact] @@ -228,7 +246,7 @@ namespace Microsoft.OpenApi.OData.Edm.Tests // Assert Assert.NotNull(paths); - Assert.Equal(3, paths.Count()); + Assert.Equal(4, paths.Count()); Assert.Contains("/Me", paths.Select(p => p.GetPathItemName())); } @@ -250,7 +268,7 @@ namespace Microsoft.OpenApi.OData.Edm.Tests // Assert Assert.NotNull(paths); - Assert.Equal(3, paths.Count()); + Assert.Equal(4, paths.Count()); Assert.Contains("/Customers/NS.delta()", paths.Select(p => p.GetPathItemName())); } @@ -272,7 +290,7 @@ namespace Microsoft.OpenApi.OData.Edm.Tests // Assert Assert.NotNull(paths); - Assert.Equal(3, paths.Count()); + Assert.Equal(4, paths.Count()); Assert.Contains("/Customers({ID})/NS.renew", paths.Select(p => p.GetPathItemName())); } @@ -301,7 +319,7 @@ namespace Microsoft.OpenApi.OData.Edm.Tests // Assert Assert.NotNull(paths); - Assert.Equal(4, paths.Count()); + Assert.Equal(5, paths.Count()); if (containsTarget) { @@ -338,7 +356,7 @@ namespace Microsoft.OpenApi.OData.Edm.Tests // Assert Assert.NotNull(paths); - Assert.Equal(4, paths.Count()); + Assert.Equal(5, paths.Count()); if (containsTarget) { @@ -373,7 +391,7 @@ namespace Microsoft.OpenApi.OData.Edm.Tests // Assert Assert.NotNull(paths); - Assert.Equal(4, paths.Count()); + Assert.Equal(5, paths.Count()); Assert.Contains("/GetNearestCustomers()", paths.Select(p => p.GetPathItemName())); Assert.Contains("/ResetDataSource", paths.Select(p => p.GetPathItemName())); } @@ -410,7 +428,7 @@ namespace Microsoft.OpenApi.OData.Edm.Tests // Assert Assert.NotNull(paths); - Assert.Equal(7, paths.Count()); + Assert.Equal(10, paths.Count()); var pathItems = paths.Select(p => p.GetPathItemName()).ToList(); Assert.DoesNotContain("/Orders({id})/SingleCustomer", pathItems); @@ -453,7 +471,7 @@ namespace Microsoft.OpenApi.OData.Edm.Tests // Assert Assert.NotNull(paths); - Assert.Equal(7, paths.Count()); + Assert.Equal(9, paths.Count()); var pathItems = paths.Select(p => p.GetPathItemName()).ToList(); Assert.DoesNotContain("/Orders({id})/MultipleCustomers({ID})", pathItems); @@ -483,7 +501,7 @@ namespace Microsoft.OpenApi.OData.Edm.Tests // Assert Assert.NotNull(paths); - Assert.Equal(9, paths.Count()); + Assert.Equal(12, paths.Count()); var pathItems = paths.Select(p => p.GetPathItemName()).ToList(); Assert.Contains("/Orders({id})/MultipleCustomers", pathItems); @@ -516,7 +534,7 @@ namespace Microsoft.OpenApi.OData.Edm.Tests // Assert Assert.NotNull(paths); - Assert.Equal(7, paths.Count()); + Assert.Equal(10, paths.Count()); var pathItems = paths.Select(p => p.GetPathItemName()).ToList(); Assert.Contains("/Orders({id})/MultipleCustomers", pathItems); @@ -552,14 +570,14 @@ namespace Microsoft.OpenApi.OData.Edm.Tests { if (hasStream) { - Assert.Equal(13, paths.Count()); + Assert.Equal(15, paths.Count()); Assert.Contains(TodosValuePath, paths.Select(p => p.GetPathItemName())); Assert.Contains(TodosLogoPath, paths.Select(p => p.GetPathItemName())); Assert.DoesNotContain(TodosContentPath, paths.Select(p => p.GetPathItemName())); } else { - Assert.Equal(12, paths.Count()); + Assert.Equal(14, paths.Count()); Assert.Contains(TodosLogoPath, paths.Select(p => p.GetPathItemName())); Assert.DoesNotContain(TodosContentPath, paths.Select(p => p.GetPathItemName())); Assert.DoesNotContain(TodosValuePath, paths.Select(p => p.GetPathItemName())); @@ -567,7 +585,7 @@ namespace Microsoft.OpenApi.OData.Edm.Tests } else if (streamPropName.Equals("content")) { - Assert.Equal(12, paths.Count()); + Assert.Equal(14, paths.Count()); Assert.Contains(TodosContentPath, paths.Select(p => p.GetPathItemName())); Assert.DoesNotContain(TodosLogoPath, paths.Select(p => p.GetPathItemName())); Assert.DoesNotContain(TodosValuePath, paths.Select(p => p.GetPathItemName())); diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiPathItemGeneratorTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiPathItemGeneratorTests.cs index b163330..9eae7de 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiPathItemGeneratorTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiPathItemGeneratorTests.cs @@ -57,13 +57,16 @@ namespace Microsoft.OpenApi.OData.Generator.Tests // Assert Assert.NotNull(pathItems); - Assert.Equal(7, pathItems.Count); + Assert.Equal(10, pathItems.Count); Assert.Contains("/People", pathItems.Keys); + Assert.Contains("/People/$count", pathItems.Keys); Assert.Contains("/People/{UserName}", pathItems.Keys); Assert.Contains("/City", pathItems.Keys); + Assert.Contains("/City/$count", pathItems.Keys); Assert.Contains("/City/{Name}", pathItems.Keys); Assert.Contains("/CountryOrRegion", pathItems.Keys); + Assert.Contains("/CountryOrRegion/$count", pathItems.Keys); Assert.Contains("/CountryOrRegion/{Name}", pathItems.Keys); Assert.Contains("/Me", pathItems.Keys); } @@ -114,9 +117,10 @@ namespace Microsoft.OpenApi.OData.Generator.Tests // Assert Assert.NotNull(pathItems); - Assert.Equal(3, pathItems.Count); + Assert.Equal(4, pathItems.Count); Assert.Contains("/Customers", pathItems.Keys); + Assert.Contains("/Customers/$count", pathItems.Keys); Assert.Contains("/Customers({ID})", pathItems.Keys); Assert.Contains(expected, pathItems.Keys); } diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiPathsGeneratorTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiPathsGeneratorTests.cs index ac03f72..a7c63dd 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiPathsGeneratorTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiPathsGeneratorTests.cs @@ -56,13 +56,16 @@ namespace Microsoft.OpenApi.OData.Generator.Tests // Assert Assert.NotNull(paths); - Assert.Equal(7, paths.Count); + Assert.Equal(10, paths.Count); Assert.Contains("/People", paths.Keys); + Assert.Contains("/People/$count", paths.Keys); Assert.Contains("/People/{UserName}", paths.Keys); Assert.Contains("/City", paths.Keys); + Assert.Contains("/City/$count", paths.Keys); Assert.Contains("/City/{Name}", paths.Keys); Assert.Contains("/CountryOrRegion", paths.Keys); + Assert.Contains("/CountryOrRegion/$count", paths.Keys); Assert.Contains("/CountryOrRegion/{Name}", paths.Keys); Assert.Contains("/Me", paths.Keys); } @@ -84,13 +87,16 @@ namespace Microsoft.OpenApi.OData.Generator.Tests // Assert Assert.NotNull(paths); - Assert.Equal(7, paths.Count); + Assert.Equal(10, paths.Count); Assert.Contains("/some/prefix/People", paths.Keys); + Assert.Contains("/some/prefix/People/$count", paths.Keys); Assert.Contains("/some/prefix/People/{UserName}", paths.Keys); Assert.Contains("/some/prefix/City", paths.Keys); + Assert.Contains("/some/prefix/City/$count", paths.Keys); Assert.Contains("/some/prefix/City/{Name}", paths.Keys); Assert.Contains("/some/prefix/CountryOrRegion", paths.Keys); + Assert.Contains("/some/prefix/CountryOrRegion/$count", paths.Keys); Assert.Contains("/some/prefix/CountryOrRegion/{Name}", paths.Keys); Assert.Contains("/some/prefix/Me", paths.Keys); } @@ -112,9 +118,10 @@ namespace Microsoft.OpenApi.OData.Generator.Tests // Assert Assert.NotNull(paths); - Assert.Equal(4, paths.Count); + Assert.Equal(5, paths.Count); Assert.Contains("/Accounts", paths.Keys); + Assert.Contains("/Accounts/$count", paths.Keys); Assert.Contains("/Accounts/{id}", paths.Keys); Assert.Contains("/Accounts/{id}/Attachments()", paths.Keys); Assert.Contains("/Accounts/{id}/AttachmentsAdd", paths.Keys); diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.V2.json b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.V2.json index 6cfcbf9..46db39d 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.V2.json +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.V2.json @@ -260,6 +260,26 @@ "x-ms-docs-operation-type": "operation" } }, + "/City/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.City", + "produces": [ + "text/plain" + ], + "responses": { + "200": { + "description": "The count of the resource", + "schema": { + "$ref": "#/definitions/ODataCountResponse" + } + }, + "default": { + "$ref": "#/responses/error" + } + } + } + }, "/CountryOrRegion": { "get": { "tags": [ @@ -510,6 +530,26 @@ "x-ms-docs-operation-type": "operation" } }, + "/CountryOrRegion/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.CountryOrRegion", + "produces": [ + "text/plain" + ], + "responses": { + "200": { + "description": "The count of the resource", + "schema": { + "$ref": "#/definitions/ODataCountResponse" + } + }, + "default": { + "$ref": "#/responses/error" + } + } + } + }, "/Me": { "get": { "tags": [ @@ -856,6 +896,26 @@ }, "x-ms-docs-operation-type": "operation" } + }, + "/People/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.People", + "produces": [ + "text/plain" + ], + "responses": { + "200": { + "description": "The count of the resource", + "schema": { + "$ref": "#/definitions/ODataCountResponse" + } + }, + "default": { + "$ref": "#/responses/error" + } + } + } } }, "definitions": { @@ -1029,6 +1089,10 @@ "type": "string" } } + }, + "ODataCountResponse": { + "format": "int32", + "type": "integer" } }, "parameters": { diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.V2.yaml b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.V2.yaml index cb4900b..ca55821 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.V2.yaml +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.V2.yaml @@ -170,6 +170,19 @@ paths: default: $ref: '#/responses/error' x-ms-docs-operation-type: operation + /City/$count: + get: + summary: Get the number of the resource + operationId: Get.Count.City + produces: + - text/plain + responses: + '200': + description: The count of the resource + schema: + $ref: '#/definitions/ODataCountResponse' + default: + $ref: '#/responses/error' /CountryOrRegion: get: tags: @@ -333,6 +346,19 @@ paths: default: $ref: '#/responses/error' x-ms-docs-operation-type: operation + /CountryOrRegion/$count: + get: + summary: Get the number of the resource + operationId: Get.Count.CountryOrRegion + produces: + - text/plain + responses: + '200': + description: The count of the resource + schema: + $ref: '#/definitions/ODataCountResponse' + default: + $ref: '#/responses/error' /Me: get: tags: @@ -566,6 +592,19 @@ paths: default: $ref: '#/responses/error' x-ms-docs-operation-type: operation + /People/$count: + get: + summary: Get the number of the resource + operationId: Get.Count.People + produces: + - text/plain + responses: + '200': + description: The count of the resource + schema: + $ref: '#/definitions/ODataCountResponse' + default: + $ref: '#/responses/error' definitions: DefaultNs.Color: title: Color @@ -679,6 +718,9 @@ definitions: type: string target: type: string + ODataCountResponse: + format: int32 + type: integer parameters: top: in: query diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.json b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.json index 3a8577f..7c35933 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.json +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.json @@ -293,6 +293,27 @@ "x-ms-docs-operation-type": "operation" } }, + "/City/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.City", + "responses": { + "200": { + "description": "The count of the resource", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ODataCountResponse" + } + } + } + }, + "default": { + "$ref": "#/components/responses/error" + } + } + } + }, "/CountryOrRegion": { "get": { "tags": [ @@ -575,6 +596,27 @@ "x-ms-docs-operation-type": "operation" } }, + "/CountryOrRegion/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.CountryOrRegion", + "responses": { + "200": { + "description": "The count of the resource", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ODataCountResponse" + } + } + } + }, + "default": { + "$ref": "#/components/responses/error" + } + } + } + }, "/Me": { "get": { "tags": [ @@ -961,6 +1003,27 @@ }, "x-ms-docs-operation-type": "operation" } + }, + "/People/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.People", + "responses": { + "200": { + "description": "The count of the resource", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ODataCountResponse" + } + } + } + }, + "default": { + "$ref": "#/components/responses/error" + } + } + } } }, "components": { @@ -1135,6 +1198,10 @@ "type": "string" } } + }, + "ODataCountResponse": { + "type": "integer", + "format": "int32" } }, "responses": { diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.yaml b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.yaml index e67d06b..905302e 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.yaml +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.yaml @@ -190,6 +190,19 @@ paths: default: $ref: '#/components/responses/error' x-ms-docs-operation-type: operation + /City/$count: + get: + summary: Get the number of the resource + operationId: Get.Count.City + responses: + '200': + description: The count of the resource + content: + text/plain: + schema: + $ref: '#/components/schemas/ODataCountResponse' + default: + $ref: '#/components/responses/error' /CountryOrRegion: get: tags: @@ -374,6 +387,19 @@ paths: default: $ref: '#/components/responses/error' x-ms-docs-operation-type: operation + /CountryOrRegion/$count: + get: + summary: Get the number of the resource + operationId: Get.Count.CountryOrRegion + responses: + '200': + description: The count of the resource + content: + text/plain: + schema: + $ref: '#/components/schemas/ODataCountResponse' + default: + $ref: '#/components/responses/error' /Me: get: tags: @@ -634,6 +660,19 @@ paths: default: $ref: '#/components/responses/error' x-ms-docs-operation-type: operation + /People/$count: + get: + summary: Get the number of the resource + operationId: Get.Count.People + responses: + '200': + description: The count of the resource + content: + text/plain: + schema: + $ref: '#/components/schemas/ODataCountResponse' + default: + $ref: '#/components/responses/error' components: schemas: DefaultNs.Color: @@ -748,6 +787,9 @@ components: type: string target: type: string + ODataCountResponse: + type: integer + format: int32 responses: error: description: error diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Empty.OpenApi.V2.json b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Empty.OpenApi.V2.json index b9b87c7..e7c4786 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Empty.OpenApi.V2.json +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Empty.OpenApi.V2.json @@ -1,4 +1,4 @@ -{ +{ "swagger": "2.0", "info": { "title": "OData Service for namespace ", @@ -67,6 +67,10 @@ "type": "string" } } + }, + "ODataCountResponse": { + "format": "int32", + "type": "integer" } }, "parameters": { diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Empty.OpenApi.V2.yaml b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Empty.OpenApi.V2.yaml index c1586c9..b02a897 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Empty.OpenApi.V2.yaml +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Empty.OpenApi.V2.yaml @@ -1,4 +1,4 @@ -swagger: '2.0' +swagger: '2.0' info: title: 'OData Service for namespace ' description: This OData service is located at http://localhost @@ -46,6 +46,9 @@ definitions: type: string target: type: string + ODataCountResponse: + format: int32 + type: integer parameters: top: in: query diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Empty.OpenApi.json b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Empty.OpenApi.json index b7ace77..4c2bcc7 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Empty.OpenApi.json +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Empty.OpenApi.json @@ -1,4 +1,4 @@ -{ +{ "openapi": "3.0.1", "info": { "title": "OData Service for namespace ", @@ -69,6 +69,10 @@ "type": "string" } } + }, + "ODataCountResponse": { + "type": "integer", + "format": "int32" } }, "responses": { diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Empty.OpenApi.yaml b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Empty.OpenApi.yaml index 28eaf3e..04f3b17 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Empty.OpenApi.yaml +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Empty.OpenApi.yaml @@ -1,4 +1,4 @@ -openapi: 3.0.1 +openapi: 3.0.1 info: title: 'OData Service for namespace ' description: This OData service is located at http://localhost @@ -46,6 +46,9 @@ components: type: string target: type: string + ODataCountResponse: + type: integer + format: int32 responses: error: description: error diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.V2.json b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.V2.json index 326eeb1..2c01342 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.V2.json +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.V2.json @@ -1,4 +1,4 @@ -{ +{ "swagger": "2.0", "info": { "title": "OData Service for namespace Default", @@ -289,6 +289,26 @@ "x-ms-docs-operation-type": "operation" } }, + "/Categories/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.Categories", + "produces": [ + "text/plain" + ], + "responses": { + "200": { + "description": "The count of the resource", + "schema": { + "$ref": "#/definitions/ODataCountResponse" + } + }, + "default": { + "$ref": "#/responses/error" + } + } + } + }, "/Documents": { "get": { "tags": [ @@ -827,6 +847,39 @@ "x-ms-docs-operation-type": "operation" } }, + "/Documents({Id})/Revisions/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.Revisions", + "produces": [ + "text/plain" + ], + "parameters": [ + { + "in": "path", + "name": "Id", + "description": "key: Id of DocumentDto", + "required": true, + "type": "integer", + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "x-ms-docs-key-type": "DocumentDto" + } + ], + "responses": { + "200": { + "description": "The count of the resource", + "schema": { + "$ref": "#/definitions/ODataCountResponse" + } + }, + "default": { + "$ref": "#/responses/error" + } + } + } + }, "/Documents({Id})/Revisions/$ref": { "get": { "tags": [ @@ -983,6 +1036,26 @@ "x-ms-docs-operation-type": "operation" } }, + "/Documents/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.Documents", + "produces": [ + "text/plain" + ], + "responses": { + "200": { + "description": "The count of the resource", + "schema": { + "$ref": "#/definitions/ODataCountResponse" + } + }, + "default": { + "$ref": "#/responses/error" + } + } + } + }, "/Libraries": { "get": { "tags": [ @@ -1483,6 +1556,39 @@ "x-ms-docs-operation-type": "operation" } }, + "/Libraries({Id})/Documents/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.Documents", + "produces": [ + "text/plain" + ], + "parameters": [ + { + "in": "path", + "name": "Id", + "description": "key: Id of LibraryDto", + "required": true, + "type": "integer", + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "x-ms-docs-key-type": "LibraryDto" + } + ], + "responses": { + "200": { + "description": "The count of the resource", + "schema": { + "$ref": "#/definitions/ODataCountResponse" + } + }, + "default": { + "$ref": "#/responses/error" + } + } + } + }, "/Libraries({Id})/Documents/$ref": { "get": { "tags": [ @@ -1625,6 +1731,26 @@ "x-ms-docs-operation-type": "operation" } }, + "/Libraries/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.Libraries", + "produces": [ + "text/plain" + ], + "responses": { + "200": { + "description": "The count of the resource", + "schema": { + "$ref": "#/definitions/ODataCountResponse" + } + }, + "default": { + "$ref": "#/responses/error" + } + } + } + }, "/Revisions": { "get": { "tags": [ @@ -2184,6 +2310,26 @@ "x-ms-docs-operation-type": "operation" } }, + "/Revisions/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.Revisions", + "produces": [ + "text/plain" + ], + "responses": { + "200": { + "description": "The count of the resource", + "schema": { + "$ref": "#/definitions/ODataCountResponse" + } + }, + "default": { + "$ref": "#/responses/error" + } + } + } + }, "/Tasks": { "get": { "tags": [ @@ -2722,6 +2868,39 @@ "x-ms-docs-operation-type": "operation" } }, + "/Tasks({Id})/Revisions/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.Revisions", + "produces": [ + "text/plain" + ], + "parameters": [ + { + "in": "path", + "name": "Id", + "description": "key: Id of DocumentDto", + "required": true, + "type": "integer", + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "x-ms-docs-key-type": "DocumentDto" + } + ], + "responses": { + "200": { + "description": "The count of the resource", + "schema": { + "$ref": "#/definitions/ODataCountResponse" + } + }, + "default": { + "$ref": "#/responses/error" + } + } + } + }, "/Tasks({Id})/Revisions/$ref": { "get": { "tags": [ @@ -2877,6 +3056,26 @@ }, "x-ms-docs-operation-type": "operation" } + }, + "/Tasks/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.Tasks", + "produces": [ + "text/plain" + ], + "responses": { + "200": { + "description": "The count of the resource", + "schema": { + "$ref": "#/definitions/ODataCountResponse" + } + }, + "default": { + "$ref": "#/responses/error" + } + } + } } }, "definitions": { @@ -4637,6 +4836,10 @@ "type": "string" } } + }, + "ODataCountResponse": { + "format": "int32", + "type": "integer" } }, "parameters": { diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.V2.yaml b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.V2.yaml index 4275c6d..2eaef7d 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.V2.yaml +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.V2.yaml @@ -1,4 +1,4 @@ -swagger: '2.0' +swagger: '2.0' info: title: OData Service for namespace Default description: This OData service is located at http://localhost @@ -199,6 +199,19 @@ paths: default: $ref: '#/responses/error' x-ms-docs-operation-type: operation + /Categories/$count: + get: + summary: Get the number of the resource + operationId: Get.Count.Categories + produces: + - text/plain + responses: + '200': + description: The count of the resource + schema: + $ref: '#/definitions/ODataCountResponse' + default: + $ref: '#/responses/error' /Documents: get: tags: @@ -588,6 +601,29 @@ paths: default: $ref: '#/responses/error' x-ms-docs-operation-type: operation + '/Documents({Id})/Revisions/$count': + get: + summary: Get the number of the resource + operationId: Get.Count.Revisions + produces: + - text/plain + parameters: + - in: path + name: Id + description: 'key: Id of DocumentDto' + required: true + type: integer + format: int32 + maximum: 2147483647 + minimum: -2147483648 + x-ms-docs-key-type: DocumentDto + responses: + '200': + description: The count of the resource + schema: + $ref: '#/definitions/ODataCountResponse' + default: + $ref: '#/responses/error' '/Documents({Id})/Revisions/$ref': get: tags: @@ -701,6 +737,19 @@ paths: default: $ref: '#/responses/error' x-ms-docs-operation-type: operation + /Documents/$count: + get: + summary: Get the number of the resource + operationId: Get.Count.Documents + produces: + - text/plain + responses: + '200': + description: The count of the resource + schema: + $ref: '#/definitions/ODataCountResponse' + default: + $ref: '#/responses/error' /Libraries: get: tags: @@ -1063,6 +1112,29 @@ paths: default: $ref: '#/responses/error' x-ms-docs-operation-type: operation + '/Libraries({Id})/Documents/$count': + get: + summary: Get the number of the resource + operationId: Get.Count.Documents + produces: + - text/plain + parameters: + - in: path + name: Id + description: 'key: Id of LibraryDto' + required: true + type: integer + format: int32 + maximum: 2147483647 + minimum: -2147483648 + x-ms-docs-key-type: LibraryDto + responses: + '200': + description: The count of the resource + schema: + $ref: '#/definitions/ODataCountResponse' + default: + $ref: '#/responses/error' '/Libraries({Id})/Documents/$ref': get: tags: @@ -1162,6 +1234,19 @@ paths: default: $ref: '#/responses/error' x-ms-docs-operation-type: operation + /Libraries/$count: + get: + summary: Get the number of the resource + operationId: Get.Count.Libraries + produces: + - text/plain + responses: + '200': + description: The count of the resource + schema: + $ref: '#/definitions/ODataCountResponse' + default: + $ref: '#/responses/error' /Revisions: get: tags: @@ -1581,6 +1666,19 @@ paths: default: $ref: '#/responses/error' x-ms-docs-operation-type: operation + /Revisions/$count: + get: + summary: Get the number of the resource + operationId: Get.Count.Revisions + produces: + - text/plain + responses: + '200': + description: The count of the resource + schema: + $ref: '#/definitions/ODataCountResponse' + default: + $ref: '#/responses/error' /Tasks: get: tags: @@ -1970,6 +2068,29 @@ paths: default: $ref: '#/responses/error' x-ms-docs-operation-type: operation + '/Tasks({Id})/Revisions/$count': + get: + summary: Get the number of the resource + operationId: Get.Count.Revisions + produces: + - text/plain + parameters: + - in: path + name: Id + description: 'key: Id of DocumentDto' + required: true + type: integer + format: int32 + maximum: 2147483647 + minimum: -2147483648 + x-ms-docs-key-type: DocumentDto + responses: + '200': + description: The count of the resource + schema: + $ref: '#/definitions/ODataCountResponse' + default: + $ref: '#/responses/error' '/Tasks({Id})/Revisions/$ref': get: tags: @@ -2083,6 +2204,19 @@ paths: default: $ref: '#/responses/error' x-ms-docs-operation-type: operation + /Tasks/$count: + get: + summary: Get the number of the resource + operationId: Get.Count.Tasks + produces: + - text/plain + responses: + '200': + description: The count of the resource + schema: + $ref: '#/definitions/ODataCountResponse' + default: + $ref: '#/responses/error' definitions: Siterra.Documents.App.DTO.DocumentDto: title: DocumentDto @@ -3439,6 +3573,9 @@ definitions: type: string target: type: string + ODataCountResponse: + format: int32 + type: integer parameters: top: in: query diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.json b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.json index 383ef8e..6d77ca6 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.json +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.json @@ -1,4 +1,4 @@ -{ +{ "openapi": "3.0.1", "info": { "title": "OData Service for namespace Default", @@ -322,6 +322,27 @@ "x-ms-docs-operation-type": "operation" } }, + "/Categories/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.Categories", + "responses": { + "200": { + "description": "The count of the resource", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ODataCountResponse" + } + } + } + }, + "default": { + "$ref": "#/components/responses/error" + } + } + } + }, "/Documents": { "get": { "tags": [ @@ -929,6 +950,42 @@ "x-ms-docs-operation-type": "operation" } }, + "/Documents({Id})/Revisions/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.Revisions", + "parameters": [ + { + "name": "Id", + "in": "path", + "description": "key: Id of DocumentDto", + "required": true, + "schema": { + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer", + "format": "int32" + }, + "x-ms-docs-key-type": "DocumentDto" + } + ], + "responses": { + "200": { + "description": "The count of the resource", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ODataCountResponse" + } + } + } + }, + "default": { + "$ref": "#/components/responses/error" + } + } + } + }, "/Documents({Id})/Revisions/$ref": { "get": { "tags": [ @@ -1095,6 +1152,27 @@ "x-ms-docs-operation-type": "operation" } }, + "/Documents/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.Documents", + "responses": { + "200": { + "description": "The count of the resource", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ODataCountResponse" + } + } + } + }, + "default": { + "$ref": "#/components/responses/error" + } + } + } + }, "/Libraries": { "get": { "tags": [ @@ -1661,6 +1739,42 @@ "x-ms-docs-operation-type": "operation" } }, + "/Libraries({Id})/Documents/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.Documents", + "parameters": [ + { + "name": "Id", + "in": "path", + "description": "key: Id of LibraryDto", + "required": true, + "schema": { + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer", + "format": "int32" + }, + "x-ms-docs-key-type": "LibraryDto" + } + ], + "responses": { + "200": { + "description": "The count of the resource", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ODataCountResponse" + } + } + } + }, + "default": { + "$ref": "#/components/responses/error" + } + } + } + }, "/Libraries({Id})/Documents/$ref": { "get": { "tags": [ @@ -1813,6 +1927,27 @@ "x-ms-docs-operation-type": "operation" } }, + "/Libraries/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.Libraries", + "responses": { + "200": { + "description": "The count of the resource", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ODataCountResponse" + } + } + } + }, + "default": { + "$ref": "#/components/responses/error" + } + } + } + }, "/Revisions": { "get": { "tags": [ @@ -2497,6 +2632,27 @@ "x-ms-docs-operation-type": "operation" } }, + "/Revisions/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.Revisions", + "responses": { + "200": { + "description": "The count of the resource", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ODataCountResponse" + } + } + } + }, + "default": { + "$ref": "#/components/responses/error" + } + } + } + }, "/Tasks": { "get": { "tags": [ @@ -3104,6 +3260,42 @@ "x-ms-docs-operation-type": "operation" } }, + "/Tasks({Id})/Revisions/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.Revisions", + "parameters": [ + { + "name": "Id", + "in": "path", + "description": "key: Id of DocumentDto", + "required": true, + "schema": { + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer", + "format": "int32" + }, + "x-ms-docs-key-type": "DocumentDto" + } + ], + "responses": { + "200": { + "description": "The count of the resource", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ODataCountResponse" + } + } + } + }, + "default": { + "$ref": "#/components/responses/error" + } + } + } + }, "/Tasks({Id})/Revisions/$ref": { "get": { "tags": [ @@ -3269,6 +3461,27 @@ }, "x-ms-docs-operation-type": "operation" } + }, + "/Tasks/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.Tasks", + "responses": { + "200": { + "description": "The count of the resource", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ODataCountResponse" + } + } + } + }, + "default": { + "$ref": "#/components/responses/error" + } + } + } } }, "components": { @@ -5226,6 +5439,10 @@ "type": "string" } } + }, + "ODataCountResponse": { + "type": "integer", + "format": "int32" } }, "responses": { diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.yaml b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.yaml index 7ceeab4..6e4807a 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.yaml +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.yaml @@ -1,4 +1,4 @@ -openapi: 3.0.1 +openapi: 3.0.1 info: title: OData Service for namespace Default description: This OData service is located at http://localhost @@ -219,6 +219,19 @@ paths: default: $ref: '#/components/responses/error' x-ms-docs-operation-type: operation + /Categories/$count: + get: + summary: Get the number of the resource + operationId: Get.Count.Categories + responses: + '200': + description: The count of the resource + content: + text/plain: + schema: + $ref: '#/components/schemas/ODataCountResponse' + default: + $ref: '#/components/responses/error' /Documents: get: tags: @@ -652,6 +665,30 @@ paths: default: $ref: '#/components/responses/error' x-ms-docs-operation-type: operation + '/Documents({Id})/Revisions/$count': + get: + summary: Get the number of the resource + operationId: Get.Count.Revisions + parameters: + - name: Id + in: path + description: 'key: Id of DocumentDto' + required: true + schema: + maximum: 2147483647 + minimum: -2147483648 + type: integer + format: int32 + x-ms-docs-key-type: DocumentDto + responses: + '200': + description: The count of the resource + content: + text/plain: + schema: + $ref: '#/components/schemas/ODataCountResponse' + default: + $ref: '#/components/responses/error' '/Documents({Id})/Revisions/$ref': get: tags: @@ -770,6 +807,19 @@ paths: default: $ref: '#/components/responses/error' x-ms-docs-operation-type: operation + /Documents/$count: + get: + summary: Get the number of the resource + operationId: Get.Count.Documents + responses: + '200': + description: The count of the resource + content: + text/plain: + schema: + $ref: '#/components/schemas/ODataCountResponse' + default: + $ref: '#/components/responses/error' /Libraries: get: tags: @@ -1175,6 +1225,30 @@ paths: default: $ref: '#/components/responses/error' x-ms-docs-operation-type: operation + '/Libraries({Id})/Documents/$count': + get: + summary: Get the number of the resource + operationId: Get.Count.Documents + parameters: + - name: Id + in: path + description: 'key: Id of LibraryDto' + required: true + schema: + maximum: 2147483647 + minimum: -2147483648 + type: integer + format: int32 + x-ms-docs-key-type: LibraryDto + responses: + '200': + description: The count of the resource + content: + text/plain: + schema: + $ref: '#/components/schemas/ODataCountResponse' + default: + $ref: '#/components/responses/error' '/Libraries({Id})/Documents/$ref': get: tags: @@ -1279,6 +1353,19 @@ paths: default: $ref: '#/components/responses/error' x-ms-docs-operation-type: operation + /Libraries/$count: + get: + summary: Get the number of the resource + operationId: Get.Count.Libraries + responses: + '200': + description: The count of the resource + content: + text/plain: + schema: + $ref: '#/components/schemas/ODataCountResponse' + default: + $ref: '#/components/responses/error' /Revisions: get: tags: @@ -1778,6 +1865,19 @@ paths: default: $ref: '#/components/responses/error' x-ms-docs-operation-type: operation + /Revisions/$count: + get: + summary: Get the number of the resource + operationId: Get.Count.Revisions + responses: + '200': + description: The count of the resource + content: + text/plain: + schema: + $ref: '#/components/schemas/ODataCountResponse' + default: + $ref: '#/components/responses/error' /Tasks: get: tags: @@ -2211,6 +2311,30 @@ paths: default: $ref: '#/components/responses/error' x-ms-docs-operation-type: operation + '/Tasks({Id})/Revisions/$count': + get: + summary: Get the number of the resource + operationId: Get.Count.Revisions + parameters: + - name: Id + in: path + description: 'key: Id of DocumentDto' + required: true + schema: + maximum: 2147483647 + minimum: -2147483648 + type: integer + format: int32 + x-ms-docs-key-type: DocumentDto + responses: + '200': + description: The count of the resource + content: + text/plain: + schema: + $ref: '#/components/schemas/ODataCountResponse' + default: + $ref: '#/components/responses/error' '/Tasks({Id})/Revisions/$ref': get: tags: @@ -2329,6 +2453,19 @@ paths: default: $ref: '#/components/responses/error' x-ms-docs-operation-type: operation + /Tasks/$count: + get: + summary: Get the number of the resource + operationId: Get.Count.Tasks + responses: + '200': + description: The count of the resource + content: + text/plain: + schema: + $ref: '#/components/schemas/ODataCountResponse' + default: + $ref: '#/components/responses/error' components: schemas: Siterra.Documents.App.DTO.DocumentDto: @@ -3831,6 +3968,9 @@ components: type: string target: type: string + ODataCountResponse: + type: integer + format: int32 responses: error: description: error diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.V2.json b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.V2.json index 7949025..31c8c74 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.V2.json +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.V2.json @@ -1,4 +1,4 @@ -{ +{ "swagger": "2.0", "info": { "title": "OData Service for namespace Microsoft.OData.Service.Sample.TrippinInMemory.Models", @@ -265,6 +265,26 @@ "x-ms-docs-operation-type": "operation" } }, + "/Airlines/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.Airlines", + "produces": [ + "text/plain" + ], + "responses": { + "200": { + "description": "The count of the resource", + "schema": { + "$ref": "#/definitions/ODataCountResponse" + } + }, + "default": { + "$ref": "#/responses/error" + } + } + } + }, "/Airports": { "get": { "tags": [ @@ -527,6 +547,26 @@ "x-ms-docs-operation-type": "operation" } }, + "/Airports/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.Airports", + "produces": [ + "text/plain" + ], + "responses": { + "200": { + "description": "The count of the resource", + "schema": { + "$ref": "#/definitions/ODataCountResponse" + } + }, + "default": { + "$ref": "#/responses/error" + } + } + } + }, "/GetNearestAirport(lat={lat},lon={lon})": { "get": { "tags": [ @@ -1000,6 +1040,26 @@ "x-ms-docs-operation-type": "operation" } }, + "/Me/Friends/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.Friends", + "produces": [ + "text/plain" + ], + "responses": { + "200": { + "description": "The count of the resource", + "schema": { + "$ref": "#/definitions/ODataCountResponse" + } + }, + "default": { + "$ref": "#/responses/error" + } + } + } + }, "/Me/Friends/$ref": { "get": { "tags": [ @@ -1836,6 +1896,39 @@ "x-ms-docs-operation-type": "operation" } }, + "/Me/Trips/{TripId}/PlanItems/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.PlanItems", + "produces": [ + "text/plain" + ], + "parameters": [ + { + "in": "path", + "name": "TripId", + "description": "key: TripId of Trip", + "required": true, + "type": "integer", + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "x-ms-docs-key-type": "Trip" + } + ], + "responses": { + "200": { + "description": "The count of the resource", + "schema": { + "$ref": "#/definitions/ODataCountResponse" + } + }, + "default": { + "$ref": "#/responses/error" + } + } + } + }, "/Me/Trips/{TripId}/PlanItems/$ref": { "get": { "tags": [ @@ -1968,6 +2061,26 @@ "x-ms-docs-operation-type": "operation" } }, + "/Me/Trips/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.Trips", + "produces": [ + "text/plain" + ], + "responses": { + "200": { + "description": "The count of the resource", + "schema": { + "$ref": "#/definitions/ODataCountResponse" + } + }, + "default": { + "$ref": "#/responses/error" + } + } + } + }, "/NewComePeople": { "get": { "tags": [ @@ -2634,6 +2747,36 @@ "x-ms-docs-operation-type": "operation" } }, + "/NewComePeople/{UserName}/Friends/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.Friends", + "produces": [ + "text/plain" + ], + "parameters": [ + { + "in": "path", + "name": "UserName", + "description": "key: UserName of Person", + "required": true, + "type": "string", + "x-ms-docs-key-type": "Person" + } + ], + "responses": { + "200": { + "description": "The count of the resource", + "schema": { + "$ref": "#/definitions/ODataCountResponse" + } + }, + "default": { + "$ref": "#/responses/error" + } + } + } + }, "/NewComePeople/{UserName}/Friends/$ref": { "get": { "tags": [ @@ -3592,6 +3735,47 @@ "x-ms-docs-operation-type": "operation" } }, + "/NewComePeople/{UserName}/Trips/{TripId}/PlanItems/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.PlanItems", + "produces": [ + "text/plain" + ], + "parameters": [ + { + "in": "path", + "name": "UserName", + "description": "key: UserName of Person", + "required": true, + "type": "string", + "x-ms-docs-key-type": "Person" + }, + { + "in": "path", + "name": "TripId", + "description": "key: TripId of Trip", + "required": true, + "type": "integer", + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "x-ms-docs-key-type": "Trip" + } + ], + "responses": { + "200": { + "description": "The count of the resource", + "schema": { + "$ref": "#/definitions/ODataCountResponse" + } + }, + "default": { + "$ref": "#/responses/error" + } + } + } + }, "/NewComePeople/{UserName}/Trips/{TripId}/PlanItems/$ref": { "get": { "tags": [ @@ -3740,6 +3924,56 @@ "x-ms-docs-operation-type": "operation" } }, + "/NewComePeople/{UserName}/Trips/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.Trips", + "produces": [ + "text/plain" + ], + "parameters": [ + { + "in": "path", + "name": "UserName", + "description": "key: UserName of Person", + "required": true, + "type": "string", + "x-ms-docs-key-type": "Person" + } + ], + "responses": { + "200": { + "description": "The count of the resource", + "schema": { + "$ref": "#/definitions/ODataCountResponse" + } + }, + "default": { + "$ref": "#/responses/error" + } + } + } + }, + "/NewComePeople/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.NewComePeople", + "produces": [ + "text/plain" + ], + "responses": { + "200": { + "description": "The count of the resource", + "schema": { + "$ref": "#/definitions/ODataCountResponse" + } + }, + "default": { + "$ref": "#/responses/error" + } + } + } + }, "/People": { "get": { "tags": [ @@ -4406,6 +4640,36 @@ "x-ms-docs-operation-type": "operation" } }, + "/People/{UserName}/Friends/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.Friends", + "produces": [ + "text/plain" + ], + "parameters": [ + { + "in": "path", + "name": "UserName", + "description": "key: UserName of Person", + "required": true, + "type": "string", + "x-ms-docs-key-type": "Person" + } + ], + "responses": { + "200": { + "description": "The count of the resource", + "schema": { + "$ref": "#/definitions/ODataCountResponse" + } + }, + "default": { + "$ref": "#/responses/error" + } + } + } + }, "/People/{UserName}/Friends/$ref": { "get": { "tags": [ @@ -5364,6 +5628,47 @@ "x-ms-docs-operation-type": "operation" } }, + "/People/{UserName}/Trips/{TripId}/PlanItems/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.PlanItems", + "produces": [ + "text/plain" + ], + "parameters": [ + { + "in": "path", + "name": "UserName", + "description": "key: UserName of Person", + "required": true, + "type": "string", + "x-ms-docs-key-type": "Person" + }, + { + "in": "path", + "name": "TripId", + "description": "key: TripId of Trip", + "required": true, + "type": "integer", + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "x-ms-docs-key-type": "Trip" + } + ], + "responses": { + "200": { + "description": "The count of the resource", + "schema": { + "$ref": "#/definitions/ODataCountResponse" + } + }, + "default": { + "$ref": "#/responses/error" + } + } + } + }, "/People/{UserName}/Trips/{TripId}/PlanItems/$ref": { "get": { "tags": [ @@ -5512,6 +5817,56 @@ "x-ms-docs-operation-type": "operation" } }, + "/People/{UserName}/Trips/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.Trips", + "produces": [ + "text/plain" + ], + "parameters": [ + { + "in": "path", + "name": "UserName", + "description": "key: UserName of Person", + "required": true, + "type": "string", + "x-ms-docs-key-type": "Person" + } + ], + "responses": { + "200": { + "description": "The count of the resource", + "schema": { + "$ref": "#/definitions/ODataCountResponse" + } + }, + "default": { + "$ref": "#/responses/error" + } + } + } + }, + "/People/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.People", + "produces": [ + "text/plain" + ], + "responses": { + "200": { + "description": "The count of the resource", + "schema": { + "$ref": "#/definitions/ODataCountResponse" + } + }, + "default": { + "$ref": "#/responses/error" + } + } + } + }, "/ResetDataSource": { "post": { "tags": [ @@ -6135,6 +6490,10 @@ "type": "string" } } + }, + "ODataCountResponse": { + "format": "int32", + "type": "integer" } }, "parameters": { diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.V2.yaml b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.V2.yaml index 5a5533a..9f81cb6 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.V2.yaml +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.V2.yaml @@ -1,4 +1,4 @@ -swagger: '2.0' +swagger: '2.0' info: title: OData Service for namespace Microsoft.OData.Service.Sample.TrippinInMemory.Models description: This OData service is located at http://services.odata.org/TrippinRESTierService @@ -175,6 +175,19 @@ paths: default: $ref: '#/responses/error' x-ms-docs-operation-type: operation + /Airlines/$count: + get: + summary: Get the number of the resource + operationId: Get.Count.Airlines + produces: + - text/plain + responses: + '200': + description: The count of the resource + schema: + $ref: '#/definitions/ODataCountResponse' + default: + $ref: '#/responses/error' /Airports: get: tags: @@ -350,6 +363,19 @@ paths: default: $ref: '#/responses/error' x-ms-docs-operation-type: operation + /Airports/$count: + get: + summary: Get the number of the resource + operationId: Get.Count.Airports + produces: + - text/plain + responses: + '200': + description: The count of the resource + schema: + $ref: '#/definitions/ODataCountResponse' + default: + $ref: '#/responses/error' '/GetNearestAirport(lat={lat},lon={lon})': get: tags: @@ -684,6 +710,19 @@ paths: default: $ref: '#/responses/error' x-ms-docs-operation-type: operation + /Me/Friends/$count: + get: + summary: Get the number of the resource + operationId: Get.Count.Friends + produces: + - text/plain + responses: + '200': + description: The count of the resource + schema: + $ref: '#/definitions/ODataCountResponse' + default: + $ref: '#/responses/error' /Me/Friends/$ref: get: tags: @@ -1261,6 +1300,29 @@ paths: default: $ref: '#/responses/error' x-ms-docs-operation-type: operation + '/Me/Trips/{TripId}/PlanItems/$count': + get: + summary: Get the number of the resource + operationId: Get.Count.PlanItems + produces: + - text/plain + parameters: + - in: path + name: TripId + description: 'key: TripId of Trip' + required: true + type: integer + format: int32 + maximum: 2147483647 + minimum: -2147483648 + x-ms-docs-key-type: Trip + responses: + '200': + description: The count of the resource + schema: + $ref: '#/definitions/ODataCountResponse' + default: + $ref: '#/responses/error' '/Me/Trips/{TripId}/PlanItems/$ref': get: tags: @@ -1350,6 +1412,19 @@ paths: default: $ref: '#/responses/error' x-ms-docs-operation-type: operation + /Me/Trips/$count: + get: + summary: Get the number of the resource + operationId: Get.Count.Trips + produces: + - text/plain + responses: + '200': + description: The count of the resource + schema: + $ref: '#/definitions/ODataCountResponse' + default: + $ref: '#/responses/error' /NewComePeople: get: tags: @@ -1825,6 +1900,26 @@ paths: default: $ref: '#/responses/error' x-ms-docs-operation-type: operation + '/NewComePeople/{UserName}/Friends/$count': + get: + summary: Get the number of the resource + operationId: Get.Count.Friends + produces: + - text/plain + parameters: + - in: path + name: UserName + description: 'key: UserName of Person' + required: true + type: string + x-ms-docs-key-type: Person + responses: + '200': + description: The count of the resource + schema: + $ref: '#/definitions/ODataCountResponse' + default: + $ref: '#/responses/error' '/NewComePeople/{UserName}/Friends/$ref': get: tags: @@ -2493,6 +2588,35 @@ paths: default: $ref: '#/responses/error' x-ms-docs-operation-type: operation + '/NewComePeople/{UserName}/Trips/{TripId}/PlanItems/$count': + get: + summary: Get the number of the resource + operationId: Get.Count.PlanItems + produces: + - text/plain + parameters: + - in: path + name: UserName + description: 'key: UserName of Person' + required: true + type: string + x-ms-docs-key-type: Person + - in: path + name: TripId + description: 'key: TripId of Trip' + required: true + type: integer + format: int32 + maximum: 2147483647 + minimum: -2147483648 + x-ms-docs-key-type: Trip + responses: + '200': + description: The count of the resource + schema: + $ref: '#/definitions/ODataCountResponse' + default: + $ref: '#/responses/error' '/NewComePeople/{UserName}/Trips/{TripId}/PlanItems/$ref': get: tags: @@ -2594,6 +2718,39 @@ paths: default: $ref: '#/responses/error' x-ms-docs-operation-type: operation + '/NewComePeople/{UserName}/Trips/$count': + get: + summary: Get the number of the resource + operationId: Get.Count.Trips + produces: + - text/plain + parameters: + - in: path + name: UserName + description: 'key: UserName of Person' + required: true + type: string + x-ms-docs-key-type: Person + responses: + '200': + description: The count of the resource + schema: + $ref: '#/definitions/ODataCountResponse' + default: + $ref: '#/responses/error' + /NewComePeople/$count: + get: + summary: Get the number of the resource + operationId: Get.Count.NewComePeople + produces: + - text/plain + responses: + '200': + description: The count of the resource + schema: + $ref: '#/definitions/ODataCountResponse' + default: + $ref: '#/responses/error' /People: get: tags: @@ -3069,6 +3226,26 @@ paths: default: $ref: '#/responses/error' x-ms-docs-operation-type: operation + '/People/{UserName}/Friends/$count': + get: + summary: Get the number of the resource + operationId: Get.Count.Friends + produces: + - text/plain + parameters: + - in: path + name: UserName + description: 'key: UserName of Person' + required: true + type: string + x-ms-docs-key-type: Person + responses: + '200': + description: The count of the resource + schema: + $ref: '#/definitions/ODataCountResponse' + default: + $ref: '#/responses/error' '/People/{UserName}/Friends/$ref': get: tags: @@ -3737,6 +3914,35 @@ paths: default: $ref: '#/responses/error' x-ms-docs-operation-type: operation + '/People/{UserName}/Trips/{TripId}/PlanItems/$count': + get: + summary: Get the number of the resource + operationId: Get.Count.PlanItems + produces: + - text/plain + parameters: + - in: path + name: UserName + description: 'key: UserName of Person' + required: true + type: string + x-ms-docs-key-type: Person + - in: path + name: TripId + description: 'key: TripId of Trip' + required: true + type: integer + format: int32 + maximum: 2147483647 + minimum: -2147483648 + x-ms-docs-key-type: Trip + responses: + '200': + description: The count of the resource + schema: + $ref: '#/definitions/ODataCountResponse' + default: + $ref: '#/responses/error' '/People/{UserName}/Trips/{TripId}/PlanItems/$ref': get: tags: @@ -3838,6 +4044,39 @@ paths: default: $ref: '#/responses/error' x-ms-docs-operation-type: operation + '/People/{UserName}/Trips/$count': + get: + summary: Get the number of the resource + operationId: Get.Count.Trips + produces: + - text/plain + parameters: + - in: path + name: UserName + description: 'key: UserName of Person' + required: true + type: string + x-ms-docs-key-type: Person + responses: + '200': + description: The count of the resource + schema: + $ref: '#/definitions/ODataCountResponse' + default: + $ref: '#/responses/error' + /People/$count: + get: + summary: Get the number of the resource + operationId: Get.Count.People + produces: + - text/plain + responses: + '200': + description: The count of the resource + schema: + $ref: '#/definitions/ODataCountResponse' + default: + $ref: '#/responses/error' /ResetDataSource: post: tags: @@ -4244,6 +4483,9 @@ definitions: type: string target: type: string + ODataCountResponse: + format: int32 + type: integer parameters: top: in: query diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.json b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.json index 4c06fd0..c74a395 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.json +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.json @@ -1,4 +1,4 @@ -{ +{ "openapi": "3.0.1", "info": { "title": "OData Service for namespace Microsoft.OData.Service.Sample.TrippinInMemory.Models", @@ -297,6 +297,27 @@ "x-ms-docs-operation-type": "operation" } }, + "/Airlines/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.Airlines", + "responses": { + "200": { + "description": "The count of the resource", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ODataCountResponse" + } + } + } + }, + "default": { + "$ref": "#/components/responses/error" + } + } + } + }, "/Airports": { "get": { "tags": [ @@ -591,6 +612,27 @@ "x-ms-docs-operation-type": "operation" } }, + "/Airports/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.Airports", + "responses": { + "200": { + "description": "The count of the resource", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ODataCountResponse" + } + } + } + }, + "default": { + "$ref": "#/components/responses/error" + } + } + } + }, "/GetNearestAirport(lat={lat},lon={lon})": { "get": { "tags": [ @@ -1151,6 +1193,27 @@ "x-ms-docs-operation-type": "operation" } }, + "/Me/Friends/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.Friends", + "responses": { + "200": { + "description": "The count of the resource", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ODataCountResponse" + } + } + } + }, + "default": { + "$ref": "#/components/responses/error" + } + } + } + }, "/Me/Friends/$ref": { "get": { "tags": [ @@ -2074,6 +2137,42 @@ "x-ms-docs-operation-type": "operation" } }, + "/Me/Trips/{TripId}/PlanItems/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.PlanItems", + "parameters": [ + { + "name": "TripId", + "in": "path", + "description": "key: TripId of Trip", + "required": true, + "schema": { + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer", + "format": "int32" + }, + "x-ms-docs-key-type": "Trip" + } + ], + "responses": { + "200": { + "description": "The count of the resource", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ODataCountResponse" + } + } + } + }, + "default": { + "$ref": "#/components/responses/error" + } + } + } + }, "/Me/Trips/{TripId}/PlanItems/$ref": { "get": { "tags": [ @@ -2216,6 +2315,27 @@ "x-ms-docs-operation-type": "operation" } }, + "/Me/Trips/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.Trips", + "responses": { + "200": { + "description": "The count of the resource", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ODataCountResponse" + } + } + } + }, + "default": { + "$ref": "#/components/responses/error" + } + } + } + }, "/NewComePeople": { "get": { "tags": [ @@ -2961,6 +3081,39 @@ "x-ms-docs-operation-type": "operation" } }, + "/NewComePeople/{UserName}/Friends/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.Friends", + "parameters": [ + { + "name": "UserName", + "in": "path", + "description": "key: UserName of Person", + "required": true, + "schema": { + "type": "string" + }, + "x-ms-docs-key-type": "Person" + } + ], + "responses": { + "200": { + "description": "The count of the resource", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ODataCountResponse" + } + } + } + }, + "default": { + "$ref": "#/components/responses/error" + } + } + } + }, "/NewComePeople/{UserName}/Friends/$ref": { "get": { "tags": [ @@ -4044,6 +4197,52 @@ "x-ms-docs-operation-type": "operation" } }, + "/NewComePeople/{UserName}/Trips/{TripId}/PlanItems/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.PlanItems", + "parameters": [ + { + "name": "UserName", + "in": "path", + "description": "key: UserName of Person", + "required": true, + "schema": { + "type": "string" + }, + "x-ms-docs-key-type": "Person" + }, + { + "name": "TripId", + "in": "path", + "description": "key: TripId of Trip", + "required": true, + "schema": { + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer", + "format": "int32" + }, + "x-ms-docs-key-type": "Trip" + } + ], + "responses": { + "200": { + "description": "The count of the resource", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ODataCountResponse" + } + } + } + }, + "default": { + "$ref": "#/components/responses/error" + } + } + } + }, "/NewComePeople/{UserName}/Trips/{TripId}/PlanItems/$ref": { "get": { "tags": [ @@ -4206,6 +4405,60 @@ "x-ms-docs-operation-type": "operation" } }, + "/NewComePeople/{UserName}/Trips/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.Trips", + "parameters": [ + { + "name": "UserName", + "in": "path", + "description": "key: UserName of Person", + "required": true, + "schema": { + "type": "string" + }, + "x-ms-docs-key-type": "Person" + } + ], + "responses": { + "200": { + "description": "The count of the resource", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ODataCountResponse" + } + } + } + }, + "default": { + "$ref": "#/components/responses/error" + } + } + } + }, + "/NewComePeople/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.NewComePeople", + "responses": { + "200": { + "description": "The count of the resource", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ODataCountResponse" + } + } + } + }, + "default": { + "$ref": "#/components/responses/error" + } + } + } + }, "/People": { "get": { "tags": [ @@ -4951,6 +5204,39 @@ "x-ms-docs-operation-type": "operation" } }, + "/People/{UserName}/Friends/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.Friends", + "parameters": [ + { + "name": "UserName", + "in": "path", + "description": "key: UserName of Person", + "required": true, + "schema": { + "type": "string" + }, + "x-ms-docs-key-type": "Person" + } + ], + "responses": { + "200": { + "description": "The count of the resource", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ODataCountResponse" + } + } + } + }, + "default": { + "$ref": "#/components/responses/error" + } + } + } + }, "/People/{UserName}/Friends/$ref": { "get": { "tags": [ @@ -6034,6 +6320,52 @@ "x-ms-docs-operation-type": "operation" } }, + "/People/{UserName}/Trips/{TripId}/PlanItems/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.PlanItems", + "parameters": [ + { + "name": "UserName", + "in": "path", + "description": "key: UserName of Person", + "required": true, + "schema": { + "type": "string" + }, + "x-ms-docs-key-type": "Person" + }, + { + "name": "TripId", + "in": "path", + "description": "key: TripId of Trip", + "required": true, + "schema": { + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer", + "format": "int32" + }, + "x-ms-docs-key-type": "Trip" + } + ], + "responses": { + "200": { + "description": "The count of the resource", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ODataCountResponse" + } + } + } + }, + "default": { + "$ref": "#/components/responses/error" + } + } + } + }, "/People/{UserName}/Trips/{TripId}/PlanItems/$ref": { "get": { "tags": [ @@ -6196,6 +6528,60 @@ "x-ms-docs-operation-type": "operation" } }, + "/People/{UserName}/Trips/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.Trips", + "parameters": [ + { + "name": "UserName", + "in": "path", + "description": "key: UserName of Person", + "required": true, + "schema": { + "type": "string" + }, + "x-ms-docs-key-type": "Person" + } + ], + "responses": { + "200": { + "description": "The count of the resource", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ODataCountResponse" + } + } + } + }, + "default": { + "$ref": "#/components/responses/error" + } + } + } + }, + "/People/$count": { + "get": { + "summary": "Get the number of the resource", + "operationId": "Get.Count.People", + "responses": { + "200": { + "description": "The count of the resource", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ODataCountResponse" + } + } + } + }, + "default": { + "$ref": "#/components/responses/error" + } + } + } + }, "/ResetDataSource": { "post": { "tags": [ @@ -6964,6 +7350,10 @@ "type": "string" } } + }, + "ODataCountResponse": { + "type": "integer", + "format": "int32" } }, "responses": { diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.yaml b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.yaml index 7b9f87f..1003e1a 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.yaml +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.yaml @@ -1,4 +1,4 @@ -openapi: 3.0.1 +openapi: 3.0.1 info: title: OData Service for namespace Microsoft.OData.Service.Sample.TrippinInMemory.Models description: This OData service is located at http://services.odata.org/TrippinRESTierService @@ -194,6 +194,19 @@ paths: default: $ref: '#/components/responses/error' x-ms-docs-operation-type: operation + /Airlines/$count: + get: + summary: Get the number of the resource + operationId: Get.Count.Airlines + responses: + '200': + description: The count of the resource + content: + text/plain: + schema: + $ref: '#/components/schemas/ODataCountResponse' + default: + $ref: '#/components/responses/error' /Airports: get: tags: @@ -390,6 +403,19 @@ paths: default: $ref: '#/components/responses/error' x-ms-docs-operation-type: operation + /Airports/$count: + get: + summary: Get the number of the resource + operationId: Get.Count.Airports + responses: + '200': + description: The count of the resource + content: + text/plain: + schema: + $ref: '#/components/schemas/ODataCountResponse' + default: + $ref: '#/components/responses/error' '/GetNearestAirport(lat={lat},lon={lon})': get: tags: @@ -772,6 +798,19 @@ paths: default: $ref: '#/components/responses/error' x-ms-docs-operation-type: operation + /Me/Friends/$count: + get: + summary: Get the number of the resource + operationId: Get.Count.Friends + responses: + '200': + description: The count of the resource + content: + text/plain: + schema: + $ref: '#/components/schemas/ODataCountResponse' + default: + $ref: '#/components/responses/error' /Me/Friends/$ref: get: tags: @@ -1396,6 +1435,30 @@ paths: default: $ref: '#/components/responses/error' x-ms-docs-operation-type: operation + '/Me/Trips/{TripId}/PlanItems/$count': + get: + summary: Get the number of the resource + operationId: Get.Count.PlanItems + parameters: + - name: TripId + in: path + description: 'key: TripId of Trip' + required: true + schema: + maximum: 2147483647 + minimum: -2147483648 + type: integer + format: int32 + x-ms-docs-key-type: Trip + responses: + '200': + description: The count of the resource + content: + text/plain: + schema: + $ref: '#/components/schemas/ODataCountResponse' + default: + $ref: '#/components/responses/error' '/Me/Trips/{TripId}/PlanItems/$ref': get: tags: @@ -1490,6 +1553,19 @@ paths: default: $ref: '#/components/responses/error' x-ms-docs-operation-type: operation + /Me/Trips/$count: + get: + summary: Get the number of the resource + operationId: Get.Count.Trips + responses: + '200': + description: The count of the resource + content: + text/plain: + schema: + $ref: '#/components/schemas/ODataCountResponse' + default: + $ref: '#/components/responses/error' /NewComePeople: get: tags: @@ -2015,6 +2091,27 @@ paths: default: $ref: '#/components/responses/error' x-ms-docs-operation-type: operation + '/NewComePeople/{UserName}/Friends/$count': + get: + summary: Get the number of the resource + operationId: Get.Count.Friends + parameters: + - name: UserName + in: path + description: 'key: UserName of Person' + required: true + schema: + type: string + x-ms-docs-key-type: Person + responses: + '200': + description: The count of the resource + content: + text/plain: + schema: + $ref: '#/components/schemas/ODataCountResponse' + default: + $ref: '#/components/responses/error' '/NewComePeople/{UserName}/Friends/$ref': get: tags: @@ -2749,6 +2846,37 @@ paths: default: $ref: '#/components/responses/error' x-ms-docs-operation-type: operation + '/NewComePeople/{UserName}/Trips/{TripId}/PlanItems/$count': + get: + summary: Get the number of the resource + operationId: Get.Count.PlanItems + parameters: + - name: UserName + in: path + description: 'key: UserName of Person' + required: true + schema: + type: string + x-ms-docs-key-type: Person + - name: TripId + in: path + description: 'key: TripId of Trip' + required: true + schema: + maximum: 2147483647 + minimum: -2147483648 + type: integer + format: int32 + x-ms-docs-key-type: Trip + responses: + '200': + description: The count of the resource + content: + text/plain: + schema: + $ref: '#/components/schemas/ODataCountResponse' + default: + $ref: '#/components/responses/error' '/NewComePeople/{UserName}/Trips/{TripId}/PlanItems/$ref': get: tags: @@ -2857,6 +2985,40 @@ paths: default: $ref: '#/components/responses/error' x-ms-docs-operation-type: operation + '/NewComePeople/{UserName}/Trips/$count': + get: + summary: Get the number of the resource + operationId: Get.Count.Trips + parameters: + - name: UserName + in: path + description: 'key: UserName of Person' + required: true + schema: + type: string + x-ms-docs-key-type: Person + responses: + '200': + description: The count of the resource + content: + text/plain: + schema: + $ref: '#/components/schemas/ODataCountResponse' + default: + $ref: '#/components/responses/error' + /NewComePeople/$count: + get: + summary: Get the number of the resource + operationId: Get.Count.NewComePeople + responses: + '200': + description: The count of the resource + content: + text/plain: + schema: + $ref: '#/components/schemas/ODataCountResponse' + default: + $ref: '#/components/responses/error' /People: get: tags: @@ -3382,6 +3544,27 @@ paths: default: $ref: '#/components/responses/error' x-ms-docs-operation-type: operation + '/People/{UserName}/Friends/$count': + get: + summary: Get the number of the resource + operationId: Get.Count.Friends + parameters: + - name: UserName + in: path + description: 'key: UserName of Person' + required: true + schema: + type: string + x-ms-docs-key-type: Person + responses: + '200': + description: The count of the resource + content: + text/plain: + schema: + $ref: '#/components/schemas/ODataCountResponse' + default: + $ref: '#/components/responses/error' '/People/{UserName}/Friends/$ref': get: tags: @@ -4116,6 +4299,37 @@ paths: default: $ref: '#/components/responses/error' x-ms-docs-operation-type: operation + '/People/{UserName}/Trips/{TripId}/PlanItems/$count': + get: + summary: Get the number of the resource + operationId: Get.Count.PlanItems + parameters: + - name: UserName + in: path + description: 'key: UserName of Person' + required: true + schema: + type: string + x-ms-docs-key-type: Person + - name: TripId + in: path + description: 'key: TripId of Trip' + required: true + schema: + maximum: 2147483647 + minimum: -2147483648 + type: integer + format: int32 + x-ms-docs-key-type: Trip + responses: + '200': + description: The count of the resource + content: + text/plain: + schema: + $ref: '#/components/schemas/ODataCountResponse' + default: + $ref: '#/components/responses/error' '/People/{UserName}/Trips/{TripId}/PlanItems/$ref': get: tags: @@ -4224,6 +4438,40 @@ paths: default: $ref: '#/components/responses/error' x-ms-docs-operation-type: operation + '/People/{UserName}/Trips/$count': + get: + summary: Get the number of the resource + operationId: Get.Count.Trips + parameters: + - name: UserName + in: path + description: 'key: UserName of Person' + required: true + schema: + type: string + x-ms-docs-key-type: Person + responses: + '200': + description: The count of the resource + content: + text/plain: + schema: + $ref: '#/components/schemas/ODataCountResponse' + default: + $ref: '#/components/responses/error' + /People/$count: + get: + summary: Get the number of the resource + operationId: Get.Count.People + responses: + '200': + description: The count of the resource + content: + text/plain: + schema: + $ref: '#/components/schemas/ODataCountResponse' + default: + $ref: '#/components/responses/error' /ResetDataSource: post: tags: @@ -4698,6 +4946,9 @@ components: type: string target: type: string + ODataCountResponse: + type: integer + format: int32 responses: error: description: error