Skip to content

Commit 92588da

Browse files
committed
support put operations on complex properties
1 parent 2dfd772 commit 92588da

File tree

8 files changed

+298
-110
lines changed

8 files changed

+298
-110
lines changed

docs/csdl/TripService.xml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,15 @@
3535
<Property Name="Name" Type="Edm.String" />
3636
<Property Name="IcaoCode" Type="Edm.String" Nullable="false" />
3737
<Property Name="IataCode" Type="Edm.String" />
38-
<Property Name="Location" Type="Microsoft.OData.Service.Sample.TrippinInMemory.Models.AirportLocation" />
38+
<Property Name="Location" Type="Microsoft.OData.Service.Sample.TrippinInMemory.Models.AirportLocation">
39+
<Annotation Term="Org.OData.Capabilities.V1.UpdateRestrictions">
40+
<Record>
41+
<PropertyValue Property="UpdateMethod">
42+
<EnumMember>Org.OData.Capabilities.V1.HttpMethod/PUT</EnumMember>
43+
</PropertyValue>
44+
</Record>
45+
</Annotation>
46+
</Property>
3947
</EntityType>
4048
<ComplexType Name="Location">
4149
<Property Name="Address" Type="Edm.String" />

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

Lines changed: 2 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -3,116 +3,12 @@
33
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
44
// ------------------------------------------------------------
55

6-
using System.Collections.Generic;
7-
using System.Linq;
8-
using Microsoft.OData.Edm;
96
using Microsoft.OpenApi.Models;
10-
using Microsoft.OpenApi.OData.Common;
11-
using Microsoft.OpenApi.OData.Edm;
12-
using Microsoft.OpenApi.OData.Generator;
13-
using Microsoft.OpenApi.OData.Vocabulary.Capabilities;
147

158
namespace Microsoft.OpenApi.OData.Operation;
169

17-
internal class ComplexPropertyPatchOperationHandler : ComplexPropertyBaseOperationHandler
10+
internal class ComplexPropertyPatchOperationHandler : ComplexPropertyUpdateOperationHandler
1811
{
1912
/// <inheritdoc />
2013
public override OperationType OperationType => OperationType.Patch;
21-
22-
/// <inheritdoc/>
23-
protected override void SetBasicInfo(OpenApiOperation operation)
24-
{
25-
// Summary
26-
operation.Summary = $"Update property {ComplexPropertySegment.Property.Name} value.";
27-
28-
// Description
29-
operation.Description = Context.Model.GetDescriptionAnnotation(ComplexPropertySegment.Property);
30-
31-
// OperationId
32-
if (Context.Settings.EnableOperationId)
33-
{
34-
string typeName = ComplexPropertySegment.ComplexType.Name;
35-
operation.OperationId = ComplexPropertySegment.Property.Name + "." + typeName + ".Update" + Utils.UpperFirstChar(typeName);
36-
}
37-
}
38-
39-
/// <inheritdoc/>
40-
protected override void SetRequestBody(OpenApiOperation operation)
41-
{
42-
OpenApiSchema schema = ComplexPropertySegment.Property.Type.IsCollection() ?
43-
new OpenApiSchema
44-
{
45-
Type = "array",
46-
Items = new OpenApiSchema
47-
{
48-
Reference = new OpenApiReference
49-
{
50-
Type = ReferenceType.Schema,
51-
Id = ComplexPropertySegment.ComplexType.FullName()
52-
}
53-
}
54-
}
55-
:
56-
new OpenApiSchema
57-
{
58-
Reference = new OpenApiReference
59-
{
60-
Type = ReferenceType.Schema,
61-
Id = ComplexPropertySegment.ComplexType.FullName()
62-
}
63-
};
64-
65-
operation.RequestBody = new OpenApiRequestBody
66-
{
67-
Required = true,
68-
Description = "New property values",
69-
Content = new Dictionary<string, OpenApiMediaType>
70-
{
71-
{
72-
Constants.ApplicationJsonMediaType, new OpenApiMediaType
73-
{
74-
Schema = schema
75-
}
76-
}
77-
}
78-
};
79-
80-
base.SetRequestBody(operation);
81-
}
82-
83-
/// <inheritdoc/>
84-
protected override void SetResponses(OpenApiOperation operation)
85-
{
86-
operation.AddErrorResponses(Context.Settings, true);
87-
base.SetResponses(operation);
88-
}
89-
protected override void SetSecurity(OpenApiOperation operation)
90-
{
91-
UpdateRestrictionsType update = Context.Model.GetRecord<UpdateRestrictionsType>(ComplexPropertySegment.Property, CapabilitiesConstants.UpdateRestrictions);
92-
if (update == null || update.Permissions == null)
93-
{
94-
return;
95-
}
96-
97-
operation.Security = Context.CreateSecurityRequirements(update.Permissions).ToList();
98-
}
99-
100-
protected override void AppendCustomParameters(OpenApiOperation operation)
101-
{
102-
UpdateRestrictionsType update = Context.Model.GetRecord<UpdateRestrictionsType>(ComplexPropertySegment.Property, CapabilitiesConstants.UpdateRestrictions);
103-
if (update == null)
104-
{
105-
return;
106-
}
107-
108-
if (update.CustomHeaders != null)
109-
{
110-
AppendCustomParameters(operation, update.CustomHeaders, ParameterLocation.Header);
111-
}
112-
113-
if (update.CustomQueryOptions != null)
114-
{
115-
AppendCustomParameters(operation, update.CustomQueryOptions, ParameterLocation.Query);
116-
}
117-
}
118-
}
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// ------------------------------------------------------------
2+
// Copyright (c) Microsoft Corporation. All rights reserved.
3+
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
4+
// ------------------------------------------------------------
5+
6+
using Microsoft.OpenApi.Models;
7+
8+
namespace Microsoft.OpenApi.OData.Operation;
9+
10+
internal class ComplexPropertyPutOperationHandler : ComplexPropertyUpdateOperationHandler
11+
{
12+
/// <inheritdoc />
13+
public override OperationType OperationType => OperationType.Put;
14+
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// ------------------------------------------------------------
2+
// Copyright (c) Microsoft Corporation. All rights reserved.
3+
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
4+
// ------------------------------------------------------------
5+
6+
using System.Collections.Generic;
7+
using System.Linq;
8+
using Microsoft.OData.Edm;
9+
using Microsoft.OpenApi.Models;
10+
using Microsoft.OpenApi.OData.Common;
11+
using Microsoft.OpenApi.OData.Edm;
12+
using Microsoft.OpenApi.OData.Generator;
13+
using Microsoft.OpenApi.OData.Vocabulary.Capabilities;
14+
15+
namespace Microsoft.OpenApi.OData.Operation;
16+
17+
internal abstract class ComplexPropertyUpdateOperationHandler : ComplexPropertyBaseOperationHandler
18+
{
19+
/// <inheritdoc/>
20+
protected override void SetBasicInfo(OpenApiOperation operation)
21+
{
22+
// Summary
23+
operation.Summary = $"Update property {ComplexPropertySegment.Property.Name} value.";
24+
25+
// Description
26+
operation.Description = Context.Model.GetDescriptionAnnotation(ComplexPropertySegment.Property);
27+
28+
// OperationId
29+
if (Context.Settings.EnableOperationId)
30+
{
31+
string typeName = ComplexPropertySegment.ComplexType.Name;
32+
operation.OperationId = ComplexPropertySegment.Property.Name + "." + typeName + ".Update" + Utils.UpperFirstChar(typeName);
33+
}
34+
}
35+
36+
/// <inheritdoc/>
37+
protected override void SetRequestBody(OpenApiOperation operation)
38+
{
39+
OpenApiSchema schema = ComplexPropertySegment.Property.Type.IsCollection() ?
40+
new OpenApiSchema
41+
{
42+
Type = "array",
43+
Items = new OpenApiSchema
44+
{
45+
Reference = new OpenApiReference
46+
{
47+
Type = ReferenceType.Schema,
48+
Id = ComplexPropertySegment.ComplexType.FullName()
49+
}
50+
}
51+
}
52+
:
53+
new OpenApiSchema
54+
{
55+
Reference = new OpenApiReference
56+
{
57+
Type = ReferenceType.Schema,
58+
Id = ComplexPropertySegment.ComplexType.FullName()
59+
}
60+
};
61+
62+
operation.RequestBody = new OpenApiRequestBody
63+
{
64+
Required = true,
65+
Description = "New property values",
66+
Content = new Dictionary<string, OpenApiMediaType>
67+
{
68+
{
69+
Constants.ApplicationJsonMediaType, new OpenApiMediaType
70+
{
71+
Schema = schema
72+
}
73+
}
74+
}
75+
};
76+
77+
base.SetRequestBody(operation);
78+
}
79+
80+
/// <inheritdoc/>
81+
protected override void SetResponses(OpenApiOperation operation)
82+
{
83+
operation.AddErrorResponses(Context.Settings, false);
84+
base.SetResponses(operation);
85+
}
86+
protected override void SetSecurity(OpenApiOperation operation)
87+
{
88+
UpdateRestrictionsType update = Context.Model.GetRecord<UpdateRestrictionsType>(ComplexPropertySegment.Property, CapabilitiesConstants.UpdateRestrictions);
89+
if (update == null || update.Permissions == null)
90+
{
91+
return;
92+
}
93+
94+
operation.Security = Context.CreateSecurityRequirements(update.Permissions).ToList();
95+
}
96+
97+
protected override void AppendCustomParameters(OpenApiOperation operation)
98+
{
99+
UpdateRestrictionsType update = Context.Model.GetRecord<UpdateRestrictionsType>(ComplexPropertySegment.Property, CapabilitiesConstants.UpdateRestrictions);
100+
if (update == null)
101+
{
102+
return;
103+
}
104+
105+
if (update.CustomHeaders != null)
106+
{
107+
AppendCustomParameters(operation, update.CustomHeaders, ParameterLocation.Header);
108+
}
109+
110+
if (update.CustomQueryOptions != null)
111+
{
112+
AppendCustomParameters(operation, update.CustomQueryOptions, ParameterLocation.Query);
113+
}
114+
}
115+
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,12 @@ private readonly IDictionary<ODataPathKind, IDictionary<OperationType, IOperatio
9898
{OperationType.Get, new ODataTypeCastGetOperationHandler() },
9999
}},
100100

101-
// .../entity/propertyOfComplexType
101+
// .../entity/propertyOfComplexType (Get/Patch/Put/Delete)
102102
{ODataPathKind.ComplexProperty, new Dictionary<OperationType, IOperationHandler>
103103
{
104104
{OperationType.Get, new ComplexPropertyGetOperationHandler() },
105105
{OperationType.Patch, new ComplexPropertyPatchOperationHandler() },
106+
{OperationType.Put, new ComplexPropertyPutOperationHandler() },
106107
{OperationType.Post, new ComplexPropertyPostOperationHandler() },
107108
{OperationType.Delete, new ComplexPropertyDeleteOperationHandler() },
108109
}},

src/Microsoft.OpenApi.OData.Reader/PathItem/ComplexPropertyItemHandler.cs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using Microsoft.OData.Edm;
77
using Microsoft.OpenApi.Models;
88
using Microsoft.OpenApi.OData.Edm;
9+
using Microsoft.OpenApi.OData.Vocabulary.Capabilities;
910

1011
namespace Microsoft.OpenApi.OData.PathItem;
1112

@@ -14,11 +15,26 @@ internal class ComplexPropertyItemHandler : PathItemHandler
1415
/// <inheritdoc/>
1516
protected override ODataPathKind HandleKind => ODataPathKind.ComplexProperty;
1617

17-
/// <inheritdoc/>
18+
/// <summary>
19+
/// Gets the complex property
20+
/// </summary>
21+
protected IEdmStructuralProperty ComplexProperty { get; private set; }
22+
23+
/// <inheritdoc/>
1824
protected override void SetOperations(OpenApiPathItem item)
1925
{
2026
AddOperation(item, OperationType.Get);
21-
AddOperation(item, OperationType.Patch);
27+
28+
UpdateRestrictionsType update = Context.Model.GetRecord<UpdateRestrictionsType>(ComplexProperty);
29+
if (update != null && update.IsUpdateMethodPut)
30+
{
31+
AddOperation(item, OperationType.Put);
32+
}
33+
else
34+
{
35+
AddOperation(item, OperationType.Patch);
36+
}
37+
2238
if(Path.LastSegment is ODataComplexPropertySegment segment)
2339
{
2440
if(segment.Property.Type.IsNullable)
@@ -27,4 +43,14 @@ protected override void SetOperations(OpenApiPathItem item)
2743
AddOperation(item, OperationType.Post);
2844
}
2945
}
46+
47+
/// <inheritdoc/>
48+
protected override void Initialize(ODataContext context, ODataPath path)
49+
{
50+
base.Initialize(context, path);
51+
52+
// The last segment should be the complex property segment.
53+
ODataComplexPropertySegment navigationSourceSegment = path.LastSegment as ODataComplexPropertySegment;
54+
ComplexProperty = navigationSourceSegment.Property;
55+
}
3056
}

0 commit comments

Comments
 (0)