Skip to content

Commit e8b5b0a

Browse files
Use Computed annotation in the CSDL to declare property as ReadOnly (#273)
* Use Computed annotation in the CSDL to set property as readonly * Add tests * Add release notes * Remove unnecessary assignment of read-only attribute to property
1 parent cd43e27 commit e8b5b0a

File tree

10 files changed

+64
-14
lines changed

10 files changed

+64
-14
lines changed

src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSchemaGenerator.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
using System.Linq;
1717
using Microsoft.OpenApi.Interfaces;
1818
using Microsoft.OpenApi.OData.OpenApiExtensions;
19+
using Microsoft.OpenApi.OData.Vocabulary.Core;
1920

2021
namespace Microsoft.OpenApi.OData.Generator
2122
{
@@ -363,6 +364,9 @@ public static OpenApiSchema CreatePropertySchema(this ODataContext context, IEdm
363364
// whose value is the value of the unqualified annotation Core.Description of the property.
364365
schema.Description = context.Model.GetDescriptionAnnotation(property);
365366

367+
// Set property with Computed Annotation in CSDL to readonly
368+
schema.ReadOnly = context.Model.GetBoolean(property, CoreConstants.Computed) ?? false;
369+
366370
return schema;
367371
}
368372

src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
<RepositoryUrl>https://github.com/Microsoft/OpenAPI.NET.OData</RepositoryUrl>
2323
<PackageReleaseNotes>
2424
- Fixes response schemas of actions and functions that return a collection to contain the nextLink property #231
25+
- Use Computed annotation in the CSDL to declare property as ReadOnly #254
2526
- Fixes duplicated actions/functions request body/response schemas #241
2627
</PackageReleaseNotes>
2728
<AssemblyName>Microsoft.OpenApi.OData.Reader</AssemblyName>

src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetPostOperationHandler.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using Microsoft.OpenApi.OData.Edm;
1212
using Microsoft.OpenApi.OData.Generator;
1313
using Microsoft.OpenApi.OData.Vocabulary.Capabilities;
14+
using Microsoft.OpenApi.OData.Vocabulary.Core;
1415

1516
namespace Microsoft.OpenApi.OData.Operation
1617
{
@@ -124,7 +125,7 @@ private IDictionary<string, OpenApiMediaType> GetContentDescription()
124125
if (EntitySet.EntityType().HasStream)
125126
{
126127
IEnumerable<string> mediaTypes = Context.Model.GetCollection(EntitySet.EntityType(),
127-
CapabilitiesConstants.AcceptableMediaTypes);
128+
CoreConstants.AcceptableMediaTypes);
128129

129130
if (mediaTypes != null)
130131
{

src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityOperationalHandler.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
using Microsoft.OpenApi.Models;
1010
using Microsoft.OpenApi.OData.Common;
1111
using Microsoft.OpenApi.OData.Edm;
12-
using Microsoft.OpenApi.OData.Vocabulary.Capabilities;
1312
using Microsoft.OpenApi.OData.Vocabulary.Core;
1413
using System.Collections.Generic;
1514
using System.Linq;
@@ -151,7 +150,7 @@ protected IDictionary<string, OpenApiMediaType> GetContentDescription()
151150
if (annotatableElement != null)
152151
{
153152
mediaTypes = Context.Model.GetCollection(annotatableElement,
154-
CapabilitiesConstants.AcceptableMediaTypes);
153+
CoreConstants.AcceptableMediaTypes);
155154
}
156155

157156
if (mediaTypes != null)

src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/CapabilitiesConstants.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,5 @@ internal class CapabilitiesConstants
9494
/// Org.OData.Capabilities.V1.KeyAsSegmentSupported
9595
/// </summary>
9696
public const string KeyAsSegmentSupported = "Org.OData.Capabilities.V1.KeyAsSegmentSupported";
97-
98-
/// <summary>
99-
/// Org.OData.Core.V1.AcceptableMediaTypes
100-
/// </summary>
101-
public const string AcceptableMediaTypes = "Org.OData.Core.V1.AcceptableMediaTypes";
10297
}
10398
}

src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/CoreConstants.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,16 @@ internal static class CoreConstants
2020
/// </summary>
2121
public const string Revisions = "Org.OData.Core.V1.Revisions";
2222

23+
/// <summary>
24+
/// Org.OData.Core.V1.AcceptableMediaTypes
25+
/// </summary>
26+
public const string AcceptableMediaTypes = "Org.OData.Core.V1.AcceptableMediaTypes";
27+
28+
/// <summary>
29+
/// Org.OData.Core.V1.Computed
30+
/// </summary>
31+
public const string Computed = "Org.OData.Core.V1.Computed";
32+
2333
/// <summary>
2434
/// External docs description.
2535
/// </summary>

test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiSchemaGeneratorTests.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -803,6 +803,46 @@ public void CreatePropertySchemaForNullableEnumPropertyReturnSchema(OpenApiSpecV
803803
}".ChangeLineBreaks(), json);
804804
}
805805
}
806+
807+
[Theory]
808+
[InlineData(OpenApiSpecVersion.OpenApi3_0)]
809+
[InlineData(OpenApiSpecVersion.OpenApi2_0)]
810+
public void CreatePropertySchemaWithComputedAnnotationReturnsCorrectSchema(OpenApiSpecVersion specVersion)
811+
{
812+
// Arrange
813+
IEdmModel model = EdmModelHelper.GraphBetaModel;
814+
ODataContext context = new(model);
815+
816+
context.Settings.OpenApiSpecVersion = specVersion;
817+
818+
IEdmEntityType entityType = model.SchemaElements.OfType<IEdmEntityType>().First(e => e.Name == "bookingAppointment");
819+
IEdmProperty property = entityType.Properties().FirstOrDefault(x => x.Name == "duration");
820+
821+
// Act
822+
var schema = context.CreatePropertySchema(property);
823+
Assert.NotNull(schema);
824+
string json = schema.SerializeAsJson(specVersion);
825+
826+
// Assert
827+
if (specVersion == OpenApiSpecVersion.OpenApi2_0)
828+
{
829+
Assert.Equal(@"{
830+
""format"": ""duration"",
831+
""pattern"": ""^-?P([0-9]+D)?(T([0-9]+H)?([0-9]+M)?([0-9]+([.][0-9]+)?S)?)?$"",
832+
""type"": ""string"",
833+
""readOnly"": true
834+
}".ChangeLineBreaks(), json);
835+
}
836+
else
837+
{
838+
Assert.Equal(@"{
839+
""pattern"": ""^-?P([0-9]+D)?(T([0-9]+H)?([0-9]+M)?([0-9]+([.][0-9]+)?S)?)?$"",
840+
""type"": ""string"",
841+
""format"": ""duration"",
842+
""readOnly"": true
843+
}".ChangeLineBreaks(), json);
844+
}
845+
}
806846
#endregion
807847

808848
#region BaseTypeToDerivedTypesSchema

test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EntitySetPostOperationHandlerTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
using Microsoft.OpenApi.OData.Common;
1111
using Microsoft.OpenApi.OData.Edm;
1212
using Microsoft.OpenApi.OData.Tests;
13-
using Microsoft.OpenApi.OData.Vocabulary.Capabilities;
13+
using Microsoft.OpenApi.OData.Vocabulary.Core;
1414
using System.Xml.Linq;
1515
using Xunit;
1616

@@ -28,7 +28,7 @@ public class EntitySetPostOperationHandlerTests
2828
public void CreateEntitySetPostOperationReturnsCorrectOperation(bool enableOperationId, bool hasStream, bool useHTTPStatusCodeClass2XX)
2929
{
3030
// Arrange
31-
string qualifiedName = CapabilitiesConstants.AcceptableMediaTypes;
31+
string qualifiedName = CoreConstants.AcceptableMediaTypes;
3232
string annotation = $@"
3333
<Annotation Term=""{qualifiedName}"" >
3434
<Collection>

test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/MediaEntityGetOperationHandlerTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
using Microsoft.OData.Edm.Csdl;
88
using Microsoft.OpenApi.OData.Common;
99
using Microsoft.OpenApi.OData.Edm;
10-
using Microsoft.OpenApi.OData.Vocabulary.Capabilities;
10+
using Microsoft.OpenApi.OData.Vocabulary.Core;
1111
using System.Linq;
1212
using System.Xml.Linq;
1313
using Xunit;
@@ -26,7 +26,7 @@ public class MediaEntityGetOperationHandlerTests
2626
public void CreateMediaEntityGetOperationReturnsCorrectOperation(bool enableOperationId, bool useHTTPStatusCodeClass2XX)
2727
{
2828
// Arrange
29-
string qualifiedName = CapabilitiesConstants.AcceptableMediaTypes;
29+
string qualifiedName = CoreConstants.AcceptableMediaTypes;
3030
string annotation = $@"
3131
<Annotation Term=""{qualifiedName}"" >
3232
<Collection>

test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/MediaEntityPutOperationHandlerTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
using Microsoft.OData.Edm;
77
using Microsoft.OpenApi.OData.Common;
88
using Microsoft.OpenApi.OData.Edm;
9-
using Microsoft.OpenApi.OData.Vocabulary.Capabilities;
9+
using Microsoft.OpenApi.OData.Vocabulary.Core;
1010
using System.Linq;
1111
using Xunit;
1212

@@ -22,7 +22,7 @@ public class MediaEntityPutOperationHandlerTests
2222
public void CreateMediaEntityPutOperationReturnsCorrectOperation(bool enableOperationId)
2323
{
2424
// Arrange
25-
string qualifiedName = CapabilitiesConstants.AcceptableMediaTypes;
25+
string qualifiedName = CoreConstants.AcceptableMediaTypes;
2626
string annotation = $@"
2727
<Annotation Term=""{qualifiedName}"" >
2828
<Collection>

0 commit comments

Comments
 (0)