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()); }
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()); }