-
Notifications
You must be signed in to change notification settings - Fork 473
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
44 changed files
with
7,590 additions
and
42 deletions.
There are no files selected for viewing
68 changes: 68 additions & 0 deletions
68
src/Microsoft.AspNet.OData.Shared/Common/ODataPathHelper.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
//----------------------------------------------------------------------------- | ||
// <copyright file="ODataPathHelper.cs" company=".NET Foundation"> | ||
// Copyright (c) .NET Foundation and Contributors. All rights reserved. | ||
// See License.txt in the project root for license information. | ||
// </copyright> | ||
//------------------------------------------------------------------------------ | ||
|
||
using System.Collections.Generic; | ||
using System.Linq; | ||
using Microsoft.OData.UriParser; | ||
|
||
namespace Microsoft.AspNet.OData.Common | ||
{ | ||
/// <summary> | ||
/// Helper methods for <see cref="ODataPath"/>. | ||
/// </summary> | ||
internal static class ODataPathHelper | ||
{ | ||
/// <summary> | ||
/// Get the keys from a <see cref="KeySegment"/>. | ||
/// </summary> | ||
/// <param name="keySegment">The <see cref="KeySegment"/> to extract the keys.</param> | ||
/// <returns>Dictionary of keys.</returns> | ||
public static Dictionary<string, object> KeySegmentAsDictionary(KeySegment keySegment) | ||
{ | ||
if (keySegment == null) | ||
{ | ||
throw Error.ArgumentNull(nameof(keySegment)); | ||
} | ||
|
||
return keySegment.Keys.ToDictionary(d => d.Key, d => d.Value); | ||
} | ||
|
||
/// <summary> | ||
/// Get the position of the next <see cref="KeySegment"/> in a list of <see cref="ODataPathSegment"/>. | ||
/// </summary> | ||
/// <param name="pathSegments">List of <see cref="ODataPathSegment"/>.</param> | ||
/// <param name="currentPosition">Current position in the list of <see cref="ODataPathSegment"/>.</param> | ||
/// <returns>Position of the next <see cref="KeySegment"/> if it exists, or -1 otherwise.</returns> | ||
public static int GetNextKeySegmentPosition(IReadOnlyList<ODataPathSegment> pathSegments, int currentPosition) | ||
{ | ||
if (pathSegments == null) | ||
{ | ||
throw Error.ArgumentNull(nameof(pathSegments)); | ||
} | ||
|
||
if (currentPosition < 0 || currentPosition >= pathSegments.Count) | ||
{ | ||
return -1; | ||
} | ||
|
||
if (pathSegments[currentPosition] is KeySegment) | ||
{ | ||
currentPosition++; | ||
} | ||
|
||
for (int i = currentPosition; i < pathSegments.Count; i++) | ||
{ | ||
if (pathSegments[i] is KeySegment) | ||
{ | ||
return i; | ||
} | ||
} | ||
|
||
return -1; | ||
} | ||
} | ||
} |
192 changes: 192 additions & 0 deletions
192
src/Microsoft.AspNet.OData.Shared/DefaultEdmODataAPIHandler.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
//----------------------------------------------------------------------------- | ||
// <copyright file="DefaultEdmODataAPIHandler.cs" company=".NET Foundation"> | ||
// Copyright (c) .NET Foundation and Contributors. All rights reserved. | ||
// See License.txt in the project root for license information. | ||
// </copyright> | ||
//------------------------------------------------------------------------------ | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Diagnostics; | ||
using System.Linq; | ||
using Microsoft.OData.Edm; | ||
|
||
namespace Microsoft.AspNet.OData | ||
{ | ||
/// <summary> | ||
/// This is the default patch handler for non-CLR types. This class has default get, create, delete and updateRelatedObject | ||
/// methods that are used to patch an original collection when the collection is provided. | ||
/// </summary> | ||
internal class DefaultEdmODataAPIHandler : EdmODataAPIHandler | ||
{ | ||
private IEdmEntityType entityType; | ||
private ICollection<IEdmStructuredObject> originalList; | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="DefaultEdmODataAPIHandler"/> class. | ||
/// </summary> | ||
/// <param name="originalList">Original collection of the type which needs to be updated.</param> | ||
/// <param name="entityType">The Edm entity type of the collection.</param> | ||
public DefaultEdmODataAPIHandler(ICollection<IEdmStructuredObject> originalList, IEdmEntityType entityType) | ||
{ | ||
Debug.Assert(entityType != null, "entityType != null"); | ||
|
||
this.entityType = entityType; | ||
this.originalList = originalList ?? new List<IEdmStructuredObject>(); | ||
} | ||
|
||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] | ||
public override ODataAPIResponseStatus TryGet(IDictionary<string, object> keyValues, out IEdmStructuredObject originalObject, out string errorMessage) | ||
{ | ||
ODataAPIResponseStatus status = ODataAPIResponseStatus.Success; | ||
errorMessage = string.Empty; | ||
originalObject = null; | ||
|
||
Debug.Assert(keyValues != null, "keyValues != null"); | ||
|
||
try | ||
{ | ||
originalObject = GetFilteredItem(keyValues); | ||
|
||
if (originalObject == null) | ||
{ | ||
status = ODataAPIResponseStatus.NotFound; | ||
} | ||
} | ||
catch (Exception ex) | ||
{ | ||
status = ODataAPIResponseStatus.Failure; | ||
errorMessage = ex.Message; | ||
} | ||
|
||
return status; | ||
} | ||
|
||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] | ||
public override ODataAPIResponseStatus TryCreate(IDictionary<string, object> keyValues, out IEdmStructuredObject createdObject, out string errorMessage) | ||
{ | ||
createdObject = null; | ||
errorMessage = string.Empty; | ||
|
||
try | ||
{ | ||
createdObject = new EdmEntityObject(entityType); | ||
originalList.Add(createdObject); | ||
|
||
return ODataAPIResponseStatus.Success; | ||
} | ||
catch (Exception ex) | ||
{ | ||
errorMessage = ex.Message; | ||
|
||
return ODataAPIResponseStatus.Failure; | ||
} | ||
} | ||
|
||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] | ||
public override ODataAPIResponseStatus TryDelete(IDictionary<string, object> keyValues, out string errorMessage) | ||
{ | ||
errorMessage = string.Empty; | ||
|
||
try | ||
{ | ||
EdmStructuredObject originalObject = GetFilteredItem(keyValues); | ||
|
||
if (originalObject != null) | ||
{ | ||
originalList.Remove(originalObject); | ||
} | ||
|
||
return ODataAPIResponseStatus.Success; | ||
} | ||
catch (Exception ex) | ||
{ | ||
errorMessage = ex.Message; | ||
|
||
return ODataAPIResponseStatus.Failure; | ||
} | ||
} | ||
|
||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] | ||
public override ODataAPIResponseStatus TryAddRelatedObject(IEdmStructuredObject resource, out string errorMessage) | ||
{ | ||
errorMessage = string.Empty; | ||
|
||
try | ||
{ | ||
originalList.Add(resource); | ||
|
||
return ODataAPIResponseStatus.Success; | ||
} | ||
catch (Exception ex) | ||
{ | ||
errorMessage = ex.Message; | ||
|
||
return ODataAPIResponseStatus.Failure; | ||
} | ||
} | ||
|
||
public override EdmODataAPIHandler GetNestedHandler(IEdmStructuredObject parent, string navigationPropertyName) | ||
{ | ||
IEdmNavigationProperty navProperty = entityType.NavigationProperties().FirstOrDefault(navProp => navProp.Name == navigationPropertyName); | ||
|
||
if (navProperty == null) | ||
{ | ||
return null; | ||
} | ||
|
||
IEdmEntityType nestedEntityType = navProperty.ToEntityType(); | ||
|
||
object obj; | ||
|
||
if (parent.TryGetPropertyValue(navigationPropertyName, out obj)) | ||
{ | ||
ICollection<IEdmStructuredObject> nestedList = obj as ICollection<IEdmStructuredObject>; | ||
|
||
return new DefaultEdmODataAPIHandler(nestedList, nestedEntityType); | ||
} | ||
|
||
return null; | ||
} | ||
|
||
/// <summary> | ||
/// Filter the object based on the set of keys. | ||
/// </summary> | ||
/// <param name="keyValues">Key-value pairs for the object keys.</param> | ||
/// <returns>The filtered object.</returns> | ||
/// <remarks>There will only be very few key elements usually, mostly 1, so performance wont be impacted.</remarks> | ||
private EdmStructuredObject GetFilteredItem(IDictionary<string, object> keyValues) | ||
{ | ||
if (originalList.Count == 0) | ||
{ | ||
return null; | ||
} | ||
|
||
foreach (EdmStructuredObject item in originalList) | ||
{ | ||
bool isMatch = true; | ||
|
||
foreach (KeyValuePair<string, object> keyValue in keyValues) | ||
{ | ||
object value; | ||
if (item.TryGetPropertyValue(keyValue.Key, out value)) | ||
{ | ||
if (!Equals(value, keyValue.Value)) | ||
{ | ||
// Not a match, so try the next one | ||
isMatch = false; | ||
break; | ||
} | ||
} | ||
} | ||
|
||
if (isMatch) | ||
{ | ||
return item; | ||
} | ||
} | ||
|
||
return null; | ||
} | ||
} | ||
} |
Oops, something went wrong.