private static void BuildFilterWithBinaryOperator() { var personTypeRef = new EdmEntityTypeReference(TripPinModel.Person, false); var friendsProp = (IEdmNavigationProperty)TripPinModel.Person.FindProperty("Friends"); var firstNameProp = TripPinModel.Person.FindProperty("FirstName"); var lastNameProp = TripPinModel.Person.FindProperty("LastName"); var topIt = new EntityRangeVariable("$it", personTypeRef, TripPinModel.PeopleSet); var topItRef = new EntityRangeVariableReferenceNode("$it", topIt); var friendsNavNode = new CollectionNavigationNode(friendsProp, topItRef); var e0 = new EntityRangeVariable("e0", personTypeRef, friendsNavNode); var e0Ref = new EntityRangeVariableReferenceNode("e0", e0); var fun1 = new SingleValueFunctionCallNode( "startswith", new QueryNode[] { new SingleValuePropertyAccessNode(e0Ref, firstNameProp), new ConstantNode("var1", "'var1'") }, EdmCoreModel.Instance.GetBoolean(false)); var friendsNavNode2 = new CollectionNavigationNode(friendsProp, e0Ref); var e1 = new EntityRangeVariable("e1", personTypeRef, friendsNavNode2); var e1Ref = new EntityRangeVariableReferenceNode("e1", e1); var fun2 = new SingleValueFunctionCallNode( "contains", new QueryNode[] { new SingleValuePropertyAccessNode(e1Ref, lastNameProp), new ConstantNode("var2", "'var2'") }, EdmCoreModel.Instance.GetBoolean(false)); // Actually $it also needed, but would not be used in UriBuilder, so omit it here. var any2 = new AnyNode(new Collection<RangeVariable> { e1 }, e1) { Body = fun2, Source = friendsNavNode2 }; var any1 = new AnyNode(new Collection<RangeVariable> { e0 }, e0) { Body = new BinaryOperatorNode(BinaryOperatorKind.And, fun1, any2), Source = friendsNavNode }; var odataUri = new ODataUri { Path = new ODataPath(new EntitySetSegment(TripPinModel.PeopleSet)), ServiceRoot = TripPinRoot, Filter = new FilterClause(any1, topIt) }; var builder = new ODataUriBuilder(ODataUrlConventions.Default, odataUri); Console.WriteLine(builder.BuildUri()); // http://services.odata.org/V4/TripPinService/People?$filter=Friends%2Fany( // e0:startswith(e0%2FFirstName%2C'var1') and e0%2FFriends%2Fany(e1:contains(e1%2FLastName%2C'var2'))) }
public static AndConstraint <SingleValueFunctionCallNode> ShouldBeSingleValueFunctionCallQueryNode(this QueryNode token, string name, IEdmTypeReference returnType = null) { token.Should().BeOfType <SingleValueFunctionCallNode>(); SingleValueFunctionCallNode functionCallNode = token.As <SingleValueFunctionCallNode>(); functionCallNode.Name.Should().Be(name); if (returnType != null) { functionCallNode.TypeReference.ShouldBeEquivalentTo(returnType); } return(new AndConstraint <SingleValueFunctionCallNode>(functionCallNode)); }
public void TranslatorShouldTranslateIsOfFunctionCallWithImplicitParameter() { ConstantNode constantNode; var testSubjectWithResourceTypeLiteral = CreateTestSubjectWithResourceTypeStringLiteral(out constantNode); QueryNode node = new SingleValueFunctionCallNode("isof", new[] { constantNode }, null); var result = testSubjectWithResourceTypeLiteral.TranslateNode(node); var expected = Expression.TypeIs(this.implicitParameterExpression, typeof(Customer)); CompareExpressions(expected, result); }
public void ArgumentsAreSetCorrectly() { QueryNode[] args = new QueryNode[] { new ConstantNode(1), new ConstantNode(2), new ConstantNode(3), new ConstantNode(4), new ConstantNode(5) }; SingleValueFunctionCallNode singleValueFunction = new SingleValueFunctionCallNode("stuff", args, EdmCoreModel.Instance.GetInt32(true)); singleValueFunction.Parameters.Should().BeEquivalentTo(args); }
private static Expression CastFunction(SingleValueFunctionCallNode nodeIn, List <Expression> expressions) { EdmPrimitiveTypeKind primitiveKind = nodeIn.TypeReference.PrimitiveKind(); if (primitiveKind == EdmPrimitiveTypeKind.DateTimeOffset && expressions[0].Type == typeof(DateTime)) { return(expressions[0]); } Type clrType = ModelBuilder.PrimitiveTypeHelper.GetClrType(primitiveKind); return(Expression.Convert(expressions[0], clrType)); }
/// <summary> /// Binds a 'time' function to create a LINQ <see cref="Expression"/>. /// </summary> /// <param name="node">The query node to bind.</param> /// <param name="context">The query binder context.</param> /// <returns>The LINQ <see cref="Expression"/> created.</returns> protected virtual Expression BindTime(SingleValueFunctionCallNode node, QueryBinderContext context) { CheckArgumentNull(node, context, "time"); Expression[] arguments = BindArguments(node.Parameters, context); // We should support DateTime & DateTimeOffset even though DateTime is not part of OData v4 Spec. Contract.Assert(arguments.Length == 1 && ExpressionBinderHelper.IsDateOrOffset(arguments[0].Type)); // EF doesn't support new TimeOfDay(int, int, int, int), also doesn't support other property access, for example DateTimeOffset.DateTime. // Therefore, we just return the source (DateTime or DateTimeOffset). return(arguments[0]); }
private string BindSingleValueFunctionCallNode(SingleValueFunctionCallNode singleValueFunctionCallNode, ICollection <BinderNode> nodes) { var arguments = singleValueFunctionCallNode.Parameters.ToList(); switch (singleValueFunctionCallNode.Name) { case "concat": return(singleValueFunctionCallNode.Name + "(" + Bind(arguments[0], nodes) + "," + Bind(arguments[1], nodes) + ")"); default: return(singleValueFunctionCallNode.Name + "(" + Bind(arguments[0], nodes) + ")"); } }
public static SingleValueFunctionCallNode ShouldBeSingleValueFunctionCallQueryNode(this QueryNode node, string name, IEdmTypeReference returnType = null) { Assert.NotNull(node); SingleValueFunctionCallNode functionCallNode = Assert.IsType <SingleValueFunctionCallNode>(node); Assert.Equal(name, functionCallNode.Name); if (returnType != null) { Assert.True(functionCallNode.TypeReference.IsEquivalentTo(returnType)); } return(functionCallNode); }
public override FilterNode <ClrValue> Visit(SingleValueFunctionCallNode nodeIn) { var fieldNode = nodeIn.Parameters.ElementAt(0); if (string.Equals(nodeIn.Name, "empty", StringComparison.OrdinalIgnoreCase)) { return(ClrFilter.Empty(PropertyPathVisitor.Visit(fieldNode))); } if (string.Equals(nodeIn.Name, "empty", StringComparison.OrdinalIgnoreCase)) { return(ClrFilter.Empty(PropertyPathVisitor.Visit(fieldNode))); } if (string.Equals(nodeIn.Name, "exists", StringComparison.OrdinalIgnoreCase)) { return(ClrFilter.Exists(PropertyPathVisitor.Visit(fieldNode))); } var valueNode = nodeIn.Parameters.ElementAt(1); if (string.Equals(nodeIn.Name, "matchs", StringComparison.OrdinalIgnoreCase)) { var value = ConstantWithTypeVisitor.Visit(valueNode); return(ClrFilter.Matchs(PropertyPathVisitor.Visit(fieldNode), value)); } if (string.Equals(nodeIn.Name, "endswith", StringComparison.OrdinalIgnoreCase)) { var value = ConstantWithTypeVisitor.Visit(valueNode); return(ClrFilter.EndsWith(PropertyPathVisitor.Visit(fieldNode), value)); } if (string.Equals(nodeIn.Name, "startswith", StringComparison.OrdinalIgnoreCase)) { var value = ConstantWithTypeVisitor.Visit(valueNode); return(ClrFilter.StartsWith(PropertyPathVisitor.Visit(fieldNode), value)); } if (string.Equals(nodeIn.Name, "contains", StringComparison.OrdinalIgnoreCase)) { var value = ConstantWithTypeVisitor.Visit(valueNode); return(ClrFilter.Contains(PropertyPathVisitor.Visit(fieldNode), value)); } throw new NotSupportedException(); }
/// <summary> /// Binds a 'isof' function to create a LINQ <see cref="Expression"/>. /// </summary> /// <param name="node">The query node to bind.</param> /// <param name="context">The query binder context.</param> /// <returns>The LINQ <see cref="Expression"/> created.</returns> protected virtual Expression BindIsOf(SingleValueFunctionCallNode node, QueryBinderContext context) { CheckArgumentNull(node, context, "isof"); Expression[] arguments = BindArguments(node.Parameters, context); // Edm.Boolean isof(type) or // Edm.Boolean isof(expression,type) Contract.Assert(arguments.Length == 1 || arguments.Length == 2); Expression source = arguments.Length == 1 ? context.CurrentParameter : arguments[0]; if (source == NullConstant) { return(FalseConstant); } string typeName = (string)((ConstantNode)node.Parameters.Last()).Value; IEdmType edmType = context.Model.FindType(typeName); Type clrType = null; if (edmType != null) { // bool nullable = source.Type.IsNullable(); IEdmTypeReference edmTypeReference = edmType.ToEdmTypeReference(false); clrType = context.Model.GetClrType(edmTypeReference); } if (clrType == null) { return(FalseConstant); } bool isSourcePrimitiveOrEnum = context.Model.GetEdmPrimitiveTypeReference(source.Type) != null || TypeHelper.IsEnum(source.Type); bool isTargetPrimitiveOrEnum = context.Model.GetEdmPrimitiveTypeReference(clrType) != null || TypeHelper.IsEnum(clrType); if (isSourcePrimitiveOrEnum && isTargetPrimitiveOrEnum) { if (TypeHelper.IsNullable(source.Type)) { clrType = TypeHelper.ToNullable(clrType); } } // Be caution: Type method of LINQ to Entities only supports entity type. return(Expression.Condition(Expression.TypeIs(source, clrType), TrueConstant, FalseConstant)); }
/// <summary> /// Binds 'ceiling' function to create a LINQ <see cref="Expression"/>. /// </summary> /// <param name="node">The query node to bind.</param> /// <param name="context">The query binder context.</param> /// <returns>The LINQ <see cref="Expression"/> created.</returns> protected virtual Expression BindCeiling(SingleValueFunctionCallNode node, QueryBinderContext context) { CheckArgumentNull(node, context, "ceiling"); Expression[] arguments = BindArguments(node.Parameters, context); Contract.Assert(arguments.Length == 1 && ExpressionBinderHelper.IsDoubleOrDecimal(arguments[0].Type)); MethodInfo ceiling = ExpressionBinderHelper.IsType <double>(arguments[0].Type) ? ClrCanonicalFunctions.CeilingOfDouble : ClrCanonicalFunctions.CeilingOfDecimal; return(ExpressionBinderHelper.MakeFunctionCall(ceiling, context.QuerySettings, arguments)); }
public void ArgumentsAreSetCorrectly() { QueryNode[] args = new QueryNode[] { new ConstantNode(1), new ConstantNode(2), new ConstantNode(3), new ConstantNode(4), new ConstantNode(5) }; SingleValueFunctionCallNode singleValueFunction = new SingleValueFunctionCallNode("stuff", args, EdmCoreModel.Instance.GetInt32(true)); singleValueFunction.Parameters.Should().BeEquivalentTo(args); }
/// <summary> /// Visit a SingleValueFunctionCallNode /// </summary> /// <param name="nodeIn">the node to visit</param> /// <returns>true, indicating that the node has been visited.</returns> public override bool Visit(SingleValueFunctionCallNode nodeIn) { validate(nodeIn); validate(nodeIn.TypeReference.Definition); foreach (IEdmFunction function in nodeIn.Functions) { validate(function); } foreach (QueryNode param in nodeIn.Parameters) { ValidateNode(param); } return(true); }
/// <summary> /// Translate a SingleValueFunctionCallNode. /// </summary> /// <param name="nodeIn">The node to be translated.</param> /// <returns>The translated node.</returns> public override QueryNode Visit(SingleValueFunctionCallNode nodeIn) { if (nodeIn == null) { throw Error.ArgumentNull(nameof(nodeIn)); } return(new SingleValueFunctionCallNode( nodeIn.Name, nodeIn.Functions, nodeIn.Parameters.Select(p => p.Accept(this)), nodeIn.TypeReference, nodeIn.Source == null ? null : nodeIn.Source.Accept(this))); }
private Expression BindContainsAny(SingleValueFunctionCallNode node) { var argument = Bind(node.Parameters.First()); var collection = ((IEnumerable)JsonConvert.DeserializeObject(node.Parameters.OfType <ConstantNode>().First().LiteralText, typeof(IEnumerable <>).MakeGenericType(argument.Type))).AsQueryable(); var data = Expression.Constant(collection); var anyParam = Expression.Parameter(argument.Type); var anyFunc = Expression.Lambda(Expression.Call(argument, "Contains", new Type[] { }, anyParam), anyParam); var result = Expression.Call(typeof(Queryable), "Any", new Type[] { argument.Type }, data, anyFunc); return(result); }
//private string BindNavigationPropertyNode(SingleEntityNode singleEntityNode, IEdmNavigationProperty edmNavigationProperty) //{ // return Bind(singleEntityNode) + "." + edmNavigationProperty.Name; //} private string BindSingleValueFunctionCallNode(SingleValueFunctionCallNode singleValueFunctionCallNode) { var arguments = singleValueFunctionCallNode.Parameters.ToList(); switch (singleValueFunctionCallNode.Name) { case "concat": return(singleValueFunctionCallNode.Name + "(" + Bind(arguments[0]) + "," + Bind(arguments[1]) + ")"); case "contains": return(string.Format("{0} like '%{1}%'", Bind(arguments[0]), ReplaceSQLSpecialCharacters((arguments[1] as ConstantNode).Value))); case "endswith": return(string.Format("{0} like '%{1}'", Bind(arguments[0]), ReplaceSQLSpecialCharacters((arguments[1] as ConstantNode).Value))); case "startswith": return(string.Format("{0} like '{1}%'", Bind(arguments[0]), ReplaceSQLSpecialCharacters((arguments[1] as ConstantNode).Value))); case "length": return(string.Format("len({0})", Bind(arguments[0]))); case "indexof": return(string.Format("charindex('{0}',{1}", (arguments[1] as ConstantNode).Value, Bind(arguments[0]))); case "substring": case "tolower": case "toupper": case "trim": case "year": case "years": case "month": case "months": case "day": case "days": case "hour": case "hours": case "minute": case "minutes": case "second": case "seconds": case "round": case "floor": case "ceiling": return(singleValueFunctionCallNode.Name + "(" + Bind(arguments[0]) + ")"); default: throw new NotImplementedException(); } }
/// <summary> /// Writes single value function call node to string. /// </summary> /// <param name="node">Node to write to string</param> /// <returns>String representation of node.</returns> private static string ToString(SingleValueFunctionCallNode node) { if (node != null) { return(tabHelper.Prefix + "SingleValueFunctionCallNode" + tabHelper.Indent(() => tabHelper.Prefix + "Name = " + node.Name + tabHelper.Prefix + "Return Type = " + node.TypeReference + tabHelper.Prefix + "Function = " + ToString(node.Functions) + ArgumentsToString(node.Parameters) )); } return(String.Empty); }
private IEnumerable<Customer> BindGeoIntersections(SingleValueFunctionCallNode node, IEnumerable<Customer> customers) { Debug.Assert(node.Name == "geo.intersects"); Debug.Assert(2 == node.Parameters.Count()); SingleValuePropertyAccessNode first = node.Parameters.First() as SingleValuePropertyAccessNode; ConstantNode second = node.Parameters.Last() as ConstantNode; Debug.Assert(first != null && second != null); IEdmProperty property = first.Property; GeographyPolygon polygon = second.Value as GeographyPolygon; Debug.Assert(property != null && polygon != null); return DoGeoIntersections(customers, property, polygon); }
/// <summary> /// Binds customized function to create a LINQ <see cref="Expression"/>. /// </summary> /// <param name="node">The query node to bind.</param> /// <param name="context">The query binder context.</param> /// <returns>The LINQ <see cref="Expression"/> created.</returns> protected virtual Expression BindCustomMethodExpressionOrNull(SingleValueFunctionCallNode node, QueryBinderContext context) { CheckArgumentNull(node, context); Expression[] arguments = BindArguments(node.Parameters, context); IEnumerable <Type> methodArgumentsType = arguments.Select(argument => argument.Type); // Search for custom method info that are binded to the node name MethodInfo methodInfo; if (UriFunctionsBinder.TryGetMethodInfo(node.Name, methodArgumentsType, out methodInfo)) { return(ExpressionBinderHelper.MakeFunctionCall(methodInfo, context.QuerySettings, arguments)); } return(null); }
//$filter=contains(EnterpriseName,%27NPDB%27) //$filter=startswith(EnterpriseName,%27NPDB%27) //$filter=endswith(EnterpriseName,%27NPDB%27) public SingleValueFunctionResolver(SingleValueFunctionCallNode function) { if (function != null) { var property = function.Parameters.First() as SingleValuePropertyAccessNode; var constant = function.Parameters.Last() as ConstantNode; Name = function.Name; Query = function.Kind; if (property != null && property.Property != null && constant != null && constant.Value != null) { Property = property.Property.Name; Value = constant.Value.ToString(); } } }
//$filter=contains(EnterpriseName,%27NPDB%27) //$filter=startswith(EnterpriseName,%27NPDB%27) //$filter=endswith(EnterpriseName,%27NPDB%27) public SingleValueFunctionResolver(SingleValueFunctionCallNode function) { if (function != null) { var property = function.Parameters.First() as SingleValuePropertyAccessNode; var constant = function.Parameters.Last() as ConstantNode; Name = function.Name; Query = function.Kind; if (property != null && property.Property != null && constant != null && constant.Value != null) { Property = property.Property.Name; Value = constant.Value.ToString(); } } }
private IEnumerable <Customer> BindGeoIntersections(SingleValueFunctionCallNode node, IEnumerable <Customer> customers) { Debug.Assert(node.Name == "geo.intersects"); Debug.Assert(2 == node.Parameters.Count()); SingleValuePropertyAccessNode first = node.Parameters.First() as SingleValuePropertyAccessNode; ConstantNode second = node.Parameters.Last() as ConstantNode; Debug.Assert(first != null && second != null); IEdmProperty property = first.Property; GeographyPolygon polygon = second.Value as GeographyPolygon; Debug.Assert(property != null && polygon != null); return(DoGeoIntersections(customers, property, polygon)); }
private static Condition BindSingleValueFunctionCallNode(SingleValueFunctionCallNode singleValueFunctionCallNode) { switch (singleValueFunctionCallNode.Name) { case "startswith": return(BindStartsWith(singleValueFunctionCallNode)); case "endswith": return(BindEndsWith(singleValueFunctionCallNode)); case "substringof": return(BindSubstringof(singleValueFunctionCallNode)); default: throw new NotSupportedException(string.Format("Function call {0} isn't supported.", singleValueFunctionCallNode.Name)); } }
/// <summary> /// Binds time related functions to create a LINQ <see cref="Expression"/>. /// </summary> /// <param name="node">The query node to bind.</param> /// <param name="context">The query binder context.</param> /// <returns>The LINQ <see cref="Expression"/> created.</returns> protected virtual Expression BindTimeRelatedProperty(SingleValueFunctionCallNode node, QueryBinderContext context) { CheckArgumentNull(node, context); Expression[] arguments = BindArguments(node.Parameters, context); Contract.Assert(arguments.Length == 1 && ExpressionBinderHelper.IsTimeRelated(arguments[0].Type)); // We should support DateTime & DateTimeOffset even though DateTime is not part of OData v4 Spec. Expression parameter = arguments[0]; PropertyInfo property; if (ExpressionBinderHelper.IsTimeOfDay(parameter.Type)) { Contract.Assert(ClrCanonicalFunctions.TimeOfDayProperties.ContainsKey(node.Name)); property = ClrCanonicalFunctions.TimeOfDayProperties[node.Name]; } #if NET6_0 else if (parameter.Type.IsTimeOnly()) { Contract.Assert(ClrCanonicalFunctions.TimeOnlyProperties.ContainsKey(node.Name)); property = ClrCanonicalFunctions.TimeOnlyProperties[node.Name]; } #endif else if (ExpressionBinderHelper.IsDateTime(parameter.Type)) { Contract.Assert(ClrCanonicalFunctions.DateTimeProperties.ContainsKey(node.Name)); property = ClrCanonicalFunctions.DateTimeProperties[node.Name]; } else if (ExpressionBinderHelper.IsTimeSpan(parameter.Type)) { Contract.Assert(ClrCanonicalFunctions.TimeSpanProperties.ContainsKey(node.Name)); property = ClrCanonicalFunctions.TimeSpanProperties[node.Name]; } else { Contract.Assert(ClrCanonicalFunctions.DateTimeOffsetProperties.ContainsKey(node.Name)); property = ClrCanonicalFunctions.DateTimeOffsetProperties[node.Name]; } return(ExpressionBinderHelper.MakeFunctionCall(property, context.QuerySettings, parameter)); }
/* * [EnableQuery] * public IHttpActionResult Get() * { * return Ok(db.Customers); * }*/ public IHttpActionResult Get(ODataQueryOptions <Customer> options) { IList <Customer> customers = db.Customers.ToList(); FilterQueryOption filter = options.Filter; FilterClause filterClause = filter.FilterClause; SingleValueFunctionCallNode functionCall = filterClause.Expression as SingleValueFunctionCallNode; if (functionCall != null) { if (functionCall.Name == "geo.intersects") { customers = BindGeoIntersections(functionCall, customers).ToList(); } } return(Ok(customers)); }
public override Expression BindSingleValueFunctionCallNode(SingleValueFunctionCallNode node) { if (node.Name == "containsany") { return(BindContainsAny(node)); } if (node.Name == "incollection") { return(BindInCollection(node)); } if (node.Name == "notincollection") { return(BindNotInCollection(node)); } var exp = base.BindSingleValueFunctionCallNode(node); return(exp); }
/// <summary> /// Override this method to validate Function calls, such as 'length', 'years', etc. /// </summary> /// <remarks> /// This method is intended to be called from method overrides in subclasses. This method also supports unit-testing scenarios and is not intended to be called from user code. /// Call the Validate method to validate a <see cref="FilterQueryOption"/> instance. /// </remarks> /// <param name="node"></param> /// <param name="settings"></param> public virtual void ValidateSingleValueFunctionCallNode(SingleValueFunctionCallNode node, ODataValidationSettings settings) { if (node == null) { throw Error.ArgumentNull("node"); } if (settings == null) { throw Error.ArgumentNull("settings"); } ValidateFunction(node.Name, settings); foreach (QueryNode argumentNode in node.Parameters) { ValidateQueryNode(argumentNode, settings); } }
public void ArgumentsAreSetCorrectly() { QueryNode[] args = new QueryNode[] { new ConstantNode(1), new ConstantNode(2), new ConstantNode(3), new ConstantNode(4), new ConstantNode(5) }; SingleValueFunctionCallNode singleValueFunction = new SingleValueFunctionCallNode("stuff", args, EdmCoreModel.Instance.GetInt32(true)); Assert.Equal(5, singleValueFunction.Parameters.Count()); int index = 1; foreach (var parameter in singleValueFunction.Parameters) { var constantNode = Assert.IsType <ConstantNode>(parameter); Assert.Equal(index++, constantNode.Value); } }
/// <summary> /// Bind $it to the <see cref="SingleValueFunctionCallNode"/> translated string. /// </summary> /// <param name="node">node to bind.</param> /// <param name="filterClauseRangeVariable">The <see cref="FilterClause"/> range variable.</param> /// <returns>The translated string with $it binding.</returns> private string BindSingleValueFunctionCallNode(SingleValueFunctionCallNode node, ResourceRangeVariable filterClauseRangeVariable) { string translatedNode = this.TranslateNode(node); ResourceRangeVariableReferenceNode firstParameterRangeVariableNode = GetResourceRangeVariableReferenceNode(node); char[] separators = { '(', ')' }; string[] subtrings = translatedNode.Trim().Split(separators, StringSplitOptions.RemoveEmptyEntries); string withinBrackets = subtrings[1]; char[] parameterSeparators = { ',' }; string[] parameters = withinBrackets.Trim().Split(parameterSeparators, StringSplitOptions.RemoveEmptyEntries); string leftParameter = parameters[0]; string rightParameter = parameters.Length == 2 ? parameters[1] : String.Empty; if (firstParameterRangeVariableNode != null && IsDifferentSource(filterClauseRangeVariable, firstParameterRangeVariableNode)) { leftParameter = ExpressionConstants.It + ExpressionConstants.SymbolForwardSlash + leftParameter; translatedNode = parameters.Length == 1 ? subtrings[0] + '(' + leftParameter + ')' : subtrings[0] + '(' + leftParameter + ',' + rightParameter + ')'; } return(translatedNode); }
public void BuildExpandOrderby_AliasInFunction() { Uri fullUri = new Uri("http://gobbledygook/People?$expand=MyPet2Set($orderby=concat(Color, @p1 )asc )&@p1='abc'"); ODataUriParser odataUriParser = new ODataUriParser(HardCodedTestModel.TestModel, serviceRoot, fullUri); SetODataUriParserSettingsTo(this.settings, odataUriParser.Settings); odataUriParser.UrlKeyDelimiter = ODataUrlKeyDelimiter.Parentheses; ODataUri odataUri = odataUriParser.ParseUri(); IDictionary <string, SingleValueNode> aliasNodes = odataUri.ParameterAliasNodes; SingleValueFunctionCallNode node = (odataUri.SelectAndExpand.SelectedItems.First() as ExpandedNavigationSelectItem).OrderByOption.Expression as SingleValueFunctionCallNode; node.Parameters.Last().ShouldBeParameterAliasNode("@p1", EdmCoreModel.Instance.GetString(true)); aliasNodes["@p1"].ShouldBeConstantQueryNode("abc"); Uri actualUri = odataUri.BuildUri(ODataUrlKeyDelimiter.Parentheses); Assert.Equal("http://gobbledygook/People?$expand=" + Uri.EscapeDataString("MyPet2Set($orderby=concat(Color,@p1))") + "&@p1=" + Uri.EscapeDataString("'abc'"), actualUri.OriginalString); actualUri = odataUri.BuildUri(ODataUrlKeyDelimiter.Slash); Assert.Equal("http://gobbledygook/People?$expand=" + Uri.EscapeDataString("MyPet2Set($orderby=concat(Color,@p1))") + "&@p1=" + Uri.EscapeDataString("'abc'"), actualUri.OriginalString); }
/// <summary> /// We return the <see cref="ResourceRangeVariableReferenceNode"/> within a <see cref="QueryNode"/> /// </summary> /// <param name="node">The node to extract the ResourceRangeVariableReferenceNode.</param> /// <returns>The extracted ResourceRangeVariableReferenceNode.</returns> private ResourceRangeVariableReferenceNode GetResourceRangeVariableReferenceNode(QueryNode node) { switch (node.Kind) { case QueryNodeKind.SingleValuePropertyAccess: SingleValuePropertyAccessNode singleValuePropertyAccessNode = node as SingleValuePropertyAccessNode; return(GetResourceRangeVariableReferenceNode(singleValuePropertyAccessNode.Source)); case QueryNodeKind.Convert: ConvertNode convertNode = node as ConvertNode; return(GetResourceRangeVariableReferenceNode(convertNode.Source)); case QueryNodeKind.Any: AnyNode anyNode = node as AnyNode; return(GetResourceRangeVariableReferenceNode(anyNode.Source)); case QueryNodeKind.SingleValueFunctionCall: SingleValueFunctionCallNode singleValueFunctionCallNode = node as SingleValueFunctionCallNode; return(GetResourceRangeVariableReferenceNode(singleValueFunctionCallNode.Parameters.First())); case QueryNodeKind.ResourceRangeVariableReference: return(node as ResourceRangeVariableReferenceNode); case QueryNodeKind.SingleValueOpenPropertyAccess: SingleValueOpenPropertyAccessNode singleValueOpenPropertyAccessNode = node as SingleValueOpenPropertyAccessNode; return(GetResourceRangeVariableReferenceNode(singleValueOpenPropertyAccessNode.Source)); case QueryNodeKind.SingleComplexNode: SingleComplexNode singleComplexNode = node as SingleComplexNode; return(GetResourceRangeVariableReferenceNode(singleComplexNode.Source)); case QueryNodeKind.CollectionComplexNode: CollectionComplexNode collectionComplexNode = node as CollectionComplexNode; return(GetResourceRangeVariableReferenceNode(collectionComplexNode.Source)); } return(null); }
/// <summary> /// Binds 'fractionalseconds' function to create a LINQ <see cref="Expression"/>. /// </summary> /// <param name="node">The query node to bind.</param> /// <param name="context">The query binder context.</param> /// <returns>The LINQ <see cref="Expression"/> created.</returns> protected virtual Expression BindFractionalSeconds(SingleValueFunctionCallNode node, QueryBinderContext context) { CheckArgumentNull(node, context, "fractionalseconds"); Expression[] arguments = BindArguments(node.Parameters, context); Contract.Assert(arguments.Length == 1 && (ExpressionBinderHelper.IsTimeRelated(arguments[0].Type))); // We should support DateTime & DateTimeOffset even though DateTime is not part of OData v4 Spec. Expression parameter = arguments[0]; PropertyInfo property; if (ExpressionBinderHelper.IsTimeOfDay(parameter.Type)) { property = ClrCanonicalFunctions.TimeOfDayProperties[ClrCanonicalFunctions.MillisecondFunctionName]; } else if (ExpressionBinderHelper.IsDateTime(parameter.Type)) { property = ClrCanonicalFunctions.DateTimeProperties[ClrCanonicalFunctions.MillisecondFunctionName]; } else if (ExpressionBinderHelper.IsTimeSpan(parameter.Type)) { property = ClrCanonicalFunctions.TimeSpanProperties[ClrCanonicalFunctions.MillisecondFunctionName]; } else { property = ClrCanonicalFunctions.DateTimeOffsetProperties[ClrCanonicalFunctions.MillisecondFunctionName]; } // Millisecond Expression milliSecond = ExpressionBinderHelper.MakePropertyAccess(property, parameter, context.QuerySettings); Expression decimalMilliSecond = Expression.Convert(milliSecond, typeof(decimal)); Expression fractionalSeconds = Expression.Divide(decimalMilliSecond, Expression.Constant(1000m, typeof(decimal))); return(ExpressionBinderHelper.CreateFunctionCallWithNullPropagation(fractionalSeconds, arguments, context.QuerySettings)); }
private static ISparqlExpression BuildFunctionExpression(SingleValueFunctionCallNode functionOperator) { var funcName = functionOperator.Name; string[] funcNames = { "contains", "endswith", "startswith", "length", "tolower", "toupper", "substring", "replace", "concat", "indexof", "trim", "year", "day","month", "hour", "minute", "second", "now", "ceiling", "floor", "round", }; if (!funcNames.Contains(funcName)) { throw new NotImplementedException($"Function {funcName} not implemented."); } if (funcName == "now") // NOW() in sparql does not work, will generate this now in .net instead. { ISparqlExpression exp = new NowFunction(); return((new UnaryExpressionFilter(exp)).Expression); } var parameter = functionOperator.Parameters.ElementAt(0); ISparqlExpression valueTerm = null; if (parameter.GetType() == typeof(SingleValuePropertyAccessNode)) { valueTerm = new VariableTerm($"?{(parameter as SingleValuePropertyAccessNode).Property.Name}"); } else if (parameter.GetType() == typeof(SingleValueFunctionCallNode)) { valueTerm = BuildFunctionExpression(parameter as SingleValueFunctionCallNode); } if (funcName == "length") { return((new UnaryExpressionFilter(new StrLenFunction(valueTerm))).Expression); } else if (funcName == "tolower") { return((new UnaryExpressionFilter(new LCaseFunction(valueTerm))).Expression); } else if (funcName == "toupper") { return((new UnaryExpressionFilter(new UCaseFunction(valueTerm))).Expression); } else if (funcName == "year") { return((new UnaryExpressionFilter(new YearFunction(valueTerm))).Expression); } else if (funcName == "day") { return((new UnaryExpressionFilter(new DayFunction(valueTerm))).Expression); } else if (funcName == "month") { return((new UnaryExpressionFilter(new MonthFunction(valueTerm))).Expression); } else if (funcName == "hour") { return((new UnaryExpressionFilter(new HoursFunction(valueTerm))).Expression); } else if (funcName == "minute") { return((new UnaryExpressionFilter(new MinutesFunction(valueTerm))).Expression); } else if (funcName == "second") { return((new UnaryExpressionFilter(new SecondsFunction(valueTerm))).Expression); } else if (funcName == "ceiling") { return((new UnaryExpressionFilter(new CeilFunction(valueTerm))).Expression); } else if (funcName == "floor") { return((new UnaryExpressionFilter(new FloorFunction(valueTerm))).Expression); } else if (funcName == "round") { return((new UnaryExpressionFilter(new RoundFunction(valueTerm))).Expression); } else { var constant = functionOperator.Parameters.ElementAt(1) as ConstantNode; ConstantTerm constantTerm = new ConstantTerm(CreateLiteralNode(constant)); if (funcName == "contains") { return((new UnaryExpressionFilter(new ContainsFunction(valueTerm, constantTerm))).Expression); } else if (funcName == "endswith") { return((new UnaryExpressionFilter(new StrEndsFunction(valueTerm, constantTerm))).Expression); } else if (funcName == "startswith") { return((new UnaryExpressionFilter(new StrStartsFunction(valueTerm, constantTerm))).Expression); } else if (funcName == "concat") { return((new UnaryExpressionFilter(new ConcatFunction(new List <ISparqlExpression> { valueTerm, constantTerm }))).Expression); } else if (funcName == "indexof") { throw new NotImplementedException("Sparql does not have counterpart of indexof function."); } else if (funcName == "trim") { throw new NotImplementedException("Sparql needs regex to do trim."); } else if (funcName == "substring") { if (functionOperator.Parameters.Count() > 2) { var constant2 = functionOperator.Parameters.ElementAt(2) as ConstantNode; ConstantTerm constantTerm2 = new ConstantTerm(CreateLiteralNode(constant2)); return((new UnaryExpressionFilter(new SubStrFunction(valueTerm, constantTerm, constantTerm2))).Expression); } else { return((new UnaryExpressionFilter(new SubStrFunction(valueTerm, constantTerm))).Expression); } } else if (funcName == "replace") { var constant2 = functionOperator.Parameters.ElementAt(2) as ConstantNode; ConstantTerm constantTerm2 = new ConstantTerm(CreateLiteralNode(constant2)); return((new UnaryExpressionFilter(new ReplaceFunction(valueTerm, constantTerm, constantTerm2))).Expression); } } return(null); }
public void NameIsSetCorrectly() { SingleValueFunctionCallNode singleValueFunction = new SingleValueFunctionCallNode("stuff", null, EdmCoreModel.Instance.GetInt32(true)); singleValueFunction.Name.Should().Be("stuff"); }
private static void VerifySingleValueFunctionCallQueryNodesAreEqual(SingleValueFunctionCallNode expected, SingleValueFunctionCallNode actual, AssertionHandler assert) { assert.AreEqual(expected.Name, actual.Name, "The names of the functions are different."); VerifyQueryNodesAreEqual(expected.Parameters, actual.Parameters, assert); QueryTestUtils.VerifyTypesAreEqual(expected.TypeReference, actual.TypeReference, assert); }
private bool TryBindIdentifier(string identifier, IEnumerable<FunctionParameterToken> arguments, QueryNode parent, BindingState state, out QueryNode boundFunction) { boundFunction = null; IEdmType bindingType = null; var singleValueParent = parent as SingleValueNode; if (singleValueParent != null) { if (singleValueParent.TypeReference != null) { bindingType = singleValueParent.TypeReference.Definition; } } else { var collectionValueParent = parent as CollectionNode; if (collectionValueParent != null) { bindingType = collectionValueParent.CollectionType.Definition; } } if (!UriEdmHelpers.IsBindingTypeValid(bindingType)) { return false; } // All functions should be fully qualified, if they aren't they they aren't functions. // When using extension, there may be function call with unqualified name. So loose the restriction here. if (identifier.IndexOf(".", StringComparison.Ordinal) == -1 && this.Resolver.GetType() == typeof(ODataUriResolver)) { return false; } IEdmOperation operation; List<FunctionParameterToken> syntacticArguments = arguments == null ? new List<FunctionParameterToken>() : arguments.ToList(); if (!FunctionOverloadResolver.ResolveOperationFromList(identifier, syntacticArguments.Select(ar => ar.ParameterName).ToList(), bindingType, state.Model, out operation, this.Resolver)) { // TODO: FunctionOverloadResolver.ResolveOperationFromList() looks up the function by parameter names, but it shouldn't ignore parameter types. (test case ParseFilter_AliasInFunction_PropertyAsValue_TypeMismatch should fail) return false; } if (singleValueParent != null && singleValueParent.TypeReference == null) { // if the parent exists, but has no type information, then we're in open type land, and we // shouldn't go any farther. throw new ODataException(ODataErrorStrings.FunctionCallBinder_CallingFunctionOnOpenProperty(identifier)); } if (operation.IsAction()) { return false; } IEdmFunction function = (IEdmFunction)operation; // TODO: $filter $orderby parameter expression which contains complex or collection should NOT be supported in this way // but should be parsed into token tree, and binded to node tree: parsedParameters.Select(p => this.bindMethod(p)); ICollection<FunctionParameterToken> parsedParameters = HandleComplexOrCollectionParameterValueIfExists(state.Configuration.Model, function, syntacticArguments, state.Configuration.Resolver.EnableCaseInsensitive); IEnumerable<QueryNode> boundArguments = parsedParameters.Select(p => this.bindMethod(p)); boundArguments = boundArguments.ToList(); // force enumerable to run : will immediately evaluate all this.bindMethod(p). IEdmTypeReference returnType = function.ReturnType; IEdmEntitySetBase returnSet = null; var singleEntityNode = parent as SingleEntityNode; if (singleEntityNode != null) { returnSet = function.GetTargetEntitySet(singleEntityNode.NavigationSource, state.Model); } string functionName = function.FullName(); if (returnType.IsEntity()) { boundFunction = new SingleEntityFunctionCallNode(functionName, new[] { function }, boundArguments, (IEdmEntityTypeReference)returnType.Definition.ToTypeReference(), returnSet, parent); } else if (returnType.IsEntityCollection()) { IEdmCollectionTypeReference collectionTypeReference = (IEdmCollectionTypeReference)returnType; boundFunction = new EntityCollectionFunctionCallNode(functionName, new[] { function }, boundArguments, collectionTypeReference, returnSet, parent); } else if (returnType.IsCollection()) { IEdmCollectionTypeReference collectionTypeReference = (IEdmCollectionTypeReference)returnType; boundFunction = new CollectionFunctionCallNode(functionName, new[] { function }, boundArguments, collectionTypeReference, parent); } else { boundFunction = new SingleValueFunctionCallNode(functionName, new[] { function }, boundArguments, returnType, parent); } return true; }
/// <summary> /// Override this method to validate Function calls, such as 'length', 'years', etc. /// </summary> /// <remarks> /// This method is intended to be called from method overrides in subclasses. This method also supports unit-testing scenarios and is not intended to be called from user code. /// Call the Validate method to validate a <see cref="FilterQueryOption"/> instance. /// </remarks> /// <param name="node"></param> /// <param name="settings"></param> public virtual void ValidateSingleValueFunctionCallNode(SingleValueFunctionCallNode node, ODataValidationSettings settings) { if (node == null) { throw Error.ArgumentNull("node"); } if (settings == null) { throw Error.ArgumentNull("settings"); } ValidateFunction(node.Name, settings); foreach (QueryNode argumentNode in node.Arguments) { ValidateQueryNode(argumentNode, settings); } }
public static IEnumerable<FilterTestCase> BuiltInStringFunctionCallTestCases(IEdmModel model) { QueryNode[] args = new QueryNode[] { new ConstantNode("Johny"), new ConstantNode ("John" ) }; yield return new FilterTestCase { Filter = "endswith('Johny','John')", ExpectedFilterCondition = new SingleValueFunctionCallNode("endswith", args, EdmCoreModel.Instance.GetBoolean(false)) }; QueryNode[] args2 = new QueryNode[] { new ConstantNode("Johny"), new ConstantNode("John") }; SingleValueFunctionCallNode outer = new SingleValueFunctionCallNode("indexof", args2, EdmCoreModel.Instance.GetInt32(false)); yield return new FilterTestCase { Filter = "indexof('Johny','John') eq 0", ExpectedFilterCondition = new BinaryOperatorNode(BinaryOperatorKind.Equal, outer, new ConstantNode(0)) }; QueryNode[] args3 = new QueryNode[] { new ConstantNode("Johny"), new ConstantNode("John"), new ConstantNode("Vitek") }; SingleValueFunctionCallNode outer2 = new SingleValueFunctionCallNode("replace", args3, EdmCoreModel.Instance.GetString(true)); yield return new FilterTestCase { Filter = "replace('Johny','John','Vitek') eq ''", ExpectedFilterCondition = new BinaryOperatorNode(BinaryOperatorKind.Equal, outer2, new ConstantNode("")) }; QueryNode[] args4 = new QueryNode[] { new ConstantNode("Johny"), new ConstantNode("John") }; yield return new FilterTestCase { Filter = "startswith('Johny','John')", ExpectedFilterCondition = new SingleValueFunctionCallNode("startswith", args4, EdmCoreModel.Instance.GetBoolean(false)) }; QueryNode[] args5 = new QueryNode[] { new ConstantNode("Johny") }; SingleValueFunctionCallNode outer3 = new SingleValueFunctionCallNode("tolower", args5, EdmCoreModel.Instance.GetString(true)); yield return new FilterTestCase { Filter = "tolower('Johny') eq 'johny'", ExpectedFilterCondition = new BinaryOperatorNode(BinaryOperatorKind.Equal, outer3, new ConstantNode("johny")) }; QueryNode[] args6 = new QueryNode[] { new ConstantNode("Johny") }; SingleValueFunctionCallNode outer4 = new SingleValueFunctionCallNode("toupper", args6, EdmCoreModel.Instance.GetString(true)); yield return new FilterTestCase { Filter = "toupper('Johny') eq 'JOHNY'", ExpectedFilterCondition = new BinaryOperatorNode(BinaryOperatorKind.Equal, outer4, new ConstantNode("JOHNY")) }; QueryNode[] args7 = new QueryNode[] { new ConstantNode("Johny") }; SingleValueFunctionCallNode outer5 = new SingleValueFunctionCallNode("trim", args7, EdmCoreModel.Instance.GetString(true)); yield return new FilterTestCase { Filter = "trim('Johny') eq ''", ExpectedFilterCondition = new BinaryOperatorNode(BinaryOperatorKind.Equal, outer5, new ConstantNode("")) }; QueryNode[] args8 = new QueryNode[] { new ConstantNode("Johny"), new ConstantNode (3) }; SingleValueFunctionCallNode outer6 = new SingleValueFunctionCallNode("substring", args8, EdmCoreModel.Instance.GetString(true)); yield return new FilterTestCase { Filter = "substring('Johny',3) eq 'ny'", ExpectedFilterCondition = new BinaryOperatorNode(BinaryOperatorKind.Equal, outer6, new ConstantNode("ny")) }; QueryNode[] args9 = new QueryNode[] { new ConstantNode("Johny"), new ConstantNode(3), new ConstantNode(1) }; SingleValueFunctionCallNode outer7 = new SingleValueFunctionCallNode("substring", args9, EdmCoreModel.Instance.GetString(true)); yield return new FilterTestCase { Filter = "substring('Johny',3,1) eq 'n'", ExpectedFilterCondition = new BinaryOperatorNode(BinaryOperatorKind.Equal, outer7, new ConstantNode("n")) }; QueryNode[] args10 = new QueryNode[] { new ConstantNode("oh"), new ConstantNode("Johny") }; yield return new FilterTestCase { Filter = "contains('oh','Johny')", ExpectedFilterCondition = new SingleValueFunctionCallNode("contains", args10, EdmCoreModel.Instance.GetBoolean(false)) }; QueryNode[] args11 = new QueryNode[] { new ConstantNode("Johny"), new ConstantNode(" Smith") }; SingleValueFunctionCallNode outer8 = new SingleValueFunctionCallNode("concat", args11, EdmCoreModel.Instance.GetString(true)); yield return new FilterTestCase { Filter = "concat('Johny',' Smith') eq ''", ExpectedFilterCondition = new BinaryOperatorNode(BinaryOperatorKind.Equal, outer8, new ConstantNode("")) }; QueryNode[] args12 = new QueryNode[] { new ConstantNode("Johny") }; SingleValueFunctionCallNode outer9 = new SingleValueFunctionCallNode("length", args12, EdmCoreModel.Instance.GetInt32(false)); yield return new FilterTestCase { Filter = "length('Johny') gt 0", ExpectedFilterCondition = new BinaryOperatorNode(BinaryOperatorKind.GreaterThan, outer9, new ConstantNode(0)) }; }
public override void ValidateSingleValueFunctionCallNode(SingleValueFunctionCallNode node, ODataValidationSettings settings) { IncrementCount("ValidateSingleValueFunctionCallQueryNode"); base.ValidateSingleValueFunctionCallNode(node, settings); }
private string BindSingleValueFunctionCallNode(SingleValueFunctionCallNode singleValueFunctionCallNode) { var arguments = singleValueFunctionCallNode.Arguments.ToList(); switch (singleValueFunctionCallNode.Name) { case "concat": return singleValueFunctionCallNode.Name + "(" + Bind(arguments[0]) + "," + Bind(arguments[1]) + ")"; case "length": case "trim": case "year": case "years": case "month": case "months": case "day": case "days": case "hour": case "hours": case "minute": case "minutes": case "second": case "seconds": case "round": case "floor": case "ceiling": return singleValueFunctionCallNode.Name + "(" + Bind(arguments[0]) + ")"; default: throw new NotImplementedException(); } }
public void KindIsSingleValueFunctionCall() { SingleValueFunctionCallNode singleValueFunction = new SingleValueFunctionCallNode("stuff", null, EdmCoreModel.Instance.GetInt32(true)); singleValueFunction.InternalKind.Should().Be(InternalQueryNodeKind.SingleValueFunctionCall); }
/// <summary> /// Writes single value function call node to string. /// </summary> /// <param name="node">Node to write to string</param> /// <returns>String representation of node.</returns> private static string ToString(SingleValueFunctionCallNode node) { if (node != null) { return tabHelper.Prefix + "SingleValueFunctionCallNode" + tabHelper.Indent(() => tabHelper.Prefix + "Name = " + node.Name + tabHelper.Prefix + "Return Type = " + node.TypeReference + tabHelper.Prefix + "Function = " + ToString(node.Functions) + ArgumentsToString(node.Parameters) ); } return String.Empty; }
private string BindSingleValueFunctionCallNode(SingleValueFunctionCallNode singleValueFunctionCallNode) { var arguments = singleValueFunctionCallNode.Parameters.ToList(); switch (singleValueFunctionCallNode.Name) { case "concat": return singleValueFunctionCallNode.Name + "(" + Bind(arguments[0]) + "," + Bind(arguments[1]) + ")"; case "contains": return string.Format("{0} like '%{1}%'", Bind(arguments[0]), (arguments[1] as ConstantNode).Value); case "endswith": return string.Format("{0} like '%{1}'", Bind(arguments[0]), (arguments[1] as ConstantNode).Value); case "startswith": return string.Format("{0} like '{1}%'", Bind(arguments[0]), (arguments[1] as ConstantNode).Value); case "length": return string.Format("len({0})", Bind(arguments[0])); case "indexof": return string.Format("charindex('{0}',{1}", (arguments[1] as ConstantNode).Value, Bind(arguments[0])); case "substring": case "tolower": case "toupper": case "trim": case "year": case "years": case "month": case "months": case "day": case "days": case "hour": case "hours": case "minute": case "minutes": case "second": case "seconds": case "round": case "floor": case "ceiling": return singleValueFunctionCallNode.Name + "(" + Bind(arguments[0]) + ")"; default: throw new NotImplementedException(); } }
public void TypeReferenceIsSetCorrectly() { SingleValueFunctionCallNode singleValueFunction = new SingleValueFunctionCallNode("stuff", null, EdmCoreModel.Instance.GetInt32(true)); singleValueFunction.TypeReference.FullName().Should().Be(EdmCoreModel.Instance.GetInt32(true).FullName()); }
/// <summary> /// Compares custom query option query nodes. /// </summary> /// <param name="left">Left side of comparison</param> /// <param name="right">Right side of comparison</param> /// <returns>True if equal, otherwise false</returns> //private bool Compare(CustomQueryOptionNode left, CustomQueryOptionNode right) //{ // if (left.Name != right.Name) return false; // if (left.Value != right.Value) return false; // return true; //} /// <summary> /// Compares single value function call query nodes. /// </summary> /// <param name="left">Left side of comparison</param> /// <param name="right">Right side of comparison</param> /// <returns>True if equal, otherwise false</returns> private bool Compare(SingleValueFunctionCallNode left, SingleValueFunctionCallNode right) { if (left.Name != right.Name) return false; if (left.TypeReference != right.TypeReference) return false; if (left.TypeReference != right.TypeReference) return false; for (int i = 0; i < left.Parameters.Count(); ++i) { if (!this.Compare(left.Parameters.ElementAt(i), right.Parameters.ElementAt(i))) return false; } return true; }
public void ArgumentsBeConvertedToEmptyCollection() { SingleValueFunctionCallNode singleValueFunction = new SingleValueFunctionCallNode("stuff", null, EdmCoreModel.Instance.GetInt32(true)); singleValueFunction.Parameters.Should().BeEmpty(); }
/// <summary> /// Visit a SingleValueFunctionCallNode /// </summary> /// <param name="nodeIn">The node to visit</param> /// <returns>The translated expression</returns> public override Expression Visit(SingleValueFunctionCallNode nodeIn) { this.CheckArgumentNull(nodeIn, "node"); return(this.TranslateFunctionCall(nodeIn.Name, nodeIn.Parameters)); }