Skip to content

Adds support for reading custom attributes #214

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
May 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions src/Microsoft.OpenApi.OData.Reader/Common/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Vocabulary;

Expand Down Expand Up @@ -128,5 +132,95 @@ internal static string NavigationPropertyPath(this ODataPath path, string naviga
path.Segments.OfType<ODataNavigationPropertySegment>().Select(e => e.Identifier));
return navigationPropertyName == null ? value : $"{value}/{navigationPropertyName}";
}

/// <summary>
/// Attempts to add the specified key and value to the dictionary.
/// </summary>
/// <typeparam name="TKey">The type of the keys in the dictionary</typeparam>
/// <typeparam name="TValue">The type of the values in the dictionary</typeparam>
/// <param name="dictionary">A dictionary with keys of type TKey and values of type TValue.</param>
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
/// <returns>true when the key and value are successfully added to the dictionary;
/// false when the dictionary already contains the specified key,
/// in which case nothing gets added.</returns>
/// <exception cref="System.ArgumentNullException">dictionary is null.</exception>
internal static bool TryAdd<TKey, TValue>(this IDictionary<TKey, TValue> dictionary,
TKey key, TValue value)
{
CheckArgumentNull(dictionary, nameof(dictionary));

if (!dictionary.ContainsKey(key))
{
dictionary.Add(key, value);
return true;
}
return false;
}

/// <summary>
/// Adds a mapping of custom extension values against custom attribute values for a given element to the provided
/// extensions object.
/// </summary>
/// <param name="extensions">The target extensions object in which the mapped extensions and custom attribute
/// values will be added to.</param>
/// <param name="context">The OData context.</param>
/// <param name="element">The target element.</param>
internal static void AddCustomAtributesToExtensions(this IDictionary<string, IOpenApiExtension> extensions, ODataContext context, IEdmElement element)
{
if (extensions == null ||
context == null ||
element == null)
{
return;
}

Dictionary<string, string> atrributesValueMap = GetCustomXMLAtrributesValueMapping(context.Model, element, context.Settings.CustomXMLAttributesMapping);

if (atrributesValueMap?.Any() ?? false)
{
foreach (var item in atrributesValueMap)
{
extensions.TryAdd(item.Key, new OpenApiString(item.Value));
}
}
}

/// <summary>
/// Correlates and retrieves custom attribute values for a given element in an Edm model
/// from a provided dictionary mapping of attribute names and extension names.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="element">The target element.</param>
/// <param name="customXMLAttributesMapping">The dictionary mapping of attribute names and extension names.</param>
/// <returns>A dictionary of extension names mapped to the custom attribute values.</returns>
private static Dictionary<string, string> GetCustomXMLAtrributesValueMapping(IEdmModel model, IEdmElement element, Dictionary<string, string> customXMLAttributesMapping)
{
Dictionary<string, string> atrributesValueMap = new();

if ((!customXMLAttributesMapping?.Any() ?? true) ||
model == null ||
element == null)
{
return atrributesValueMap;
}

foreach (var item in customXMLAttributesMapping)
{
string attributeName = item.Key.Split(':').Last(); // example, 'ags:IsHidden' --> 'IsHidden'
string extensionName = item.Value;
EdmStringConstant customXMLAttribute = model.DirectValueAnnotationsManager.GetDirectValueAnnotations(element)?
.Where(x => x.Name.Equals(attributeName, StringComparison.OrdinalIgnoreCase))?
.FirstOrDefault()?.Value as EdmStringConstant;
string attributeValue = customXMLAttribute?.Value;

if (!string.IsNullOrEmpty(attributeValue))
{
atrributesValueMap.TryAdd(extensionName, attributeValue);
}
}

return atrributesValueMap;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -327,16 +327,18 @@ public static IDictionary<string, OpenApiSchema> CreateStructuredTypePropertiesS
// structure properties
foreach (var property in structuredType.DeclaredStructuralProperties())
{
// OpenApiSchema propertySchema = property.Type.CreateSchema();
// propertySchema.Default = property.DefaultValueString != null ? new OpenApiString(property.DefaultValueString) : null;
properties.Add(property.Name, context.CreatePropertySchema(property));
OpenApiSchema propertySchema = context.CreatePropertySchema(property);
propertySchema.Description = context.Model.GetDescriptionAnnotation(property);
propertySchema.Extensions.AddCustomAtributesToExtensions(context, property);
properties.Add(property.Name, propertySchema);
}

// navigation properties
foreach (var property in structuredType.DeclaredNavigationProperties())
{
OpenApiSchema propertySchema = context.CreateEdmTypeSchema(property.Type);
propertySchema.Description = context.Model.GetDescriptionAnnotation(property);
propertySchema.Extensions.AddCustomAtributesToExtensions(context, property);
properties.Add(property.Name, propertySchema);
}

Expand Down
9 changes: 8 additions & 1 deletion src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// ------------------------------------------------------------

using System;
using System.Collections.Generic;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Extensions;
Expand Down Expand Up @@ -242,6 +243,11 @@ public string PathPrefix
/// </summary>
public bool RequireRestrictionAnnotationsToGenerateComplexPropertyPaths { get; set; } = true;

/// <summary>
/// Gets/sets a dictionary containing a mapping of custom atttribute names and extension names.
/// </summary>
public Dictionary<string, string> CustomXMLAttributesMapping { get; set; } = new();

internal OpenApiConvertSettings Clone()
{
var newSettings = new OpenApiConvertSettings
Expand Down Expand Up @@ -281,7 +287,8 @@ internal OpenApiConvertSettings Clone()
ErrorResponsesAsDefault = this.ErrorResponsesAsDefault,
InnerErrorComplexTypeName = this.InnerErrorComplexTypeName,
RequireRestrictionAnnotationsToGenerateComplexPropertyPaths = this.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths,
ExpandDerivedTypesNavigationProperties = this.ExpandDerivedTypesNavigationProperties
ExpandDerivedTypesNavigationProperties = this.ExpandDerivedTypesNavigationProperties,
CustomXMLAttributesMapping = this.CustomXMLAttributesMapping
};

return newSettings;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

using Microsoft.OData.Edm;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Vocabulary.Capabilities;

Expand Down Expand Up @@ -65,4 +66,10 @@ protected override void Initialize(ODataContext context, ODataPath path)
ODataComplexPropertySegment navigationSourceSegment = path.LastSegment as ODataComplexPropertySegment;
ComplexProperty = navigationSourceSegment.Property;
}

/// <inheritdoc/>
protected override void SetExtensions(OpenApiPathItem item)
{
item.Extensions.AddCustomAtributesToExtensions(Context, ComplexProperty);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------

using Microsoft.OData.Edm;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Vocabulary.Capabilities;

Expand Down Expand Up @@ -48,5 +50,12 @@ protected override void SetOperations(OpenApiPathItem item)
AddOperation(item, OperationType.Delete);
}
}

/// <inheritdoc/>
protected override void SetExtensions(OpenApiPathItem pathItem)
{
base.SetExtensions(pathItem);
pathItem.Extensions.AddCustomAtributesToExtensions(Context, EntitySet.EntityType());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

using Microsoft.OData.Edm;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Vocabulary.Capabilities;

Expand Down Expand Up @@ -54,5 +55,12 @@ protected override void SetBasicInfo(OpenApiPathItem pathItem)
base.SetBasicInfo(pathItem);
pathItem.Description = $"Provides operations to manage the collection of {EntitySet.EntityType().Name} entities.";
}

/// <inheritdoc/>
protected override void SetExtensions(OpenApiPathItem pathItem)
{
base.SetExtensions(pathItem);
pathItem.Extensions.AddCustomAtributesToExtensions(Context, EntitySet);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------

using System;
using System.Diagnostics;
using System.Linq;
using System.Collections.Generic;
Expand Down Expand Up @@ -241,8 +240,11 @@ protected override void SetExtensions(OpenApiPathItem item)
array.Add(new OpenApiString(p.GetPathItemName(settings)));
}

item.Extensions.Add(Constants.xMsDosGroupPath, array);
item.Extensions.Add(Constants.xMsDosGroupPath, array);
}

base.SetExtensions(item);
item.Extensions.AddCustomAtributesToExtensions(Context, NavigationProperty);
}
/// <inheritdoc/>
protected override void SetBasicInfo(OpenApiPathItem pathItem)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

using Microsoft.OData.Edm;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;

namespace Microsoft.OpenApi.OData.PathItem;
Expand Down Expand Up @@ -32,10 +33,18 @@ protected override void Initialize(ODataContext context, ODataPath path)
}
}
private IEdmStructuredType StructuredType { get; set; }

/// <inheritdoc/>
protected override void SetBasicInfo(OpenApiPathItem pathItem)
{
base.SetBasicInfo(pathItem);
pathItem.Description = $"Casts the previous resource to {(StructuredType as IEdmNamedElement).Name}.";
}

/// <inheritdoc/>
protected override void SetExtensions(OpenApiPathItem pathItem)
{
base.SetExtensions(pathItem);
pathItem.Extensions.AddCustomAtributesToExtensions(Context, StructuredType);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

using Microsoft.OData.Edm;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Vocabulary.Capabilities;

Expand Down Expand Up @@ -58,11 +59,19 @@ protected override void Initialize(ODataContext context, ODataPath path)
ODataOperationImportSegment operationImportSegment = path.FirstSegment as ODataOperationImportSegment;
EdmOperationImport = operationImportSegment.OperationImport;
}

/// <inheritdoc/>
protected override void SetBasicInfo(OpenApiPathItem pathItem)
{
base.SetBasicInfo(pathItem);
pathItem.Description = $"Provides operations to call the {EdmOperationImport.Name} method.";
}

/// <inheritdoc/>
protected override void SetExtensions(OpenApiPathItem item)
{
base.SetExtensions(item);
item.Extensions.AddCustomAtributesToExtensions(Context, EdmOperationImport);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,11 @@ protected override void SetExtensions(OpenApiPathItem item)

item.Extensions.Add(Constants.xMsDosGroupPath, array);
}

base.SetExtensions(item);
item.Extensions.AddCustomAtributesToExtensions(Context, EdmOperation);
}

/// <inheritdoc/>
protected override void SetBasicInfo(OpenApiPathItem pathItem)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
// ------------------------------------------------------------
// ------------------------------------------------------------
// 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;
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

using Microsoft.OData.Edm;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Vocabulary.Capabilities;

Expand Down Expand Up @@ -49,11 +50,19 @@ protected override void Initialize(ODataContext context, ODataPath path)
ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment;
Singleton = navigationSourceSegment.NavigationSource as IEdmSingleton;
}

/// <inheritdoc/>
protected override void SetBasicInfo(OpenApiPathItem pathItem)
{
base.SetBasicInfo(pathItem);
pathItem.Description = $"Provides operations to manage the {Singleton.EntityType().Name} singleton.";
}

/// <inheritdoc/>
protected override void SetExtensions(OpenApiPathItem pathItem)
{
base.SetExtensions(pathItem);
pathItem.Extensions.AddCustomAtributesToExtensions(Context, Singleton);
}
}
}
2 changes: 2 additions & 0 deletions src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ Microsoft.OpenApi.OData.Edm.EdmModelExtensions
Microsoft.OpenApi.OData.Edm.EdmTypeExtensions
Microsoft.OpenApi.OData.OpenApiConvertSettings.ExpandDerivedTypesNavigationProperties.get -> bool
Microsoft.OpenApi.OData.OpenApiConvertSettings.ExpandDerivedTypesNavigationProperties.set -> void
Microsoft.OpenApi.OData.OpenApiConvertSettings.CustomXMLAttributesMapping.get -> System.Collections.Generic.Dictionary<string, string>
Microsoft.OpenApi.OData.OpenApiConvertSettings.CustomXMLAttributesMapping.set -> void
Microsoft.OpenApi.OData.OpenApiConvertSettings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths.get -> bool
Microsoft.OpenApi.OData.OpenApiConvertSettings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths.set -> void
static Microsoft.OpenApi.OData.Edm.EdmTypeExtensions.ShouldPathParameterBeQuoted(this Microsoft.OData.Edm.IEdmType edmType, Microsoft.OpenApi.OData.OpenApiConvertSettings settings) -> bool
Expand Down
Loading