Skip to content

Commit

Permalink
Consolidate validation logic
Browse files Browse the repository at this point in the history
  • Loading branch information
mikepizzo committed Dec 17, 2021
1 parent 47fd7e6 commit a00e0a8
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 99 deletions.
83 changes: 48 additions & 35 deletions src/Microsoft.OData.Core/Evaluation/ODataResourceMetadataContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -174,45 +174,37 @@ internal static KeyValuePair<string, object>[] GetKeyProperties(
IEdmEntityType actualEntityType,
bool requiresId)
{

KeyValuePair<string, object>[] keyProperties = null;
string actualEntityTypeName = resource.TypeName ?? actualEntityType.FullName();
string actualEntityTypeName = resource.TypeName ?? actualEntityType?.FullName();

// if we have serializationInfo, try that first
if (serializationInfo != null)
{
if (String.IsNullOrEmpty(actualEntityTypeName))
{
throw new ODataException(Strings.ODataResourceTypeContext_ODataResourceTypeNameMissing);
}

keyProperties = ODataResourceMetadataContextWithoutModel.GetPropertiesBySerializationInfoPropertyKind(resource, ODataPropertyKind.Key, actualEntityTypeName);
}

// if we didn't get any keys from serializationInfo, try using entity type
if ((keyProperties == null || keyProperties.Length == 0) && actualEntityType != null)
{
keyProperties = GetPropertyValues(actualEntityType.Key(), resource, actualEntityType, /*isKeyProperty*/ true, requiresId).ToArray();
keyProperties = GetPropertyValues(actualEntityType.Key(), resource, actualEntityType, requiresId).ToArray();
}

if (requiresId)
{
ValidateEntityTypeHasKeyProperties(keyProperties, actualEntityTypeName);
}
else if (keyProperties == null)
{
keyProperties = Enumerable.Empty<KeyValuePair<string, object>>().ToArray();
if (!ValidateEntityTypeHasKeyProperties(keyProperties, actualEntityTypeName, requiresId))
{
return Enumerable.Empty<KeyValuePair<string, object>>().ToArray();
}

return keyProperties;
}

private static IEnumerable<KeyValuePair<string, object>> GetPropertyValues(IEnumerable<IEdmStructuralProperty> properties, ODataResourceBase resource, IEdmEntityType actualEntityType, bool isKeyProperty, bool isRequired)
private static IEnumerable<KeyValuePair<string, object>> GetPropertyValues(IEnumerable<IEdmStructuralProperty> properties, ODataResourceBase resource, IEdmEntityType actualEntityType, bool isRequired)
{
string actualEntityTypeName = actualEntityType.FullName();
object primitiveValue;
foreach (IEdmStructuralProperty property in properties)
{
if (TryGetPrimitiveOrEnumPropertyValue(resource, property.Name, actualEntityTypeName, isKeyProperty, isRequired, out primitiveValue))
if (TryGetPrimitiveOrEnumPropertyValue(resource, property.Name, actualEntityTypeName, isRequired, out primitiveValue))
{
yield return new KeyValuePair<string, object>(property.Name, primitiveValue);
}
Expand All @@ -225,11 +217,10 @@ private static IEnumerable<KeyValuePair<string, object>> GetPropertyValues(IEnum
/// <param name="resource">The resource to get the property value.</param>
/// <param name="propertyName">Name of the property.</param>
/// <param name="entityTypeName">The name of the entity type to get the property value.</param>
/// <param name="isKeyProperty">true if the property is a key property, false otherwise.</param>
/// <param name="isRequired">true, if the property value is required to be non-null.</param>
/// <param name="value">returned value, or null if no value is found.</param>
/// <param name="isRequired">true, if the property value is required.</param>
/// <returns>true, if the primitive value is found, otherwise false.</returns>
private static bool TryGetPrimitiveOrEnumPropertyValue(ODataResourceBase resource, string propertyName, string entityTypeName, bool isKeyProperty, bool isRequired, out object value)
private static bool TryGetPrimitiveOrEnumPropertyValue(ODataResourceBase resource, string propertyName, string entityTypeName, bool isRequired, out object value)
{
Debug.Assert(resource != null, "resource != null");

Expand All @@ -247,7 +238,7 @@ private static bool TryGetPrimitiveOrEnumPropertyValue(ODataResourceBase resourc
}
}

value = GetPrimitiveOrEnumPropertyValue(entityTypeName, property, isKeyProperty);
value = GetPrimitiveOrEnumPropertyValue(entityTypeName, property, isRequired);
return true;
}

Expand All @@ -256,12 +247,12 @@ private static bool TryGetPrimitiveOrEnumPropertyValue(ODataResourceBase resourc
/// </summary>
/// <param name="entityTypeName">The name of the entity type to get the property value.</param>
/// <param name="property">The ODataProperty to get the value from.</param>
/// <param name="isKeyProperty">true if the property is a key property, false otherwise.</param>
/// <param name="validateNotNull">true if property must not be null, false otherwise.</param>
/// <returns>The value of the property.</returns>
private static object GetPrimitiveOrEnumPropertyValue(string entityTypeName, ODataProperty property, bool isKeyProperty)
private static object GetPrimitiveOrEnumPropertyValue(string entityTypeName, ODataProperty property, bool validateNotNull)
{
object propertyValue = property.Value;
if (propertyValue == null && isKeyProperty)
if (propertyValue == null && validateNotNull)
{
throw new ODataException(Strings.ODataResourceMetadataContext_NullKeyValue(property.Name, entityTypeName));
}
Expand All @@ -279,12 +270,38 @@ private static object GetPrimitiveOrEnumPropertyValue(string entityTypeName, ODa
/// </summary>
/// <param name="keyProperties">Key properties of the resource.</param>
/// <param name="actualEntityTypeName">The entity type name of the resource.</param>
private static void ValidateEntityTypeHasKeyProperties(KeyValuePair<string, object>[] keyProperties, string actualEntityTypeName)
/// <param name="throwOnError">Whether to throw if validation fails.</param>
/// <returns>True, if validation succeeds, or false if validation fails.</returns>
private static bool ValidateEntityTypeHasKeyProperties(KeyValuePair<string, object>[] keyProperties, string actualEntityTypeName, bool throwOnError)
{
if (keyProperties == null || keyProperties.Length == 0)
{
throw new ODataException(Strings.ODataResourceMetadataContext_EntityTypeWithNoKeyProperties(actualEntityTypeName));
if (throwOnError)
{
throw new ODataException(Strings.ODataResourceMetadataContext_EntityTypeWithNoKeyProperties(actualEntityTypeName));
}
else
{
return false;
}
}

for (int keyProperty = 0; keyProperty < keyProperties.Length; keyProperty++)
{
if (keyProperties[keyProperty].Value == null || (keyProperties[keyProperty].Value is ODataValue && !(keyProperties[keyProperty].Value is ODataEnumValue)))
{
if (throwOnError)
{
throw new ODataException(Strings.ODataResourceMetadataContext_NullKeyValue(keyProperties[keyProperty].Key, actualEntityTypeName));
}
else
{
return false;
}
}
}

return true;
}

/// <summary>
Expand All @@ -306,7 +323,7 @@ private static KeyValuePair<string, object>[] GetPropertiesBySerializationInfoPr
{
if(property.SerializationInfo != null && property.SerializationInfo.PropertyKind == propertyKind)
{
properties.Add(new KeyValuePair<string, object>(property.Name, GetPrimitiveOrEnumPropertyValue(actualEntityTypeName, property, propertyKind == ODataPropertyKind.Key)));
properties.Add(new KeyValuePair<string, object>(property.Name, GetPrimitiveOrEnumPropertyValue(actualEntityTypeName, property, false)));
}
}
}
Expand Down Expand Up @@ -491,16 +508,12 @@ public override ICollection<KeyValuePair<string, object>> KeyProperties
IEdmEntityType entityType = this.actualResourceType as IEdmEntityType;
if (entityType != null)
{
this.keyProperties = keyProperties = GetPropertyValues(entityType.Key(), resource, entityType, /*isKeyProperty*/ true, this.requiresId).ToArray();

if (this.requiresId)
{
ValidateEntityTypeHasKeyProperties(this.keyProperties, this.ActualResourceTypeName);
}
this.keyProperties = GetPropertyValues(entityType.Key(), resource, entityType, this.requiresId).ToArray();
}
else

if (!ValidateEntityTypeHasKeyProperties(this.keyProperties, this.ActualResourceTypeName, this.requiresId))
{
this.keyProperties = Enumerable.Empty<KeyValuePair<string, object>>().ToArray();
return Enumerable.Empty<KeyValuePair<string, object>>().ToArray();
}
}

Expand All @@ -520,7 +533,7 @@ public override IEnumerable<KeyValuePair<string, object>> ETagProperties
IEdmEntityType actualEntityType = this.actualResourceType as IEdmEntityType;
IEnumerable<IEdmStructuralProperty> properties = this.ComputeETagPropertiesFromAnnotation();
this.etagProperties = properties.Any()
? GetPropertyValues(properties, resource, actualEntityType, /*isKeyProperty*/false, /*isRequired*/ true)
? GetPropertyValues(properties, resource, actualEntityType, /*isRequired*/ false)
: EmptyProperties;
}

Expand Down
68 changes: 4 additions & 64 deletions src/Microsoft.OData.Core/ODataWriterCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2810,7 +2810,7 @@ private void EnterScope(WriterState newState, ODataItem item)
/// <returns>The new odata path.</returns>
private ODataPath AppendEntitySetKeySegment(ODataPath odataPath, bool throwIfFail)
{
ODataPath path = odataPath;
ODataPath path = odataPath;

if (EdmExtensionMethods.HasKey(this.CurrentScope.NavigationSource, this.CurrentScope.ResourceType))
{
Expand All @@ -2821,74 +2821,15 @@ private ODataPath AppendEntitySetKeySegment(ODataPath odataPath, bool throwIfFai

ODataResourceSerializationInfo serializationInfo = this.GetResourceSerializationInfo(resource);

if (!throwIfFail)
{
if (resource.NonComputedProperties != null)
{
List<KeyValuePair<string, object>> keys = new List<KeyValuePair<string, object>>();

if (serializationInfo != null)
{
foreach (ODataProperty property in resource.NonComputedProperties)
{
if (property.SerializationInfo != null && property.SerializationInfo.PropertyKind == ODataPropertyKind.Key)
{
if(!CreateKeyValuePair(keys, property, property.Value))
{
return path;
}
}
}
}
else
{
HashSet<string> keySet = new HashSet<string>();
KeyValuePair<string, object>[] keys = ODataResourceMetadataContext.GetKeyProperties(resource,
serializationInfo, currentEntityType, throwIfFail);

foreach (IEdmStructuralProperty property in currentEntityType.Key())
{
keySet.Add(property.Name);
}

foreach (ODataProperty property in resource.NonComputedProperties)
{
if (keySet.Contains(property.Name))
{
if (!CreateKeyValuePair(keys, property, property.Value))
{
return path;
}
}
}
}

path = path.AddKeySegment(keys.ToArray(), currentEntityType, this.CurrentScope.NavigationSource);
}
}
else
{
KeyValuePair<string, object>[] keys = ODataResourceMetadataContext.GetKeyProperties(resource,
serializationInfo, currentEntityType, true);

path = path.AddKeySegment(keys, currentEntityType, this.CurrentScope.NavigationSource);
}
path = path.AddKeySegment(keys, currentEntityType, this.CurrentScope.NavigationSource);
}


return path;
}

private static bool CreateKeyValuePair(List<KeyValuePair<string, object>> keys, ODataProperty property, object propertyValue)
{
if (propertyValue == null || (propertyValue is ODataValue && !(propertyValue is ODataEnumValue)))
{
return false;
}

keys.Add(new KeyValuePair<string, object>(property.Name, propertyValue));

return true;
}

/// <summary>
/// Leave the current writer scope and return to the previous scope.
/// When reaching the top-level replace the 'Started' scope with a 'Completed' scope.
Expand Down Expand Up @@ -3430,7 +3371,6 @@ private Task WriteEndImplementationAsync()
return this.InterceptExceptionAsync(
async (thisParam) =>
{
bool wasenableDelta;
Scope currentScope = thisParam.CurrentScope;

switch (currentScope.State)
Expand Down

0 comments on commit a00e0a8

Please sign in to comment.