private static ODataExpression ParseMemberExpression(Expression expression, string memberNames = null) { var memberExpression = expression as MemberExpression; if (memberExpression.Expression == null) { return(new ODataExpression(EvaluateStaticMember(memberExpression))); } else { var memberName = memberExpression.Member.GetMappedName(); memberNames = memberNames == null ? memberName : string.Join(".", memberName, memberNames); switch (memberExpression.Expression.NodeType) { case ExpressionType.Parameter: return(FromReference(memberNames)); case ExpressionType.Constant: return(ParseConstantExpression(memberExpression.Expression, memberNames)); case ExpressionType.MemberAccess: if (FunctionMapping.ContainsFunction(memberName, 0)) { return(FromFunction(memberName, ParseMemberExpression(memberExpression.Expression), new List <object>())); } else { return(ParseMemberExpression(memberExpression.Expression as MemberExpression, memberNames)); } default: throw Utils.NotSupportedExpression(expression); } } }
private string FormatFunction(ExpressionContext context) { FunctionMapping mapping; var adapterVersion = context.Session == null ? AdapterVersion.Default : context.Session.Adapter.AdapterVersion; if (FunctionMapping.TryGetFunctionMapping(this.Function.FunctionName, this.Function.Arguments.Count(), adapterVersion, out mapping)) { var mappedFunction = mapping.FunctionMapper(this.Function.FunctionName, _functionCaller.Format(context), this.Function.Arguments).Function; var formattedArguments = string.Join(",", (IEnumerable <object>)mappedFunction.Arguments.Select(x => FormatExpression(x, context))); return(string.Format("{0}({1})", mappedFunction.FunctionName, formattedArguments)); } else if (string.Equals(this.Function.FunctionName, ODataLiteral.Any, StringComparison.OrdinalIgnoreCase) || string.Equals(this.Function.FunctionName, ODataLiteral.All, StringComparison.OrdinalIgnoreCase)) { var formattedArguments = string.Format("x{0}:x{0}/{1}", ArgumentCounter >= 0 ? (1 + (ArgumentCounter++) % 9).ToString() : string.Empty, FormatExpression(this.Function.Arguments.First(), new ExpressionContext(context.Session, new EntityCollection(_functionCaller.Reference, context.EntityCollection)))); return(string.Format("{0}/{1}({2})", _functionCaller.Format(context), this.Function.FunctionName.ToLower(), formattedArguments)); } else { throw new NotSupportedException(string.Format("The function {0} is not supported or called with wrong number of arguments", this.Function.FunctionName)); } }
public override DynamicMetaObject BindInvokeMember( InvokeMemberBinder binder, DynamicMetaObject[] args) { if (FunctionMapping.ContainsFunction(binder.Name, args.Count())) { var expression = Expression.New(CtorWithExpressionAndExpressionFunction, new[] { Expression.Constant(this.Value), Expression.Constant(new ExpressionFunction(binder.Name, args.Select(x => x.Value))) }); return(new DynamicMetaObject( expression, BindingRestrictions.GetTypeRestriction(Expression, LimitType))); } else if (string.Equals(binder.Name, ODataLiteral.Any, StringComparison.OrdinalIgnoreCase) || string.Equals(binder.Name, ODataLiteral.All, StringComparison.OrdinalIgnoreCase)) { var expression = Expression.New(CtorWithExpressionAndExpressionFunction, new[] { Expression.Constant(this.Value), Expression.Constant(new ExpressionFunction(binder.Name, args.Select(x => x.Value))) }); return(new DynamicMetaObject( expression, BindingRestrictions.GetTypeRestriction(Expression, LimitType))); } else { return(base.BindInvokeMember(binder, args)); } }
private bool IsFunction(string objectName, ExpressionContext context) { FunctionMapping mapping; var adapterVersion = context.Session == null ? AdapterVersion.Default : context.Session.Adapter.AdapterVersion; return(FunctionMapping.TryGetFunctionMapping(objectName, 0, adapterVersion, out mapping)); }
private string FormatFunction(ExpressionContext context) { FunctionMapping mapping; var adapterVersion = context.Session == null ? AdapterVersion.Default : context.Session.Adapter.AdapterVersion; if (FunctionMapping.TryGetFunctionMapping(this.Function.FunctionName, this.Function.Arguments.Count(), adapterVersion, out mapping)) { return(FormatMappedFunction(context, mapping)); } else if (string.Equals(this.Function.FunctionName, ODataLiteral.Any, StringComparison.OrdinalIgnoreCase) || string.Equals(this.Function.FunctionName, ODataLiteral.All, StringComparison.OrdinalIgnoreCase)) { return(FormatAnyAllFunction(context)); } else if (string.Equals(this.Function.FunctionName, ODataLiteral.IsOf, StringComparison.OrdinalIgnoreCase) || string.Equals(this.Function.FunctionName, ODataLiteral.Cast, StringComparison.OrdinalIgnoreCase)) { return(FormatIsOfCastFunction(context)); } else if (string.Equals(this.Function.FunctionName, "get_Item", StringComparison.Ordinal) && this.Function.Arguments.Count == 1) { return(FormatArrayIndexFunction(context)); } else if (string.Equals(this.Function.FunctionName, "ToString", StringComparison.Ordinal) && this.Function.Arguments.Count == 0) { return(_functionCaller.Reference); } else if (_functionCaller.IsNull && this.Function.Arguments.Count == 1) { var val = this.Function.Arguments.First(); if (val.Value != null) { var formattedVal = ODataExpression.FromValue( string.Equals(this.Function.FunctionName, "ToBoolean", StringComparison.Ordinal) ? Convert.ToBoolean(val.Value) : string.Equals(this.Function.FunctionName, "ToByte", StringComparison.Ordinal) ? Convert.ToByte(val.Value) : string.Equals(this.Function.FunctionName, "ToChar", StringComparison.Ordinal) ? Convert.ToChar(val.Value) : string.Equals(this.Function.FunctionName, "ToDateTime", StringComparison.Ordinal) ? Convert.ToDateTime(val.Value) : string.Equals(this.Function.FunctionName, "ToDecimal", StringComparison.Ordinal) ? Convert.ToDecimal(val.Value) : string.Equals(this.Function.FunctionName, "ToDouble", StringComparison.Ordinal) ? Convert.ToDouble(val.Value) : string.Equals(this.Function.FunctionName, "ToInt16", StringComparison.Ordinal) ? Convert.ToInt16(val.Value) : string.Equals(this.Function.FunctionName, "ToInt32", StringComparison.Ordinal) ? Convert.ToInt32(val.Value) : string.Equals(this.Function.FunctionName, "ToInt64", StringComparison.Ordinal) ? Convert.ToInt64(val.Value) : string.Equals(this.Function.FunctionName, "ToSByte", StringComparison.Ordinal) ? Convert.ToSByte(val.Value) : string.Equals(this.Function.FunctionName, "ToSingle", StringComparison.Ordinal) ? Convert.ToSingle(val.Value) : string.Equals(this.Function.FunctionName, "ToString", StringComparison.Ordinal) ? Convert.ToString(val.Value) : string.Equals(this.Function.FunctionName, "ToUInt16", StringComparison.Ordinal) ? Convert.ToUInt16(val.Value) : string.Equals(this.Function.FunctionName, "ToUInt32", StringComparison.Ordinal) ? Convert.ToUInt32(val.Value) : string.Equals(this.Function.FunctionName, "ToUInt64", StringComparison.Ordinal) ? (object)Convert.ToUInt64(val.Value) : null); if (formattedVal.Value != null) { return(FormatExpression(formattedVal, context)); } } } throw new NotSupportedException(string.Format("The function {0} is not supported or called with wrong number of arguments", this.Function.FunctionName)); }
private string FormatFunction(ExpressionContext context) { FunctionMapping mapping; var adapterVersion = context.Session == null ? AdapterVersion.Default : context.Session.Adapter.AdapterVersion; if (FunctionMapping.TryGetFunctionMapping(this.Function.FunctionName, this.Function.Arguments.Count(), adapterVersion, out mapping)) { return(FormatMappedFunction(context, mapping)); } else if (string.Equals(this.Function.FunctionName, ODataLiteral.Any, StringComparison.OrdinalIgnoreCase) || string.Equals(this.Function.FunctionName, ODataLiteral.All, StringComparison.OrdinalIgnoreCase)) { return(FormatAnyAllFunction(context)); } else if (string.Equals(this.Function.FunctionName, ODataLiteral.IsOf, StringComparison.OrdinalIgnoreCase) || string.Equals(this.Function.FunctionName, ODataLiteral.Cast, StringComparison.OrdinalIgnoreCase)) { return(FormatIsOfCastFunction(context)); } else if (string.Equals(this.Function.FunctionName, "get_Item", StringComparison.Ordinal) && this.Function.Arguments.Count == 1) { return(FormatArrayIndexFunction(context)); } else if (string.Equals(this.Function.FunctionName, "ToString", StringComparison.Ordinal) && this.Function.Arguments.Count == 0) { return(_functionCaller.Reference); } else { throw new NotSupportedException(string.Format("The function {0} is not supported or called with wrong number of arguments", this.Function.FunctionName)); } }
public override DynamicMetaObject BindInvokeMember( InvokeMemberBinder binder, DynamicMetaObject[] args) { var expressionFunctionConstructor = typeof(ExpressionFunction).GetConstructor(new[] { typeof(string), typeof(IEnumerable <object>) }); if (FunctionMapping.ContainsFunction(binder.Name, args.Length)) { var expression = Expression.New(CtorWithExpressionAndExpressionFunction, Expression.Convert(Expression, LimitType), Expression.New(expressionFunctionConstructor, Expression.Constant(binder.Name), Expression.NewArrayInit(typeof(object), args.Select(x => Expression.Convert(x.Expression, typeof(object)))))); return(new DynamicMetaObject( expression, BindingRestrictions.GetTypeRestriction(Expression, LimitType))); } if (string.Equals(binder.Name, ODataLiteral.Any, StringComparison.OrdinalIgnoreCase) || string.Equals(binder.Name, ODataLiteral.All, StringComparison.OrdinalIgnoreCase)) { var expression = Expression.New(CtorWithExpressionAndExpressionFunction, Expression.Convert(Expression, LimitType), Expression.New(expressionFunctionConstructor, Expression.Constant(binder.Name), Expression.NewArrayInit(typeof(object), args.Select(x => Expression.Convert(x.Expression, typeof(object)))))); return(new DynamicMetaObject( expression, BindingRestrictions.GetTypeRestriction(Expression, LimitType))); } if (string.Equals(binder.Name, ODataLiteral.IsOf, StringComparison.OrdinalIgnoreCase) || string.Equals(binder.Name, ODataLiteral.Is, StringComparison.OrdinalIgnoreCase) || string.Equals(binder.Name, ODataLiteral.Cast, StringComparison.OrdinalIgnoreCase) || string.Equals(binder.Name, ODataLiteral.As, StringComparison.OrdinalIgnoreCase)) { var functionName = string.Equals(binder.Name, ODataLiteral.Is, StringComparison.OrdinalIgnoreCase) ? ODataLiteral.IsOf : string.Equals(binder.Name, ODataLiteral.As, StringComparison.OrdinalIgnoreCase) ? ODataLiteral.Cast : binder.Name; var isNullProperty = typeof(DynamicODataExpression).GetProperty(nameof(IsNull)); var expressionFunctionArguments = Expression.Condition(Expression.MakeMemberAccess(Expression.Convert(Expression, LimitType), isNullProperty), Expression.Convert(Expression, typeof(object)), Expression.Convert(args.First().Expression, typeof(object))); var expression = Expression.New(CtorWithExpressionAndExpressionFunction, Expression.Convert(Expression, LimitType), Expression.New(expressionFunctionConstructor, Expression.Constant(functionName), Expression.NewArrayInit(typeof(object), expressionFunctionArguments))); return(new DynamicMetaObject( expression, BindingRestrictions.GetTypeRestriction(Expression, LimitType))); } return(base.BindInvokeMember(binder, args)); }
private string FormatMappedFunction(ExpressionContext context, FunctionMapping mapping) { var mappedFunction = mapping.FunctionMapper( this.Function.FunctionName, _functionCaller, this.Function.Arguments).Function; var formattedArguments = string.Join(",", (IEnumerable <object>)mappedFunction.Arguments.Select(x => FormatExpression(x, context))); return($"{mappedFunction.FunctionName}({formattedArguments})"); }
private IEnumerable <string> BuildReferencePath(List <string> segmentNames, EntityCollection entityCollection, List <string> elementNames, ExpressionContext context) { if (!elementNames.Any()) { return(segmentNames); } var objectName = elementNames.First(); if (entityCollection != null) { if (context.Session.Metadata.HasStructuralProperty(entityCollection.Name, objectName)) { var propertyName = context.Session.Metadata.GetStructuralPropertyExactName( entityCollection.Name, objectName); segmentNames.Add(propertyName); return(BuildReferencePath(segmentNames, null, elementNames.Skip(1).ToList(), context)); } else if (context.Session.Metadata.HasNavigationProperty(entityCollection.Name, objectName)) { var propertyName = context.Session.Metadata.GetNavigationPropertyExactName( entityCollection.Name, objectName); var linkName = context.Session.Metadata.GetNavigationPropertyPartnerTypeName( entityCollection.Name, objectName); var linkedEntityCollection = context.Session.Metadata.GetEntityCollection(linkName); segmentNames.Add(propertyName); return(BuildReferencePath(segmentNames, linkedEntityCollection, elementNames.Skip(1).ToList(), context)); } else if (IsFunction(objectName, context)) { var formattedFunction = FormatAsFunction(objectName, context); segmentNames.Add(formattedFunction); return(BuildReferencePath(segmentNames, null, elementNames.Skip(1).ToList(), context)); } else if (context.Session.Metadata.IsOpenType(entityCollection.Name)) { segmentNames.Add(objectName); return(BuildReferencePath(segmentNames, null, elementNames.Skip(1).ToList(), context)); } else { throw new UnresolvableObjectException(objectName, $"Invalid referenced object [{objectName}]"); } } else if (FunctionMapping.ContainsFunction(elementNames.First(), 0)) { var formattedFunction = FormatAsFunction(objectName, context); segmentNames.Add(formattedFunction); return(BuildReferencePath(segmentNames, null, elementNames.Skip(1).ToList(), context)); } else { segmentNames.AddRange(elementNames); return(BuildReferencePath(segmentNames, null, new List <string>(), context)); } }
private static FunctionDefinition CreateFunctionDefinition(string functionName, int argumentCount, string mappedFunctionName, Func <FunctionDefinition, Func <string, string, IEnumerable <object>, ODataExpression> > mapper, AdapterVersion adapterVersion = AdapterVersion.Any) { var functionCall = new ExpressionFunction.FunctionCall(functionName, argumentCount); var functionMapping = new FunctionMapping(mappedFunctionName); var function = new FunctionDefinition(functionCall, functionMapping, adapterVersion); functionMapping.FunctionMapper = mapper(function); return(function); }
private string FormatAsFunction(string objectName, ExpressionContext context) { var adapterVersion = context.Session?.Adapter.AdapterVersion ?? AdapterVersion.Default; if (FunctionMapping.TryGetFunctionMapping(objectName, 0, adapterVersion, out var mapping)) { var mappedFunction = mapping.FunctionMapper(objectName, _functionCaller, null).Function; return($"{mappedFunction.FunctionName}({FormatCallerReference()})"); } else { return(null); } }
private string FormatAsFunction(string objectName, ExpressionContext context) { FunctionMapping mapping; var adapterVersion = context.Session == null ? AdapterVersion.Default : context.Session.Adapter.AdapterVersion; if (FunctionMapping.TryGetFunctionMapping(objectName, 0, adapterVersion, out mapping)) { var mappedFunction = mapping.FunctionMapper(objectName, _functionCaller, null).Function; return(string.Format("{0}({1})", mappedFunction.FunctionName, FormatCallerReference())); } else { return(null); } }
private static ODataExpression ParseMemberExpression(Expression expression, Stack <MemberInfo> memberChain = null) { var memberExpression = expression as MemberExpression; if (memberExpression.Expression == null) { return(new ODataExpression(EvaluateStaticMember(memberExpression))); } else { memberChain ??= new Stack <MemberInfo>(); memberChain.Push(memberExpression.Member); switch (memberExpression.Expression.NodeType) { case ExpressionType.Parameter: // NOTE: Can't support ITypeCache here as we might be dealing with dynamic types/expressions var memberNames = string.Join(".", memberChain.Select(x => x.GetMappedName())); return(FromReference(memberNames)); case ExpressionType.Constant: return(ParseConstantExpression(memberExpression.Expression, memberChain)); case ExpressionType.MemberAccess: // NOTE: Can't support ITypeCache here as we might be dealing with dynamic types/expressions var memberName = memberExpression.Member.GetMappedName(); if (FunctionMapping.ContainsFunction(memberName, 0)) { return(FromFunction(memberName, ParseMemberExpression(memberExpression.Expression), new List <object>())); } else { return(ParseMemberExpression(memberExpression.Expression as MemberExpression, memberChain)); } default: throw Utils.NotSupportedExpression(expression); } } }
public override DynamicMetaObject BindGetMember(GetMemberBinder binder) { ConstructorInfo ctor; Expression[] ctorArguments; if (FunctionMapping.ContainsFunction(binder.Name, 0)) { ctor = CtorWithExpressionAndString; ctorArguments = new[] { Expression.Constant(this.Value), Expression.Constant(binder.Name) }; } else { var reference = this.HasValue && !string.IsNullOrEmpty((this.Value as ODataExpression).Reference) ? string.Join("/", (this.Value as ODataExpression).Reference, binder.Name) : binder.Name; ctor = CtorWithString; ctorArguments = new[] { Expression.Constant(reference) }; } return(new DynamicMetaObject( Expression.New(ctor, ctorArguments), BindingRestrictions.GetTypeRestriction(Expression, LimitType))); }
public override DynamicMetaObject BindGetMember(GetMemberBinder binder) { ConstructorInfo ctor; Expression[] ctorArguments; if (FunctionMapping.ContainsFunction(binder.Name, 0)) { ctor = CtorWithExpressionAndString; ctorArguments = new Expression[] { Expression.Convert(Expression, LimitType), Expression.Constant(binder.Name) }; } else { Expression <Func <bool, ODataExpression, string> > calculateReference = (hv, e) => hv && !string.IsNullOrEmpty(e.Reference) ? string.Join("/", e.Reference, binder.Name) : binder.Name; var referenceExpression = Expression.Invoke(calculateReference, Expression.Constant(HasValue), Expression.Convert(Expression, LimitType)); ctor = CtorWithString; ctorArguments = new Expression[] { referenceExpression }; } return(new DynamicMetaObject( Expression.New(ctor, ctorArguments), BindingRestrictions.GetTypeRestriction(Expression, LimitType))); }
private bool IsFunction(string objectName, ExpressionContext context) { var adapterVersion = context.Session?.Adapter.AdapterVersion ?? AdapterVersion.Default; return(FunctionMapping.TryGetFunctionMapping(objectName, 0, adapterVersion, out _)); }
public FunctionDefinition(ExpressionFunction.FunctionCall functionCall, FunctionMapping functionMapping, AdapterVersion adapterVersion = AdapterVersion.Any) { FunctionCall = functionCall; FunctionMapping = functionMapping; AdapterVersion = adapterVersion; }
private static FunctionDefinition CreateFunctionDefinition(string functionName, int argumentCount, string mappedFunctionName, Func<FunctionDefinition, Func<string, string, IEnumerable<object>, ODataExpression>> mapper, AdapterVersion adapterVersion = AdapterVersion.Any) { var functionCall = new ExpressionFunction.FunctionCall(functionName, argumentCount); var functionMapping = new FunctionMapping(mappedFunctionName); var function = new FunctionDefinition(functionCall, functionMapping, adapterVersion); functionMapping.FunctionMapper = mapper(function); return function; }
public static bool TryGetFunctionMapping(string functionName, int argumentCount, AdapterVersion adapterVersion, out FunctionMapping functionMapping) { functionMapping = null; var function = DefinedFunctions.SingleOrDefault(x => x.FunctionCall.Equals(new ExpressionFunction.FunctionCall(functionName, argumentCount)) && (x.AdapterVersion & adapterVersion) == adapterVersion); if (function != null) { functionMapping = function.FunctionMapping; } return function != null; }
public static bool TryGetFunctionMapping(string functionName, int argumentCount, AdapterVersion adapterVersion, out FunctionMapping functionMapping) { functionMapping = null; var function = DefinedFunctions.SingleOrDefault(x => x.FunctionCall.Equals(new ExpressionFunction.FunctionCall(functionName, argumentCount)) && (x.AdapterVersion & adapterVersion) == adapterVersion); if (function != null) { functionMapping = function.FunctionMapping; } return(function != null); }
public FunctionDefinition(ExpressionFunction.FunctionCall functionCall, FunctionMapping functionMapping, AdapterVersion adapterVersion = AdapterVersion.Any) { FunctionCall = functionCall; FunctionMapping = functionMapping; AdapterVersion = adapterVersion; }
private string FormatMappedFunction(ExpressionContext context, FunctionMapping mapping) { var mappedFunction = mapping.FunctionMapper( this.Function.FunctionName, _functionCaller.Format(context), this.Function.Arguments).Function; var formattedArguments = string.Join(",", (IEnumerable<object>)mappedFunction.Arguments.Select(x => FormatExpression(x, context))); return string.Format("{0}({1})", mappedFunction.FunctionName, formattedArguments); }