Compare commits

...

59 commits

Author SHA1 Message Date
Vincent Biret fa2fee8eca
Merge pull request #146 from microsoft/feature/zengin
- adds @zengin as a code owner
2021-11-26 13:20:14 -08:00
Vincent Biret 2b94eadbaf
Merge pull request #147 from microsoft/dependabot/github_actions/actions/setup-dotnet-1.9.0
Bump actions/setup-dotnet from 1.8.2 to 1.9.0
2021-11-24 11:30:27 -08:00
dependabot[bot] 2869799426
Bump actions/setup-dotnet from 1.8.2 to 1.9.0
Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 1.8.2 to 1.9.0.
- [Release notes](https://github.com/actions/setup-dotnet/releases)
- [Commits](https://github.com/actions/setup-dotnet/compare/v1.8.2...v1.9.0)

---
updated-dependencies:
- dependency-name: actions/setup-dotnet
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-24 18:20:54 +00:00
Vincent Biret 9bc67eb77e
- adds @zengin as a code owner 2021-11-24 13:08:49 -05:00
Vincent Biret 2814714d83
Merge pull request #141 from microsoft/bugifx/count-segments
fixes a bug where OData Count path items would be missing from the description
2021-11-23 17:41:26 -08:00
Vincent Biret 387d070bc1
Merge pull request #144 from microsoft/feature/codeql
- adds an initial codeql workflow
2021-11-23 17:29:16 -08:00
Vincent Biret be5bbf3723
- switches codeql workflow to windows agent due to project requirements 2021-11-23 15:51:44 -05:00
Vincent Biret d2a6bdb0e6
- adds dependabot configuration for actions as we added the first workflow 2021-11-23 15:50:46 -05:00
Vincent Biret 4a924b53d7
- adds setup dotnet step 2021-11-23 15:49:20 -05:00
Vincent Biret 8725e50617
- adds an initial codeql workflow 2021-11-23 15:45:24 -05:00
Vincent Biret 00b605f9fc
- renames dollar count segment setting
Signed-off-by: Vincent Biret <vibiret@microsoft.com>
2021-11-23 14:01:38 -05:00
Vincent Biret a8bb14f26e
- applies code review suggestions
Signed-off-by: Vincent Biret <vibiret@microsoft.com>
2021-11-23 13:40:54 -05:00
Vincent Biret 13427946de
Merge pull request #137 from microsoft/feature/net5
feature/net6
2021-11-23 10:19:28 -08:00
Vincent Biret 892003ef2a
- updates integration test files
Signed-off-by: Vincent Biret <vibiret@microsoft.com>
2021-11-23 11:49:28 -05:00
Vincent Biret 5d910fd29b
- adds support for reading annotations for count restrictions for count path
Signed-off-by: Vincent Biret <vibiret@microsoft.com>
2021-11-23 11:37:48 -05:00
Vincent Biret 4093249a19
- adds a setting to globally disable dollar count path items
Signed-off-by: Vincent Biret <vibiret@microsoft.com>
2021-11-23 10:28:01 -05:00
Vincent Biret f87c2b4951
- updates basic open api integration test for $count
Signed-off-by: Vincent Biret <vibiret@microsoft.com>
2021-11-22 16:03:00 -05:00
Vincent Biret 032fbaefb4
- fixes a bug where the operation id for count operations would not be unique
Signed-off-by: Vincent Biret <vibiret@microsoft.com>
2021-11-22 15:38:40 -05:00
Vincent Biret 10b99ca357
- updates unit tests for dolarr count fix
Signed-off-by: Vincent Biret <vibiret@microsoft.com>
2021-11-22 15:06:11 -05:00
Vincent Biret 76cfc303bc
- switches to a referenced schema for count operations
Signed-off-by: Vincent Biret <vibiret@microsoft.com>
2021-11-22 14:42:38 -05:00
Vincent Biret 2fee91b384
- code linting
Signed-off-by: Vincent Biret <vibiret@microsoft.com>
2021-11-22 14:42:38 -05:00
Vincent Biret ae11d65007
- fixes #129 a bug where odata count paths would be missing from the description
Signed-off-by: Vincent Biret <vibiret@microsoft.com>
2021-11-22 14:42:38 -05:00
Vincent Biret f08be6482f
- code linting
Signed-off-by: Vincent Biret <vibiret@microsoft.com>
2021-11-22 14:42:37 -05:00
Vincent Biret 960b31b350
- code linting
Signed-off-by: Vincent Biret <vibiret@microsoft.com>
2021-11-22 14:42:37 -05:00
Vincent Biret 70aefe98a1
- adds update docs to solution file so debug works properly
Signed-off-by: Vincent Biret <vibiret@microsoft.com>
2021-11-22 14:42:37 -05:00
Vincent Biret d2bb4bd008
- adds launch configuration for update docs tool
Signed-off-by: Vincent Biret <vibiret@microsoft.com>
2021-11-22 14:42:36 -05:00
Vincent Biret 883ca922db
- pattern matching refactoring
Signed-off-by: Vincent Biret <vibiret@microsoft.com>
2021-11-22 14:42:36 -05:00
Vincent Biret 094bf81732
- upgrades dependencies to avoid dependabot salvo after merge 2021-11-22 14:39:44 -05:00
Vincent Biret 0073118250 Merge branch 'master' into feature/net5 2021-11-22 16:40:22 +00:00
Vincent Biret 948fbc6d4c
- removes obsolete file after conversion 2021-11-22 10:55:41 -05:00
Vincent Biret ac209a55a3
- removes obsolete file after conversion 2021-11-22 10:55:13 -05:00
Vincent Biret 4a29091fce
Merge pull request #138 from microsoft/feature/projects-cleanup
feature/projects cleanup
2021-11-19 10:04:09 -08:00
Sam Xu 37b222f426 Add SourceLink, Remove non-yaml build badge, Update Nuget dependency
version
2021-11-19 09:41:54 -08:00
Vincent Biret 9073743d90
- bumps everything to net6 for supportability
Signed-off-by: Vincent Biret <vibiret@microsoft.com>
2021-11-19 11:19:41 -05:00
Vincent Biret 336a7dba80
- fixes csproj encoding 2021-11-19 11:13:58 -05:00
Vincent Biret 1d0f0d7e71
- update util to net5 2021-11-19 11:13:58 -05:00
Vincent Biret ecf4f39109
- converts gui app to net5
Signed-off-by: Vincent Biret <vibiret@microsoft.com>
2021-11-19 11:13:57 -05:00
Vincent Biret 32069a0ad9
- upgrades update docs tool to net5 and removes net 5 copy 2021-11-19 11:13:57 -05:00
Vincent Biret d0b3cc1618
- bumps to net6 2021-11-19 11:12:39 -05:00
Vincent Biret a83d3111df
Merge pull request #135 from microsoft/dependabot/nuget/Microsoft.OData.Edm-7.9.4
Bump Microsoft.OData.Edm from 7.6.1 to 7.9.4
2021-11-19 07:48:44 -08:00
Vincent Biret 7b3fa55a20
- upgrades unit test project to net5 to keep support 2021-11-19 10:43:45 -05:00
dependabot[bot] fdf8d233c6
Bump Microsoft.OData.Edm from 7.6.1 to 7.9.4
Bumps Microsoft.OData.Edm from 7.6.1 to 7.9.4.

---
updated-dependencies:
- dependency-name: Microsoft.OData.Edm
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-18 21:21:54 +00:00
Sam Xu c0d60793a6
Update versioning.props 2021-11-18 10:44:10 -08:00
dependabot[bot] af532f71b9
Bump Microsoft.OpenApi from 1.2.2 to 1.2.3 (#134)
Bumps [Microsoft.OpenApi](https://github.com/Microsoft/OpenAPI.NET) from 1.2.2 to 1.2.3.
- [Release notes](https://github.com/Microsoft/OpenAPI.NET/releases)
- [Commits](https://github.com/Microsoft/OpenAPI.NET/compare/1.2.2...1.2.3)

---
updated-dependencies:
- dependency-name: Microsoft.OpenApi
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-18 10:43:16 -08:00
Irvine Sunday 226ce62303
Fixes response objects for operations that return single primitive type values (#127)
* Refactor similar code into one function; add fix for responses for primitive types

* Add new param to method and add tests for this

* Update test files

* Address PR review suggestion
2021-11-18 21:27:16 +03:00
Irvine Sunday 03b6000a84
Fixes structured & collection-valued parameters of functions (#133)
* Use content property in collection-valued & structured parameters

Add content property and a media type object to indicate that the parameters are serialized as JSON

* Adds test for CreateParameters

Co-authored-by: Sam Xu <saxu@microsoft.com>
2021-11-18 09:42:34 -08:00
Vincent Biret 73ad41ec0e - adds a dependabot configuration to keep dependencies up to date 2021-11-18 09:39:25 -08:00
Vincent Biret cd36d59f7b - adds vs code configuration to the repository 2021-11-18 09:39:02 -08:00
Vincent Biret 75f293ef08
- adds code owners for the repository so people are added automatically to PR reviews (#131)
* - adds code owners for the repository so people are added automatically to PR reviews

* Update .github/CODEOWNERS

Co-authored-by: Irvine Sunday <40403681+irvinesunday@users.noreply.github.com>

Co-authored-by: Irvine Sunday <40403681+irvinesunday@users.noreply.github.com>
2021-11-18 09:38:29 -08:00
Sam Xu b3245711f3
Update versioning.props 2021-10-07 09:29:58 -07:00
Irvine Sunday da7f51abbf
Resolves response schemas of actions/functions that return collection (#117)
* Update response schema of action/functions that return a collection

* Update Title to use entity type name for the previous segment

* Update test files data appropriately
2021-09-21 12:05:41 +03:00
Irvine Sunday 3cce51566f
Skips generation of action/function paths for non-contained nav. props. (#115)
* Do not create actions/functions for non-containment nav. props

* Add test for Function Operations
2021-09-14 23:23:52 +03:00
Irvine Sunday 611067f2d3
[Enhancement] Creates DELETE operation for collection-valued nav. props $ref paths (#112)
* Generate collection nav. prop. entity paths for non-contained nav. props

* Revert previous changes

* Paths with DELETE operations for collection-valued nav. prop. $ref paths

* Don't create extra path for OData Key segment when creating DELETE for $ref

* Update tests

* Update test files

* Minor update to test commit signing

* Another minor update to trigger commit signing

* Update tests appropriately
2021-08-26 22:25:55 +03:00
Irvine Sunday e6a5e52e11
[Fix] Generate paths for stream properties in base types of entities (#110)
* Get all properties declared in type def. including base types

* Update/refactor tests to validate stream props. of base types are captured

* Refactor Handler class to use encapsulation to define navigation sources
2021-08-18 16:33:26 +03:00
Irvine Sunday e8ecb37c96
Fix: Expand containment navigation properties (#94)
* Expand all containment nav props; retrieve Media Entity paths prior to expanding

* Update path count to account for expanded containment nav. props.

* Remove containment in sample CSDL

Expanding workbook nav. props leads to many paths  since the containment levels go very deep

* Check for navigability of navigation props

* Comment correction

* Fix broken tests

* Check whether navigation is allowed to a navigation property

* Update tests; add tests to validate navigability of navigation properties

* Update test CSDL doc. with sample NavigationRestrictions annotations

* Concise code; move declaration closer to usage

Co-authored-by: Irvine Sunday <irochand@microsoft.com>
2021-07-09 09:55:55 -07:00
Irvine Sunday 72cd85d3ae
Set parameters' explode property to false (#108)
* Set Explode property to false for Style: Form

* Add tests for creating OrderBy, Select, Expand parameters

* Rename test method for clarity

Co-authored-by: Irvine Sunday <irochand@microsoft.com>
2021-07-09 09:55:32 -07:00
Sam Xu 9f55c250a1
Update versioning.props 2021-05-06 09:50:48 -07:00
Irvine Sunday b1fed423ab
Describes path operations descriptions from vocabulary annotations (#104)
* Add support for operation descriptions and update tests

* Update tests for Entityset paths operations descriptions

* Code cleanup

* Update test OpenAPI output files.

Co-authored-by: Irvine Sunday <irochand@microsoft.com>
2021-05-04 17:36:03 -07:00
Irvine Sunday 9d6bdd5ae0 Add async await to make UI more responsive 2021-05-04 17:35:42 -07:00
101 changed files with 6027 additions and 1016 deletions

1
.github/CODEOWNERS vendored Normal file
View file

@ -0,0 +1 @@
* @xuzhg @irvinesunday @darrelmiller @peombwa @zengin

View file

@ -29,6 +29,11 @@ variables:
steps:
- task: UseDotNet@2
displayName: 'Use .NET 6'
inputs:
version: 6.x
- task: PoliCheck@1
displayName: 'Run PoliCheck "OpenApi.OData-master\src"'
inputs:

View file

@ -27,6 +27,11 @@ variables:
steps:
- task: UseDotNet@2
displayName: 'Use .NET 6'
inputs:
version: 6.x
- task: PoliCheck@1
displayName: 'Run PoliCheck ".\src"'
inputs:

12
.github/dependabot.yml vendored Normal file
View file

@ -0,0 +1,12 @@
version: 2
updates:
- package-ecosystem: nuget
directory: "/"
schedule:
interval: daily
open-pull-requests-limit: 10
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: daily
open-pull-requests-limit: 10

75
.github/workflows/codeql-analysis.yml vendored Normal file
View file

@ -0,0 +1,75 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ master ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
schedule:
- cron: '32 2 * * 6'
jobs:
analyze:
name: Analyze
runs-on: windows-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'csharp' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://git.io/codeql-language-support
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Setup .NET
uses: actions/setup-dotnet@v1.9.0
with:
dotnet-version: 6.0.x
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

7
.vscode/extensions.json vendored Normal file
View file

@ -0,0 +1,7 @@
{
"recommendations": [
"formulahendry.dotnet-test-explorer",
"ms-dotnettools.csharp",
"editorconfig.editorconfig"
]
}

21
.vscode/launch.json vendored Normal file
View file

@ -0,0 +1,21 @@
{
"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",
"request": "attach",
"processId": "${command:pickProcess}"
}
]
}

9
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,9 @@
{
"omnisharp.enableRoslynAnalyzers": true,
"markdownlint.config": {
"MD028": false,
"MD025": {
"front_matter_title": ""
}
}
}

144
.vscode/tasks.json vendored Normal file
View file

@ -0,0 +1,144 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "process",
"group": "build",
"args": [
"build",
"${workspaceFolder}/Microsoft.OpenApi.OData.sln",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "test",
"command": "dotnet",
"type": "process",
"group": "test",
"args": [
"test",
"${workspaceFolder}/Microsoft.OpenApi.OData.sln",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary",
"--collect:\"XPlat Code Coverage\""
],
"problemMatcher": "$msCompile"
},
{
"label": "coverage:clean",
"type": "shell",
"group": "test",
"linux": {
"command": "rm",
"args": [
"-r",
"${workspaceFolder}/test/Microsoft.OpenAPI.OData.Reader.Tests/TestResults"
]
},
"windows": {
"command": "powershell",
"args": [
"-command",
"Remove-Item -Recurse -Include TestResults -Path ${workspaceFolder}/tests"
]
}
},
{
"label": "coverage:unit",
"type": "process",
"group": "test",
"linux":{
"command": "reportgenerator",
"args": [
"-reports:${workspaceFolder}/tests/**/coverage.cobertura.xml",
"-targetdir:${workspaceFolder}/reports/coverage"
],
},
"windows": {
"command": "reportgenerator",
"args": [
"-reports:${workspaceFolder}\\test\\**\\coverage.cobertura.xml",
"-targetdir:${workspaceFolder}\\reports\\coverage"
]
},
"dependsOn": [
"coverage:clean",
"test"
],
"dependsOrder": "sequence"
},
{
"label": "coverage:launch",
"type": "shell",
"linux": {
"command": "xdg-open",
"args": [
"${workspaceFolder}/reports/coverage/index.html"
]
},
"osx": {
"command": "open",
"args": [
"${workspaceFolder}/reports/coverage/index.html"
]
},
"windows": {
"command": "start",
"args": [
"${workspaceFolder}/reports/coverage/index.html"
]
},
"group": "test",
},
{
"label": "coverage:launch",
"group": "test",
"dependsOrder": "sequence",
"dependsOn": [
"coverage:unit",
"coverage:launch"
]
},
{
"label": "clean",
"command": "dotnet",
"type": "process",
"group": "build",
"args": [
"clean"
],
"problemMatcher": "$msCompile"
},
{
"label": "publish",
"command": "dotnet",
"type": "process",
"group": "build",
"args": [
"publish",
"${workspaceFolder}/Microsoft.OpenApi.OData.sln",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "watch",
"command": "dotnet",
"type": "process",
"group": "build",
"args": [
"watch",
"run",
"${workspaceFolder}/Microsoft.OpenApi.OData.sln",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
}
]
}

View file

@ -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

View file

@ -1,10 +1,3 @@
VSTS Build | Status
--------|---------
Rolling | <img src="https://identitydivision.visualstudio.com/_apis/public/build/definitions/2cfe7ec3-b94f-4ab9-85ab-2ebff928f3fd/410/badge"/>
Nightly | <img src="https://identitydivision.visualstudio.com/_apis/public/build/definitions/2cfe7ec3-b94f-4ab9-85ab-2ebff928f3fd/427/badge"/>
AzurePipeline|Status
--------|--------------
Rolling |<img src="https://identitydivision.visualstudio.com/OData/_apis/build/status/OpenApi/OpenAPI.OData-Master-Rolling?branchName=master" />

View file

@ -79,5 +79,10 @@ namespace Microsoft.OpenApi.OData.Common
/// extension for discriminator value support
/// </summary>
public static string xMsDiscriminatorValue = "x-ms-discriminator-value";
/// <summary>
/// Name used for the OpenAPI referenced schema for OData Count operations responses.
/// </summary>
public static string DollarCountSchemaName = "ODataCountResponse";
}
}

View file

@ -12,6 +12,11 @@ namespace Microsoft.OpenApi.OData.Edm
/// </summary>
public class ODataDollarCountSegment : ODataSegment
{
/// <summary>
/// Get the static instance of $count segment.
/// </summary>
internal static ODataDollarCountSegment Instance = new();
/// <inheritdoc />
public override ODataSegmentKind Kind => ODataSegmentKind.DollarCount;

View file

@ -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<string> parameters = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
HashSet<string> parameters = new HashSet<string>();
StringBuilder sb = new StringBuilder();
HashSet<string> parameters = new();
StringBuilder sb = new();
if (!string.IsNullOrWhiteSpace(settings.PathPrefix))
{

View file

@ -9,6 +9,7 @@ using System.Diagnostics;
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.OData.Vocabulary.Capabilities;
namespace Microsoft.OpenApi.OData.Edm
{
@ -56,7 +57,7 @@ namespace Microsoft.OpenApi.OData.Edm
{
if (CanFilter(entitySet))
{
RetrieveNavigationSourcePaths(entitySet);
RetrieveNavigationSourcePaths(entitySet, settings);
}
}
@ -65,7 +66,7 @@ namespace Microsoft.OpenApi.OData.Edm
{
if (CanFilter(singleton))
{
RetrieveNavigationSourcePaths(singleton);
RetrieveNavigationSourcePaths(singleton, settings);
}
}
@ -101,7 +102,7 @@ namespace Microsoft.OpenApi.OData.Edm
private IEnumerable<ODataPath> MergePaths()
{
List<ODataPath> allODataPaths = new List<ODataPath>();
List<ODataPath> allODataPaths = new();
foreach (var item in _allNavigationSourcePaths.Values)
{
allODataPaths.AddRange(item);
@ -126,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:
@ -142,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<ODataNavigationPropertySegment>().Last();
if (!_allNavigationPropertyPaths.TryGetValue(navigationPropertySegment.EntityType, out IList<ODataPath> npList))
{
@ -168,20 +169,26 @@ namespace Microsoft.OpenApi.OData.Edm
/// Retrieve the paths for <see cref="IEdmNavigationSource"/>.
/// </summary>
/// <param name="navigationSource">The navigation source.</param>
private void RetrieveNavigationSourcePaths(IEdmNavigationSource navigationSource)
/// <param name="convertSettings">The settings for the current conversion.</param>
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<CountRestrictionsType>(entitySet, CapabilitiesConstants.CountRestrictions);
if(count?.Countable ?? true)
CreateCountPath(path, convertSettings);
path.Push(new ODataKeySegment(entityType));
AppendPath(path.Clone());
}
@ -194,7 +201,7 @@ namespace Microsoft.OpenApi.OData.Edm
{
if (CanFilter(np))
{
RetrieveNavigationPropertyPaths(np, path);
RetrieveNavigationPropertyPaths(np, count, path, convertSettings);
}
}
@ -218,7 +225,7 @@ namespace Microsoft.OpenApi.OData.Edm
Debug.Assert(currentPath != null);
bool createValuePath = true;
foreach (IEdmStructuralProperty sp in entityType.DeclaredStructuralProperties())
foreach (IEdmStructuralProperty sp in entityType.StructuralProperties())
{
if (sp.Type.AsPrimitive().IsStream())
{
@ -227,7 +234,7 @@ namespace Microsoft.OpenApi.OData.Edm
currentPath.Pop();
}
if (sp.Name.Equals("content", System.StringComparison.OrdinalIgnoreCase))
if (sp.Name.Equals("content", StringComparison.OrdinalIgnoreCase))
{
createValuePath = false;
}
@ -248,12 +255,21 @@ namespace Microsoft.OpenApi.OData.Edm
/// Retrieve the path for <see cref="IEdmNavigationProperty"/>.
/// </summary>
/// <param name="navigationProperty">The navigation property.</param>
/// <param name="count">The count restrictions.</param>
/// <param name="currentPath">The current OData path.</param>
private void RetrieveNavigationPropertyPaths(IEdmNavigationProperty navigationProperty, ODataPath currentPath)
/// <param name="convertSettings">The settings for the current conversion.</param>
private void RetrieveNavigationPropertyPaths(IEdmNavigationProperty navigationProperty, CountRestrictionsType count, ODataPath currentPath, OpenApiConvertSettings convertSettings)
{
Debug.Assert(navigationProperty != null);
Debug.Assert(currentPath != null);
// Check whether the navigation property should be part of the path
NavigationRestrictionsType navigation = _model.GetRecord<NavigationRestrictionsType>(navigationProperty, CapabilitiesConstants.NavigationRestrictions);
if (navigation != null && !navigation.IsNavigable)
{
return;
}
// test the expandable for the navigation property.
bool shouldExpand = ShouldExpandNavigationProperty(navigationProperty, currentPath);
@ -261,50 +277,65 @@ namespace Microsoft.OpenApi.OData.Edm
currentPath.Push(new ODataNavigationPropertySegment(navigationProperty));
AppendPath(currentPath.Clone());
if (!navigationProperty.ContainsTarget)
{
// Non-Contained
// Single-Valued: DELETE ~/entityset/{key}/single-valued-Nav/$ref
// collection-valued: DELETE ~/entityset/{key}/collection-valued-Nav/$ref?$id ={ navKey}
ODataPath newPath = currentPath.Clone();
newPath.Push(ODataRefSegment.Instance); // $ref
AppendPath(newPath);
}
else
// Check whether a collection-valued navigation property should be indexed by key value(s).
NavigationPropertyRestriction restriction = navigation?.RestrictedProperties?.FirstOrDefault();
if (restriction == null || restriction.IndexableByKey == true)
{
IEdmEntityType navEntityType = navigationProperty.ToEntityType();
var targetsMany = navigationProperty.TargetMultiplicity() == EdmMultiplicity.Many;
var propertyPath = navigationProperty.GetPartnerPath()?.Path;
// append a navigation property key.
if (navigationProperty.TargetMultiplicity() == EdmMultiplicity.Many)
if (targetsMany && (string.IsNullOrEmpty(propertyPath) ||
(count?.IsNonCountableNavigationProperty(propertyPath) ?? true)))
{
currentPath.Push(new ODataKeySegment(navEntityType));
AppendPath(currentPath.Clone());
if (!navigationProperty.ContainsTarget)
{
// TODO: Shall we add "$ref" after {key}, and only support delete?
// ODataPath newPath = currentPath.Clone();
// newPath.Push(ODataRefSegment.Instance); // $ref
// AppendPath(newPath);
}
// ~/entityset/{key}/collection-valued-Nav/$count
CreateCountPath(currentPath, convertSettings);
}
if (shouldExpand)
if (!navigationProperty.ContainsTarget)
{
// expand to sub navigation properties
foreach (IEdmNavigationProperty subNavProperty in navEntityType.DeclaredNavigationProperties())
// Non-Contained
// Single-Valued: ~/entityset/{key}/single-valued-Nav/$ref
// Collection-valued: ~/entityset/{key}/collection-valued-Nav/$ref?$id ={navKey}
CreateRefPath(currentPath);
if (targetsMany)
{
if (CanFilter(subNavProperty))
// Collection-valued: DELETE ~/entityset/{key}/collection-valued-Nav/{key}/$ref
currentPath.Push(new ODataKeySegment(navEntityType));
CreateRefPath(currentPath);
}
// Get possible stream paths for the navigation entity type
RetrieveMediaEntityStreamPaths(navEntityType, currentPath);
}
else
{
// append a navigation property key.
if (targetsMany)
{
currentPath.Push(new ODataKeySegment(navEntityType));
AppendPath(currentPath.Clone());
}
// Get possible stream paths for the navigation entity type
RetrieveMediaEntityStreamPaths(navEntityType, currentPath);
if (shouldExpand)
{
// expand to sub navigation properties
foreach (IEdmNavigationProperty subNavProperty in navEntityType.DeclaredNavigationProperties())
{
RetrieveNavigationPropertyPaths(subNavProperty, currentPath);
if (CanFilter(subNavProperty))
{
RetrieveNavigationPropertyPaths(subNavProperty, count, currentPath, convertSettings);
}
}
}
}
// Get possible navigation property stream paths
RetrieveMediaEntityStreamPaths(navEntityType, currentPath);
if (navigationProperty.TargetMultiplicity() == EdmMultiplicity.Many)
if (targetsMany)
{
currentPath.Pop();
}
@ -333,9 +364,33 @@ namespace Microsoft.OpenApi.OData.Edm
}
}
// check whether the navigation type used to define a navigation source.
// if so, not expand it.
return !_allNavigationSources.ContainsKey(navEntityType);
return true;
}
/// <summary>
/// Create $ref paths.
/// </summary>
/// <param name="currentPath">The current OData path.</param>
private void CreateRefPath(ODataPath currentPath)
{
ODataPath newPath = currentPath.Clone();
newPath.Push(ODataRefSegment.Instance); // $ref
AppendPath(newPath);
}
/// <summary>
/// Create $count paths.
/// </summary>
/// <param name="currentPath">The current OData path.</param>
/// <param name="convertSettings">The settings for the current conversion.</param>
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);
}
/// <summary>
@ -413,7 +468,11 @@ namespace Microsoft.OpenApi.OData.Edm
}
}
}
private static readonly HashSet<ODataPathKind> _oDataPathKindsToSkipForOperations = new HashSet<ODataPathKind>() {
ODataPathKind.EntitySet,
ODataPathKind.MediaEntity,
ODataPathKind.DollarCount
};
private bool AppendBoundOperationOnNavigationSourcePath(IEdmOperation edmOperation, bool isCollection, IEdmEntityType bindingEntityType)
{
bool found = false;
@ -425,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));
@ -438,7 +496,9 @@ namespace Microsoft.OpenApi.OData.Edm
return found;
}
private static readonly HashSet<ODataPathKind> _pathKindToSkipForNavigationProperties = new () {
ODataPathKind.Ref,
};
private bool AppendBoundOperationOnNavigationPropertyPath(IEdmOperation edmOperation, bool isCollection, IEdmEntityType bindingEntityType)
{
bool found = false;
@ -446,15 +506,15 @@ namespace Microsoft.OpenApi.OData.Edm
if (_allNavigationPropertyPaths.TryGetValue(bindingEntityType, out IList<ODataPath> value))
{
foreach (var path in value)
foreach (var path in value.Where(x => !_pathKindToSkipForNavigationProperties.Contains(x.Kind)))
{
if (path.Kind == ODataPathKind.Ref)
ODataNavigationPropertySegment npSegment = path.Segments.Last(s => s is ODataNavigationPropertySegment) as ODataNavigationPropertySegment;
if (!npSegment.NavigationProperty.ContainsTarget)
{
continue;
}
ODataNavigationPropertySegment npSegment = path.Segments.Last(s => s is ODataNavigationPropertySegment) as ODataNavigationPropertySegment;
bool isLastKeySegment = path.LastSegment is ODataKeySegment;
if (isCollection)
@ -568,16 +628,15 @@ namespace Microsoft.OpenApi.OData.Edm
{
if (_allNavigationPropertyPaths.TryGetValue(baseType, out IList<ODataPath> paths))
{
foreach (var path in paths)
foreach (var path in paths.Where(x => !_pathKindToSkipForNavigationProperties.Contains(x.Kind)))
{
if (path.Kind == ODataPathKind.Ref)
var npSegment = path.Segments.OfType<ODataNavigationPropertySegment>().LastOrDefault();
if (npSegment == null)
{
continue;
}
var npSegment = path.Segments.Last(s => s is ODataNavigationPropertySegment)
as ODataNavigationPropertySegment;
if (npSegment == null)
if (!npSegment.NavigationProperty.ContainsTarget)
{
continue;
}

View file

@ -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;
}
/// <summary>
@ -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;
}
/// <summary>
@ -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;
}
/// <summary>
@ -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;
}
/// <summary>
@ -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;
}
/// <summary>
@ -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<string> properties = new List<string>();
foreach (var path in value.Elements.Select(e => e as IEdmPathExpression))
{
properties.Add(path.Path);
}
IList<string> properties =
value.Elements
.OfType<IEdmPathExpression>()
.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<string> items = new List<string>();
foreach (var item in collection.Elements)
{
IEdmStringConstantExpression itemRecord = item as IEdmStringConstantExpression;
items.Add(itemRecord.Value);
}
return items;
}
IList<string> items = collection.Elements
.OfType<IEdmStringConstantExpression>()
.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<T> items = new List<T>();
foreach (IEdmRecordExpression item in collection.Elements.OfType<IEdmRecordExpression>())
{
IList<T> items = new List<T>();
foreach (IEdmRecordExpression item in collection.Elements.OfType<IEdmRecordExpression>())
{
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;

View file

@ -42,21 +42,20 @@ namespace Microsoft.OpenApi.OData
if (settings.VerifyEdmModel)
{
IEnumerable<EdmError> 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();
}
}

View file

@ -94,13 +94,28 @@ namespace Microsoft.OpenApi.OData.Generator
Name = parameterNameMapping == null ? edmParameter.Name : parameterNameMapping[edmParameter.Name],
In = ParameterLocation.Query, // as query option
Required = true,
Schema = new OpenApiSchema
{
Type = "string",
// These Parameter Objects optionally can contain the field description,
// whose value is the value of the unqualified annotation Core.Description of the parameter.
Description = context.Model.GetDescriptionAnnotation(edmParameter)
// Create schema in the Content property to indicate that the parameters are serialized as JSON
Content = new Dictionary<string, OpenApiMediaType>
{
{
Constants.ApplicationJsonMediaType,
new OpenApiMediaType
{
Schema = new OpenApiSchema
{
Type = "array",
Items = new OpenApiSchema
{
Type = "string"
},
// These Parameter Objects optionally can contain the field description,
// whose value is the value of the unqualified annotation Core.Description of the parameter.
Description = context.Model.GetDescriptionAnnotation(edmParameter)
}
}
}
},
// The parameter description describes the format this URL-encoded JSON object or array, and/or reference to [OData-URL].
@ -400,7 +415,8 @@ namespace Microsoft.OpenApi.OData.Generator
Enum = orderByItems
}
},
Style = ParameterStyle.Form
Style = ParameterStyle.Form,
Explode = false
};
}
@ -479,7 +495,8 @@ namespace Microsoft.OpenApi.OData.Generator
Enum = selectItems
}
},
Style = ParameterStyle.Form
Style = ParameterStyle.Form,
Explode = false
};
}
@ -556,7 +573,8 @@ namespace Microsoft.OpenApi.OData.Generator
Enum = expandItems
}
},
Style = ParameterStyle.Form
Style = ParameterStyle.Form,
Explode = false
};
}

View file

@ -54,7 +54,7 @@ namespace Microsoft.OpenApi.OData.Generator
if (settings.ShowRootPath)
{
OpenApiPathItem rootPath = new OpenApiPathItem()
OpenApiPathItem rootPath = new()
{
Operations = new Dictionary<OperationType, OpenApiOperation> {
{

View file

@ -4,6 +4,7 @@
// ------------------------------------------------------------
using System.Collections.Generic;
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
@ -72,13 +73,15 @@ namespace Microsoft.OpenApi.OData.Generator
/// </summary>
/// <param name="context">The OData context.</param>
/// <param name="operationImport">The Edm operation import.</param>
/// <param name="path">The OData path.</param>
/// <returns>The created <see cref="OpenApiResponses"/>.</returns>
public static OpenApiResponses CreateResponses(this ODataContext context, IEdmOperationImport operationImport)
public static OpenApiResponses CreateResponses(this ODataContext context, IEdmOperationImport operationImport, ODataPath path)
{
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(operationImport, nameof(operationImport));
Utils.CheckArgumentNull(path, nameof(path));
return context.CreateResponses(operationImport.Operation);
return context.CreateResponses(operationImport.Operation, path);
}
/// <summary>
@ -86,13 +89,15 @@ namespace Microsoft.OpenApi.OData.Generator
/// </summary>
/// <param name="context">The OData context.</param>
/// <param name="operation">The Edm operation.</param>
/// <param name="path">The OData path.</param>
/// <returns>The created <see cref="OpenApiResponses"/>.</returns>
public static OpenApiResponses CreateResponses(this ODataContext context, IEdmOperation operation)
public static OpenApiResponses CreateResponses(this ODataContext context, IEdmOperation operation, ODataPath path)
{
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(operation, nameof(operation));
Utils.CheckArgumentNull(path, nameof(path));
OpenApiResponses responses = new OpenApiResponses();
OpenApiResponses responses = new();
if (operation.IsAction() && operation.ReturnType == null)
{
@ -100,7 +105,44 @@ namespace Microsoft.OpenApi.OData.Generator
}
else
{
OpenApiResponse response = new OpenApiResponse
OpenApiSchema schema;
if (operation.ReturnType.IsCollection())
{
// Get the entity type of the previous segment
IEdmEntityType entityType = path.Segments.Reverse().Skip(1)?.Take(1)?.FirstOrDefault()?.EntityType;
schema = new OpenApiSchema
{
Title = entityType == null ? null : $"Collection of {entityType.Name}",
Type = "object",
Properties = new Dictionary<string, OpenApiSchema>
{
{
"value", context.CreateEdmTypeSchema(operation.ReturnType)
}
}
};
}
else if (operation.ReturnType.IsPrimitive())
{
// A property or operation response that is of a primitive type is represented as an object with a single name/value pair,
// whose name is value and whose value is a primitive value.
schema = new OpenApiSchema
{
Type = "object",
Properties = new Dictionary<string, OpenApiSchema>
{
{
"value", context.CreateEdmTypeSchema(operation.ReturnType)
}
}
};
}
else
{
schema = context.CreateEdmTypeSchema(operation.ReturnType);
}
OpenApiResponse response = new()
{
Description = "Success",
Content = new Dictionary<string, OpenApiMediaType>
@ -109,7 +151,7 @@ namespace Microsoft.OpenApi.OData.Generator
Constants.ApplicationJsonMediaType,
new OpenApiMediaType
{
Schema = context.CreateEdmTypeSchema(operation.ReturnType)
Schema = schema
}
}
}
@ -117,7 +159,7 @@ namespace Microsoft.OpenApi.OData.Generator
responses.Add(Constants.StatusCode200, response);
}
// both action & function has the default response.
// Both action & function have the default response.
responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse());
return responses;

View file

@ -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;
}

View file

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>Microsoft.OpenApi.OData.Reader</AssemblyName>
@ -19,12 +19,16 @@
<Import Project="..\Build.props" />
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.PublicApiAnalyzers" Version="3.3.2">
<PackageReference Include="Microsoft.CodeAnalysis.PublicApiAnalyzers" Version="3.3.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.OData.Edm" Version="7.9.4" />
<PackageReference Include="Microsoft.OpenApi" Version="1.2.3" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.OData.Edm" Version="7.6.1" />
<PackageReference Include="Microsoft.OpenApi" Version="1.2.2" />
</ItemGroup>
<ItemGroup>

View file

@ -183,6 +183,11 @@ namespace Microsoft.OpenApi.OData
/// </summary>
public IODataPathProvider PathProvider { get; set; }
/// <summary>
/// Gets/sets a value indicating whether or not add OData $count segments in the description for collections.
/// </summary>
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;

View file

@ -25,7 +25,7 @@ namespace Microsoft.OpenApi.OData.Operation
/// this segment could be "entity set", "Collection property", "Composable function whose return is collection",etc.
/// </summary>
internal ODataSegment LastSecondSegment { get; set; }
private const int SecondLastSegmentIndex = 2;
/// <inheritdoc/>
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);
}
/// <inheritdoc/>
@ -54,10 +55,12 @@ namespace Microsoft.OpenApi.OData.Operation
/// <inheritdoc/>
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

View file

@ -45,6 +45,8 @@ namespace Microsoft.OpenApi.OData.Operation
{
operation.Summary = "Invoke " + (EdmOperationImport.IsActionImport() ? "actionImport " : "functionImport ") + EdmOperationImport.Name;
operation.Description = Context.Model.GetDescriptionAnnotation(EdmOperationImport);
if (Context.Settings.EnableOperationId)
{
if (EdmOperationImport.IsActionImport())
@ -77,7 +79,7 @@ namespace Microsoft.OpenApi.OData.Operation
// describing the structure of the success response by referencing an appropriate schema
// in the global schemas. In addition, it contains a default name/value pair for
// the OData error response referencing the global responses.
operation.Responses = Context.CreateResponses(EdmOperationImport);
operation.Responses = Context.CreateResponses(EdmOperationImport, Path);
base.SetResponses(operation);
}

View file

@ -61,6 +61,9 @@ namespace Microsoft.OpenApi.OData.Operation
// Summary
operation.Summary = "Invoke " + (EdmOperation.IsAction() ? "action " : "function ") + EdmOperation.Name;
// Description
operation.Description = Context.Model.GetDescriptionAnnotation(EdmOperation);
// OperationId
if (Context.Settings.EnableOperationId)
{
@ -163,34 +166,7 @@ namespace Microsoft.OpenApi.OData.Operation
/// <inheritdoc/>
protected override void SetResponses(OpenApiOperation operation)
{
if (EdmOperation.IsAction() && EdmOperation.ReturnType == null)
{
operation.Responses.Add(Constants.StatusCode204, Constants.StatusCode204.GetResponse());
}
else
{
// function should have a return type.
OpenApiResponse response = new OpenApiResponse
{
Description = "Success",
Content = new Dictionary<string, OpenApiMediaType>
{
{
Constants.ApplicationJsonMediaType,
new OpenApiMediaType
{
Schema = Context.CreateEdmTypeSchema(EdmOperation.ReturnType)
}
}
}
};
operation.Responses.Add(Constants.StatusCode200, response);
}
// both action & function has the default response.
operation.Responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse());
operation.Responses = Context.CreateResponses(EdmOperation, Path);
base.SetResponses(operation);
}

View file

@ -29,14 +29,17 @@ namespace Microsoft.OpenApi.OData.Operation
// Summary
operation.Summary = "Delete entity from " + EntitySet.Name;
IEdmEntityType entityType = EntitySet.EntityType();
// Description
operation.Description = Context.Model.GetDescriptionAnnotation(entityType);
// OperationId
if (Context.Settings.EnableOperationId)
{
string typeName = EntitySet.EntityType().Name;
string typeName = entityType.Name;
operation.OperationId = EntitySet.Name + "." + typeName + ".Delete" + Utils.UpperFirstChar(typeName);
}
base.SetBasicInfo(operation);
}
/// <inheritdoc/>

View file

@ -30,14 +30,17 @@ namespace Microsoft.OpenApi.OData.Operation
// Summary
operation.Summary = "Get entity from " + EntitySet.Name + " by key";
IEdmEntityType entityType = EntitySet.EntityType();
// Description
operation.Description = Context.Model.GetDescriptionAnnotation(entityType);
// OperationId
if (Context.Settings.EnableOperationId)
{
string typeName = EntitySet.EntityType().Name;
string typeName = entityType.Name;
operation.OperationId = EntitySet.Name + "." + typeName + ".Get" + Utils.UpperFirstChar(typeName);
}
base.SetBasicInfo(operation);
}
/// <inheritdoc/>

View file

@ -30,14 +30,17 @@ namespace Microsoft.OpenApi.OData.Operation
// Summary
operation.Summary = "Update entity in " + EntitySet.Name;
IEdmEntityType entityType = EntitySet.EntityType();
// Description
operation.Description = Context.Model.GetDescriptionAnnotation(entityType);
// OperationId
if (Context.Settings.EnableOperationId)
{
string typeName = EntitySet.EntityType().Name;
string typeName = entityType.Name;
operation.OperationId = EntitySet.Name + "." + typeName + ".Update" + Utils.UpperFirstChar(typeName);
}
base.SetBasicInfo(operation);
}
/// <inheritdoc/>

View file

@ -32,6 +32,15 @@ namespace Microsoft.OpenApi.OData.Operation
EntitySet = navigationSourceSegment.NavigationSource as IEdmEntitySet;
}
/// <inheritdoc/>
protected override void SetBasicInfo(OpenApiOperation operation)
{
// Description
operation.Description = Context.Model.GetDescriptionAnnotation(EntitySet);
base.SetBasicInfo(operation);
}
/// <inheritdoc/>
protected override void SetTags(OpenApiOperation operation)
{

View file

@ -4,6 +4,7 @@
// ------------------------------------------------------------
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
@ -25,14 +26,15 @@ namespace Microsoft.OpenApi.OData.Operation
protected override void SetBasicInfo(OpenApiOperation operation)
{
// Summary
if (IsNavigationPropertyPath)
operation.Summary = IsNavigationPropertyPath
? $"Get media content for the navigation property {NavigationProperty.Name} from {NavigationSource.Name}"
: $"Get media content for {NavigationSourceSegment.EntityType.Name} from {NavigationSourceSegment.Identifier}";
// Description
IEdmVocabularyAnnotatable annotatableElement = GetAnnotatableElement();
if (annotatableElement != null)
{
operation.Summary = $"Get media content for the navigation property {NavigationProperty.Name} from {NavigationSource.Name}";
}
else
{
string typeName = EntitySet.EntityType().Name;
operation.Summary = $"Get media content for {typeName} from {EntitySet.Name}";
operation.Description = Context.Model.GetDescriptionAnnotation(annotatableElement);
}
// OperationId
@ -41,8 +43,6 @@ namespace Microsoft.OpenApi.OData.Operation
string identifier = Path.LastSegment.Kind == ODataSegmentKind.StreamContent ? "Content" : Path.LastSegment.Identifier;
operation.OperationId = GetOperationId("Get", identifier);
}
base.SetBasicInfo(operation);
}
/// <inheritdoc/>
@ -67,9 +67,8 @@ namespace Microsoft.OpenApi.OData.Operation
/// <inheritdoc/>
protected override void SetSecurity(OpenApiOperation operation)
{
ReadRestrictionsType read = EntitySet != null
? Context.Model.GetRecord<ReadRestrictionsType>(EntitySet, CapabilitiesConstants.ReadRestrictions)
: Context.Model.GetRecord<ReadRestrictionsType>(Singleton, CapabilitiesConstants.ReadRestrictions);
IEdmVocabularyAnnotatable annotatableNavigationSource = (IEdmVocabularyAnnotatable)NavigationSourceSegment.NavigationSource;
ReadRestrictionsType read = Context.Model.GetRecord<ReadRestrictionsType>(annotatableNavigationSource, CapabilitiesConstants.ReadRestrictions);
if (read == null)
{
return;

View file

@ -21,14 +21,9 @@ namespace Microsoft.OpenApi.OData.Operation
internal abstract class MediaEntityOperationalHandler : NavigationPropertyOperationHandler
{
/// <summary>
/// Gets/sets the <see cref="IEdmEntitySet"/>.
/// Gets/Sets the NavigationSource segment
/// </summary>
protected IEdmEntitySet EntitySet { get; private set; }
/// <summary>
/// Gets the <see cref="IEdmSingleton"/>.
/// </summary>
protected IEdmSingleton Singleton { get; private set; }
protected ODataNavigationSourceSegment NavigationSourceSegment { get; private set; }
/// <summary>
/// Gets/Sets flag indicating whether path is navigation property path
@ -39,13 +34,7 @@ namespace Microsoft.OpenApi.OData.Operation
protected override void Initialize(ODataContext context, ODataPath path)
{
// The first segment will either be an EntitySet navigation source or a Singleton navigation source
ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment;
EntitySet = navigationSourceSegment.NavigationSource as IEdmEntitySet;
if (EntitySet == null)
{
Singleton = navigationSourceSegment.NavigationSource as IEdmSingleton;
}
NavigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment;
// Check whether path is a navigation property path
IsNavigationPropertyPath = Path.Segments.Contains(
@ -67,9 +56,9 @@ namespace Microsoft.OpenApi.OData.Operation
}
else
{
string tagIdentifier = EntitySet.Name + "." + EntitySet.EntityType().Name;
string tagIdentifier = NavigationSourceSegment.Identifier + "." + NavigationSourceSegment.EntityType.Name;
OpenApiTag tag = new OpenApiTag
OpenApiTag tag = new()
{
Name = tagIdentifier
};
@ -102,7 +91,7 @@ namespace Microsoft.OpenApi.OData.Operation
IList<string> items = new List<string>
{
EntitySet?.Name ?? Singleton.Name
NavigationSourceSegment.Identifier
};
ODataSegment lastSegment = Path.Segments.Last(c => c is ODataStreamContentSegment || c is ODataStreamPropertySegment);
@ -112,7 +101,7 @@ namespace Microsoft.OpenApi.OData.Operation
{
if (!IsNavigationPropertyPath)
{
string typeName = EntitySet?.EntityType().Name ?? Singleton.EntityType().Name;
string typeName = NavigationSourceSegment.EntityType.Name;
items.Add(typeName);
items.Add(prefix + Utils.UpperFirstChar(identifier));
}
@ -151,28 +140,8 @@ namespace Microsoft.OpenApi.OData.Operation
Format = "binary"
};
IEdmVocabularyAnnotatable annotatableElement = null;
IEdmEntityType entityType = EntitySet != null ? EntitySet.EntityType() : Singleton.EntityType();
ODataSegment lastSegmentStreamProp = Path.Segments.LastOrDefault(c => c is ODataStreamPropertySegment);
if (lastSegmentStreamProp != null)
{
// Get the annotatable stream property
// The stream property can either be a structural type or navigation type property
IEdmProperty property = GetStructuralProperty(entityType, lastSegmentStreamProp.Identifier);
if (property == null)
{
property = GetNavigationProperty(entityType, lastSegmentStreamProp.Identifier);
}
annotatableElement = property;
}
else
{
annotatableElement = entityType;
}
// Fetch the respective AcceptableMediaTypes
IEdmVocabularyAnnotatable annotatableElement = GetAnnotatableElement();
IEnumerable<string> mediaTypes = null;
if (annotatableElement != null)
{
@ -199,9 +168,42 @@ namespace Microsoft.OpenApi.OData.Operation
return content;
}
/// <summary>
/// Determines the annotatable element from the segments of a path.
/// </summary>
/// <returns>The annotable element.</returns>
protected IEdmVocabularyAnnotatable GetAnnotatableElement()
{
IEdmEntityType entityType = NavigationSourceSegment.EntityType;
ODataSegment lastSegmentProp = Path.Segments.LastOrDefault(c => c is ODataStreamPropertySegment);
if (lastSegmentProp == null)
{
int pathCount = Path.Segments.Count;
// Retrieve the segment before the stream content segment
lastSegmentProp = Path.Segments.ElementAtOrDefault(pathCount - 2);
if (lastSegmentProp == null)
{
return null;
}
}
// Get the annotatable stream property
// The stream property can either be a structural type or navigation type property
IEdmProperty property = GetStructuralProperty(entityType, lastSegmentProp.Identifier);
if (property == null)
{
property = GetNavigationProperty(entityType, lastSegmentProp.Identifier);
}
return property;
}
private IEdmStructuralProperty GetStructuralProperty(IEdmEntityType entityType, string identifier)
{
return entityType.DeclaredStructuralProperties().FirstOrDefault(x => x.Name.Equals(identifier));
return entityType.StructuralProperties().FirstOrDefault(x => x.Name.Equals(identifier));
}
private IEdmNavigationProperty GetNavigationProperty(IEdmEntityType entityType, string identifier)

View file

@ -5,6 +5,7 @@
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
@ -25,14 +26,15 @@ namespace Microsoft.OpenApi.OData.Operation
protected override void SetBasicInfo(OpenApiOperation operation)
{
// Summary
if (IsNavigationPropertyPath)
operation.Summary = IsNavigationPropertyPath
? $"Update media content for the navigation property {NavigationProperty.Name} in {NavigationSource.Name}"
: $"Update media content for {NavigationSourceSegment.EntityType.Name} in {NavigationSourceSegment.Identifier}";
// Description
IEdmVocabularyAnnotatable annotatableElement = GetAnnotatableElement();
if (annotatableElement != null)
{
operation.Summary = $"Update media content for the navigation property {NavigationProperty.Name} in {NavigationSource.Name}";
}
else
{
string typeName = EntitySet.EntityType().Name;
operation.Summary = $"Update media content for {typeName} in {EntitySet.Name}";
operation.Description = Context.Model.GetDescriptionAnnotation(annotatableElement);
}
// OperationId
@ -41,8 +43,6 @@ namespace Microsoft.OpenApi.OData.Operation
string identifier = Path.LastSegment.Kind == ODataSegmentKind.StreamContent ? "Content" : Path.LastSegment.Identifier;
operation.OperationId = GetOperationId("Update", identifier);
}
base.SetBasicInfo(operation);
}
/// <inheritdoc/>
@ -73,9 +73,8 @@ namespace Microsoft.OpenApi.OData.Operation
/// <inheritdoc/>
protected override void SetSecurity(OpenApiOperation operation)
{
UpdateRestrictionsType update = EntitySet != null
? Context.Model.GetRecord<UpdateRestrictionsType>(EntitySet, CapabilitiesConstants.UpdateRestrictions)
: Context.Model.GetRecord<UpdateRestrictionsType>(Singleton, CapabilitiesConstants.UpdateRestrictions);
IEdmVocabularyAnnotatable annotatableNavigationSource = (IEdmVocabularyAnnotatable)NavigationSourceSegment.NavigationSource;
UpdateRestrictionsType update = Context.Model.GetRecord<UpdateRestrictionsType>(annotatableNavigationSource, CapabilitiesConstants.UpdateRestrictions);
if (update == null || update.Permissions == null)
{
return;

View file

@ -84,6 +84,15 @@ namespace Microsoft.OpenApi.OData.Operation
}
}
/// <inheritdoc/>
protected override void SetBasicInfo(OpenApiOperation operation)
{
// Description
operation.Description = Context.Model.GetDescriptionAnnotation(NavigationProperty);
base.SetBasicInfo(operation);
}
/// <inheritdoc/>
protected override void SetTags(OpenApiOperation operation)
{

View file

@ -14,88 +14,82 @@ namespace Microsoft.OpenApi.OData.Operation
/// </summary>
internal class OperationHandlerProvider : IOperationHandlerProvider
{
private IDictionary<ODataPathKind, IDictionary<OperationType, IOperationHandler>> _handlers;
/// <summary>
/// Initializes a new instance of <see cref="OperationHandlerProvider"/> class.
/// </summary>
public OperationHandlerProvider()
{
_handlers = new Dictionary<ODataPathKind, IDictionary<OperationType, IOperationHandler>>();
private readonly IDictionary<ODataPathKind, IDictionary<OperationType, IOperationHandler>> _handlers
= new Dictionary<ODataPathKind, IDictionary<OperationType, IOperationHandler>>{
// entity set (Get/Post)
_handlers[ODataPathKind.EntitySet] = new Dictionary<OperationType, IOperationHandler>
{ODataPathKind.EntitySet, new Dictionary<OperationType, IOperationHandler>
{
{OperationType.Get, new EntitySetGetOperationHandler() },
{OperationType.Post, new EntitySetPostOperationHandler() }
};
}},
// entity (Get/Patch/Delete)
_handlers[ODataPathKind.Entity] = new Dictionary<OperationType, IOperationHandler>
{ODataPathKind.Entity, new Dictionary<OperationType, IOperationHandler>
{
{OperationType.Get, new EntityGetOperationHandler() },
{OperationType.Patch, new EntityPatchOperationHandler() },
{OperationType.Delete, new EntityDeleteOperationHandler() }
};
}},
// singleton (Get/Patch)
_handlers[ODataPathKind.Singleton] = new Dictionary<OperationType, IOperationHandler>
{ODataPathKind.Singleton, new Dictionary<OperationType, IOperationHandler>
{
{OperationType.Get, new SingletonGetOperationHandler() },
{OperationType.Patch, new SingletonPatchOperationHandler() }
};
}},
// edm operation (Get|Post)
_handlers[ODataPathKind.Operation] = new Dictionary<OperationType, IOperationHandler>
{ODataPathKind.Operation, new Dictionary<OperationType, IOperationHandler>
{
{OperationType.Get, new EdmFunctionOperationHandler() },
{OperationType.Post, new EdmActionOperationHandler() }
};
}},
// edm operation import (Get|Post)
_handlers[ODataPathKind.OperationImport] = new Dictionary<OperationType, IOperationHandler>
{ODataPathKind.OperationImport, new Dictionary<OperationType, IOperationHandler>
{
{OperationType.Get, new EdmFunctionImportOperationHandler() },
{OperationType.Post, new EdmActionImportOperationHandler() }
};
}},
// navigation property (Get/Patch/Post/Delete)
_handlers[ODataPathKind.NavigationProperty] = new Dictionary<OperationType, IOperationHandler>
{ODataPathKind.NavigationProperty, new Dictionary<OperationType, IOperationHandler>
{
{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<OperationType, IOperationHandler>
{ODataPathKind.Ref, new Dictionary<OperationType, IOperationHandler>
{
{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<OperationType, IOperationHandler>
{ODataPathKind.MediaEntity, new Dictionary<OperationType, IOperationHandler>
{
{OperationType.Get, new MediaEntityGetOperationHandler() },
{OperationType.Put, new MediaEntityPutOperationHandler() }
};
}},
// $metadata operation (Get)
_handlers[ODataPathKind.Metadata] = new Dictionary<OperationType, IOperationHandler>
{ODataPathKind.Metadata, new Dictionary<OperationType, IOperationHandler>
{
{OperationType.Get, new MetadataGetOperationHandler() }
};
}},
// $count operation (Get)
_handlers[ODataPathKind.DollarCount] = new Dictionary<OperationType, IOperationHandler>
{ODataPathKind.DollarCount, new Dictionary<OperationType, IOperationHandler>
{
{OperationType.Get, new DollarCountGetOperationHandler() }
};
}
}},
};
/// <inheritdoc/>
public IOperationHandler GetHandler(ODataPathKind pathKind, OperationType operationType)

View file

@ -32,6 +32,15 @@ namespace Microsoft.OpenApi.OData.Operation
Singleton = navigationSourceSegment.NavigationSource as IEdmSingleton;
}
/// <inheritdoc/>
protected override void SetBasicInfo(OpenApiOperation operation)
{
// Description
operation.Description = Context.Model.GetDescriptionAnnotation(Singleton);
base.SetBasicInfo(operation);
}
/// <inheritdoc/>
protected override void SetTags(OpenApiOperation operation)
{

View file

@ -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
/// </summary>
protected bool LastSegmentIsRefSegment { get; private set; }
/// <inheritdoc/>
protected override void SetOperations(OpenApiPathItem item)
/// <inheritdoc/>
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)

View file

@ -13,7 +13,7 @@ namespace Microsoft.OpenApi.OData.PathItem
/// </summary>
internal class PathItemHandlerProvider : IPathItemHandlerProvider
{
private IDictionary<ODataPathKind, IPathItemHandler> _handlers = new Dictionary<ODataPathKind, IPathItemHandler>
private readonly IDictionary<ODataPathKind, IPathItemHandler> _handlers = new Dictionary<ODataPathKind, IPathItemHandler>
{
// EntitySet
{ ODataPathKind.EntitySet, new EntitySetPathItemHandler() },

View file

@ -68,37 +68,62 @@ namespace Microsoft.OpenApi.OData.PathItem
// So far, we only consider the non-containment
Debug.Assert(!NavigationProperty.ContainsTarget);
// It seems OData supports to "GetRef, DeleteRef",
// Here at this time,let's only consider the "delete"
// Create the ref
if (NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many)
{
ODataSegment penultimateSegment = Path.Segments.Reverse().Skip(1).First();
if (penultimateSegment is ODataKeySegment)
{
// Collection-valued: DELETE ~/entityset/{key}/collection-valued-Nav/{key}/$ref
AddDeleteOperation(item, restriction);
}
else
{
AddReadOperation(item, restriction);
AddInsertOperation(item, restriction);
}
}
else
{
AddReadOperation(item, restriction);
AddUpdateOperation(item, restriction);
AddDeleteOperation(item, restriction);
}
}
private void AddDeleteOperation(OpenApiPathItem item, NavigationPropertyRestriction restriction)
{
DeleteRestrictionsType delete = restriction?.DeleteRestrictions;
if (delete == null || delete.IsDeletable)
{
AddOperation(item, OperationType.Delete);
}
}
private void AddReadOperation(OpenApiPathItem item, NavigationPropertyRestriction restriction)
{
ReadRestrictionsType read = restriction?.ReadRestrictions;
if (read == null || read.IsReadable)
{
AddOperation(item, OperationType.Get);
}
}
// Create the ref
if (NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many)
private void AddInsertOperation(OpenApiPathItem item, NavigationPropertyRestriction restriction)
{
InsertRestrictionsType insert = restriction?.InsertRestrictions;
if (insert == null || insert.IsInsertable)
{
InsertRestrictionsType insert = restriction?.InsertRestrictions;
if (insert == null || insert.IsInsertable)
{
AddOperation(item, OperationType.Post);
}
AddOperation(item, OperationType.Post);
}
else
{
UpdateRestrictionsType update = restriction?.UpdateRestrictions;
if (update == null || update.IsUpdatable)
{
AddOperation(item, OperationType.Put);
}
}
// delete the link
DeleteRestrictionsType delete = restriction?.DeleteRestrictions;
if (delete == null || delete.IsDeletable)
{
AddOperation(item, OperationType.Delete);
}
private void AddUpdateOperation(OpenApiPathItem item, NavigationPropertyRestriction restriction)
{
UpdateRestrictionsType update = restriction?.UpdateRestrictions;
if (update == null || update.IsUpdatable)
{
AddOperation(item, OperationType.Put);
}
}

View file

@ -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

View file

@ -36,7 +36,7 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities
/// Test the target supports count.
/// </summary>
/// <returns>True/false.</returns>
public bool IsCountable => Countable == null || Countable.Value;
public bool IsCountable => !Countable.HasValue || Countable.Value;
/// <summary>
/// Test the input property path which do not allow /$count segments.
@ -45,7 +45,7 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities
/// <returns>True/False.</returns>
public bool IsNonCountableProperty(string propertyPath)
{
return NonCountableProperties != null ? NonCountableProperties.Any(a => a == propertyPath) : false;
return NonCountableProperties != null && NonCountableProperties.Any(a => a == propertyPath);
}
/// <summary>
@ -55,9 +55,7 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities
/// <returns>True/False.</returns>
public bool IsNonCountableNavigationProperty(string navigationPropertyPath)
{
return NonCountableNavigationProperties != null ?
NonCountableNavigationProperties.Any(a => a == navigationPropertyPath) :
false;
return NonCountableNavigationProperties != null && NonCountableNavigationProperties.Any(a => a == navigationPropertyPath);
}
/// <summary>

View file

@ -175,7 +175,7 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities
// DeleteRestrictions
DeleteRestrictions = record.GetRecord<DeleteRestrictionsType>("DeleteRestrictions");
// IndexableByKey
// OptimisticConcurrencyControl
OptimisticConcurrencyControl = record.GetBoolean("OptimisticConcurrencyControl");
// ReadRestrictions

View file

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup>
</configuration>

View file

@ -16,8 +16,9 @@ using System.Text;
using Microsoft.OpenApi.Extensions;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData;
using System.Net;
using System.Xml;
using System.Threading.Tasks;
using System.Net.Http;
namespace OoasGui
{
@ -50,28 +51,28 @@ namespace OoasGui
oasRichTextBox.WordWrap = false;
}
private void jsonRadioBtn_CheckedChanged(object sender, EventArgs e)
private async void jsonRadioBtn_CheckedChanged(object sender, EventArgs e)
{
Format = OpenApiFormat.Json;
Convert();
await Convert();
}
private void yamlRadioBtn_CheckedChanged(object sender, EventArgs e)
private async void yamlRadioBtn_CheckedChanged(object sender, EventArgs e)
{
Format = OpenApiFormat.Yaml;
Convert();
await Convert();
}
private void v2RadioBtn_CheckedChanged(object sender, EventArgs e)
private async void v2RadioBtn_CheckedChanged(object sender, EventArgs e)
{
Settings.OpenApiSpecVersion = Version = OpenApiSpecVersion.OpenApi2_0;
Convert();
await Convert();
}
private void v3RadioBtn_CheckedChanged(object sender, EventArgs e)
private async void v3RadioBtn_CheckedChanged(object sender, EventArgs e)
{
Settings.OpenApiSpecVersion = Version = OpenApiSpecVersion.OpenApi3_0;
Convert();
await Convert();
}
private void fromFileRadioBtn_CheckedChanged(object sender, EventArgs e)
@ -91,7 +92,7 @@ namespace OoasGui
loadBtn.Enabled = true;
}
private void btnBrowse_Click(object sender, EventArgs e)
private async void btnBrowse_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "CSDL files (*.xml)|*.xml|All files (*.*)|*.*";
@ -106,7 +107,7 @@ namespace OoasGui
fileTextBox.Text = openFileDialog.FileName;
csdlRichTextBox.Text = text;
Settings.ServiceRoot = new Uri(openFileDialog.FileName);
Convert();
await Convert();
}
catch (Exception ex)
{
@ -119,7 +120,9 @@ namespace OoasGui
}
}
private void loadBtn_Click(object sender, EventArgs e)
private static HttpClient client = new();
private async void loadBtn_Click(object sender, EventArgs e)
{
string url = urlTextBox.Text;
@ -135,19 +138,14 @@ namespace OoasGui
requestUri = new Uri(url + "/$metadata");
}
WebRequest request = WebRequest.Create(requestUri);
HttpResponseMessage response = await client.GetAsync(requestUri);
WebResponse response = request.GetResponse();
string csdl = await response.Content.ReadAsStringAsync();
Stream receivedStream = response.GetResponseStream();
StreamReader reader = new StreamReader(receivedStream, Encoding.UTF8);
string csdl = reader.ReadToEnd();
LoadEdm(url, csdl);
csdlRichTextBox.Text = FormatXml(csdl);
Settings.ServiceRoot = requestUri;
Convert();
await Convert();
}
catch(Exception ex)
{
@ -163,6 +161,7 @@ namespace OoasGui
{
IEdmModel model;
IEnumerable<EdmError> errors;
if (!CsdlReader.TryParse(XElement.Parse(text).CreateReader(), out model, out errors))
{
StringBuilder sb = new StringBuilder();
@ -178,19 +177,24 @@ namespace OoasGui
EdmModel = model;
}
private void Convert()
private async Task Convert()
{
if (EdmModel == null)
{
return;
}
OpenApiDocument document = EdmModel.ConvertToOpenApi(Settings);
MemoryStream stream = new MemoryStream();
document.Serialize(stream, Version, Format);
stream.Flush();
stream.Position = 0;
string openApi = new StreamReader(stream).ReadToEnd();
string openApi = null;
await Task.Run(() =>
{
OpenApiDocument document = EdmModel.ConvertToOpenApi(Settings);
MemoryStream stream = new MemoryStream();
document.Serialize(stream, Version, Format);
stream.Flush();
stream.Position = 0;
openApi = new StreamReader(stream).ReadToEnd();
});
oasRichTextBox.Text = openApi;
}
@ -211,7 +215,7 @@ namespace OoasGui
return sw.ToString();
}
private void saveBtn_Click(object sender, EventArgs e)
private async void saveBtn_Click(object sender, EventArgs e)
{
SaveFileDialog saveFileDialog = new SaveFileDialog();
if (Format == OpenApiFormat.Json)
@ -220,7 +224,7 @@ namespace OoasGui
}
else
{
saveFileDialog.Filter = "YAML files (*.ymal)|*.json|All files (*.*)|*.*";
saveFileDialog.Filter = "YAML files (*.yaml)|*.yaml|All files (*.*)|*.*";
}
saveFileDialog.FilterIndex = 2;
@ -231,31 +235,34 @@ namespace OoasGui
string output = saveFileDialog.FileName;
using (FileStream fs = File.Create(output))
{
OpenApiDocument document = EdmModel.ConvertToOpenApi(Settings);
document.Serialize(fs, Version, Format);
fs.Flush();
await Task.Run(() =>
{
OpenApiDocument document = EdmModel.ConvertToOpenApi(Settings);
document.Serialize(fs, Version, Format);
fs.Flush();
});
}
}
MessageBox.Show("Saved successful!");
}
private void operationIdcheckBox_CheckedChanged(object sender, EventArgs e)
private async void operationIdcheckBox_CheckedChanged(object sender, EventArgs e)
{
Settings.EnableOperationId = !Settings.EnableOperationId;
Convert();
await Convert ();
}
private void VerifyEdmModelcheckBox_CheckedChanged(object sender, EventArgs e)
private async void VerifyEdmModelcheckBox_CheckedChanged(object sender, EventArgs e)
{
Settings.VerifyEdmModel = !Settings.VerifyEdmModel;
Convert();
await Convert();
}
private void NavPathcheckBox_CheckedChanged(object sender, EventArgs e)
private async void NavPathcheckBox_CheckedChanged(object sender, EventArgs e)
{
Settings.EnableNavigationPropertyPath = !Settings.EnableNavigationPropertyPath;
Convert();
await Convert();
}
}
}

View file

@ -1,98 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{79B190E8-EDB0-4C03-8FD8-EB48E4807CFB}</ProjectGuid>
<TargetFramework>net6.0-windows</TargetFramework>
<OutputType>WinExe</OutputType>
<RootNamespace>OoasGui</RootNamespace>
<AssemblyName>OoasGui</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<UseWindowsForms>true</UseWindowsForms>
<ImportWindowsDesktopTargets>true</ImportWindowsDesktopTargets>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.OData.Edm, Version=7.6.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.OData.Edm.7.6.1\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll</HintPath>
</Reference>
<Reference Include="Microsoft.OpenApi, Version=1.2.2.0, Culture=neutral, PublicKeyToken=3f5743946376f042, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.OpenApi.1.2.2\lib\net46\Microsoft.OpenApi.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="MainForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="MainForm.Designer.cs">
<DependentUpon>MainForm.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="MainForm.resx">
<DependentUpon>MainForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<None Include="..\..\.editorconfig">
<Link>.editorconfig</Link>
</None>
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<ProjectReference Include="..\Microsoft.OpenApi.OData.Reader\Microsoft.OpenApi.OData.Reader.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Microsoft.OpenApi.OData.Reader\Microsoft.OpenApi.OData.Reader.csproj">
<Project>{ff3acd93-19e0-486c-9c0f-fa1c2e7fc8c2}</Project>
<Name>Microsoft.OpenApi.OData.Reader</Name>
</ProjectReference>
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="Microsoft.OData.Edm" Version="7.9.4" />
<PackageReference Include="Microsoft.OpenApi" Version="1.2.3" />
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View file

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.OData.Edm" version="7.6.1" targetFramework="net461" />
<package id="Microsoft.OpenApi" version="1.2.2" targetFramework="net472" />
</packages>

View file

@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net472</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<ItemGroup>

View file

@ -5,14 +5,13 @@
//---------------------------------------------------------------------
using System;
using System.Net;
using System.IO;
using System.Text;
using System.Xml.Linq;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Csdl;
using Microsoft.OpenApi;
using Microsoft.OpenApi.OData;
using System.Net.Http;
using System.Threading.Tasks;
namespace OoasUtil
{
@ -44,20 +43,17 @@ namespace OoasUtil
/// </summary>
protected override IEdmModel GetEdmModel()
{
Uri requestUri = new Uri(Input.OriginalString + "/$metadata");
Uri requestUri = new (Input.OriginalString + "/$metadata");
WebRequest request = WebRequest.Create(requestUri);
WebResponse response = request.GetResponse();
Stream receivedStream = response.GetResponseStream();
StreamReader reader = new StreamReader(receivedStream, Encoding.UTF8);
string csdl = reader.ReadToEnd();
string csdl = GetModelDocumentAsync(requestUri).GetAwaiter().GetResult();
return CsdlReader.Parse(XElement.Parse(csdl).CreateReader());
}
private async Task<string> GetModelDocumentAsync(Uri requestUri) {
HttpResponseMessage response = await client.GetAsync(requestUri);
return await response.Content.ReadAsStringAsync();
}
private static readonly HttpClient client = new ();
protected override void ModifySettings()
{

View file

@ -1,7 +1,7 @@
// ------------------------------------------------------------
// --------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
// --------------------------------------------------------------
using System;
using System.Collections.Generic;
@ -48,7 +48,7 @@ namespace Microsoft.OpenApi.OData.Edm.Tests
// Assert
Assert.NotNull(paths);
Assert.Equal(4887, paths.Count());
Assert.Equal(17178, paths.Count());
}
[Fact]
@ -67,7 +67,7 @@ namespace Microsoft.OpenApi.OData.Edm.Tests
// Assert
Assert.NotNull(paths);
Assert.Equal(4544, 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,10 +290,84 @@ 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()));
}
[Theory]
[InlineData(true)]
[InlineData(false)]
public void GetPathsWithBoundActionOperationForContainmentNavigationPropertyPathsWorks(bool containsTarget)
{
// Arrange
string navProp = $@"<NavigationProperty Name=""Referral"" Type=""NS.NiceCustomer"" ContainsTarget=""{containsTarget}""/>";
string boundAction =
@"<Action Name=""Ack"" IsBound=""true"">
<Parameter Name=""bindingParameter"" Type=""NS.NiceCustomer"" />
<ReturnType Type=""Edm.Boolean"" />
</Action>
<EntityType Name=""NiceCustomer"">
<Property Name=""Other"" Type=""Edm.Int32"" Nullable=""true"" />
</EntityType>";
IEdmModel model = GetEdmModel(boundAction, "", navProp);
ODataPathProvider provider = new ODataPathProvider();
var settings = new OpenApiConvertSettings();
// Act
var paths = provider.GetPaths(model, settings);
// Assert
Assert.NotNull(paths);
Assert.Equal(5, paths.Count());
if (containsTarget)
{
Assert.Contains("/Customers({ID})/Referral/NS.Ack", paths.Select(p => p.GetPathItemName()));
}
else
{
Assert.DoesNotContain("/Customers({ID})/Referral/NS.Ack", paths.Select(p => p.GetPathItemName()));
}
}
[Theory]
[InlineData(true)]
[InlineData(false)]
public void GetPathsWithBoundFunctionOperationForContainmentNavigationPropertyPathsWorks(bool containsTarget)
{
// Arrange
string navProp = $@"<NavigationProperty Name=""Referral"" Type=""NS.NiceCustomer"" ContainsTarget=""{containsTarget}""/>";
string boundAction =
@"<Function Name=""Search"" IsBound=""true"">
<Parameter Name=""bindingParameter"" Type=""NS.NiceCustomer"" />
<ReturnType Type=""Collection(NS.Customer)"" />
</Function>
<EntityType Name=""NiceCustomer"">
<Property Name=""Other"" Type=""Edm.Int32"" Nullable=""true"" />
</EntityType>";
IEdmModel model = GetEdmModel(boundAction, "", navProp);
ODataPathProvider provider = new ODataPathProvider();
var settings = new OpenApiConvertSettings();
// Act
var paths = provider.GetPaths(model, settings);
// Assert
Assert.NotNull(paths);
Assert.Equal(5, paths.Count());
if (containsTarget)
{
Assert.Contains("/Customers({ID})/Referral/NS.Search()", paths.Select(p => p.GetPathItemName()));
}
else
{
Assert.DoesNotContain("/Customers({ID})/Referral/NS.Search()", paths.Select(p => p.GetPathItemName()));
}
}
[Fact]
public void GetPathsWithUnboundOperationImportWorks()
{
@ -299,13 +391,94 @@ 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()));
}
[Fact]
public void GetPathsWithNonContainedNavigationPropertytWorks()
public void GetPathsWithFalseNavigabilityInNavigationRestrictionsAnnotationWorks()
{
// Arrange
string entityType =
@"<EntityType Name=""Order"">
<Key>
<PropertyRef Name=""id"" />
</Key>
<NavigationProperty Name=""MultipleCustomers"" Type=""Collection(NS.Customer)"" />
<NavigationProperty Name=""SingleCustomer"" Type=""NS.Customer"" >
<Annotation Term=""Org.OData.Capabilities.V1.NavigationRestrictions"">
<Record>
<PropertyValue Property = ""Navigability"">
<EnumMember>Org.OData.Capabilities.V1.NavigationType/None</EnumMember>
</PropertyValue>
</Record>
</Annotation>
</NavigationProperty>
</EntityType>";
string entitySet = @"<EntitySet Name=""Orders"" EntityType=""NS.Order"" />";
IEdmModel model = GetEdmModel(entityType, entitySet);
ODataPathProvider provider = new ODataPathProvider();
var settings = new OpenApiConvertSettings();
// Act
var paths = provider.GetPaths(model, settings);
// Assert
Assert.NotNull(paths);
Assert.Equal(10, paths.Count());
var pathItems = paths.Select(p => p.GetPathItemName()).ToList();
Assert.DoesNotContain("/Orders({id})/SingleCustomer", pathItems);
Assert.DoesNotContain("/Orders({id})/SingleCustomer/$ref", pathItems);
}
[Fact]
public void GetPathsWithFalseIndexabilityByKeyInNavigationRestrictionsAnnotationWorks()
{
// Arrange
string entityType =
@"<EntityType Name=""Order"">
<Key>
<PropertyRef Name=""id"" />
</Key>
<NavigationProperty Name=""MultipleCustomers"" Type=""Collection(NS.Customer)"" ContainsTarget=""true"" >
<Annotation Term=""Org.OData.Capabilities.V1.NavigationRestrictions"">
<Record>
<PropertyValue Property=""RestrictedProperties"" >
<Collection>
<Record>
<PropertyValue Property=""IndexableByKey"" Bool=""false"" />
</Record>
</Collection>
</PropertyValue>
</Record>
</Annotation>
</NavigationProperty>
<NavigationProperty Name=""SingleCustomer"" Type=""NS.Customer"" />
</EntityType>";
string entitySet = @"<EntitySet Name=""Orders"" EntityType=""NS.Order"" />";
IEdmModel model = GetEdmModel(entityType, entitySet);
ODataPathProvider provider = new ODataPathProvider();
var settings = new OpenApiConvertSettings();
// Act
var paths = provider.GetPaths(model, settings);
// Assert
Assert.NotNull(paths);
Assert.Equal(9, paths.Count());
var pathItems = paths.Select(p => p.GetPathItemName()).ToList();
Assert.DoesNotContain("/Orders({id})/MultipleCustomers({ID})", pathItems);
}
[Fact]
public void GetPathsWithNonContainedNavigationPropertyWorks()
{
// Arrange
string entityType =
@ -328,17 +501,18 @@ namespace Microsoft.OpenApi.OData.Edm.Tests
// Assert
Assert.NotNull(paths);
Assert.Equal(8, paths.Count());
Assert.Equal(12, paths.Count());
var pathItems = paths.Select(p => p.GetPathItemName()).ToList();
Assert.Contains("/Orders({id})/MultipleCustomers", pathItems);
Assert.Contains("/Orders({id})/SingleCustomer", pathItems);
Assert.Contains("/Orders({id})/SingleCustomer/$ref", pathItems);
Assert.Contains("/Orders({id})/MultipleCustomers/$ref", pathItems);
Assert.Contains("/Orders({id})/MultipleCustomers({ID})/$ref", pathItems);
}
[Fact]
public void GetPathsWithContainedNavigationPropertytWorks()
public void GetPathsWithContainedNavigationPropertyWorks()
{
// Arrange
string entityType =
@ -360,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);
@ -369,45 +543,56 @@ namespace Microsoft.OpenApi.OData.Edm.Tests
}
[Theory]
[InlineData(true, "Logo")]
[InlineData(false, "Logo")]
[InlineData(true, "Content")]
[InlineData(false, "Content")]
[InlineData(true, "logo")]
[InlineData(false, "logo")]
[InlineData(true, "content")]
[InlineData(false, "content")]
public void GetPathsWithStreamPropertyAndWithEntityHasStreamWorks(bool hasStream, string streamPropName)
{
// Arrange
IEdmModel model = GetEdmModel(hasStream, streamPropName);
ODataPathProvider provider = new ODataPathProvider();
var settings = new OpenApiConvertSettings();
const string TodosContentPath = "/todos({id})/content";
const string TodosValuePath = "/todos({id})/$value";
const string TodosLogoPath = "/todos({id})/logo";
// Act
var paths = provider.GetPaths(model,settings);
var paths = provider.GetPaths(model, settings);
// Assert
Assert.NotNull(paths);
Assert.Contains("/catalog/content", paths.Select(p => p.GetPathItemName()));
Assert.Contains("/catalog/thumbnailPhoto", paths.Select(p => p.GetPathItemName()));
Assert.Contains("/me/photo/$value", paths.Select(p => p.GetPathItemName()));
if (hasStream && !streamPropName.Equals("Content", StringComparison.OrdinalIgnoreCase))
if (streamPropName.Equals("logo"))
{
Assert.Equal(7, paths.Count());
Assert.Equal(new[] { "/me", "/me/photo", "/me/photo/$value", "/Todos", "/Todos({Id})", "/Todos({Id})/$value", "/Todos({Id})/Logo" },
paths.Select(p => p.GetPathItemName()));
if (hasStream)
{
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(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()));
}
}
else if ((hasStream && streamPropName.Equals("Content", StringComparison.OrdinalIgnoreCase)) ||
(!hasStream && streamPropName.Equals("Content", StringComparison.OrdinalIgnoreCase)))
else if (streamPropName.Equals("content"))
{
Assert.Equal(6, paths.Count());
Assert.Equal(new[] { "/me", "/me/photo", "/me/photo/$value", "/Todos", "/Todos({Id})", "/Todos({Id})/Content" },
paths.Select(p => p.GetPathItemName()));
}
else // !hasStream && !streamPropName.Equals("Content")
{
Assert.Equal(6, paths.Count());
Assert.Equal(new[] { "/me", "/me/photo", "/me/photo/$value", "/Todos", "/Todos({Id})", "/Todos({Id})/Logo"},
paths.Select(p => p.GetPathItemName()));
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()));
}
}
private static IEdmModel GetEdmModel(string schemaElement, string containerElement)
private static IEdmModel GetEdmModel(string schemaElement, string containerElement, string propertySchema = null)
{
string template = $@"<?xml version=""1.0"" encoding=""utf-16""?>
<Schema Namespace=""NS"" xmlns=""http://docs.oasis-open.org/odata/ns/edm"">
@ -416,6 +601,7 @@ namespace Microsoft.OpenApi.OData.Edm.Tests
<PropertyRef Name=""ID"" />
</Key>
<Property Name=""ID"" Type=""Edm.Int32"" Nullable=""false"" />
{propertySchema}
</EntityType>
{schemaElement}
<EntityContainer Name =""Default"">
@ -495,13 +681,13 @@ namespace Microsoft.OpenApi.OData.Edm.Tests
string template = @"<edmx:Edmx Version=""4.0"" xmlns:edmx=""http://docs.oasis-open.org/odata/ns/edmx"">
<edmx:DataServices>
<Schema Namespace=""microsoft.graph"" xmlns=""http://docs.oasis-open.org/odata/ns/edm"">
<EntityType Name=""Todo"" HasStream=""{0}"">
<EntityType Name=""todo"" HasStream=""{0}"">
<Key>
<PropertyRef Name=""Id"" />
<PropertyRef Name=""id"" />
</Key>
<Property Name=""Id"" Type=""Edm.Int32"" Nullable=""false"" />
<Property Name=""id"" Type=""Edm.Int32"" Nullable=""false"" />
<Property Name=""{1}"" Type=""Edm.Stream""/>
<Property Name = ""Description"" Type = ""Edm.String"" />
<Property Name = ""description"" Type = ""Edm.String"" />
</EntityType>
<EntityType Name=""user"" OpenType=""true"">
<NavigationProperty Name = ""photo"" Type = ""microsoft.graph.profilePhoto"" ContainsTarget = ""true"" />
@ -510,9 +696,23 @@ namespace Microsoft.OpenApi.OData.Edm.Tests
<Property Name = ""height"" Type = ""Edm.Int32"" />
<Property Name = ""width"" Type = ""Edm.Int32"" />
</EntityType >
<EntityType Name=""document"">
<Property Name=""content"" Type=""Edm.Stream""/>
<Property Name=""thumbnailPhoto"" Type=""Edm.Stream""/>
</EntityType>
<EntityType Name=""catalog"" BaseType=""microsoft.graph.document"">
<NavigationProperty Name=""reports"" Type = ""Collection(microsoft.graph.report)"" />
</EntityType>
<EntityType Name=""report"">
<Key>
<PropertyRef Name=""id"" />
</Key>
<Property Name=""id"" Type=""Edm.Int32"" Nullable=""false"" />
</EntityType>
<EntityContainer Name =""GraphService"">
<EntitySet Name=""Todos"" EntityType=""microsoft.graph.Todo"" />
<EntitySet Name=""todos"" EntityType=""microsoft.graph.todo"" />
<Singleton Name=""me"" Type=""microsoft.graph.user"" />
<Singleton Name=""catalog"" Type=""microsoft.graph.catalog"" />
</EntityContainer>
</Schema>
</edmx:DataServices>

View file

@ -4,9 +4,13 @@
// ------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Csdl;
using Microsoft.OpenApi.Extensions;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Tests;
using Xunit;
@ -184,5 +188,270 @@ schema:
}";
Assert.Equal(expected.ChangeLineBreaks(), json);
}
[Fact]
public void CreateOrderByAndSelectAndExpandParametersWorks()
{
// Arrange
IEdmModel model = GetEdmModel();
ODataContext context = new ODataContext(model, new OpenApiConvertSettings());
IEdmEntitySet entitySet = model.EntityContainer.FindEntitySet("Customers");
IEdmSingleton singleton = model.EntityContainer.FindSingleton("Catalog");
IEdmEntityType entityType = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Customer");
IEdmNavigationProperty navigationProperty = entityType.DeclaredNavigationProperties().First(c => c.Name == "Addresses");
// Act & Assert
// OrderBy
string orderByItemsText = @"""enum"": [
""ID"",
""ID desc""
],";
VerifyCreateOrderByParameter(entitySet, context, orderByItemsText);
VerifyCreateOrderByParameter(singleton, context);
VerifyCreateOrderByParameter(navigationProperty, context);
// Select
string selectItemsText = @"""enum"": [
""ID"",
""Addresses""
],";
VerifyCreateSelectParameter(entitySet, context, selectItemsText);
VerifyCreateSelectParameter(singleton, context);
VerifyCreateSelectParameter(navigationProperty, context);
// Expand
string expandItemsText = @"""enum"": [
""*"",
""Addresses""
],";
VerifyCreateExpandParameter(entitySet, context, expandItemsText);
string expandItemsDefaultText = @"""enum"": [
""*""
],";
VerifyCreateExpandParameter(singleton, context, expandItemsDefaultText);
VerifyCreateExpandParameter(navigationProperty, context, expandItemsDefaultText);
}
private void VerifyCreateOrderByParameter(IEdmElement edmElement, ODataContext context, string orderByItemsText = null)
{
// Arrange & Act
OpenApiParameter parameter;
switch (edmElement)
{
case IEdmEntitySet entitySet:
parameter = context.CreateOrderBy(entitySet);
break;
case IEdmSingleton singleton:
parameter = context.CreateOrderBy(singleton);
break;
case IEdmNavigationProperty navigationProperty:
parameter = context.CreateOrderBy(navigationProperty);
break;
default:
return;
}
string itemsText = orderByItemsText == null
? @"""type"": ""string"""
: $@"{orderByItemsText}
""type"": ""string""";
// Assert
Assert.NotNull(parameter);
string json = parameter.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0);
string expected = $@"{{
""name"": ""$orderby"",
""in"": ""query"",
""description"": ""Order items by property values"",
""style"": ""form"",
""explode"": false,
""schema"": {{
""uniqueItems"": true,
""type"": ""array"",
""items"": {{
{itemsText}
}}
}}
}}";
Assert.Equal(expected.ChangeLineBreaks(), json);
}
private void VerifyCreateSelectParameter(IEdmElement edmElement, ODataContext context, string selectItemsText = null)
{
// Arrange & Act
OpenApiParameter parameter;
switch (edmElement)
{
case IEdmEntitySet entitySet:
parameter = context.CreateSelect(entitySet);
break;
case IEdmSingleton singleton:
parameter = context.CreateSelect(singleton);
break;
case IEdmNavigationProperty navigationProperty:
parameter = context.CreateSelect(navigationProperty);
break;
default:
return;
}
string itemsText = selectItemsText == null
? @"""type"": ""string"""
: $@"{selectItemsText}
""type"": ""string""";
// Assert
Assert.NotNull(parameter);
string json = parameter.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0);
string expected = $@"{{
""name"": ""$select"",
""in"": ""query"",
""description"": ""Select properties to be returned"",
""style"": ""form"",
""explode"": false,
""schema"": {{
""uniqueItems"": true,
""type"": ""array"",
""items"": {{
{itemsText}
}}
}}
}}";
Assert.Equal(expected.ChangeLineBreaks(), json);
}
private void VerifyCreateExpandParameter(IEdmElement edmElement, ODataContext context, string expandItemsText)
{
// Arrange & Act
OpenApiParameter parameter;
switch (edmElement)
{
case IEdmEntitySet entitySet:
parameter = context.CreateExpand(entitySet);
break;
case IEdmSingleton singleton:
parameter = context.CreateExpand(singleton);
break;
case IEdmNavigationProperty navigationProperty:
parameter = context.CreateExpand(navigationProperty);
break;
default:
return;
}
// Assert
Assert.NotNull(parameter);
string json = parameter.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0);
string expected = $@"{{
""name"": ""$expand"",
""in"": ""query"",
""description"": ""Expand related entities"",
""style"": ""form"",
""explode"": false,
""schema"": {{
""uniqueItems"": true,
""type"": ""array"",
""items"": {{
{expandItemsText}
""type"": ""string""
}}
}}
}}";
Assert.Equal(expected.ChangeLineBreaks(), json);
}
[Fact]
public void CreateParametersWorks()
{
// Arrange
IEdmModel model = EdmModelHelper.GraphBetaModel;
ODataContext context = new ODataContext(model);
IEdmSingleton deviceMgmt = model.EntityContainer.FindSingleton("deviceManagement");
Assert.NotNull(deviceMgmt);
IEdmFunction function1 = model.SchemaElements.OfType<IEdmFunction>().First(f => f.Name == "getRoleScopeTagsByIds");
Assert.NotNull(function1);
IEdmFunction function2 = model.SchemaElements.OfType<IEdmFunction>().First(f => f.Name == "getRoleScopeTagsByResource");
Assert.NotNull(function2);
// Act
IList<OpenApiParameter> parameters1 = context.CreateParameters(function1);
IList<OpenApiParameter> parameters2 = context.CreateParameters(function2);
// Assert
Assert.NotNull(parameters1);
OpenApiParameter parameter1 = Assert.Single(parameters1);
Assert.NotNull(parameters2);
OpenApiParameter parameter2 = Assert.Single(parameters2);
string json1 = parameter1.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0);
string expectedPayload1 = $@"{{
""name"": ""ids"",
""in"": ""query"",
""description"": ""The URL-encoded JSON object"",
""required"": true,
""content"": {{
""application/json"": {{
""schema"": {{
""type"": ""array"",
""items"": {{
""type"": ""string""
}}
}}
}}
}}
}}";
string json2 = parameter2.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0);
string expectedPayload2 = $@"{{
""name"": ""resource"",
""in"": ""path"",
""required"": true,
""schema"": {{
""type"": ""string"",
""nullable"": true
}}
}}";
Assert.Equal(expectedPayload1.ChangeLineBreaks(), json1);
Assert.Equal(expectedPayload2.ChangeLineBreaks(), json2);
}
public static IEdmModel GetEdmModel()
{
const string modelText = @"<edmx:Edmx Version=""4.0"" xmlns:edmx=""http://docs.oasis-open.org/odata/ns/edmx"">
<edmx:DataServices>
<Schema Namespace=""NS"" xmlns=""http://docs.oasis-open.org/odata/ns/edm"">
<EntityType Name=""Customer"">
<Key>
<PropertyRef Name=""ID"" />
</Key>
<Property Name=""ID"" Type=""Edm.Int32"" Nullable=""false"" />
<NavigationProperty Name=""Addresses"" Type=""Collection(NS.Address)"" />
</EntityType>
<EntityContainer Name =""Default"">
<EntitySet Name=""Customers"" EntityType=""NS.Customer"" />
<Singleton Name=""Catalog"" Type=""NS.Catalog"" />
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>";
bool result = CsdlReader.TryParse(XElement.Parse(modelText).CreateReader(), out IEdmModel model, out _);
Assert.True(result);
return model;
}
}
}

View file

@ -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);
}

View file

@ -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);

View file

@ -104,7 +104,7 @@ namespace Microsoft.OpenApi.OData.Generator.Tests
ODataContext context = null;
// Act & Assert
Assert.Throws<ArgumentNullException>("context", () => context.CreateResponses(operationImport: null));
Assert.Throws<ArgumentNullException>("context", () => context.CreateResponses(operationImport: null, path: null));
}
[Fact]
@ -114,7 +114,19 @@ namespace Microsoft.OpenApi.OData.Generator.Tests
ODataContext context = new ODataContext(EdmCoreModel.Instance);
// Act & Assert
Assert.Throws<ArgumentNullException>("operationImport", () => context.CreateResponses(operationImport: null));
Assert.Throws<ArgumentNullException>("operationImport", () => context.CreateResponses(operationImport: null, path: null));
}
[Fact]
public void CreateResponseForoperationImportThrowArgumentNullPath()
{
// Arrange
ODataContext context = new ODataContext(EdmCoreModel.Instance);
EdmFunction function = new EdmFunction("NS", "MyFunction", EdmCoreModel.Instance.GetString(false));
EdmFunctionImport functionImport = new EdmFunctionImport(new EdmEntityContainer("NS", "Default"), "MyFunctionImport", function);
// Act & Assert
Assert.Throws<ArgumentNullException>("path", () => context.CreateResponses(operationImport: functionImport, path: null));
}
[Fact]
@ -124,7 +136,7 @@ namespace Microsoft.OpenApi.OData.Generator.Tests
ODataContext context = null;
// Act & Assert
Assert.Throws<ArgumentNullException>("context", () => context.CreateResponses(operation: null));
Assert.Throws<ArgumentNullException>("context", () => context.CreateResponses(operation: null, path: null));
}
[Fact]
@ -134,7 +146,19 @@ namespace Microsoft.OpenApi.OData.Generator.Tests
ODataContext context = new ODataContext(EdmCoreModel.Instance);
// Act & Assert
Assert.Throws<ArgumentNullException>("operation", () => context.CreateResponses(operation: null));
Assert.Throws<ArgumentNullException>("operation", () => context.CreateResponses(operation: null, path: null));
}
[Fact]
public void CreateResponseForOperationThrowArgumentNullPath()
{
// Arrange
ODataContext context = new ODataContext(EdmCoreModel.Instance);
EdmFunction function = new EdmFunction("NS", "MyFunction", EdmCoreModel.Instance.GetString(false));
EdmFunctionImport functionImport = new EdmFunctionImport(new EdmEntityContainer("NS", "Default"), "MyFunctionImport", function);
// Act & Assert
Assert.Throws<ArgumentNullException>("path", () => context.CreateResponses(operation: function, path: null));
}
[Theory]
@ -157,13 +181,15 @@ namespace Microsoft.OpenApi.OData.Generator.Tests
{
IEdmOperationImport operationImport = model.EntityContainer.OperationImports().First(o => o.Name == operationName);
Assert.NotNull(operationImport); // guard
responses = context.CreateResponses(operationImport);
ODataPath path = new ODataPath(new ODataOperationImportSegment(operationImport));
responses = context.CreateResponses(operationImport, path);
}
else
{
IEdmOperation operation = model.SchemaElements.OfType<IEdmOperation>().First(o => o.Name == operationName);
Assert.NotNull(operation); // guard
responses = context.CreateResponses(operation);
ODataPath path = new ODataPath(new ODataOperationSegment(operation));
responses = context.CreateResponses(operation, path);
}
// Assert
@ -195,7 +221,7 @@ namespace Microsoft.OpenApi.OData.Generator.Tests
Assert.NotNull(mediaType.Schema.AnyOf);
var anyOf = Assert.Single(mediaType.Schema.AnyOf);
Assert.Equal("Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person", anyOf.Reference.Id);
}
}
}
[Theory]
@ -214,13 +240,15 @@ namespace Microsoft.OpenApi.OData.Generator.Tests
{
IEdmOperationImport operationImport = model.EntityContainer.OperationImports().First(o => o.Name == actionName);
Assert.NotNull(operationImport); // guard
responses = context.CreateResponses(operationImport);
ODataPath path = new ODataPath(new ODataOperationImportSegment(operationImport));
responses = context.CreateResponses(operationImport, path);
}
else
{
IEdmOperation operation = model.SchemaElements.OfType<IEdmOperation>().First(o => o.Name == actionName);
Assert.NotNull(operation); // guard
responses = context.CreateResponses(operation);
ODataPath path = new ODataPath(new ODataOperationSegment(operation));
responses = context.CreateResponses(operation, path);
}
// Assert

View file

@ -1,9 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>Microsoft.OpenApi.OData.Reader.Tests</AssemblyName>
<RootNamespace>Microsoft.OpenApi.OData.Reader.Tests</RootNamespace>
<TargetFrameworks>net472;netcoreapp2.1</TargetFrameworks>
<TargetFrameworks>net472;net6.0</TargetFrameworks>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\..\tool\35MSSharedLib1024.snk</AssemblyOriginatorKeyFile>
<DelaySign>true</DelaySign>
@ -61,10 +61,10 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
<PackageReference Include="Microsoft.OpenApi" Version="1.2.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="Microsoft.OpenApi" Version="1.2.3" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View file

@ -35,6 +35,7 @@ namespace Microsoft.OpenApi.OData.Operation.Tests
// Assert
Assert.NotNull(operation);
Assert.Equal("Invoke actionImport ResetDataSource", operation.Summary);
Assert.Equal("Resets the data source to default values.", operation.Description);
Assert.NotNull(operation.Tags);
Assert.NotNull(operation.Parameters);

View file

@ -37,6 +37,7 @@ namespace Microsoft.OpenApi.OData.Operation.Tests
// Assert
Assert.NotNull(operation);
Assert.Equal("Invoke action ShareTrip", operation.Summary);
Assert.Equal("Details of the shared trip.", operation.Description);
Assert.NotNull(operation.Tags);
var tag = Assert.Single(operation.Tags);
Assert.Equal("People.Actions", tag.Name);

View file

@ -34,6 +34,7 @@ namespace Microsoft.OpenApi.OData.Operation.Tests
// Assert
Assert.NotNull(operation);
Assert.Equal("Invoke functionImport GetPersonWithMostFriends", operation.Summary);
Assert.Equal("The person with most friends.", operation.Description);
Assert.NotNull(operation.Tags);
var tag = Assert.Single(operation.Tags);
Assert.Equal("People", tag.Name);

View file

@ -74,6 +74,7 @@ namespace Microsoft.OpenApi.OData.Operation.Tests
// Assert
Assert.NotNull(operation);
Assert.Equal($"Invoke function {functionName}", operation.Summary);
Assert.Equal("Collection of contract attachments.", operation.Description);
Assert.NotNull(operation.Tags);
var tag = Assert.Single(operation.Tags);
Assert.Equal($"{entitySetName}.Functions", tag.Name);

View file

@ -37,6 +37,7 @@ namespace Microsoft.OpenApi.OData.Operation.Tests
// Assert
Assert.NotNull(delete);
Assert.Equal("Delete entity from Customers", delete.Summary);
Assert.Equal("A business customer.", delete.Description);
Assert.NotNull(delete.Tags);
var tag = Assert.Single(delete.Tags);
Assert.Equal("Customers.Customer", tag.Name);

View file

@ -38,6 +38,7 @@ namespace Microsoft.OpenApi.OData.Operation.Tests
// Assert
Assert.NotNull(get);
Assert.Equal("Get entity from Customers by key", get.Summary);
Assert.Equal("A business customer.", get.Description);
Assert.NotNull(get.Tags);
var tag = Assert.Single(get.Tags);
Assert.Equal("Customers.Customer", tag.Name);

View file

@ -37,6 +37,7 @@ namespace Microsoft.OpenApi.OData.Operation.Tests
// Assert
Assert.NotNull(patch);
Assert.Equal("Update entity in Customers", patch.Summary);
Assert.Equal("A business customer.", patch.Description);
Assert.NotNull(patch.Tags);
var tag = Assert.Single(patch.Tags);
Assert.Equal("Customers.Customer", tag.Name);

View file

@ -332,13 +332,16 @@ namespace Microsoft.OpenApi.OData.Operation.Tests
<edmx:DataServices>
<Schema Namespace=""NS"" xmlns=""http://docs.oasis-open.org/odata/ns/edm"">
<EntityType Name=""Customer"">
<Annotation Term=""Org.OData.Core.V1.Description"" String=""A business customer."" />
<Key>
<PropertyRef Name=""ID"" />
</Key>
<Property Name=""ID"" Type=""Edm.Int32"" Nullable=""false"" />
</EntityType>
<EntityContainer Name =""Default"">
<EntitySet Name=""Customers"" EntityType=""NS.Customer"" />
<EntitySet Name=""Customers"" EntityType=""NS.Customer"">
<Annotation Term=""Org.OData.Core.V1.Description"" String=""Collection of business customers."" />
</EntitySet>
</EntityContainer>
<Annotations Target=""NS.Default/Customers"">
{0}

View file

@ -59,6 +59,7 @@ namespace Microsoft.OpenApi.OData.Operation.Tests
// Assert
Assert.NotNull(post);
Assert.Equal("Add new entity to " + entitySet.Name, post.Summary);
Assert.Equal("Collection of business customers.", post.Description);
Assert.NotNull(post.Tags);
var tag = Assert.Single(post.Tags);
Assert.Equal("Customers.Customer", tag.Name);
@ -240,7 +241,9 @@ namespace Microsoft.OpenApi.OData.Operation.Tests
<Property Name=""ID"" Type=""Edm.Int32"" Nullable=""false"" />
</EntityType>
<EntityContainer Name =""Default"">
<EntitySet Name=""Customers"" EntityType=""NS.Customer"" />
<EntitySet Name=""Customers"" EntityType=""NS.Customer"">
<Annotation Term=""Org.OData.Core.V1.Description"" String=""Collection of business customers."" />
</EntitySet>
</EntityContainer>
<Annotations Target=""NS.Customer"">
{1}

View file

@ -31,7 +31,8 @@ namespace Microsoft.OpenApi.OData.Operation.Tests
<String>image/png</String>
<String>image/jpeg</String>
</Collection>
</Annotation>";
</Annotation>
<Annotation Term=""Org.OData.Core.V1.Description"" String=""The logo image."" />";
// Assert
VerifyMediaEntityGetOperation("", enableOperationId);
@ -54,13 +55,13 @@ namespace Microsoft.OpenApi.OData.Operation.Tests
Assert.NotNull(me);
IEdmEntityType todo = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Todo");
IEdmStructuralProperty sp = todo.DeclaredStructuralProperties().First(c => c.Name == "Logo");
IEdmStructuralProperty sp = todo.StructuralProperties().First(c => c.Name == "Logo");
ODataPath path = new ODataPath(new ODataNavigationSourceSegment(todos),
new ODataKeySegment(todos.EntityType()),
new ODataStreamPropertySegment(sp.Name));
IEdmEntityType user = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "user");
IEdmNavigationProperty navProperty = user.DeclaredNavigationProperties().First(c => c.Name == "photo");
IEdmNavigationProperty navProperty = user.NavigationProperties().First(c => c.Name == "photo");
ODataPath path2 = new ODataPath(new ODataNavigationSourceSegment(me),
new ODataNavigationPropertySegment(navProperty),
new ODataStreamContentSegment());
@ -74,6 +75,7 @@ namespace Microsoft.OpenApi.OData.Operation.Tests
Assert.NotNull(getOperation2);
Assert.Equal("Get media content for Todo from Todos", getOperation.Summary);
Assert.Equal("Get media content for the navigation property photo from me", getOperation2.Summary);
Assert.Equal("The user's profile photo.", getOperation2.Description);
Assert.NotNull(getOperation.Tags);
Assert.NotNull(getOperation2.Tags);
@ -94,6 +96,7 @@ namespace Microsoft.OpenApi.OData.Operation.Tests
Assert.Equal(2, getOperation.Responses[Constants.StatusCode200].Content.Keys.Count);
Assert.True(getOperation.Responses[Constants.StatusCode200].Content.ContainsKey("image/png"));
Assert.True(getOperation.Responses[Constants.StatusCode200].Content.ContainsKey("image/jpeg"));
Assert.Equal("The logo image.", getOperation.Description);
Assert.Equal(1, getOperation2.Responses[Constants.StatusCode200].Content.Keys.Count);
Assert.True(getOperation2.Responses[Constants.StatusCode200].Content.ContainsKey(Constants.ApplicationOctetStreamMediaType));
@ -132,7 +135,9 @@ namespace Microsoft.OpenApi.OData.Operation.Tests
<Property Name = ""Description"" Type = ""Edm.String"" />
</EntityType>
<EntityType Name=""user"" OpenType=""true"">
<NavigationProperty Name = ""photo"" Type = ""microsoft.graph.profilePhoto"" ContainsTarget = ""true"" />
<NavigationProperty Name = ""photo"" Type = ""microsoft.graph.profilePhoto"" ContainsTarget = ""true"" >
<Annotation Term=""Org.OData.Core.V1.Description"" String=""The user's profile photo."" />
</NavigationProperty>
</EntityType>
<EntityType Name=""profilePhoto"" HasStream=""true"">
<Property Name = ""height"" Type = ""Edm.Int32"" />

View file

@ -29,7 +29,8 @@ namespace Microsoft.OpenApi.OData.Operation.Tests
<String>image/png</String>
<String>image/jpeg</String>
</Collection>
</Annotation>";
</Annotation>
<Annotation Term=""Org.OData.Core.V1.Description"" String=""The logo image."" />";
// Assert
VerifyMediaEntityPutOperation("", enableOperationId);
@ -51,13 +52,13 @@ namespace Microsoft.OpenApi.OData.Operation.Tests
Assert.NotNull(todos);
IEdmEntityType todo = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Todo");
IEdmStructuralProperty sp = todo.DeclaredStructuralProperties().First(c => c.Name == "Logo");
IEdmStructuralProperty sp = todo.StructuralProperties().First(c => c.Name == "Logo");
ODataPath path = new ODataPath(new ODataNavigationSourceSegment(todos),
new ODataKeySegment(todos.EntityType()),
new ODataStreamPropertySegment(sp.Name));
IEdmEntityType user = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "user");
IEdmNavigationProperty navProperty = user.DeclaredNavigationProperties().First(c => c.Name == "photo");
IEdmNavigationProperty navProperty = user.NavigationProperties().First(c => c.Name == "photo");
ODataPath path2 = new ODataPath(new ODataNavigationSourceSegment(me),
new ODataNavigationPropertySegment(navProperty),
new ODataStreamContentSegment());
@ -71,6 +72,7 @@ namespace Microsoft.OpenApi.OData.Operation.Tests
Assert.NotNull(putOperation2);
Assert.Equal("Update media content for Todo in Todos", putOperation.Summary);
Assert.Equal("Update media content for the navigation property photo in me", putOperation2.Summary);
Assert.Equal("The user's profile photo.", putOperation2.Description);
Assert.NotNull(putOperation.Tags);
Assert.NotNull(putOperation2.Tags);
@ -91,6 +93,7 @@ namespace Microsoft.OpenApi.OData.Operation.Tests
Assert.Equal(2, putOperation.RequestBody.Content.Keys.Count);
Assert.True(putOperation.RequestBody.Content.ContainsKey("image/png"));
Assert.True(putOperation.RequestBody.Content.ContainsKey("image/jpeg"));
Assert.Equal("The logo image.", putOperation.Description);
Assert.Equal(1, putOperation2.RequestBody.Content.Keys.Count);
Assert.True(putOperation2.RequestBody.Content.ContainsKey(Constants.ApplicationOctetStreamMediaType));

View file

@ -40,6 +40,7 @@ namespace Microsoft.OpenApi.OData.Operation.Tests
// Assert
Assert.NotNull(operation);
Assert.Equal("Delete navigation property Trips for People", operation.Summary);
Assert.Equal("Collection of trips.", operation.Description);
Assert.NotNull(operation.Tags);
var tag = Assert.Single(operation.Tags);
Assert.Equal("People.Trip", tag.Name);

View file

@ -42,6 +42,7 @@ namespace Microsoft.OpenApi.OData.Operation.Tests
// Assert
Assert.NotNull(operation);
Assert.Equal("Get Trips from People", operation.Summary);
Assert.Equal("Collection of trips.", operation.Description);
Assert.NotNull(operation.Tags);
var tag = Assert.Single(operation.Tags);
Assert.Equal("People.Trip", tag.Name);

View file

@ -42,6 +42,7 @@ namespace Microsoft.OpenApi.OData.Operation.Tests
// Assert
Assert.NotNull(operation);
Assert.Equal("Update the navigation property BestFriend in People", operation.Summary);
Assert.Equal("The best friend.", operation.Description);
Assert.NotNull(operation.Tags);
var tag = Assert.Single(operation.Tags);
Assert.Equal("People.Person", tag.Name);

View file

@ -42,6 +42,7 @@ namespace Microsoft.OpenApi.OData.Operation.Tests
// Assert
Assert.NotNull(operation);
Assert.Equal("Create new navigation property to Trips for People", operation.Summary);
Assert.Equal("Collection of trips.", operation.Description);
Assert.NotNull(operation.Tags);
var tag = Assert.Single(operation.Tags);
Assert.Equal("People.Trip", tag.Name);

View file

@ -43,6 +43,7 @@ namespace Microsoft.OpenApi.OData.Operation.Tests
// Assert
Assert.NotNull(operation);
Assert.Equal("Delete ref of navigation property Trips for People", operation.Summary);
Assert.Equal("Collection of trips.", operation.Description);
Assert.NotNull(operation.Tags);
var tag = Assert.Single(operation.Tags);
Assert.Equal("People.Trip", tag.Name);

View file

@ -43,6 +43,7 @@ namespace Microsoft.OpenApi.OData.Operation.Tests
// Assert
Assert.NotNull(operation);
Assert.Equal("Get ref of Trips from People", operation.Summary);
Assert.Equal("Collection of trips.", operation.Description);
Assert.NotNull(operation.Tags);
var tag = Assert.Single(operation.Tags);
Assert.Equal("People.Trip", tag.Name);

View file

@ -43,6 +43,7 @@ namespace Microsoft.OpenApi.OData.Operation.Tests
// Assert
Assert.NotNull(operation);
Assert.Equal("Create new navigation property ref to Trips for People", operation.Summary);
Assert.Equal("Collection of trips.", operation.Description);
Assert.NotNull(operation.Tags);
var tag = Assert.Single(operation.Tags);
Assert.Equal("People.Trip", tag.Name);

View file

@ -43,6 +43,7 @@ namespace Microsoft.OpenApi.OData.Operation.Tests
// Assert
Assert.NotNull(operation);
Assert.Equal("Update the ref of navigation property BestFriend in People", operation.Summary);
Assert.Equal("The best friend.", operation.Description);
Assert.NotNull(operation.Tags);
var tag = Assert.Single(operation.Tags);
Assert.Equal("People.Person", tag.Name);

View file

@ -42,6 +42,7 @@ namespace Microsoft.OpenApi.OData.Operation.Tests
// Assert
Assert.NotNull(get);
Assert.Equal("Get Me", get.Summary);
Assert.Equal("My signed-in instance.", get.Description);
Assert.NotNull(get.Tags);
var tag = Assert.Single(get.Tags);
Assert.Equal("Me.Customer", tag.Name);
@ -249,7 +250,9 @@ namespace Microsoft.OpenApi.OData.Operation.Tests
<Property Name=""ID"" Type=""Edm.Int32"" Nullable=""false"" />
</EntityType>
<EntityContainer Name =""Default"">
<Singleton Name=""Me"" Type=""NS.Customer"" />
<Singleton Name=""Me"" Type=""NS.Customer"">
<Annotation Term=""Org.OData.Core.V1.Description"" String=""My signed-in instance."" />
</Singleton>
</EntityContainer>
<Annotations Target=""NS.Default/Me"">
{0}

View file

@ -57,6 +57,7 @@ namespace Microsoft.OpenApi.OData.PathItem.Tests
}
[Theory]
[InlineData(true, new OperationType[] { OperationType.Delete})]
[InlineData(true, new OperationType[] { OperationType.Get, OperationType.Post})]
[InlineData(false, new OperationType[] { OperationType.Get, OperationType.Put, OperationType.Delete })]
public void CreateNavigationPropertyRefPathItemReturnsCorrectPathItem(bool collectionNav, OperationType[] expected)
@ -73,10 +74,23 @@ namespace Microsoft.OpenApi.OData.PathItem.Tests
(collectionNav ? c.TargetMultiplicity() == EdmMultiplicity.Many : c.TargetMultiplicity() != EdmMultiplicity.Many));
Assert.NotNull(property);
ODataPath path = new ODataPath(new ODataNavigationSourceSegment(entitySet),
ODataPath path;
if (collectionNav && expected.Contains(OperationType.Delete))
{
// DELETE ~/entityset/{key}/collection-valued-Nav/{key}/$ref
path = new ODataPath(new ODataNavigationSourceSegment(entitySet),
new ODataKeySegment(entityType),
new ODataNavigationPropertySegment(property),
new ODataKeySegment(property.ToEntityType()),
ODataRefSegment.Instance);
}
else
{
path = new ODataPath(new ODataNavigationSourceSegment(entitySet),
new ODataKeySegment(entityType),
new ODataNavigationPropertySegment(property),
ODataRefSegment.Instance);
}
// Act
var pathItem = _pathItemHandler.CreatePathItem(context, path);

View file

@ -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": [
@ -599,6 +639,7 @@
"People.Person"
],
"summary": "Get entities from People",
"description": "People's description.",
"operationId": "People.Person.ListPerson",
"produces": [
"application/json"
@ -692,6 +733,7 @@
"People.Person"
],
"summary": "Add new entity to People",
"description": "People's description.",
"operationId": "People.Person.CreatePerson",
"consumes": [
"application/json"
@ -854,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": {
@ -1027,6 +1089,10 @@
"type": "string"
}
}
},
"ODataCountResponse": {
"format": "int32",
"type": "integer"
}
},
"parameters": {

View file

@ -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:
@ -394,6 +420,7 @@ paths:
tags:
- People.Person
summary: Get entities from People
description: People's description.
operationId: People.Person.ListPerson
produces:
- application/json
@ -454,6 +481,7 @@ paths:
tags:
- People.Person
summary: Add new entity to People
description: People's description.
operationId: People.Person.CreatePerson
consumes:
- application/json
@ -564,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
@ -677,6 +718,9 @@ definitions:
type: string
target:
type: string
ODataCountResponse:
format: int32
type: integer
parameters:
top:
in: query

View file

@ -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": [
@ -672,6 +714,7 @@
"People.Person"
],
"summary": "Get entities from People",
"description": "People's description.",
"operationId": "People.Person.ListPerson",
"parameters": [
{
@ -781,6 +824,7 @@
"People.Person"
],
"summary": "Add new entity to People",
"description": "People's description.",
"operationId": "People.Person.CreatePerson",
"requestBody": {
"description": "New entity",
@ -959,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": {
@ -1133,6 +1198,10 @@
"type": "string"
}
}
},
"ODataCountResponse": {
"type": "integer",
"format": "int32"
}
},
"responses": {

View file

@ -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:
@ -441,6 +467,7 @@ paths:
tags:
- People.Person
summary: Get entities from People
description: People's description.
operationId: People.Person.ListPerson
parameters:
- $ref: '#/components/parameters/top'
@ -513,6 +540,7 @@ paths:
tags:
- People.Person
summary: Add new entity to People
description: People's description.
operationId: People.Person.CreatePerson
requestBody:
description: New entity
@ -632,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:
@ -746,6 +787,9 @@ components:
type: string
target:
type: string
ODataCountResponse:
type: integer
format: int32
responses:
error:
description: error

View file

@ -19,7 +19,7 @@
<Property Name="size" Type="Edm.Int64" />
<Property Name="type" Type="Edm.String" />
<Property Name="date" Type="Edm.DateTimeOffset" />
<Property Name="comment" Type="Edm.String" />
<Property Name="comment" Type="Edm.String" />
</ComplexType>
<EntityType Name="AccountApiModel" BaseType="Microsoft.OData.Service.Sample.Contract.BaseEntityApiModel">
<Property Name="priority" Type="Edm.Int32" />
@ -31,6 +31,7 @@
</Schema>
<Schema Namespace="Default" xmlns="http://docs.oasis-open.org/odata/ns/edm">
<Function Name="Attachments" IsBound="true">
<Annotation Term="Org.OData.Core.V1.Description" String="Collection of contract attachments." />
<Parameter Name="bindingParameter" Type="Microsoft.OData.Service.Sample.Contract.BaseEntityApiModel" />
<ReturnType Type="Collection(Microsoft.OData.Service.Sample.Contract.AttachmentApiModel)" />
</Function>

View file

@ -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": {

View file

@ -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

View file

@ -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": {

View file

@ -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

View file

@ -2133,6 +2133,7 @@
<NavigationProperty Name="managedAppRegistrations" Type="Collection(microsoft.graph.managedAppRegistration)" />
<NavigationProperty Name="devices" Type="Collection(microsoft.graph.device)" ContainsTarget="true" />
<NavigationProperty Name="joinedTeams" Type="Collection(microsoft.graph.group)" ContainsTarget="true" />
<NavigationProperty Name="joinedGroups" Type="Collection(graph.group)" ContainsTarget="true" />
<NavigationProperty Name="deviceManagementTroubleshootingEvents" Type="Collection(microsoft.graph.deviceManagementTroubleshootingEvent)" ContainsTarget="true" />
</EntityType>
<ComplexType Name="assignedLicense">
@ -9355,6 +9356,16 @@
<Property Name="failureCategory" Type="microsoft.graph.deviceEnrollmentFailureReason" Nullable="false" />
<Property Name="failureReason" Type="Edm.String" Unicode="false" />
</EntityType>
<Function Name="getRoleScopeTagsByIds" IsBound="true">
<Parameter Name="bindingParameter" Type="graph.deviceManagement" />
<Parameter Name="ids" Type="Collection(Edm.String)" Unicode="false" />
<ReturnType Type="Collection(graph.roleScopeTag)" />
</Function>
<Function Name="getRoleScopeTagsByResource" IsBound="true">
<Parameter Name="bindingParameter" Type="graph.deviceManagement" />
<Parameter Name="resource" Type="Edm.String" Unicode="false" />
<ReturnType Type="Collection(graph.roleScopeTag)" />
</Function>
<Function Name="delta" IsBound="true">
<Parameter Name="bindingParameter" Type="Collection(microsoft.graph.user)" />
<ReturnType Type="Collection(microsoft.graph.user)" />
@ -13622,6 +13633,15 @@
<NavigationPropertyBinding Path="microsoft.graph.educationUser/classes" Target="classes" />
</Singleton>
</EntityContainer>
<Annotations Target="microsoft.graph.driveItem/workbook">
<Annotation Term="Org.OData.Capabilities.V1.NavigationRestrictions">
<Record>
<PropertyValue Property="Navigability">
<EnumMember>Org.OData.Capabilities.V1.NavigationType/None</EnumMember>
</PropertyValue>
</Record>
</Annotation>
</Annotations>
<Annotations Target="microsoft.graph.directoryObject">
<Annotation Term="Org.OData.Capabilities.V1.ExpandRestrictions">
<Record>
@ -13712,6 +13732,17 @@
<PropertyValue Property="Deletable" Bool="false" />
</Record>
</Annotation>
<Annotation Term="Org.OData.Capabilities.V1.NavigationRestrictions">
<Record>
<PropertyValue Property="RestrictedProperties">
<Collection>
<Record>
<PropertyValue Property="IndexableByKey" Bool="false" />
</Record>
</Collection>
</PropertyValue>
</Record>
</Annotation>
</Annotations>
<Annotations Target="microsoft.graph.user/mailFolders">
<Annotation Term="Org.OData.Capabilities.V1.ChangeTracking">

View file

@ -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": [
@ -773,6 +793,93 @@
"x-ms-docs-operation-type": "operation"
}
},
"/Documents({Id})/Revisions({Id1})/$ref": {
"delete": {
"tags": [
"Documents.RevisionDto"
],
"summary": "Delete ref of navigation property Revisions for Documents",
"operationId": "Documents.DeleteRefRevisions",
"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"
},
{
"in": "path",
"name": "Id1",
"description": "key: Id of RevisionDto",
"required": true,
"type": "integer",
"format": "int32",
"maximum": 2147483647,
"minimum": -2147483648,
"x-ms-docs-key-type": "RevisionDto"
},
{
"in": "header",
"name": "If-Match",
"description": "ETag",
"type": "string"
},
{
"in": "query",
"name": "@id",
"description": "Delete Uri",
"type": "string"
}
],
"responses": {
"204": {
"description": "Success"
},
"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": [
@ -929,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": [
@ -1375,6 +1502,93 @@
"x-ms-docs-operation-type": "operation"
}
},
"/Libraries({Id})/Documents({Id1})/$ref": {
"delete": {
"tags": [
"Libraries.DocumentDto"
],
"summary": "Delete ref of navigation property Documents for Libraries",
"operationId": "Libraries.DeleteRefDocuments",
"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"
},
{
"in": "path",
"name": "Id1",
"description": "key: Id of DocumentDto",
"required": true,
"type": "integer",
"format": "int32",
"maximum": 2147483647,
"minimum": -2147483648,
"x-ms-docs-key-type": "DocumentDto"
},
{
"in": "header",
"name": "If-Match",
"description": "ETag",
"type": "string"
},
{
"in": "query",
"name": "@id",
"description": "Delete Uri",
"type": "string"
}
],
"responses": {
"204": {
"description": "Success"
},
"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": [
@ -1517,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": [
@ -2076,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": [
@ -2560,6 +2814,93 @@
"x-ms-docs-operation-type": "operation"
}
},
"/Tasks({Id})/Revisions({Id1})/$ref": {
"delete": {
"tags": [
"Tasks.RevisionDto"
],
"summary": "Delete ref of navigation property Revisions for Tasks",
"operationId": "Tasks.DeleteRefRevisions",
"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"
},
{
"in": "path",
"name": "Id1",
"description": "key: Id of RevisionDto",
"required": true,
"type": "integer",
"format": "int32",
"maximum": 2147483647,
"minimum": -2147483648,
"x-ms-docs-key-type": "RevisionDto"
},
{
"in": "header",
"name": "If-Match",
"description": "ETag",
"type": "string"
},
{
"in": "query",
"name": "@id",
"description": "Delete Uri",
"type": "string"
}
],
"responses": {
"204": {
"description": "Success"
},
"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": [
@ -2715,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": {
@ -4475,6 +4836,10 @@
"type": "string"
}
}
},
"ODataCountResponse": {
"format": "int32",
"type": "integer"
}
},
"parameters": {

View file

@ -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:
@ -549,6 +562,68 @@ paths:
default:
$ref: '#/responses/error'
x-ms-docs-operation-type: operation
'/Documents({Id})/Revisions({Id1})/$ref':
delete:
tags:
- Documents.RevisionDto
summary: Delete ref of navigation property Revisions for Documents
operationId: Documents.DeleteRefRevisions
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
- in: path
name: Id1
description: 'key: Id of RevisionDto'
required: true
type: integer
format: int32
maximum: 2147483647
minimum: -2147483648
x-ms-docs-key-type: RevisionDto
- in: header
name: If-Match
description: ETag
type: string
- in: query
name: '@id'
description: Delete Uri
type: string
responses:
'204':
description: Success
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:
@ -662,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:
@ -985,6 +1073,68 @@ paths:
default:
$ref: '#/responses/error'
x-ms-docs-operation-type: operation
'/Libraries({Id})/Documents({Id1})/$ref':
delete:
tags:
- Libraries.DocumentDto
summary: Delete ref of navigation property Documents for Libraries
operationId: Libraries.DeleteRefDocuments
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
- in: path
name: Id1
description: 'key: Id of DocumentDto'
required: true
type: integer
format: int32
maximum: 2147483647
minimum: -2147483648
x-ms-docs-key-type: DocumentDto
- in: header
name: If-Match
description: ETag
type: string
- in: query
name: '@id'
description: Delete Uri
type: string
responses:
'204':
description: Success
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:
@ -1084,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:
@ -1503,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:
@ -1853,6 +2029,68 @@ paths:
default:
$ref: '#/responses/error'
x-ms-docs-operation-type: operation
'/Tasks({Id})/Revisions({Id1})/$ref':
delete:
tags:
- Tasks.RevisionDto
summary: Delete ref of navigation property Revisions for Tasks
operationId: Tasks.DeleteRefRevisions
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
- in: path
name: Id1
description: 'key: Id of RevisionDto'
required: true
type: integer
format: int32
maximum: 2147483647
minimum: -2147483648
x-ms-docs-key-type: RevisionDto
- in: header
name: If-Match
description: ETag
type: string
- in: query
name: '@id'
description: Delete Uri
type: string
responses:
'204':
description: Success
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:
@ -1966,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
@ -3322,6 +3573,9 @@ definitions:
type: string
target:
type: string
ODataCountResponse:
format: int32
type: integer
parameters:
top:
in: query

View file

@ -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": [
@ -867,6 +888,104 @@
"x-ms-docs-operation-type": "operation"
}
},
"/Documents({Id})/Revisions({Id1})/$ref": {
"delete": {
"tags": [
"Documents.RevisionDto"
],
"summary": "Delete ref of navigation property Revisions for Documents",
"operationId": "Documents.DeleteRefRevisions",
"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"
},
{
"name": "Id1",
"in": "path",
"description": "key: Id of RevisionDto",
"required": true,
"schema": {
"maximum": 2147483647,
"minimum": -2147483648,
"type": "integer",
"format": "int32"
},
"x-ms-docs-key-type": "RevisionDto"
},
{
"name": "If-Match",
"in": "header",
"description": "ETag",
"schema": {
"type": "string"
}
},
{
"name": "@id",
"in": "query",
"description": "Delete Uri",
"schema": {
"type": "string"
}
}
],
"responses": {
"204": {
"description": "Success"
},
"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": [
@ -1033,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": [
@ -1537,6 +1677,104 @@
"x-ms-docs-operation-type": "operation"
}
},
"/Libraries({Id})/Documents({Id1})/$ref": {
"delete": {
"tags": [
"Libraries.DocumentDto"
],
"summary": "Delete ref of navigation property Documents for Libraries",
"operationId": "Libraries.DeleteRefDocuments",
"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"
},
{
"name": "Id1",
"in": "path",
"description": "key: Id of DocumentDto",
"required": true,
"schema": {
"maximum": 2147483647,
"minimum": -2147483648,
"type": "integer",
"format": "int32"
},
"x-ms-docs-key-type": "DocumentDto"
},
{
"name": "If-Match",
"in": "header",
"description": "ETag",
"schema": {
"type": "string"
}
},
{
"name": "@id",
"in": "query",
"description": "Delete Uri",
"schema": {
"type": "string"
}
}
],
"responses": {
"204": {
"description": "Success"
},
"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": [
@ -1689,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": [
@ -2373,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": [
@ -2918,6 +3198,104 @@
"x-ms-docs-operation-type": "operation"
}
},
"/Tasks({Id})/Revisions({Id1})/$ref": {
"delete": {
"tags": [
"Tasks.RevisionDto"
],
"summary": "Delete ref of navigation property Revisions for Tasks",
"operationId": "Tasks.DeleteRefRevisions",
"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"
},
{
"name": "Id1",
"in": "path",
"description": "key: Id of RevisionDto",
"required": true,
"schema": {
"maximum": 2147483647,
"minimum": -2147483648,
"type": "integer",
"format": "int32"
},
"x-ms-docs-key-type": "RevisionDto"
},
{
"name": "If-Match",
"in": "header",
"description": "ETag",
"schema": {
"type": "string"
}
},
{
"name": "@id",
"in": "query",
"description": "Delete Uri",
"schema": {
"type": "string"
}
}
],
"responses": {
"204": {
"description": "Success"
},
"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": [
@ -3083,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": {
@ -5040,6 +5439,10 @@
"type": "string"
}
}
},
"ODataCountResponse": {
"type": "integer",
"format": "int32"
}
},
"responses": {

View file

@ -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:
@ -609,6 +622,73 @@ paths:
default:
$ref: '#/components/responses/error'
x-ms-docs-operation-type: operation
'/Documents({Id})/Revisions({Id1})/$ref':
delete:
tags:
- Documents.RevisionDto
summary: Delete ref of navigation property Revisions for Documents
operationId: Documents.DeleteRefRevisions
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
- name: Id1
in: path
description: 'key: Id of RevisionDto'
required: true
schema:
maximum: 2147483647
minimum: -2147483648
type: integer
format: int32
x-ms-docs-key-type: RevisionDto
- name: If-Match
in: header
description: ETag
schema:
type: string
- name: '@id'
in: query
description: Delete Uri
schema:
type: string
responses:
'204':
description: Success
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:
@ -727,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:
@ -1089,6 +1182,73 @@ paths:
default:
$ref: '#/components/responses/error'
x-ms-docs-operation-type: operation
'/Libraries({Id})/Documents({Id1})/$ref':
delete:
tags:
- Libraries.DocumentDto
summary: Delete ref of navigation property Documents for Libraries
operationId: Libraries.DeleteRefDocuments
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
- name: Id1
in: path
description: 'key: Id of DocumentDto'
required: true
schema:
maximum: 2147483647
minimum: -2147483648
type: integer
format: int32
x-ms-docs-key-type: DocumentDto
- name: If-Match
in: header
description: ETag
schema:
type: string
- name: '@id'
in: query
description: Delete Uri
schema:
type: string
responses:
'204':
description: Success
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:
@ -1193,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:
@ -1692,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:
@ -2082,6 +2268,73 @@ paths:
default:
$ref: '#/components/responses/error'
x-ms-docs-operation-type: operation
'/Tasks({Id})/Revisions({Id1})/$ref':
delete:
tags:
- Tasks.RevisionDto
summary: Delete ref of navigation property Revisions for Tasks
operationId: Tasks.DeleteRefRevisions
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
- name: Id1
in: path
description: 'key: Id of RevisionDto'
required: true
schema:
maximum: 2147483647
minimum: -2147483648
type: integer
format: int32
x-ms-docs-key-type: RevisionDto
- name: If-Match
in: header
description: ETag
schema:
type: string
- name: '@id'
in: query
description: Delete Uri
schema:
type: string
responses:
'204':
description: Success
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:
@ -2200,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:
@ -3702,6 +3968,9 @@ components:
type: string
target:
type: string
ODataCountResponse:
type: integer
format: int32
responses:
error:
description: error

View file

@ -18,8 +18,12 @@
<Property Name="FavoriteFeature" Type="Microsoft.OData.Service.Sample.TrippinInMemory.Models.Feature" Nullable="false" />
<Property Name="Features" Type="Collection(Microsoft.OData.Service.Sample.TrippinInMemory.Models.Feature)" Nullable="false" />
<NavigationProperty Name="Friends" Type="Collection(Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person)" />
<NavigationProperty Name="BestFriend" Type="Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person" />
<NavigationProperty Name="Trips" Type="Collection(Microsoft.OData.Service.Sample.TrippinInMemory.Models.Trip)" ContainsTarget="true"/>
<NavigationProperty Name="BestFriend" Type="Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person">
<Annotation Term="Org.OData.Core.V1.Description" String="The best friend." />
</NavigationProperty>
<NavigationProperty Name="Trips" Type="Collection(Microsoft.OData.Service.Sample.TrippinInMemory.Models.Trip)" ContainsTarget="true">
<Annotation Term="Org.OData.Core.V1.Description" String="Collection of trips." />
</NavigationProperty>
</EntityType>
<EntityType Name="Airline">
<Key>
@ -137,6 +141,7 @@
<ReturnType Type="Edm.Boolean" Nullable="false" />
</Function>
<Action Name="ShareTrip" IsBound="true">
<Annotation Term="Org.OData.Core.V1.Description" String="Details of the shared trip." />
<Parameter Name="personInstance" Type="Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person" />
<Parameter Name="userName" Type="Edm.String" Nullable="false" Unicode="false" />
<Parameter Name="tripId" Type="Edm.Int32" Nullable="false" />
@ -164,9 +169,13 @@
<EntitySet Name="Airports" EntityType="Microsoft.OData.Service.Sample.TrippinInMemory.Models.Airport" />
<EntitySet Name="NewComePeople" EntityType="Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person" />
<Singleton Name="Me" Type="Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person" />
<FunctionImport Name="GetPersonWithMostFriends" Function="Microsoft.OData.Service.Sample.TrippinInMemory.Models.GetPersonWithMostFriends" EntitySet="People" />
<FunctionImport Name="GetPersonWithMostFriends" Function="Microsoft.OData.Service.Sample.TrippinInMemory.Models.GetPersonWithMostFriends" EntitySet="People">
<Annotation Term="Org.OData.Core.V1.Description" String="The person with most friends." />
</FunctionImport>
<FunctionImport Name="GetNearestAirport" Function="Microsoft.OData.Service.Sample.TrippinInMemory.Models.GetNearestAirport" EntitySet="Airports" />
<ActionImport Name="ResetDataSource" Action="Microsoft.OData.Service.Sample.TrippinInMemory.Models.ResetDataSource" />
<ActionImport Name="ResetDataSource" Action="Microsoft.OData.Service.Sample.TrippinInMemory.Models.ResetDataSource">
<Annotation Term="Org.OData.Core.V1.Description" String="Resets the data source to default values." />
</ActionImport>
</EntityContainer>
</Schema>
</edmx:DataServices>

View file

@ -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:
@ -380,6 +406,7 @@ paths:
tags:
- People
summary: Invoke functionImport GetPersonWithMostFriends
description: The person with most friends.
operationId: FunctionImport.GetPersonWithMostFriends
produces:
- application/json
@ -465,6 +492,7 @@ paths:
tags:
- Me.Person
summary: Get BestFriend from Me
description: The best friend.
operationId: Me.GetBestFriend
produces:
- application/json
@ -514,6 +542,7 @@ paths:
tags:
- Me.Person
summary: Get ref of BestFriend from Me
description: The best friend.
operationId: Me.GetRefBestFriend
produces:
- application/json
@ -529,6 +558,7 @@ paths:
tags:
- Me.Person
summary: Update the ref of navigation property BestFriend in Me
description: The best friend.
operationId: Me.UpdateRefBestFriend
consumes:
- application/json
@ -551,6 +581,7 @@ paths:
tags:
- Me.Person
summary: Delete ref of navigation property BestFriend for Me
description: The best friend.
operationId: Me.DeleteRefBestFriend
parameters:
- in: header
@ -652,6 +683,46 @@ paths:
default:
$ref: '#/responses/error'
x-ms-docs-operation-type: operation
'/Me/Friends/{UserName}/$ref':
delete:
tags:
- Me.Person
summary: Delete ref of navigation property Friends for Me
operationId: Me.DeleteRefFriends
parameters:
- in: path
name: UserName
description: 'key: UserName of Person'
required: true
type: string
x-ms-docs-key-type: Person
- in: header
name: If-Match
description: ETag
type: string
- in: query
name: '@id'
description: Delete Uri
type: string
responses:
'204':
description: Success
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:
@ -769,9 +840,13 @@ paths:
'200':
description: Success
schema:
type: array
items:
$ref: '#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Trip'
title: Collection of Person
type: object
properties:
value:
type: array
items:
$ref: '#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Trip'
default:
$ref: '#/responses/error'
x-ms-docs-operation-type: function
@ -804,9 +879,13 @@ paths:
'200':
description: Success
schema:
type: array
items:
$ref: '#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person'
title: Collection of Person
type: object
properties:
value:
type: array
items:
$ref: '#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person'
default:
$ref: '#/responses/error'
x-ms-docs-operation-type: action
@ -815,6 +894,7 @@ paths:
tags:
- Me.Actions
summary: Invoke action ShareTrip
description: Details of the shared trip.
operationId: Me.ShareTrip
consumes:
- application/json
@ -857,8 +937,11 @@ paths:
'200':
description: Success
schema:
default: false
type: boolean
type: object
properties:
value:
default: false
type: boolean
default:
$ref: '#/responses/error'
x-ms-docs-operation-type: function
@ -867,6 +950,7 @@ paths:
tags:
- Me.Trip
summary: Get Trips from Me
description: Collection of trips.
operationId: Me.ListTrips
produces:
- application/json
@ -942,6 +1026,7 @@ paths:
tags:
- Me.Trip
summary: Create new navigation property to Trips for Me
description: Collection of trips.
operationId: Me.CreateTrips
consumes:
- application/json
@ -967,6 +1052,7 @@ paths:
tags:
- Me.Trip
summary: Get Trips from Me
description: Collection of trips.
operationId: Me.GetTrips
produces:
- application/json
@ -1017,6 +1103,7 @@ paths:
tags:
- Me.Trip
summary: Update the navigation property Trips in Me
description: Collection of trips.
operationId: Me.UpdateTrips
consumes:
- application/json
@ -1046,6 +1133,7 @@ paths:
tags:
- Me.Trip
summary: Delete navigation property Trips for Me
description: Collection of trips.
operationId: Me.DeleteTrips
parameters:
- in: path
@ -1089,9 +1177,13 @@ paths:
'200':
description: Success
schema:
type: array
items:
$ref: '#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person'
title: Collection of Trip
type: object
properties:
value:
type: array
items:
$ref: '#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person'
default:
$ref: '#/responses/error'
x-ms-docs-operation-type: function
@ -1169,6 +1261,68 @@ paths:
default:
$ref: '#/responses/error'
x-ms-docs-operation-type: operation
'/Me/Trips/{TripId}/PlanItems/{PlanItemId}/$ref':
delete:
tags:
- Me.Trips.PlanItem
summary: Delete ref of navigation property PlanItems for Me
operationId: Me.Trips.DeleteRefPlanItems
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
- in: path
name: PlanItemId
description: 'key: PlanItemId of PlanItem'
required: true
type: integer
format: int32
maximum: 2147483647
minimum: -2147483648
x-ms-docs-key-type: PlanItem
- in: header
name: If-Match
description: ETag
type: string
- in: query
name: '@id'
description: Delete Uri
type: string
responses:
'204':
description: Success
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:
@ -1258,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:
@ -1478,6 +1645,7 @@ paths:
tags:
- NewComePeople.Person
summary: Get BestFriend from NewComePeople
description: The best friend.
operationId: NewComePeople.GetBestFriend
produces:
- application/json
@ -1533,6 +1701,7 @@ paths:
tags:
- NewComePeople.Person
summary: Get ref of BestFriend from NewComePeople
description: The best friend.
operationId: NewComePeople.GetRefBestFriend
produces:
- application/json
@ -1555,6 +1724,7 @@ paths:
tags:
- NewComePeople.Person
summary: Update the ref of navigation property BestFriend in NewComePeople
description: The best friend.
operationId: NewComePeople.UpdateRefBestFriend
consumes:
- application/json
@ -1583,6 +1753,7 @@ paths:
tags:
- NewComePeople.Person
summary: Delete ref of navigation property BestFriend for NewComePeople
description: The best friend.
operationId: NewComePeople.DeleteRefBestFriend
parameters:
- in: path
@ -1696,6 +1867,59 @@ paths:
default:
$ref: '#/responses/error'
x-ms-docs-operation-type: operation
'/NewComePeople/{UserName}/Friends/{UserName1}/$ref':
delete:
tags:
- NewComePeople.Person
summary: Delete ref of navigation property Friends for NewComePeople
operationId: NewComePeople.DeleteRefFriends
parameters:
- in: path
name: UserName
description: 'key: UserName of Person'
required: true
type: string
x-ms-docs-key-type: Person
- in: path
name: UserName1
description: 'key: UserName of Person'
required: true
type: string
x-ms-docs-key-type: Person
- in: header
name: If-Match
description: ETag
type: string
- in: query
name: '@id'
description: Delete Uri
type: string
responses:
'204':
description: Success
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:
@ -1838,9 +2062,13 @@ paths:
'200':
description: Success
schema:
type: array
items:
$ref: '#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Trip'
title: Collection of Person
type: object
properties:
value:
type: array
items:
$ref: '#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Trip'
default:
$ref: '#/responses/error'
x-ms-docs-operation-type: function
@ -1879,9 +2107,13 @@ paths:
'200':
description: Success
schema:
type: array
items:
$ref: '#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person'
title: Collection of Person
type: object
properties:
value:
type: array
items:
$ref: '#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person'
default:
$ref: '#/responses/error'
x-ms-docs-operation-type: action
@ -1890,6 +2122,7 @@ paths:
tags:
- NewComePeople.Actions
summary: Invoke action ShareTrip
description: Details of the shared trip.
operationId: NewComePeople.Person.ShareTrip
consumes:
- application/json
@ -1944,8 +2177,11 @@ paths:
'200':
description: Success
schema:
default: false
type: boolean
type: object
properties:
value:
default: false
type: boolean
default:
$ref: '#/responses/error'
x-ms-docs-operation-type: function
@ -1954,6 +2190,7 @@ paths:
tags:
- NewComePeople.Trip
summary: Get Trips from NewComePeople
description: Collection of trips.
operationId: NewComePeople.ListTrips
produces:
- application/json
@ -2035,6 +2272,7 @@ paths:
tags:
- NewComePeople.Trip
summary: Create new navigation property to Trips for NewComePeople
description: Collection of trips.
operationId: NewComePeople.CreateTrips
consumes:
- application/json
@ -2066,6 +2304,7 @@ paths:
tags:
- NewComePeople.Trip
summary: Get Trips from NewComePeople
description: Collection of trips.
operationId: NewComePeople.GetTrips
produces:
- application/json
@ -2122,6 +2361,7 @@ paths:
tags:
- NewComePeople.Trip
summary: Update the navigation property Trips in NewComePeople
description: Collection of trips.
operationId: NewComePeople.UpdateTrips
consumes:
- application/json
@ -2157,6 +2397,7 @@ paths:
tags:
- NewComePeople.Trip
summary: Delete navigation property Trips for NewComePeople
description: Collection of trips.
operationId: NewComePeople.DeleteTrips
parameters:
- in: path
@ -2212,9 +2453,13 @@ paths:
'200':
description: Success
schema:
type: array
items:
$ref: '#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person'
title: Collection of Trip
type: object
properties:
value:
type: array
items:
$ref: '#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person'
default:
$ref: '#/responses/error'
x-ms-docs-operation-type: function
@ -2298,6 +2543,80 @@ paths:
default:
$ref: '#/responses/error'
x-ms-docs-operation-type: operation
'/NewComePeople/{UserName}/Trips/{TripId}/PlanItems/{PlanItemId}/$ref':
delete:
tags:
- NewComePeople.Trips.PlanItem
summary: Delete ref of navigation property PlanItems for NewComePeople
operationId: NewComePeople.Trips.DeleteRefPlanItems
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
- in: path
name: PlanItemId
description: 'key: PlanItemId of PlanItem'
required: true
type: integer
format: int32
maximum: 2147483647
minimum: -2147483648
x-ms-docs-key-type: PlanItem
- in: header
name: If-Match
description: ETag
type: string
- in: query
name: '@id'
description: Delete Uri
type: string
responses:
'204':
description: Success
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:
@ -2399,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:
@ -2619,6 +2971,7 @@ paths:
tags:
- People.Person
summary: Get BestFriend from People
description: The best friend.
operationId: People.GetBestFriend
produces:
- application/json
@ -2674,6 +3027,7 @@ paths:
tags:
- People.Person
summary: Get ref of BestFriend from People
description: The best friend.
operationId: People.GetRefBestFriend
produces:
- application/json
@ -2696,6 +3050,7 @@ paths:
tags:
- People.Person
summary: Update the ref of navigation property BestFriend in People
description: The best friend.
operationId: People.UpdateRefBestFriend
consumes:
- application/json
@ -2724,6 +3079,7 @@ paths:
tags:
- People.Person
summary: Delete ref of navigation property BestFriend for People
description: The best friend.
operationId: People.DeleteRefBestFriend
parameters:
- in: path
@ -2837,6 +3193,59 @@ paths:
default:
$ref: '#/responses/error'
x-ms-docs-operation-type: operation
'/People/{UserName}/Friends/{UserName1}/$ref':
delete:
tags:
- People.Person
summary: Delete ref of navigation property Friends for People
operationId: People.DeleteRefFriends
parameters:
- in: path
name: UserName
description: 'key: UserName of Person'
required: true
type: string
x-ms-docs-key-type: Person
- in: path
name: UserName1
description: 'key: UserName of Person'
required: true
type: string
x-ms-docs-key-type: Person
- in: header
name: If-Match
description: ETag
type: string
- in: query
name: '@id'
description: Delete Uri
type: string
responses:
'204':
description: Success
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:
@ -2979,9 +3388,13 @@ paths:
'200':
description: Success
schema:
type: array
items:
$ref: '#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Trip'
title: Collection of Person
type: object
properties:
value:
type: array
items:
$ref: '#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Trip'
default:
$ref: '#/responses/error'
x-ms-docs-operation-type: function
@ -3020,9 +3433,13 @@ paths:
'200':
description: Success
schema:
type: array
items:
$ref: '#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person'
title: Collection of Person
type: object
properties:
value:
type: array
items:
$ref: '#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person'
default:
$ref: '#/responses/error'
x-ms-docs-operation-type: action
@ -3031,6 +3448,7 @@ paths:
tags:
- People.Actions
summary: Invoke action ShareTrip
description: Details of the shared trip.
operationId: People.Person.ShareTrip
consumes:
- application/json
@ -3085,8 +3503,11 @@ paths:
'200':
description: Success
schema:
default: false
type: boolean
type: object
properties:
value:
default: false
type: boolean
default:
$ref: '#/responses/error'
x-ms-docs-operation-type: function
@ -3095,6 +3516,7 @@ paths:
tags:
- People.Trip
summary: Get Trips from People
description: Collection of trips.
operationId: People.ListTrips
produces:
- application/json
@ -3176,6 +3598,7 @@ paths:
tags:
- People.Trip
summary: Create new navigation property to Trips for People
description: Collection of trips.
operationId: People.CreateTrips
consumes:
- application/json
@ -3207,6 +3630,7 @@ paths:
tags:
- People.Trip
summary: Get Trips from People
description: Collection of trips.
operationId: People.GetTrips
produces:
- application/json
@ -3263,6 +3687,7 @@ paths:
tags:
- People.Trip
summary: Update the navigation property Trips in People
description: Collection of trips.
operationId: People.UpdateTrips
consumes:
- application/json
@ -3298,6 +3723,7 @@ paths:
tags:
- People.Trip
summary: Delete navigation property Trips for People
description: Collection of trips.
operationId: People.DeleteTrips
parameters:
- in: path
@ -3353,9 +3779,13 @@ paths:
'200':
description: Success
schema:
type: array
items:
$ref: '#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person'
title: Collection of Trip
type: object
properties:
value:
type: array
items:
$ref: '#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person'
default:
$ref: '#/responses/error'
x-ms-docs-operation-type: function
@ -3439,6 +3869,80 @@ paths:
default:
$ref: '#/responses/error'
x-ms-docs-operation-type: operation
'/People/{UserName}/Trips/{TripId}/PlanItems/{PlanItemId}/$ref':
delete:
tags:
- People.Trips.PlanItem
summary: Delete ref of navigation property PlanItems for People
operationId: People.Trips.DeleteRefPlanItems
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
- in: path
name: PlanItemId
description: 'key: PlanItemId of PlanItem'
required: true
type: integer
format: int32
maximum: 2147483647
minimum: -2147483648
x-ms-docs-key-type: PlanItem
- in: header
name: If-Match
description: ETag
type: string
- in: query
name: '@id'
description: Delete Uri
type: string
responses:
'204':
description: Success
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:
@ -3540,11 +4044,45 @@ 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:
- ResetDataSource
summary: Invoke actionImport ResetDataSource
description: Resets the data source to default values.
operationId: ActionImport.ResetDataSource
responses:
'204':
@ -3592,6 +4130,7 @@ definitions:
BestFriend:
$ref: '#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person'
Trips:
description: Collection of trips.
type: array
items:
$ref: '#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Trip'
@ -3944,6 +4483,9 @@ definitions:
type: string
target:
type: string
ODataCountResponse:
format: int32
type: integer
parameters:
top:
in: query

View file

@ -74,7 +74,7 @@ namespace UpdateDocs
output = oas20 + "/" + fileName + ".json";
File.WriteAllText(output, document.SerializeAsJson(OpenApiSpecVersion.OpenApi2_0));
Console.WriteLine("Output [ " + fileName + " ] Succeessful!");
Console.WriteLine("Output [ " + fileName + " ] Successful!");
}
Console.WriteLine("\n==> All Done!");

View file

@ -1,64 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{6D5453C2-E35F-4CC6-B774-4C676F5F33D1}</ProjectGuid>
<TargetFramework>net6.0</TargetFramework>
<OutputType>Exe</OutputType>
<RootNamespace>UpdateDocs</RootNamespace>
<AssemblyName>UpdateDocs</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\net461\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.OData.Edm, Version=7.6.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>packages\Microsoft.OData.Edm.7.6.1\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll</HintPath>
</Reference>
<Reference Include="Microsoft.OpenApi, Version=1.2.2.0, Culture=neutral, PublicKeyToken=3f5743946376f042, processorArchitecture=MSIL">
<HintPath>packages\Microsoft.OpenApi.1.2.2\lib\net46\Microsoft.OpenApi.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<ProjectReference Include="..\..\src\Microsoft.OpenApi.OData.Reader\Microsoft.OpenApi.OData.Reader.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.OpenApi.OData.Reader\Microsoft.OpenApi.OData.Reader.csproj">
<Project>{ff3acd93-19e0-486c-9c0f-fa1c2e7fc8c2}</Project>
<Name>Microsoft.OpenApi.OData.Reader</Name>
</ProjectReference>
<PackageReference Include="Microsoft.OData.Edm" Version="7.9.4" />
<PackageReference Include="Microsoft.OpenApi" Version="1.2.3" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View file

@ -7,8 +7,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UpdateDocs", "UpdateDocs.cs
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.OpenApi.OData.Reader", "..\..\src\Microsoft.OpenApi.OData.Reader\Microsoft.OpenApi.OData.Reader.csproj", "{B7A15A06-0B61-4557-9BD4-0E4F32DE119D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UpdateDocsCore", "..\UpdateDocsCore\UpdateDocsCore.csproj", "{810B988E-24A2-4B6F-8FD3-B5B9FB25A44B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -23,10 +21,6 @@ Global
{B7A15A06-0B61-4557-9BD4-0E4F32DE119D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B7A15A06-0B61-4557-9BD4-0E4F32DE119D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B7A15A06-0B61-4557-9BD4-0E4F32DE119D}.Release|Any CPU.Build.0 = Release|Any CPU
{810B988E-24A2-4B6F-8FD3-B5B9FB25A44B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{810B988E-24A2-4B6F-8FD3-B5B9FB25A44B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{810B988E-24A2-4B6F-8FD3-B5B9FB25A44B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{810B988E-24A2-4B6F-8FD3-B5B9FB25A44B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View file

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.OData.Edm" version="7.6.1" targetFramework="net461" />
<package id="Microsoft.OpenApi" version="1.2.2" targetFramework="net461" />
</packages>

View file

@ -1,98 +0,0 @@
//---------------------------------------------------------------------
// <copyright file="Program.cs" company="Microsoft">
// Copyright (C) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
// </copyright>
//---------------------------------------------------------------------
using System;
using System.IO;
using System.Xml.Linq;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Csdl;
using Microsoft.OpenApi;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData;
using Microsoft.OpenApi.Extensions;
namespace UpdateDocs
{
class Program
{
static int Main(string[] args)
{
// we assume the path are existed for simplicity.
string path = Directory.GetCurrentDirectory();
string csdl = path + "/../../../../../docs/csdl";
string oas20 = path + "/../../../../../docs/oas_2_0";
string oas30 = path + "/../../../../../docs/oas3_0_0";
foreach (var filePath in Directory.GetFiles(csdl, "*.xml"))
{
Console.WriteLine(filePath);
IEdmModel model = LoadEdmModel(filePath);
if (model == null)
{
continue;
}
FileInfo fileInfo = new FileInfo(filePath);
string fileName = fileInfo.Name.Substring(0, fileInfo.Name.Length - 4);
OpenApiConvertSettings settings = new OpenApiConvertSettings();
if (fileName.Contains("graph.beta"))
{
settings.PrefixEntityTypeNameBeforeKey = true;
settings.ServiceRoot = new Uri("https://graph.microsoft.com/beta");
}
else if (fileName.Contains("graph1.0"))
{
settings.PrefixEntityTypeNameBeforeKey = true;
settings.ServiceRoot = new Uri("https://graph.microsoft.com/v1.0");
}
OpenApiDocument document = model.ConvertToOpenApi(settings);
string output;/* = oas20 + "/" + fileName + ".yaml";
File.WriteAllText(output, document.SerializeAsYaml(OpenApiSpecVersion.OpenApi2_0));
output = oas20 + "/" + fileName + ".json";
File.WriteAllText(output, document.SerializeAsJson(OpenApiSpecVersion.OpenApi2_0));
output = oas30 + "/" + fileName + ".yaml";
File.WriteAllText(output, document.SerializeAsYaml(OpenApiSpecVersion.OpenApi3_0));
output = oas30 + "/" + fileName + ".json";
File.WriteAllText(output, document.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0));
*/
settings.EnableKeyAsSegment = true;
settings.EnableUnqualifiedCall = true;
output = oas30 + "/" + fileName + ".json";
document = model.ConvertToOpenApi(settings);
File.WriteAllText(output, document.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0));
output = oas20 + "/" + fileName + ".json";
File.WriteAllText(output, document.SerializeAsJson(OpenApiSpecVersion.OpenApi2_0));
Console.WriteLine("Output [ " + fileName + " ] Succeessful!");
}
Console.WriteLine("\n==> All Done!");
return 0;
}
public static IEdmModel LoadEdmModel(string file)
{
try
{
string csdl = File.ReadAllText(file);
return CsdlReader.Parse(XElement.Parse(csdl).CreateReader());
}
catch
{
Console.WriteLine("Cannot load EDM from file: " + file);
return null;
}
}
}
}

View file

@ -1,12 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.OpenApi.OData.Reader\Microsoft.OpenApi.OData.Reader.csproj" />
</ItemGroup>
</Project>

Some files were not shown because too many files have changed in this diff Show more