示例#1
0
        /// <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);
        }
示例#2
0
        /// <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);
        }
示例#3
0
        /// <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);
        }
示例#4
0
            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);
            }
示例#5
0
 /// <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));
 }
示例#6
0
 /// <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;
 }
示例#7
0
 /// <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)));
 }
示例#8
0
 /// <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));
 }
示例#9
0
 /// <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;
 }
示例#10
0
 /// <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;
 }
示例#11
0
 /// <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;
 }