diff --git a/readme.md b/readme.md index 26fe90fd..264579fe 100644 --- a/readme.md +++ b/readme.md @@ -728,6 +728,29 @@ public enum ModelDiagramFormat snippet source | anchor +The entity types included in the diagram can be filtered. Foreign keys to an excluded entity type are omitted. + + + +```cs +await Verify(data.Model) + // exclude the Employee entity + .ModelDiagramFilter(_ => _.ClrType != typeof(Employee)); +``` +snippet source | anchor + + +To render only the table names, without columns: + + + +```cs +await Verify(data.Model) + .ModelAsDiagram(namesOnly: true); +``` +snippet source | anchor + + A rendered png may not be pixel identical across machines, so compare using [ssim](https://github.com/VerifyTests/Verify/blob/main/docs/comparer.md): diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 2297d5e6..1085ce18 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -2,7 +2,7 @@ CS1591;CS0649;CS8632;EF1001;NU1608;NU1109 - 16.1.2 + 16.2.0 preview 1.0.0 EntityFramework, Verify diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index ad3a3da4..58ce6941 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -6,7 +6,7 @@ - + diff --git a/src/Verify.EntityFramework.Tests/ModelDiagramTests.Filter.verified.md b/src/Verify.EntityFramework.Tests/ModelDiagramTests.Filter.verified.md new file mode 100644 index 00000000..eca8564d --- /dev/null +++ b/src/Verify.EntityFramework.Tests/ModelDiagramTests.Filter.verified.md @@ -0,0 +1,7 @@ +```mermaid +erDiagram + Companies["**Companies**"] { + int Id pk + nvarchar(max) Name + } +``` \ No newline at end of file diff --git a/src/Verify.EntityFramework.Tests/ModelDiagramTests.NamesOnly.verified.md b/src/Verify.EntityFramework.Tests/ModelDiagramTests.NamesOnly.verified.md new file mode 100644 index 00000000..a1190cb0 --- /dev/null +++ b/src/Verify.EntityFramework.Tests/ModelDiagramTests.NamesOnly.verified.md @@ -0,0 +1,6 @@ +```mermaid +erDiagram + Companies["**Companies**"] + Employees["**Employees**"] + Companies ||--o{ Employees : "FK_Employees_Companies_CompanyId" +``` \ No newline at end of file diff --git a/src/Verify.EntityFramework.Tests/ModelDiagramTests.cs b/src/Verify.EntityFramework.Tests/ModelDiagramTests.cs index e8124cd0..5204e7ea 100644 --- a/src/Verify.EntityFramework.Tests/ModelDiagramTests.cs +++ b/src/Verify.EntityFramework.Tests/ModelDiagramTests.cs @@ -30,6 +30,33 @@ await Verify(data.Model) #endregion } + [Test] + public async Task Filter() + { + await using var data = BuildData(); + + #region ModelDiagramFilter + + await Verify(data.Model) + // exclude the Employee entity + .ModelDiagramFilter(_ => _.ClrType != typeof(Employee)); + + #endregion + } + + [Test] + public async Task NamesOnly() + { + await using var data = BuildData(); + + #region ModelDiagramNamesOnly + + await Verify(data.Model) + .ModelAsDiagram(namesOnly: true); + + #endregion + } + [Test] public async Task SvgOnly() { diff --git a/src/Verify.EntityFramework/ModelDiagram.cs b/src/Verify.EntityFramework/ModelDiagram.cs index e00a64de..1cdbc263 100644 --- a/src/Verify.EntityFramework/ModelDiagram.cs +++ b/src/Verify.EntityFramework/ModelDiagram.cs @@ -5,24 +5,29 @@ namespace VerifyTests; public static class VerifyEntityFrameworkModelDiagram { const string contextKey = "EntityFramework.ModelDiagram"; + const string filterKey = "EntityFramework.ModelDiagramFilter"; + const string namesOnlyKey = "EntityFramework.ModelDiagramNamesOnly"; /// /// Select the files produced when an is verified as a Mermaid ER diagram. /// /// The settings to apply to. /// The files to produce. Can be combined, with one file verified per format. + /// When true, only the table names are rendered, without columns. public static SettingsTask ModelAsDiagram( this SettingsTask settings, - ModelDiagramFormat formats = ModelDiagramFormat.Markdown) + ModelDiagramFormat formats = ModelDiagramFormat.Markdown, + bool namesOnly = false) { - settings.CurrentSettings.ModelAsDiagram(formats); + settings.CurrentSettings.ModelAsDiagram(formats, namesOnly); return settings; } - /// + /// public static void ModelAsDiagram( this VerifySettings settings, - ModelDiagramFormat formats = ModelDiagramFormat.Markdown) + ModelDiagramFormat formats = ModelDiagramFormat.Markdown, + bool namesOnly = false) { if ((formats & ModelDiagramFormat.All) == 0) { @@ -30,8 +35,29 @@ public static void ModelAsDiagram( } settings.Context[contextKey] = formats; + settings.Context[namesOnlyKey] = namesOnly; } + /// + /// Select the entity types included when an is verified as a Mermaid ER diagram. + /// Foreign keys to an excluded entity type are omitted. + /// + /// The settings to apply to. + /// Returns true for the entity types to include. + public static SettingsTask ModelDiagramFilter( + this SettingsTask settings, + Func filter) + { + settings.CurrentSettings.ModelDiagramFilter(filter); + return settings; + } + + /// + public static void ModelDiagramFilter( + this VerifySettings settings, + Func filter) => + settings.Context[filterKey] = filter; + internal static async Task Convert(IModel model, IReadOnlyDictionary context) { var formats = ModelDiagramFormat.Markdown; @@ -40,23 +66,32 @@ internal static async Task Convert(IModel model, IReadOnlyDict formats = (ModelDiagramFormat) value; } + var namesOnly = context.TryGetValue(namesOnlyKey, out var namesOnlyValue) && + (bool) namesOnlyValue; + + Func? filter = null; + if (context.TryGetValue(filterKey, out var filterValue)) + { + filter = (Func) filterValue; + } + var targets = new List(); if (formats.HasFlag(ModelDiagramFormat.Markdown)) { - var markdown = await EfToMermaid.RenderMarkdown(model); + var markdown = await EfToMermaid.RenderMarkdown(model, filter, namesOnly); targets.Add(new("md", markdown)); } if (formats.HasFlag(ModelDiagramFormat.Svg)) { - var svg = await EfToMermaid.RenderSvg(model); + var svg = await EfToMermaid.RenderSvg(model, filter, namesOnly); targets.Add(new("svg", svg)); } if (formats.HasFlag(ModelDiagramFormat.Png)) { - var png = await EfToMermaid.RenderPng(model); + var png = await EfToMermaid.RenderPng(model, filter, namesOnly); targets.Add(new("png", new MemoryStream(png))); }