Skip to content

Commit

Permalink
Built-In Functions to be customized OData#378
Browse files Browse the repository at this point in the history
* CustomUriFunctions - public API to add/remove or override builtIn functions.
* CustomUriFunctions and BuiltInFunctions tests
* Changed class name from 'BuiltInFunctions' to 'BuiltInUriFunctions'.
* The new class 'UriFunctionsHelper' contains general usage for both BuiltIn and Custom functions.
  • Loading branch information
YogiBear52 authored and LaylaLiu committed Jan 13, 2016
1 parent 422a0e2 commit 174da80
Show file tree
Hide file tree
Showing 19 changed files with 1,158 additions and 182 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1174,9 +1174,6 @@
<Compile Include="$(ODataCrossTargettingSourcePath)\UriParser\Binders\UnaryOperatorBinder.cs">
<Link>Microsoft\OData\Core\UriParser\Binders\UnaryOperatorBinder.cs</Link>
</Compile>
<Compile Include="$(ODataCrossTargettingSourcePath)\UriParser\BuiltInFunctions.cs">
<Link>Microsoft\OData\Core\UriParser\BuiltInFunctions.cs</Link>
</Compile>
<Compile Include="$(ODataCrossTargettingSourcePath)\UriParser\ExceptionUtil.cs">
<Link>Microsoft\OData\Core\UriParser\ExceptionUtil.cs</Link>
</Compile>
Expand Down Expand Up @@ -1403,11 +1400,13 @@
<Link>Microsoft\OData\Core\UriParser\SemanticAst\EntitySetSegment.cs</Link>
</Compile>
<Compile Include="$(ODataCrossTargettingSourcePath)\UriParser\SemanticAst\ExpandedNavigationSelectItem.cs">
<Link>Microsoft\OData\Core\UriParser\SemanticAst\ExpandedNavigationSelectItem.cs</Link>
</Compile>

<Link>Microsoft\OData\Core\UriParser\SemanticAst\ExpandedNavigationSelectItem.cs</Link>
</Compile>
<Compile Include="$(ODataCrossTargettingSourcePath)\UriParser\SemanticAst\ExpandedReferenceSelectItem.cs">
<Link>Microsoft\OData\Core\UriParser\SemanticAst\ExpandedReferenceSelectItem.cs</Link>
</Compile>
</Compile>

<Compile Include="$(ODataCrossTargettingSourcePath)\UriParser\SemanticAst\FilterClause.cs">
<Link>Microsoft\OData\Core\UriParser\SemanticAst\FilterClause.cs</Link>
</Compile>
Expand Down Expand Up @@ -1737,6 +1736,7 @@
</Compile>
</ItemGroup>
<ItemGroup>

<Compile Include="$(ODataCrossTargettingSourcePath)\UriParser\Extensions\AggregationVerb.cs">
<Link>Microsoft\OData\Core\UriParser\Extensions\AggregationVerb.cs</Link>
</Compile>
Expand Down Expand Up @@ -1778,6 +1778,17 @@
</Compile>
<Compile Include="$(ODataCrossTargettingSourcePath)\UriParser\Extensions\TreeNodeKinds\TransformationNodeKind.cs">
<Link>Microsoft\OData\Core\UriParser\Extensions\TreeNodeKinds\TransformationNodeKind.cs</Link>

</Compile>
<Compile Include="..\UriParser\BuiltInUriFunctions.cs">
<Link>Microsoft\OData\Core\UriParser\BuiltInUriFunctions.cs</Link>
</Compile>
<Compile Include="..\UriParser\CustomUriFunctions.cs">
<Link>Microsoft\OData\Core\UriParser\CustomUriFunctions.cs</Link>
</Compile>
<Compile Include="..\UriParser\UriFunctionsHelper.cs">
<Link>Microsoft\OData\Core\UriParser\UriFunctionsHelper.cs</Link>

</Compile>
<Compile Include="ShippingAssemblyAttributes.cs" />
<Compile Include="$(AssemblyKeysCSharpFilePath)">
Expand Down
4 changes: 3 additions & 1 deletion src/Microsoft.OData.Core/Microsoft.OData.Core.Net45.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,8 @@
<Compile Include="UriParser\Binders\SelectPathSegmentTokenBinder.cs" />
<Compile Include="UriParser\Binders\SelectTreeNormalizer.cs" />
<Compile Include="UriParser\Binders\UnaryOperatorBinder.cs" />
<Compile Include="UriParser\BuiltInFunctions.cs" />
<Compile Include="UriParser\BuiltInUriFunctions.cs" />
<Compile Include="UriParser\CustomUriFunctions.cs" />
<Compile Include="UriParser\ExceptionUtil.cs" />
<Compile Include="UriParser\ExpressionLexer.cs" />
<Compile Include="UriParser\ExpressionLexerLiteralExtensions.cs" />
Expand Down Expand Up @@ -579,6 +580,7 @@
<Compile Include="UriParser\TreeNodeKinds\RequestTargetKind.cs" />
<Compile Include="UriParser\TreeNodeKinds\UnaryOperatorKind.cs" />
<Compile Include="UriParser\TypePromotionUtils.cs" />
<Compile Include="UriParser\UriFunctionsHelper.cs" />
<Compile Include="UriParser\UriQueryConstants.cs" />
<Compile Include="UriParser\UriUtils.cs" />
<Compile Include="UriParser\Visitors\IPathSegmentTokenVisitor.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,8 @@
<Compile Include="UriParser\Binders\SelectPathSegmentTokenBinder.cs" />
<Compile Include="UriParser\Binders\SelectTreeNormalizer.cs" />
<Compile Include="UriParser\Binders\UnaryOperatorBinder.cs" />
<Compile Include="UriParser\BuiltInFunctions.cs" />
<Compile Include="UriParser\BuiltInUriFunctions.cs" />
<Compile Include="UriParser\CustomUriFunctions.cs" />
<Compile Include="UriParser\ExceptionUtil.cs" />
<Compile Include="UriParser\ExpressionLexer.cs" />
<Compile Include="UriParser\ExpressionLexerLiteralExtensions.cs" />
Expand Down Expand Up @@ -578,6 +579,7 @@
<Compile Include="UriParser\TreeNodeKinds\RequestTargetKind.cs" />
<Compile Include="UriParser\TreeNodeKinds\UnaryOperatorKind.cs" />
<Compile Include="UriParser\TypePromotionUtils.cs" />
<Compile Include="UriParser\UriFunctionsHelper.cs" />
<Compile Include="UriParser\UriQueryConstants.cs" />
<Compile Include="UriParser\UriUtils.cs" />
<Compile Include="UriParser\Visitors\IPathSegmentTokenVisitor.cs" />
Expand Down
3 changes: 3 additions & 0 deletions src/Microsoft.OData.Core/Microsoft.OData.Core.cs
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,9 @@ internal sealed class TextRes {
internal const string FunctionOverloadResolver_MultipleOperationOverloads = "FunctionOverloadResolver_MultipleOperationOverloads";
internal const string FunctionOverloadResolver_FoundInvalidOperation = "FunctionOverloadResolver_FoundInvalidOperation";
internal const string FunctionOverloadResolver_FoundInvalidOperationImport = "FunctionOverloadResolver_FoundInvalidOperationImport";
internal const string CustomUriFunctions_AddCustomUriFunction_BuiltInExistsNoOverride = "CustomUriFunctions_AddCustomUriFunction_BuiltInExistsNoOverride";
internal const string CustomUriFunctions_AddCustomUriFunction_BuiltInExistsFullSignature = "CustomUriFunctions_AddCustomUriFunction_BuiltInExistsFullSignature";
internal const string CustomUriFunctions_AddCustomUriFunction_CustomFunctionOverloadExists = "CustomUriFunctions_AddCustomUriFunction_CustomFunctionOverloadExists";
internal const string RequestUriProcessor_InvalidValueForEntitySegment = "RequestUriProcessor_InvalidValueForEntitySegment";
internal const string RequestUriProcessor_InvalidValueForKeySegment = "RequestUriProcessor_InvalidValueForKeySegment";
internal const string RequestUriProcessor_EmptySegmentInRequestUrl = "RequestUriProcessor_EmptySegmentInRequestUrl";
Expand Down
4 changes: 3 additions & 1 deletion src/Microsoft.OData.Core/Microsoft.OData.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,8 @@
<Compile Include="UriParser\Binders\SelectPathSegmentTokenBinder.cs" />
<Compile Include="UriParser\Binders\SelectTreeNormalizer.cs" />
<Compile Include="UriParser\Binders\UnaryOperatorBinder.cs" />
<Compile Include="UriParser\BuiltInFunctions.cs" />
<Compile Include="UriParser\BuiltInUriFunctions.cs" />
<Compile Include="UriParser\CustomUriFunctions.cs" />
<Compile Include="UriParser\ExceptionUtil.cs" />
<Compile Include="UriParser\ExpressionLexer.cs" />
<Compile Include="UriParser\ExpressionLexerLiteralExtensions.cs" />
Expand Down Expand Up @@ -578,6 +579,7 @@
<Compile Include="UriParser\TreeNodeKinds\RequestTargetKind.cs" />
<Compile Include="UriParser\TreeNodeKinds\UnaryOperatorKind.cs" />
<Compile Include="UriParser\TypePromotionUtils.cs" />
<Compile Include="UriParser\UriFunctionsHelper.cs" />
<Compile Include="UriParser\UriQueryConstants.cs" />
<Compile Include="UriParser\UriUtils.cs" />
<Compile Include="UriParser\Visitors\IPathSegmentTokenVisitor.cs" />
Expand Down
4 changes: 4 additions & 0 deletions src/Microsoft.OData.Core/Microsoft.OData.Core.txt
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,10 @@ FunctionOverloadResolver_MultipleOperationOverloads=Multiple action and function
FunctionOverloadResolver_FoundInvalidOperation=The operation overloads matching '{0}' are invalid. This is most likely an error in the IEdmModel.
FunctionOverloadResolver_FoundInvalidOperationImport=The operation import overloads matching '{0}' are invalid. This is most likely an error in the IEdmModel.

CustomUriFunctions_AddCustomUriFunction_BuiltInExistsNoOverride=The given custom function '{0}' already exists as a Built-In function. Consider use 'OverrideBuiltInFunction = true' parameter.
CustomUriFunctions_AddCustomUriFunction_BuiltInExistsFullSignature=The given custom function '{0}' already exists as a Built-In function in one of it's overloads. Thus cannot override the Built-In function.
CustomUriFunctions_AddCustomUriFunction_CustomFunctionOverloadExists=The given function name '{0}' already exists as a custom function with the same overload.

RequestUriProcessor_InvalidValueForEntitySegment=The ODataPathSegment provided (Id = {0}) is not an EntitySetSegment.
RequestUriProcessor_InvalidValueForKeySegment=The KeySegment provided (Id = {0}) is either null, having no keys, or does not target a single resource.

Expand Down
21 changes: 21 additions & 0 deletions src/Microsoft.OData.Core/Parameterized.Microsoft.OData.Core.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5568,6 +5568,27 @@ internal static string FunctionOverloadResolver_FoundInvalidOperationImport(obje
return Microsoft.OData.Core.TextRes.GetString(Microsoft.OData.Core.TextRes.FunctionOverloadResolver_FoundInvalidOperationImport, p0);
}

/// <summary>
/// A string like "The given custom function '{0}' already exists as a Built-In function. Consider use 'OverrideBuiltInFunction = true' parameter."
/// </summary>
internal static string CustomUriFunctions_AddCustomUriFunction_BuiltInExistsNoOverride(object p0) {
return Microsoft.OData.Core.TextRes.GetString(Microsoft.OData.Core.TextRes.CustomUriFunctions_AddCustomUriFunction_BuiltInExistsNoOverride, p0);
}

/// <summary>
/// A string like "The given custom function '{0}' already exists as a Built-In function in one of it's overloads. Thus cannot override the Built-In function."
/// </summary>
internal static string CustomUriFunctions_AddCustomUriFunction_BuiltInExistsFullSignature(object p0) {
return Microsoft.OData.Core.TextRes.GetString(Microsoft.OData.Core.TextRes.CustomUriFunctions_AddCustomUriFunction_BuiltInExistsFullSignature, p0);
}

/// <summary>
/// A string like "The given function name '{0}' already exists as a custom function with the same overload."
/// </summary>
internal static string CustomUriFunctions_AddCustomUriFunction_CustomFunctionOverloadExists(object p0) {
return Microsoft.OData.Core.TextRes.GetString(Microsoft.OData.Core.TextRes.CustomUriFunctions_AddCustomUriFunction_CustomFunctionOverloadExists, p0);
}

/// <summary>
/// A string like "The ODataPathSegment provided (Id = {0}) is not an EntitySetSegment."
/// </summary>
Expand Down
18 changes: 12 additions & 6 deletions src/Microsoft.OData.Core/UriParser/Binders/FunctionCallBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ internal static FunctionSignatureWithReturnType MatchSignatureToBuiltInFunction(
{
throw new ODataException(ODataErrorStrings.MetadataBinder_NoApplicableFunctionFound(
functionName,
BuiltInFunctions.BuildFunctionSignatureListDescription(functionName, signatures)));
UriFunctionsHelper.BuildFunctionSignatureListDescription(functionName, signatures)));
}
}

Expand All @@ -140,16 +140,22 @@ internal static FunctionSignatureWithReturnType MatchSignatureToBuiltInFunction(

/// <summary>
/// Finds all signatures for the given function name.
/// Search in BuiltIn uri functions first, and then in custom uri functions.
/// </summary>
/// <param name="functionName">The function to get the signatures for.</param>
/// <returns>The signatures which match the supplied function name.</returns>
internal static FunctionSignatureWithReturnType[] GetBuiltInFunctionSignatures(string functionName)
internal static FunctionSignatureWithReturnType[] GetUriFunctionSignatures(string functionName)
{
// Try to find the function in our built-in functions
FunctionSignatureWithReturnType[] signatures;
if (!BuiltInFunctions.TryGetBuiltInFunction(functionName, out signatures))

// Try to find the function in the user custom functions
if (!CustomUriFunctions.TryGetCustomFunction(functionName, out signatures))
{
throw new ODataException(ODataErrorStrings.MetadataBinder_UnknownFunction(functionName));
// Try to find the function in our built-in functionn
if (!BuiltInUriFunctions.TryGetBuiltInFunction(functionName, out signatures))
{
throw new ODataException(ODataErrorStrings.MetadataBinder_UnknownFunction(functionName));
}
}

return signatures;
Expand Down Expand Up @@ -262,7 +268,7 @@ private QueryNode BindAsBuiltInFunction(FunctionCallToken functionCallToken, Lis
}

// Do some validation and get potential built-in functions that could match what we saw
FunctionSignatureWithReturnType[] signatures = GetBuiltInFunctionSignatures(functionCallTokenName);
FunctionSignatureWithReturnType[] signatures = GetUriFunctionSignatures(functionCallTokenName);
SingleValueNode[] argumentNodeArray = ValidateArgumentsAreSingleValue(functionCallTokenName, argumentNodes);
FunctionSignatureWithReturnType signature = MatchSignatureToBuiltInFunction(functionCallTokenName, argumentNodeArray, signatures);
if (signature.ReturnType != null)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//---------------------------------------------------------------------
// <copyright file="BuiltInFunctions.cs" company="Microsoft">
// <copyright file="BuiltInUriFunctions.cs" company="Microsoft">
// Copyright (C) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
// </copyright>
//---------------------------------------------------------------------
Expand All @@ -20,9 +20,9 @@ namespace Microsoft.OData.Core.UriParser
#endregion Namespaces

/// <summary>
/// Class containing definitions of all the built-in functions.
/// Class containing definitions of all the built-in functions in OData Protocol.
/// </summary>
internal static class BuiltInFunctions
internal static class BuiltInUriFunctions
{
/// <summary>
/// Dictionary of the name of the built-in function and all the signatures.
Expand All @@ -42,47 +42,6 @@ internal static bool TryGetBuiltInFunction(string name, out FunctionSignatureWit
return builtInFunctions.TryGetValue(name, out signatures);
}

/// <summary>Builds a description of a list of function signatures.</summary>
/// <param name="name">Function name.</param>
/// <param name="signatures">Function signatures.</param>
/// <returns>A string with ';'-separated list of function signatures.</returns>
internal static string BuildFunctionSignatureListDescription(string name, IEnumerable<FunctionSignature> signatures)
{
Debug.Assert(name != null, "name != null");
Debug.Assert(signatures != null, "signatures != null");

StringBuilder builder = new StringBuilder();
string descriptionSeparator = "";
foreach (FunctionSignatureWithReturnType signature in signatures)
{
builder.Append(descriptionSeparator);
descriptionSeparator = "; ";

string parameterSeparator = "";
builder.Append(name);
builder.Append('(');
foreach (IEdmTypeReference type in signature.ArgumentTypes)
{
builder.Append(parameterSeparator);
parameterSeparator = ", ";

if (type.IsODataPrimitiveTypeKind() && type.IsNullable)
{
builder.Append(type.FullName());
builder.Append(" Nullable=true");
}
else
{
builder.Append(type.FullName());
}
}

builder.Append(')');
}

return builder.ToString();
}

/// <summary>
/// Creates all of the spatial functions
/// </summary>
Expand Down
Loading

0 comments on commit 174da80

Please sign in to comment.