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()); }
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()); }
public SourceText GetStoredProcedureText(Definition.Schema schema, List <Definition.StoredProcedure> storedProcedures) { var entityName = storedProcedures.First().EntityName; var rootDir = _output.GetOutputRootDir(); var fileContent = File.ReadAllText(Path.Combine(rootDir.FullName, "DataContext", "StoredProcedures", "StoredProcedureExtensions.cs")); var tree = CSharpSyntaxTree.ParseText(fileContent); var root = tree.GetCompilationUnitRoot(); // If its an extension, add usings for the lib if (_configFile.Config.Project.Role.Kind == ERoleKind.Extension) { var libUsingDirective = SyntaxFactory.UsingDirective(SyntaxFactory.ParseName($"{_configFile.Config.Project.Role.LibNamespace}")); root = root.AddUsings(libUsingDirective).NormalizeWhitespace(); var libModelUsingDirective = SyntaxFactory.UsingDirective(SyntaxFactory.ParseName($"{_configFile.Config.Project.Role.LibNamespace}.Models")); root = root.AddUsings(libModelUsingDirective).NormalizeWhitespace(); var libOutputsUsingDirective = SyntaxFactory.UsingDirective(SyntaxFactory.ParseName($"{_configFile.Config.Project.Role.LibNamespace}.Outputs")); root = root.AddUsings(libOutputsUsingDirective).NormalizeWhitespace(); } else { // For libs and default projects // Add Using for common Models (e.g. CrudResult) if (storedProcedures.Any(i => i.ReadWriteKind == Definition.ReadWriteKindEnum.Write)) { for (var i = 0; i < root.Usings.Count; i++) { var usingDirective = root.Usings[i]; var newUsingName = _configFile.Config.Project.Role.Kind == ERoleKind.Lib ? SyntaxFactory.ParseName($"{usingDirective.Name.ToString().Replace("Source.DataContext", _configFile.Config.Project.Output.Namespace)}") : SyntaxFactory.ParseName($"{usingDirective.Name.ToString().Replace("Source", _configFile.Config.Project.Output.Namespace)}"); root = root.ReplaceNode(usingDirective, usingDirective.WithName(newUsingName)); } } } // Add Using for Models // TODO: i.Output?.Count() -> Implement a Property "IsScalar" and "IsJson" if (storedProcedures.Any(i => i.ReadWriteKind == Definition.ReadWriteKindEnum.Read && i.Output?.Count() > 1)) { var modelUsingDirective = _configFile.Config.Project.Role.Kind == ERoleKind.Lib ? SyntaxFactory.UsingDirective(SyntaxFactory.ParseName($"{_configFile.Config.Project.Output.Namespace}.Models.{schema.Name}")) : SyntaxFactory.UsingDirective(SyntaxFactory.ParseName($"{_configFile.Config.Project.Output.Namespace}.DataContext.Models.{schema.Name}")); root = root.AddUsings(modelUsingDirective).NormalizeWhitespace(); } // Add Usings for Inputs if (storedProcedures.Any(s => s.HasInputs())) { var inputUsingDirective = _configFile.Config.Project.Role.Kind == ERoleKind.Lib ? SyntaxFactory.UsingDirective(SyntaxFactory.ParseName($"{_configFile.Config.Project.Output.Namespace}.Inputs.{schema.Name}")) : SyntaxFactory.UsingDirective(SyntaxFactory.ParseName($"{_configFile.Config.Project.Output.Namespace}.DataContext.Inputs.{schema.Name}")); root = root.AddUsings(inputUsingDirective.NormalizeWhitespace().WithLeadingTrivia(SyntaxFactory.CarriageReturnLineFeed)).WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed); } // Add Usings for Outputs if (storedProcedures.Any(s => s.HasOutputs() && !s.IsDefaultOutput())) { var inputUsingDirective = _configFile.Config.Project.Role.Kind == ERoleKind.Lib ? SyntaxFactory.UsingDirective(SyntaxFactory.ParseName($"{_configFile.Config.Project.Output.Namespace}.Outputs.{schema.Name}")) : SyntaxFactory.UsingDirective(SyntaxFactory.ParseName($"{_configFile.Config.Project.Output.Namespace}.DataContext.Outputs.{schema.Name}")); root = root.AddUsings(inputUsingDirective.NormalizeWhitespace().WithLeadingTrivia(SyntaxFactory.CarriageReturnLineFeed)).WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed); } // Add Usings for TableTypes // If Inputs contains a TableType, add using for TableTypes var tableTypeSchemas = storedProcedures.SelectMany(sp => sp.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)); 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.NormalizeWhitespace().WithLeadingTrivia(SyntaxFactory.CarriageReturnLineFeed)).WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed); } // Remove Template Usings var usings = root.Usings.Where(_ => !_.Name.ToString().StartsWith("Source.")); root = root.WithUsings(new SyntaxList <UsingDirectiveSyntax>(usings)); // 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("StoredProcedure", entityName)); var nsNode = (NamespaceDeclarationSyntax)root.Members[0]; var classNode = (ClassDeclarationSyntax)nsNode.Members[0]; // Generate Methods foreach (var storedProcedure in storedProcedures) { nsNode = (NamespaceDeclarationSyntax)root.Members[0]; classNode = (ClassDeclarationSyntax)nsNode.Members[0]; // Extension for IAppDbContextPipe var originMethodNode = (MethodDeclarationSyntax)classNode.Members[0]; originMethodNode = GenerateStoredProcedureMethodText(originMethodNode, storedProcedure); root = root.AddMethod(ref classNode, originMethodNode); nsNode = (NamespaceDeclarationSyntax)root.Members[0]; classNode = (ClassDeclarationSyntax)nsNode.Members[0]; // Overloaded extension with IAppDbContext var overloadOptionsMethodNode = (MethodDeclarationSyntax)classNode.Members[1]; overloadOptionsMethodNode = GenerateStoredProcedureMethodText(overloadOptionsMethodNode, storedProcedure, true); root = root.AddMethod(ref classNode, overloadOptionsMethodNode); } // Remove template Method nsNode = (NamespaceDeclarationSyntax)root.Members[0]; classNode = (ClassDeclarationSyntax)nsNode.Members[0]; root = root.ReplaceNode(classNode, classNode.WithMembers(new SyntaxList <MemberDeclarationSyntax>(classNode.Members.Cast <MethodDeclarationSyntax>().Skip(2)))); return(root.NormalizeWhitespace().GetText()); }
public SourceText GetTableTypeText(Definition.Schema schema, Definition.TableType tableType) { var rootDir = _output.GetOutputRootDir(); var fileContent = File.ReadAllText(Path.Combine(rootDir.FullName, "DataContext", "TableTypes", "TableType.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)); } // If its an extension, add usings for the lib if (_configFile.Config.Project.Role.Kind == ERoleKind.Extension) { var libModelUsingDirective = SyntaxFactory.UsingDirective(SyntaxFactory.ParseName($"{_configFile.Config.Project.Role.LibNamespace}.TableTypes")); root = root.AddUsings(libModelUsingDirective).NormalizeWhitespace(); } var nsNode = (NamespaceDeclarationSyntax)root.Members[0]; // Replace ClassName var classNode = (ClassDeclarationSyntax)nsNode.Members[0]; var classIdentifier = SyntaxFactory.ParseToken($"{classNode.Identifier.ValueText.Replace("TableType", $"{GetTypeNameForTableType(tableType)}")} "); classNode = classNode.WithIdentifier(classIdentifier); root = root.ReplaceNode(nsNode, nsNode.AddMembers(classNode)); // Create Properties if (tableType.Columns != null) { foreach (var column in tableType.Columns) { nsNode = (NamespaceDeclarationSyntax)root.Members[0]; classNode = (ClassDeclarationSyntax)nsNode.Members[1]; var propertyNode = (PropertyDeclarationSyntax)classNode.Members[0]; var propertyIdentifier = SyntaxFactory.ParseToken($" {column.Name} "); propertyNode = propertyNode .WithType(ParseTypeFromSqlDbTypeName(column.SqlTypeName, column.IsNullable ?? false)); propertyNode = propertyNode .WithIdentifier(propertyIdentifier); // Add Attribute for NVARCHAR with MaxLength if (column.SqlTypeName.Equals(SqlDbType.NVarChar.ToString(), StringComparison.InvariantCultureIgnoreCase) && column.MaxLength.HasValue) { var attributes = propertyNode.AttributeLists.Add( SyntaxFactory.AttributeList(SyntaxFactory.SingletonSeparatedList <AttributeSyntax>( SyntaxFactory.Attribute(SyntaxFactory.IdentifierName("MaxLength"), SyntaxFactory.ParseAttributeArgumentList($"({column.MaxLength})")) )).NormalizeWhitespace()); propertyNode = propertyNode.WithAttributeLists(attributes); } root = root.AddProperty(ref classNode, propertyNode); } } // Remove template Property nsNode = (NamespaceDeclarationSyntax)root.Members[0]; classNode = (ClassDeclarationSyntax)nsNode.Members[1]; root = root.ReplaceNode(classNode, classNode.WithMembers(new SyntaxList <MemberDeclarationSyntax>(classNode.Members.Cast <PropertyDeclarationSyntax>().Skip(1)))); // Remove template Class nsNode = (NamespaceDeclarationSyntax)root.Members[0]; root = root.ReplaceNode(nsNode, nsNode.WithMembers(new SyntaxList <MemberDeclarationSyntax>(nsNode.Members.Cast <ClassDeclarationSyntax>().Skip(1)))); return(root.NormalizeWhitespace().GetText()); }