Пример #1
0
        public SourceText GetOutputTextForStoredProcedure(Definition.Schema schema, Definition.StoredProcedure storedProcedure)
        {
            var rootDir     = _output.GetOutputRootDir();
            var fileContent = File.ReadAllText(Path.Combine(rootDir.FullName, "DataContext", "Outputs", "Output.cs"));

            var tree = CSharpSyntaxTree.ParseText(fileContent);
            var root = tree.GetCompilationUnitRoot();

            // Replace Namespace
            if (_configFile.Config.Project.Role.Kind == ERoleKind.Lib)
            {
                root = root.ReplaceNamespace(ns => ns.Replace("Source.DataContext", _configFile.Config.Project.Output.Namespace).Replace("Schema", schema.Name));
            }
            else
            {
                root = root.ReplaceNamespace(ns => ns.Replace("Source", _configFile.Config.Project.Output.Namespace).Replace("Schema", schema.Name));
            }

            // Replace ClassName
            root = root.ReplaceClassName(ci => ci.Replace("Output", storedProcedure.GetOutputTypeName()));

            // Generate Properies
            // https://stackoverflow.com/questions/45160694/adding-new-field-declaration-to-class-with-roslyn
            var nsNode       = (NamespaceDeclarationSyntax)root.Members[0];
            var classNode    = (ClassDeclarationSyntax)nsNode.Members[0];
            var propertyNode = (PropertyDeclarationSyntax)classNode.Members[0];
            var outputs      = storedProcedure.Input?.Where(i => i.IsOutput).ToList() ?? new List <StoredProcedureInputModel>();

            foreach (var output in outputs)
            {
                nsNode    = (NamespaceDeclarationSyntax)root.Members[0];
                classNode = (ClassDeclarationSyntax)nsNode.Members[0];

                var propertyIdentifier = TokenHelper.Parse(output.Name);
                propertyNode = propertyNode
                               .WithType(ParseTypeFromSqlDbTypeName(output.SqlTypeName, output.IsNullable ?? false));

                propertyNode = propertyNode
                               .WithIdentifier(propertyIdentifier);

                root = root.AddProperty(ref classNode, propertyNode);
            }

            // Remove template Property
            nsNode    = (NamespaceDeclarationSyntax)root.Members[0];
            classNode = (ClassDeclarationSyntax)nsNode.Members[0];
            root      = root.ReplaceNode(classNode, classNode.WithMembers(new SyntaxList <MemberDeclarationSyntax>(classNode.Members.Cast <PropertyDeclarationSyntax>().Skip(1))));

            return(root.NormalizeWhitespace().GetText());
        }
Пример #2
0
        private MethodDeclarationSyntax GenerateStoredProcedureMethodText(MethodDeclarationSyntax methodNode, Definition.StoredProcedure storedProcedure, bool isOverload = false)
        {
            // Replace MethodName
            var methodName       = $"{storedProcedure.Name}Async";
            var methodIdentifier = SyntaxFactory.ParseToken(methodName);

            methodNode = methodNode.WithIdentifier(methodIdentifier);

            var parameters = new[] { SyntaxFactory.Parameter(SyntaxFactory.Identifier("input"))
                                     .WithType(SyntaxFactory.ParseTypeName($"{storedProcedure.Name}Input")) };

            var parameterList = methodNode.ParameterList;

            parameterList = parameterList.WithParameters(
                parameterList.Parameters.InsertRange(2, parameters).RemoveAt(1)
                );
            methodNode = methodNode.WithParameterList(parameterList);

            // Get Method Body as Statements
            var methodBody       = methodNode.Body;
            var statements       = methodBody.Statements.ToList();
            var returnExpression = (statements.Last() as ReturnStatementSyntax).Expression.GetText().ToString();

            if (isOverload)
            {
                returnExpression = returnExpression.Replace("CrudActionAsync", methodName);
            }
            else
            {
                // Generate Sql-Parameters
                var sqlParamSyntax      = (LocalDeclarationStatementSyntax)statements.Single(i => i is LocalDeclarationStatementSyntax);
                var sqlParamSyntaxIndex = statements.IndexOf(sqlParamSyntax);

                var arguments = new List <SyntaxNodeOrToken>();
                var inputs    = storedProcedure.Input.ToList();
                var lastInput = inputs.Last();
                inputs.ForEach(i =>
                {
                    var isLastItem = i == lastInput;

                    var args = new List <SyntaxNodeOrToken>();
                    args.Add(SyntaxFactory.Argument(SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(i.Name.Remove(0, 1)))));
                    args.Add(SyntaxFactory.Token(SyntaxKind.CommaToken));
                    args.Add(SyntaxFactory.Argument(SyntaxFactory.IdentifierName($"input.{GetPropertyFromSqlInputTableType(i.Name)}")));

                    if (i.IsOutput)
                    {
                        args.Add(SyntaxFactory.Token(SyntaxKind.CommaToken));
                        args.Add(SyntaxFactory.Argument(SyntaxFactory.LiteralExpression(SyntaxKind.TrueLiteralExpression)));
                    }

                    arguments.Add(SyntaxFactory.InvocationExpression(
                                      SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
                                                                           SyntaxFactory.IdentifierName("AppDbContext"),
                                                                           SyntaxFactory.IdentifierName((i.IsTableType ?? false) ? "GetCollectionParameter" : "GetParameter")))
                                  .WithArgumentList(SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList <ArgumentSyntax>(args))));

                    if (!isLastItem)
                    {
                        arguments.Add(SyntaxFactory.Token(SyntaxKind.CommaToken));
                    }
                });

                statements[sqlParamSyntaxIndex] = SyntaxFactory.LocalDeclarationStatement(SyntaxFactory.VariableDeclaration(SyntaxFactory.IdentifierName("var"))
                                                                                          .WithVariables(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.VariableDeclarator(SyntaxFactory.Identifier("parameters"))
                                                                                                                                              .WithInitializer(SyntaxFactory.EqualsValueClause(
                                                                                                                                                                   SyntaxFactory.ObjectCreationExpression(
                                                                                                                                                                       SyntaxFactory.GenericName(
                                                                                                                                                                           SyntaxFactory.Identifier("List"))
                                                                                                                                                                       .WithTypeArgumentList(SyntaxFactory.TypeArgumentList(SyntaxFactory.SingletonSeparatedList <TypeSyntax>(SyntaxFactory.IdentifierName("SqlParameter")))))
                                                                                                                                                                   .WithInitializer(SyntaxFactory.InitializerExpression(SyntaxKind.CollectionInitializerExpression,
                                                                                                                                                                                                                        SyntaxFactory.SeparatedList <ExpressionSyntax>(arguments))))))));

                methodBody = methodBody.WithStatements(new SyntaxList <StatementSyntax>(statements.Skip(2)));

                returnExpression = returnExpression.Replace("schema.CrudAction", storedProcedure.SqlObjectName);
            }

            methodNode = methodNode.WithBody(methodBody);

            // Replace ReturnType and ReturnLine
            var returnType  = "Task<CrudResult>";
            var returnModel = "CrudResult";

            if (!storedProcedure.HasResult() && storedProcedure.HasOutputs())
            {
                var outputType = storedProcedure.GetOutputTypeName();

                returnType       = $"Task<{outputType}>";
                returnExpression = returnExpression.Replace("ExecuteSingleAsync<CrudResult>", $"ExecuteAsync<{outputType}>");
            }
            else if (storedProcedure.IsScalarResult())
            {
                var output = storedProcedure.Output.FirstOrDefault();
                returnModel = ParseTypeFromSqlDbTypeName(output.SqlTypeName, output.IsNullable ?? false).ToString();

                returnType       = $"Task<{returnModel}>";
                returnExpression = returnExpression.Replace("ExecuteSingleAsync<CrudResult>", $"ReadJsonAsync");
            }
            else
            {
                switch (storedProcedure.OperationKind)
                {
                case Definition.OperationKindEnum.Find:
                case Definition.OperationKindEnum.List:
                    returnModel = storedProcedure.Name;
                    break;
                }

                switch (storedProcedure.ResultKind)
                {
                case Definition.ResultKindEnum.Single:
                    returnType       = $"Task<{returnModel}>";
                    returnExpression = returnExpression.Replace("ExecuteSingleAsync<CrudResult>", $"ExecuteSingleAsync<{returnModel}>");
                    break;

                case Definition.ResultKindEnum.List:
                    returnType       = $"Task<List<{returnModel}>>";
                    returnExpression = returnExpression.Replace("ExecuteSingleAsync<CrudResult>", $"ExecuteListAsync<{returnModel}>");
                    break;
                }
            }

            methodNode = methodNode.WithReturnType(SyntaxFactory.ParseTypeName(returnType).WithTrailingTrivia(SyntaxFactory.Space));

            var returnStatementSyntax      = statements.Single(i => i is ReturnStatementSyntax);
            var returnStatementSyntaxIndex = statements.IndexOf(returnStatementSyntax);

            statements[returnStatementSyntaxIndex] = SyntaxFactory.ReturnStatement(SyntaxFactory.ParseExpression(returnExpression).WithLeadingTrivia(SyntaxFactory.Space))
                                                     .WithLeadingTrivia(SyntaxFactory.Tab, SyntaxFactory.Tab, SyntaxFactory.Tab)
                                                     .WithTrailingTrivia(SyntaxFactory.CarriageReturn);

            methodBody = methodBody.WithStatements(new SyntaxList <StatementSyntax>(statements));
            methodNode = methodNode.WithBody(methodBody);

            return(methodNode.NormalizeWhitespace());
        }
Пример #3
0
        public SourceText GetInputTextForStoredProcedure(Definition.Schema schema, Definition.StoredProcedure storedProcedure)
        {
            var rootDir     = _output.GetOutputRootDir();
            var fileContent = File.ReadAllText(Path.Combine(rootDir.FullName, "DataContext", "Inputs", "Input.cs"));

            var tree = CSharpSyntaxTree.ParseText(fileContent);
            var root = tree.GetCompilationUnitRoot();

            // If Inputs contains a TableType, add using for TableTypes
            var schemesForTableTypes = storedProcedure.Input.Where(i => i.IsTableType ?? false)
                                       .GroupBy(t => (t.TableTypeSchemaName, t.TableTypeName), (key, group) => new
            {
                TableTypeSchemaName = key.TableTypeSchemaName,
                Result = group.First()
            }).Select(g => g.Result).ToList();

            var tableTypeSchemas = storedProcedure.Input.Where(i => i.IsTableType ?? false)
                                   .GroupBy(t => t.TableTypeSchemaName, (key, group) => key).ToList();

            foreach (var tableTypeSchema in tableTypeSchemas)
            {
                var tableTypeSchemaConfig = _configFile.Config.Schema.Find(s => s.Name.Equals(tableTypeSchema));
                // is schema of table type ignored and its an extension?
                var useFromLib = tableTypeSchemaConfig?.Status != SchemaStatusEnum.Build &&
                                 _configFile.Config.Project.Role.Kind == ERoleKind.Extension;

                var paramUsingDirective = useFromLib
                                    ? SyntaxFactory.UsingDirective(SyntaxFactory.ParseName($"{_configFile.Config.Project.Role.LibNamespace}.TableTypes.{tableTypeSchema.FirstCharToUpper()}"))
                                    : _configFile.Config.Project.Role.Kind == ERoleKind.Lib
                                        ? SyntaxFactory.UsingDirective(SyntaxFactory.ParseName($"{_configFile.Config.Project.Output.Namespace}.TableTypes.{tableTypeSchema.FirstCharToUpper()}"))
                                        : SyntaxFactory.UsingDirective(SyntaxFactory.ParseName($"{_configFile.Config.Project.Output.Namespace}.DataContext.TableTypes.{tableTypeSchema.FirstCharToUpper()}"));
                root = root.AddUsings(paramUsingDirective);
            }

            // Replace Namespace
            if (_configFile.Config.Project.Role.Kind == ERoleKind.Lib)
            {
                root = root.ReplaceNamespace(ns => ns.Replace("Source.DataContext", _configFile.Config.Project.Output.Namespace).Replace("Schema", schema.Name));
            }
            else
            {
                root = root.ReplaceNamespace(ns => ns.Replace("Source", _configFile.Config.Project.Output.Namespace).Replace("Schema", schema.Name));
            }

            // Replace ClassName
            root = root.ReplaceClassName(ci => ci.Replace("Input", $"{storedProcedure.Name}Input"));
            var nsNode    = (NamespaceDeclarationSyntax)root.Members[0];
            var classNode = (ClassDeclarationSyntax)nsNode.Members[0];


            // Create obsolete constructor
            var obsoleteContructor = classNode.CreateConstructor($"{storedProcedure.Name}Input");

            root      = root.AddObsoleteAttribute(ref obsoleteContructor, "This empty contructor will be removed in vNext. Please use constructor with parameters.");
            root      = root.AddConstructor(ref classNode, obsoleteContructor);
            nsNode    = (NamespaceDeclarationSyntax)root.Members[0];
            classNode = (ClassDeclarationSyntax)nsNode.Members[0];

            var inputs = storedProcedure.Input.Where(i => !i.IsOutput).ToList();
            // Constructor with params
            var constructor = classNode.CreateConstructor($"{storedProcedure.Name}Input");
            var parameters  = inputs.Select(input =>
            {
                return(SyntaxFactory.Parameter(SyntaxFactory.Identifier(GetIdentifierFromSqlInputTableType(input.Name)))
                       .WithType(
                           input.IsTableType ?? false
                        ? GetTypeSyntaxForTableType(input)
                        : ParseTypeFromSqlDbTypeName(input.SqlTypeName, input.IsNullable ?? false)
                           ));
            }).ToArray();

            var constructorParams = constructor.ParameterList.AddParameters(parameters);

            constructor = constructor.WithParameterList(constructorParams);

            foreach (var input in inputs)
            {
                var constructorStatement = ExpressionHelper.AssignmentStatement(TokenHelper.Parse(input.Name).ToString(), GetIdentifierFromSqlInputTableType(input.Name));
                var newStatements        = constructor.Body.Statements.Add(constructorStatement);
                constructor = constructor.WithBody(constructor.Body.WithStatements(newStatements));
            }

            root      = root.AddConstructor(ref classNode, constructor);
            nsNode    = (NamespaceDeclarationSyntax)root.Members[0];
            classNode = (ClassDeclarationSyntax)nsNode.Members[0];

            // Generate Properies
            // https://stackoverflow.com/questions/45160694/adding-new-field-declaration-to-class-with-roslyn

            foreach (var item in storedProcedure.Input)
            {
                nsNode    = (NamespaceDeclarationSyntax)root.Members[0];
                classNode = (ClassDeclarationSyntax)nsNode.Members[0];

                var isTableType  = item.IsTableType ?? false;
                var propertyType = isTableType
                    ? GetTypeSyntaxForTableType(item)
                    : ParseTypeFromSqlDbTypeName(item.SqlTypeName, item.IsNullable ?? false);

                var propertyNode = classNode.CreateProperty(propertyType, item.Name);

                if (!isTableType)
                {
                    // Add Attribute for NVARCHAR with MaxLength
                    if ((item.SqlTypeName?.Equals(SqlDbType.NVarChar.ToString(), StringComparison.InvariantCultureIgnoreCase) ?? false) &&
                        item.MaxLength.HasValue)
                    {
                        var attributes = propertyNode.AttributeLists.Add(
                            SyntaxFactory.AttributeList(SyntaxFactory.SingletonSeparatedList <AttributeSyntax>(
                                                            SyntaxFactory.Attribute(SyntaxFactory.IdentifierName("MaxLength"), SyntaxFactory.ParseAttributeArgumentList($"({item.MaxLength})"))
                                                            )).NormalizeWhitespace());

                        propertyNode = propertyNode.WithAttributeLists(attributes);
                    }
                }

                root = root.AddProperty(ref classNode, propertyNode);
            }

            return(root.NormalizeWhitespace().GetText());
        }