-
-
Notifications
You must be signed in to change notification settings - Fork 301
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* revert * More stringlength fixes
- Loading branch information
Showing
17 changed files
with
571 additions
and
381 deletions.
There are no files selected for viewing
229 changes: 221 additions & 8 deletions
229
src/Core/RevEng.Core.80/Routines/Functions/FunctionScaffolder.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,242 @@ | ||
using System.Collections.Generic; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Text; | ||
using Microsoft.EntityFrameworkCore.Design; | ||
using Microsoft.EntityFrameworkCore.Infrastructure; | ||
using Microsoft.EntityFrameworkCore.Scaffolding; | ||
using NetTopologySuite.Geometries; | ||
using RevEng.Common; | ||
using RevEng.Core.Abstractions; | ||
using RevEng.Core.Abstractions.Metadata; | ||
using RevEng.Core.Routines.Extensions; | ||
|
||
namespace RevEng.Core.Routines.Functions | ||
{ | ||
public abstract class FunctionScaffolder : RoutineScaffolder | ||
public abstract class FunctionScaffolder : IRoutineScaffolder | ||
{ | ||
#pragma warning disable SA1401 // Fields should be private | ||
internal readonly ICSharpHelper Code; | ||
internal IndentedStringBuilder Sb; | ||
#pragma warning restore SA1401 // Fields should be private | ||
private readonly IClrTypeMapper typeMapper; | ||
|
||
protected FunctionScaffolder([System.Diagnostics.CodeAnalysis.NotNull] ICSharpHelper code, IClrTypeMapper typeMapper) | ||
: base(code, typeMapper) | ||
{ | ||
ArgumentNullException.ThrowIfNull(code); | ||
|
||
Code = code; | ||
this.typeMapper = typeMapper; | ||
} | ||
|
||
public new string FileNameSuffix { get; set; } | ||
public string FileNameSuffix { get; set; } | ||
|
||
public new SavedModelFiles Save(ScaffoldedModel scaffoldedModel, string outputDir, string nameSpaceValue, bool useAsyncCalls) | ||
public SavedModelFiles Save(ScaffoldedModel scaffoldedModel, string outputDir, string nameSpaceValue, bool useAsyncCalls) | ||
{ | ||
return base.Save(scaffoldedModel, outputDir, nameSpaceValue, useAsyncCalls); | ||
ArgumentNullException.ThrowIfNull(scaffoldedModel); | ||
|
||
Directory.CreateDirectory(outputDir); | ||
|
||
var contextPath = Path.GetFullPath(Path.Combine(outputDir, scaffoldedModel.ContextFile.Path)); | ||
var path = Path.GetDirectoryName(contextPath); | ||
if (path != null) | ||
{ | ||
Directory.CreateDirectory(path); | ||
File.WriteAllText(contextPath, scaffoldedModel.ContextFile.Code, Encoding.UTF8); | ||
} | ||
|
||
var additionalFiles = new List<string>(); | ||
|
||
foreach (var entityTypeFile in scaffoldedModel.AdditionalFiles) | ||
{ | ||
var additionalFilePath = Path.Combine(outputDir, entityTypeFile.Path); | ||
var addpath = Path.GetDirectoryName(additionalFilePath); | ||
if (addpath != null) | ||
{ | ||
Directory.CreateDirectory(addpath); | ||
File.WriteAllText(additionalFilePath, entityTypeFile.Code, Encoding.UTF8); | ||
additionalFiles.Add(additionalFilePath); | ||
} | ||
} | ||
|
||
return new SavedModelFiles(contextPath, additionalFiles); | ||
} | ||
|
||
public new ScaffoldedModel ScaffoldModel(RoutineModel model, ModuleScaffolderOptions scaffolderOptions, List<string> schemas, ref List<string> errors) | ||
public ScaffoldedModel ScaffoldModel(RoutineModel model, ModuleScaffolderOptions scaffolderOptions, List<string> schemas, ref List<string> errors) | ||
{ | ||
ArgumentNullException.ThrowIfNull(model); | ||
|
||
ArgumentNullException.ThrowIfNull(errors); | ||
|
||
ArgumentNullException.ThrowIfNull(scaffolderOptions); | ||
|
||
var result = new ScaffoldedModel(); | ||
var path = string.Empty; | ||
|
||
errors.AddRange(model.Errors); | ||
|
||
schemas = schemas ?? new List<string>(); | ||
|
||
foreach (var routine in model.Routines.Where(r => string.IsNullOrEmpty(r.MappedType) && (!(r is Function f) || !f.IsScalar))) | ||
{ | ||
var i = 1; | ||
|
||
foreach (var resultSet in routine.Results) | ||
{ | ||
if (routine.NoResultSet) | ||
{ | ||
continue; | ||
} | ||
|
||
var suffix = string.Empty; | ||
if (routine.Results.Count > 1) | ||
{ | ||
suffix = $"{i++}"; | ||
} | ||
|
||
var typeName = ScaffoldHelper.GenerateIdentifierName(routine, model, Code, scaffolderOptions.UsePascalIdentifiers) + "Result" + suffix; | ||
|
||
var classContent = WriteResultClass(resultSet, scaffolderOptions, typeName, routine.Schema); | ||
|
||
if (!string.IsNullOrEmpty(routine.Schema)) | ||
{ | ||
schemas.Add($"{routine.Schema}Schema"); | ||
} | ||
|
||
path = scaffolderOptions.UseSchemaFolders | ||
? Path.Combine(routine.Schema, $"{typeName}.cs") | ||
: $"{typeName}.cs"; | ||
#if CORE90 | ||
result.AdditionalFiles.Add(new ScaffoldedFile(path, classContent)); | ||
#else | ||
result.AdditionalFiles.Add(new ScaffoldedFile | ||
{ | ||
Code = classContent, | ||
Path = path, | ||
}); | ||
#endif | ||
} | ||
} | ||
|
||
var dbContext = WriteDbContext(scaffolderOptions, model, schemas.Distinct().ToList()); | ||
|
||
path = Path.GetFullPath(Path.Combine(scaffolderOptions.ContextDir, scaffolderOptions.ContextName + $"{FileNameSuffix}.cs")); | ||
#if CORE90 | ||
result.ContextFile = new ScaffoldedFile(path, dbContext); | ||
#else | ||
result.ContextFile = new ScaffoldedFile | ||
{ | ||
Code = dbContext, | ||
Path = path, | ||
}; | ||
#endif | ||
return result; | ||
} | ||
|
||
protected abstract string WriteDbContext(ModuleScaffolderOptions scaffolderOptions, RoutineModel model, List<string> schemas); | ||
|
||
private string WriteResultClass(List<ModuleResultElement> resultElements, ModuleScaffolderOptions options, string name, string schemaName) | ||
{ | ||
return base.ScaffoldModel(model, scaffolderOptions, schemas, ref errors); | ||
var @namespace = options.ModelNamespace; | ||
|
||
Sb = new IndentedStringBuilder(); | ||
|
||
Sb.AppendLine(PathHelper.Header); | ||
|
||
if (resultElements.Exists(p => typeMapper.GetClrType(p) == typeof(Geometry))) | ||
{ | ||
Sb.AppendLine("using NetTopologySuite.Geometries;"); | ||
} | ||
|
||
Sb.AppendLine("using System;"); | ||
Sb.AppendLine("using System.Collections.Generic;"); | ||
if (options.UseDecimalDataAnnotation) | ||
{ | ||
Sb.AppendLine("using System.ComponentModel.DataAnnotations;"); | ||
} | ||
|
||
Sb.AppendLine("using System.ComponentModel.DataAnnotations.Schema;"); | ||
Sb.AppendLine(); | ||
|
||
if (options.NullableReferences) | ||
{ | ||
Sb.AppendLine("#nullable enable"); | ||
Sb.AppendLine(); | ||
} | ||
|
||
Sb.AppendLine($"namespace {@namespace}{(options.UseSchemaNamespaces ? $".{schemaName}Schema" : string.Empty)}"); | ||
Sb.AppendLine("{"); | ||
|
||
using (Sb.Indent()) | ||
{ | ||
GenerateClass(resultElements, name, options.NullableReferences, options.UseDecimalDataAnnotation, options.UsePascalIdentifiers); | ||
} | ||
|
||
Sb.AppendLine("}"); | ||
|
||
return Sb.ToString(); | ||
} | ||
|
||
private void GenerateClass(List<ModuleResultElement> resultElements, string name, bool nullableReferences, bool useDecimalDataAnnotation, bool usePascalCase) | ||
{ | ||
Sb.AppendLine($"public partial class {name}"); | ||
Sb.AppendLine("{"); | ||
|
||
using (Sb.Indent()) | ||
{ | ||
GenerateProperties(resultElements, nullableReferences, useDecimalDataAnnotation, usePascalCase); | ||
} | ||
|
||
Sb.AppendLine("}"); | ||
} | ||
|
||
private void GenerateProperties(List<ModuleResultElement> resultElements, bool nullableReferences, bool useDecimalDataAnnotation, bool usePascalCase) | ||
{ | ||
foreach (var property in resultElements.OrderBy(e => e.Ordinal)) | ||
{ | ||
var propertyNames = ScaffoldHelper.GeneratePropertyName(property.Name, Code, usePascalCase); | ||
|
||
if (property.StoreType == "decimal" && useDecimalDataAnnotation) | ||
{ | ||
Sb.AppendLine($"[Column(\"{property.Name}\", TypeName = \"{property.StoreType}({property.Precision},{property.Scale})\")]"); | ||
} | ||
else | ||
{ | ||
if (!string.IsNullOrEmpty(propertyNames.Item2)) | ||
{ | ||
Sb.AppendLine(propertyNames.Item2); | ||
} | ||
} | ||
|
||
if (useDecimalDataAnnotation | ||
&& ((property.StoreType.StartsWith("varchar", StringComparison.OrdinalIgnoreCase) | ||
Check failure on line 213 in src/Core/RevEng.Core.80/Routines/Functions/FunctionScaffolder.cs GitHub Actions / build
Check failure on line 213 in src/Core/RevEng.Core.80/Routines/Functions/FunctionScaffolder.cs GitHub Actions / build
Check failure on line 213 in src/Core/RevEng.Core.80/Routines/Functions/FunctionScaffolder.cs GitHub Actions / build
|
||
|| property.StoreType.StartsWith("nvarchar", StringComparison.OrdinalIgnoreCase)) | ||
&& property.MaxLength > 0)) | ||
{ | ||
var maxLength = property.StoreType.StartsWith("varchar", StringComparison.OrdinalIgnoreCase) ? property.MaxLength : property.MaxLength / 2; | ||
|
||
Sb.AppendLine($"[StringLength({maxLength})]"); | ||
} | ||
|
||
var propertyType = typeMapper.GetClrType(property); | ||
var nullableAnnotation = string.Empty; | ||
var defaultAnnotation = string.Empty; | ||
|
||
if (nullableReferences && !propertyType.IsValueType) | ||
{ | ||
if (property.Nullable) | ||
{ | ||
nullableAnnotation = "?"; | ||
} | ||
else | ||
{ | ||
defaultAnnotation = $" = default!;"; | ||
} | ||
} | ||
|
||
Sb.AppendLine($"public {Code.Reference(propertyType)}{nullableAnnotation} {propertyNames.Item1} {{ get; set; }}{defaultAnnotation}"); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.