/// <summary> /// Checks if the node is a grouped node, and adds it to the list of grouped nodes if so. /// </summary> /// <typeparam name="T"> /// The type of the node. /// </typeparam> /// <param name="node"> /// The node. /// </param> /// <param name="baseCall"> /// The method to call when the expression is not a grouped node. /// </param> /// <returns> /// The node or the result of the <paramref name="baseCall"/>. /// </returns> private Node CheckForGroups <T>(T node, Func <T, Node> baseCall) where T : SqlExpressionBase { var isGrouping = this.select.Groupings.Contains(node); if ((this.data.GetScope(node) == NodeScope.Row) || isGrouping) { if (this.groupedNodes.IndexOf(node) == -1) { this.groupedNodes.Add(node); } var field = new FieldReferenceSqlExpression($"group{this.groupedNodes.IndexOf(node)}"); if (!isGrouping || this.visitingGroupings > 0) { return(field); } var fields = new List <SqlExpressionBase> { field, }; var result = new FunctionCallSqlExpression("$GROUP_FIRST", new ReadOnlyCollection <SqlExpressionBase>(fields)); this.data.MarkAsGroupFunction(result); this.data.SetScope(node, NodeScope.Group); this.data.SetFunction(result, new FunctionDescriptor(result.Name, false, (Expression <Func <IAsyncEnumerable <object>, Task <object> > >)(objs => objs.FirstAsync()))); return(result); } if (this.data.GetScope(node) == NodeScope.Group && node is FunctionCallSqlExpression) { this.visitingGroupings++; } var nodeResult = baseCall(node); if (this.data.GetScope(node) == NodeScope.Group && node is FunctionCallSqlExpression) { this.visitingGroupings--; } if (!ReferenceEquals(node, nodeResult)) { this.data.CopyValues(node, nodeResult); } return(nodeResult); }
/// <summary> /// Replaces strings and field references to enum values. /// </summary> /// <param name="node"> /// The node to replace values with. /// </param> /// <returns> /// The node with replaced. /// </returns> private Node ReplaceEnumArguments([NotNull] FunctionCallSqlExpression node) { var arguments = node.Arguments; var function = this.Data.GetFunction(node); for (var i = 0; i < function.Arguments.Count; i++) { var arg = arguments[i]; var param = function.Arguments[i].Type.SimplifiedType; if (!param.GetTypeInfo().IsEnum) { continue; } var constExpr = arg as ConstSqlExpression; var fieldExpr = arg as FieldReferenceSqlExpression; ConstSqlExpression enumExpr; if (fieldExpr != null && fieldExpr.Source == null) { enumExpr = new ConstSqlExpression(Enum.Parse(param, fieldExpr.Name, true)); } else if (constExpr?.Value is int) { enumExpr = new ConstSqlExpression(Enum.ToObject(param, constExpr.Value)); } else if (constExpr?.Value is string) { enumExpr = new ConstSqlExpression(Enum.Parse(param, (string)constExpr.Value, true)); } else { continue; } arguments = new ReadOnlyCollection <SqlExpressionBase>( new List <SqlExpressionBase>(arguments) { [i] = this.Data.CopyValues(arguments[i], enumExpr), }); } return(arguments != node.Arguments ? this.Data.CopyValues(node, new FunctionCallSqlExpression(node.Name, arguments)) : node); }
/// <summary> /// The visit function call async. /// </summary> /// <param name="node"> /// The node. /// </param> /// <returns> /// The <see cref="Task"/>. /// </returns> protected internal override Node VisitFunctionCallSqlExpression([NotNull] FunctionCallSqlExpression node) { var function = this.Scope.GetFunction(node.Name, node.Arguments); if (function == null) { this.AddError(node, $"Cannot find function {node.GetDisplay()}."); this.Data.SetType(node, new TypeDescriptor(typeof(object))); this.Data.SetFunction(node, this.Scope.GetFunction(node.Name, node.Arguments)); this.Data.SetScope(node, NodeScope.Constant); return(node); } var returnType = function.ReturnType.SimplifiedType.IsConstructedGenericType && function.ReturnType.SimplifiedType.GetGenericTypeDefinition() == typeof(Task <>) ? function.ReturnType.SimplifiedType.GenericTypeArguments[0] : function.ReturnType.SimplifiedType; this.Data.SetType(node, function.ReturnType); this.Data.SetFunction(node, this.Scope.GetFunction(node.Name, node.Arguments)); var result = this.ValidateChildren(this.ReplaceEnumArguments(node)); for (var i = 0; i < function.Arguments.Count; i++) { Converter.ValidateConversion(node.Arguments[i], this.Data.GetType(node.Arguments[i]).SimplifiedType, function.Arguments[i].Type.SimplifiedType); } this.Data.SetScope(node, this.Scope.IsGroupByExpression(node) || (node.Arguments.All(a => this.Data.GetScope(a) != NodeScope.Row) && node.Arguments.Any(a => this.Data.GetScope(a) == NodeScope.Group)) ? NodeScope.Group : NodeScope.Row); if (function.Arguments.Count > 0 && function.Arguments.Any(argument => argument.Type.Interfaces.Any(i => i.HasInterface(typeof(IAsyncEnumerable <>))))) { this.Data.SetScope(result, NodeScope.Group); this.Data.MarkAsGroupFunction(result); } return(result); }
protected internal override Node VisitFunctionCallSqlExpression([NotNull] FunctionCallSqlExpression node) { this.Builder.Append($"{node.Name?.ToUpperInvariant()}("); var first = true; foreach (var argument in node.Arguments) { if (!first) { this.Builder.Append(", "); } first = false; this.Visit(argument); } this.Builder.Append(")"); return(node); }
/// <summary> /// Visits a <see cref="FunctionCallSqlExpression"/> expression. /// </summary> /// <param name="node"> /// The node. /// </param> /// <returns> /// The node, or a new version of the node. /// </returns> protected internal virtual Node VisitFunctionCallSqlExpression([NotNull] FunctionCallSqlExpression node) { return(node.VisitChildren(this)); }
/// <summary> /// Initializes a new instance of the <see cref="Trigger"/> class. /// </summary> /// <param name="function"> /// The function. /// </param> public Trigger(FunctionCallSqlExpression function) { this.Function = function; }
/// <summary> /// Visits a <see cref="FunctionCallSqlExpression"/> expression. /// </summary> /// <param name="node"> /// The node. /// </param> /// <returns> /// The node, or a new version of the node. /// </returns> protected internal override Node VisitFunctionCallSqlExpression(FunctionCallSqlExpression node) { return(this.CheckForGroups(node, n => base.VisitFunctionCallSqlExpression(n))); }
/// <summary> /// Visits a <see cref="FunctionCallSqlExpression"/> expression. /// </summary> /// <param name="node"> /// The node. /// </param> /// <returns> /// The node, or a new version of the node. /// </returns> protected internal override Node VisitFunctionCallSqlExpression(FunctionCallSqlExpression node) { return(this.VisitImplementation(node) ?? base.VisitFunctionCallSqlExpression(node)); }
/// <summary> /// Initializes a new instance of the <see cref="FunctionSource"/> class. /// </summary> /// <param name="function"> /// The function. /// </param> /// <param name="alias"> /// The alias. /// </param> public FunctionSource(FunctionCallSqlExpression function, string alias) { this.Function = function; this.Alias = alias; }
/// <summary> /// Initializes a new instance of the <see cref="FunctionTarget"/> class. /// </summary> /// <param name="function"> /// The function. /// </param> public FunctionTarget(FunctionCallSqlExpression function) { this.Function = function; }
/// <summary> /// Initializes a new instance of the <see cref="UseStatement"/> class. /// </summary> /// <param name="settingFunction"> /// The expression. /// </param> /// <param name="functionName"> /// The function Uri. /// </param> public UseStatement(FunctionCallSqlExpression settingFunction, string functionName) { this.SettingFunction = settingFunction; this.FunctionName = functionName; }