diff --git a/README.md b/README.md index 9dc1f69..c732691 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ MasterMemory === -Source Generator based Embedded Typed Readonly In-Memory Document Database for .NET and Unity. +Source Generator based Embedded Typed Readonly In-Memory Document Database for .NET and Unity. ![image](https://user-images.githubusercontent.com/46207/61031896-61890800-a3fb-11e9-86b7-84c821d347a4.png) @@ -26,6 +26,7 @@ This ensures both optimal performance and excellent usability. - [DataTable configuration](#datatable-configuration) - [MemoryDatabase/RangeView](#memorydatabaserangeview) - [Extend Table](#extend-table) +- [Relations](#relations) - [ImmutableBuilder](#immutablebuilder) - [Validator](#validator) - [Metadata](#metadata) @@ -362,7 +363,7 @@ public sealed partial class MonsterTable int maxHp; #pragma warning disable CS0649 readonly int minHp; -#pragma warning restore CS0649 +#pragma warning restore CS0649 // called after constructed partial void OnAfterConstruct() @@ -371,7 +372,7 @@ public sealed partial class MonsterTable // you can use Unsafe.AsRef to set readonly field Unsafe.AsRef(minHp) = All.Select(x => x.MaxHp).Min(); } - + // add custom method other than standard Find method public IEnumerable GetRangedMonster(int arg1) { @@ -380,6 +381,72 @@ public sealed partial class MonsterTable } ``` +Relations +--- + +You can extend table with relations. This is possible by using the `partial void OnAfterContruct(BaseMasterMemory db)`. Here is an example: + +```csharp +[MemoryTable("person_rel"), MessagePackObject(true)] +public record PersonRelation +{ + // index definition by attributes. + [PrimaryKey] public int PersonId { get; set; } + + public string Name { get; set; } +} + +[MemoryTable("person_rel_item"), MessagePackObject(true)] +public record PersonRelationItem +{ + [PrimaryKey, NonUnique] + [SecondaryKey(0), NonUnique] + public int PersonId { get; set; } + + [PrimaryKey, NonUnique] + [SecondaryKey(1), NonUnique] + public int ItemId { get; set; } +} + +[MemoryTable("relation_item"), MessagePackObject(true)] +public record RelationItem +{ + [PrimaryKey] public int ItemId { get; set; } + + public string Name { get; set; } +} +``` + +Then implement the extension method within PersonRelation table: +```csharp +public sealed partial class PersonRelationTable +{ + private MemoryDatabase _database; + + partial void OnAfterConstruct(MemoryDatabaseBase db) + { + _database = (MemoryDatabase)db; + } + + public IEnumerable GetItemsFromPerson(int personId) + { + foreach (var item in _database.PersonRelationItemTable.FindByPersonId(personId)) + { + yield return _database.RelationItemTable.FindByItemId(item.ItemId); + } + } +} +``` + +Now you can use `GetItemsFromPerson` method to get all items from a person: + +```csharp + +var items = db.PersonRelationTable.GetItemsFromPerson(1); + +// this will return "Spear", "Bow", "Axe" +``` + ImmutableBuilder --- If you want to add/modify data to loaded database, you can use `ToImmutableBuilder` method. diff --git a/sandbox/ConsoleApp/ConsoleApp.csproj b/sandbox/ConsoleApp/ConsoleApp.csproj index bf4149d..07a2056 100644 --- a/sandbox/ConsoleApp/ConsoleApp.csproj +++ b/sandbox/ConsoleApp/ConsoleApp.csproj @@ -2,7 +2,7 @@ Exe - net9.0 + net10.0 diff --git a/sandbox/GeneratorSandbox/GeneratorSandbox.csproj b/sandbox/GeneratorSandbox/GeneratorSandbox.csproj index 3b24d7d..55ae607 100644 --- a/sandbox/GeneratorSandbox/GeneratorSandbox.csproj +++ b/sandbox/GeneratorSandbox/GeneratorSandbox.csproj @@ -2,7 +2,7 @@ Exe - net9.0 + net10.0 enable enable diff --git a/sandbox/PerfTest2/PerfTest2.csproj b/sandbox/PerfTest2/PerfTest2.csproj index 71176cc..cbb6313 100644 --- a/sandbox/PerfTest2/PerfTest2.csproj +++ b/sandbox/PerfTest2/PerfTest2.csproj @@ -2,7 +2,7 @@ Exe - net9.0 + net10.0 1701;1702;NU1904 diff --git a/src/MasterMemory.SourceGenerator/GeneratorCore/ImmutableBuilderTemplate.cs b/src/MasterMemory.SourceGenerator/GeneratorCore/ImmutableBuilderTemplate.cs index 81b0877..0cd2289 100644 --- a/src/MasterMemory.SourceGenerator/GeneratorCore/ImmutableBuilderTemplate.cs +++ b/src/MasterMemory.SourceGenerator/GeneratorCore/ImmutableBuilderTemplate.cs @@ -1,12 +1,12 @@ -// ------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version: 17.0.0.0 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version: 16.0.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ namespace MasterMemory.GeneratorCore { using System.Linq; @@ -17,7 +17,7 @@ namespace MasterMemory.GeneratorCore /// /// Class to produce the template output /// - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "17.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "16.0.0.0")] public partial class ImmutableBuilderTemplate : ImmutableBuilderTemplateBase { /// @@ -25,103 +25,242 @@ public partial class ImmutableBuilderTemplate : ImmutableBuilderTemplateBase /// public virtual string TransformText() { - this.Write("// \r\n#pragma warning disable\r\n#nullable enable\r\n\r\n"); + this.Write("// \n#pragma warning disable\n#nullable enable\n\n"); + this.Write(this.ToStringHelper.ToStringWithCulture(Using)); - this.Write("\r\n\r\nnamespace "); + + #line default + #line hidden + this.Write("\n\nnamespace "); + this.Write(this.ToStringHelper.ToStringWithCulture(Namespace)); - this.Write("\r\n{\r\n public sealed class "); + + #line default + #line hidden + this.Write("\n{\n public sealed class "); + this.Write(this.ToStringHelper.ToStringWithCulture(ClassName)); - this.Write(" : ImmutableBuilderBase\r\n {\r\n "); + + #line default + #line hidden + this.Write(" : ImmutableBuilderBase\n {\n "); + this.Write(this.ToStringHelper.ToStringWithCulture(PrefixClassName)); - this.Write("MemoryDatabase memory;\r\n\r\n public "); + + #line default + #line hidden + this.Write("MemoryDatabase memory;\n\n public "); + this.Write(this.ToStringHelper.ToStringWithCulture(ClassName)); + + #line default + #line hidden this.Write("("); + this.Write(this.ToStringHelper.ToStringWithCulture(PrefixClassName)); - this.Write("MemoryDatabase memory)\r\n {\r\n this.memory = memory;\r\n }\r\n" + - "\r\n public "); + + #line default + #line hidden + this.Write("MemoryDatabase memory)\n {\n this.memory = memory;\n }\n\n public "); + this.Write(this.ToStringHelper.ToStringWithCulture(PrefixClassName)); - this.Write("MemoryDatabase Build()\r\n {\r\n return memory;\r\n }\r\n\r\n"); + + #line default + #line hidden + this.Write("MemoryDatabase Build()\n {\n return memory;\n }\n\n"); for(var i = 0; i < GenerationContexts.Length; i++) { var item = GenerationContexts[i]; this.Write(" public void ReplaceAll(System.Collections.Generic.IList<"); + this.Write(this.ToStringHelper.ToStringWithCulture(item.ClassName)); - this.Write("> data)\r\n {\r\n var newData = CloneAndSortBy(data, x => "); + + #line default + #line hidden + this.Write("> data)\n {\n var newData = CloneAndSortBy(data, x => "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.PrimaryKey.BuildKeyAccessor("x"))); + + #line default + #line hidden this.Write(", "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.PrimaryKey.BuildComparer())); - this.Write(");\r\n var table = new "); + + #line default + #line hidden + this.Write(");\n var table = new "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.ClassName)); - this.Write("Table(newData);\r\n memory = new "); + + #line default + #line hidden + this.Write("Table(this.memory, newData);\n memory = new "); + this.Write(this.ToStringHelper.ToStringWithCulture(PrefixClassName)); - this.Write("MemoryDatabase(\r\n"); + + #line default + #line hidden + this.Write("MemoryDatabase(\n"); for(var j = 0; j < GenerationContexts.Length; j++) { var item2 = GenerationContexts[j]; this.Write(" "); + this.Write(this.ToStringHelper.ToStringWithCulture((i == j) ? "table" : "memory." + item2.ClassName + "Table")); + + #line default + #line hidden + this.Write(this.ToStringHelper.ToStringWithCulture((j == GenerationContexts.Length - 1) ? "" : ",")); - this.Write("\r\n"); + + #line default + #line hidden + this.Write("\n"); } - this.Write(" \r\n );\r\n }\r\n\r\n"); + this.Write(" );\n }\n\n"); if(!item.PrimaryKey.IsNonUnique) { this.Write(" public void Remove"); + this.Write(this.ToStringHelper.ToStringWithCulture(item.ClassName)); + + #line default + #line hidden this.Write("("); + this.Write(this.ToStringHelper.ToStringWithCulture(item.PrimaryKey.BuildTypeName())); - this.Write("[] keys)\r\n {\r\n var data = RemoveCore(memory."); + + #line default + #line hidden + this.Write("[] keys)\n {\n var data = RemoveCore(memory."); + this.Write(this.ToStringHelper.ToStringWithCulture(item.ClassName)); + + #line default + #line hidden this.Write("Table.GetRawDataUnsafe(), keys, x => "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.PrimaryKey.BuildKeyAccessor("x"))); + + #line default + #line hidden this.Write(", "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.PrimaryKey.BuildComparer())); - this.Write(");\r\n var newData = CloneAndSortBy(data, x => "); + + #line default + #line hidden + this.Write(");\n var newData = CloneAndSortBy(data, x => "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.PrimaryKey.BuildKeyAccessor("x"))); + + #line default + #line hidden this.Write(", "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.PrimaryKey.BuildComparer())); - this.Write(");\r\n var table = new "); + + #line default + #line hidden + this.Write(");\n var table = new "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.ClassName)); - this.Write("Table(newData);\r\n memory = new "); + + #line default + #line hidden + this.Write("Table(this.memory, newData);\n memory = new "); + this.Write(this.ToStringHelper.ToStringWithCulture(PrefixClassName)); - this.Write("MemoryDatabase(\r\n"); + + #line default + #line hidden + this.Write("MemoryDatabase(\n"); for(var j = 0; j < GenerationContexts.Length; j++) { var item2 = GenerationContexts[j]; this.Write(" "); + this.Write(this.ToStringHelper.ToStringWithCulture((i == j) ? "table" : "memory." + item2.ClassName + "Table")); + + #line default + #line hidden + this.Write(this.ToStringHelper.ToStringWithCulture((j == GenerationContexts.Length - 1) ? "" : ",")); - this.Write("\r\n"); + + #line default + #line hidden + this.Write("\n"); } - this.Write(" \r\n );\r\n }\r\n\r\n public void Diff("); + this.Write(" );\n }\n\n public void Diff("); + this.Write(this.ToStringHelper.ToStringWithCulture(item.ClassName)); - this.Write("[] addOrReplaceData)\r\n {\r\n var data = DiffCore(memory."); + + #line default + #line hidden + this.Write("[] addOrReplaceData)\n {\n var data = DiffCore(memory."); + this.Write(this.ToStringHelper.ToStringWithCulture(item.ClassName)); + + #line default + #line hidden this.Write("Table.GetRawDataUnsafe(), addOrReplaceData, x => "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.PrimaryKey.BuildKeyAccessor("x"))); + + #line default + #line hidden this.Write(", "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.PrimaryKey.BuildComparer())); - this.Write(");\r\n var newData = CloneAndSortBy(data, x => "); + + #line default + #line hidden + this.Write(");\n var newData = CloneAndSortBy(data, x => "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.PrimaryKey.BuildKeyAccessor("x"))); + + #line default + #line hidden this.Write(", "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.PrimaryKey.BuildComparer())); - this.Write(");\r\n var table = new "); + + #line default + #line hidden + this.Write(");\n var table = new "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.ClassName)); - this.Write("Table(newData);\r\n memory = new "); + + #line default + #line hidden + this.Write("Table(this.memory, newData);\n memory = new "); + this.Write(this.ToStringHelper.ToStringWithCulture(PrefixClassName)); - this.Write("MemoryDatabase(\r\n"); + + #line default + #line hidden + this.Write("MemoryDatabase(\n"); for(var j = 0; j < GenerationContexts.Length; j++) { var item2 = GenerationContexts[j]; this.Write(" "); + this.Write(this.ToStringHelper.ToStringWithCulture((i == j) ? "table" : "memory." + item2.ClassName + "Table")); + + #line default + #line hidden + this.Write(this.ToStringHelper.ToStringWithCulture((j == GenerationContexts.Length - 1) ? "" : ",")); - this.Write("\r\n"); + + #line default + #line hidden + this.Write("\n"); } - this.Write(" \r\n );\r\n }\r\n"); + this.Write(" );\n }\n"); } - this.Write("\r\n"); + this.Write("\n"); } - this.Write(" }\r\n}"); + this.Write(" }\n}\n"); return this.GenerationEnvironment.ToString(); } } - #region Base class - /// - /// Base class for this transformation - /// - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "17.0.0.0")] + #region Base class + /// + /// Base class for this transformation + /// + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "16.0.0.0")] public class ImmutableBuilderTemplateBase { #region Fields @@ -136,7 +275,7 @@ public class ImmutableBuilderTemplateBase /// /// The string builder that generation-time code is using to assemble generated output /// - public System.Text.StringBuilder GenerationEnvironment + protected System.Text.StringBuilder GenerationEnvironment { get { diff --git a/src/MasterMemory.SourceGenerator/GeneratorCore/ImmutableBuilderTemplate.tt b/src/MasterMemory.SourceGenerator/GeneratorCore/ImmutableBuilderTemplate.tt index ba392fc..7813fbb 100644 --- a/src/MasterMemory.SourceGenerator/GeneratorCore/ImmutableBuilderTemplate.tt +++ b/src/MasterMemory.SourceGenerator/GeneratorCore/ImmutableBuilderTemplate.tt @@ -29,11 +29,11 @@ namespace <#= Namespace #> public void ReplaceAll(System.Collections.Generic.IList<<#= item.ClassName #>> data) { var newData = CloneAndSortBy(data, x => <#= item.PrimaryKey.BuildKeyAccessor("x") #>, <#= item.PrimaryKey.BuildComparer() #>); - var table = new <#= item.ClassName #>Table(newData); + var table = new <#= item.ClassName #>Table(this.memory, newData); memory = new <#= PrefixClassName #>MemoryDatabase( <# for(var j = 0; j < GenerationContexts.Length; j++) { var item2 = GenerationContexts[j]; #> <#= (i == j) ? "table" : "memory." + item2.ClassName + "Table" #><#= (j == GenerationContexts.Length - 1) ? "" : "," #> -<# } #> +<# } #> ); } @@ -42,11 +42,11 @@ namespace <#= Namespace #> { var data = RemoveCore(memory.<#= item.ClassName #>Table.GetRawDataUnsafe(), keys, x => <#= item.PrimaryKey.BuildKeyAccessor("x") #>, <#= item.PrimaryKey.BuildComparer() #>); var newData = CloneAndSortBy(data, x => <#= item.PrimaryKey.BuildKeyAccessor("x") #>, <#= item.PrimaryKey.BuildComparer() #>); - var table = new <#= item.ClassName #>Table(newData); + var table = new <#= item.ClassName #>Table(this.memory, newData); memory = new <#= PrefixClassName #>MemoryDatabase( <# for(var j = 0; j < GenerationContexts.Length; j++) { var item2 = GenerationContexts[j]; #> <#= (i == j) ? "table" : "memory." + item2.ClassName + "Table" #><#= (j == GenerationContexts.Length - 1) ? "" : "," #> -<# } #> +<# } #> ); } @@ -54,15 +54,15 @@ namespace <#= Namespace #> { var data = DiffCore(memory.<#= item.ClassName #>Table.GetRawDataUnsafe(), addOrReplaceData, x => <#= item.PrimaryKey.BuildKeyAccessor("x") #>, <#= item.PrimaryKey.BuildComparer() #>); var newData = CloneAndSortBy(data, x => <#= item.PrimaryKey.BuildKeyAccessor("x") #>, <#= item.PrimaryKey.BuildComparer() #>); - var table = new <#= item.ClassName #>Table(newData); + var table = new <#= item.ClassName #>Table(this.memory, newData); memory = new <#= PrefixClassName #>MemoryDatabase( <# for(var j = 0; j < GenerationContexts.Length; j++) { var item2 = GenerationContexts[j]; #> <#= (i == j) ? "table" : "memory." + item2.ClassName + "Table" #><#= (j == GenerationContexts.Length - 1) ? "" : "," #> -<# } #> +<# } #> ); } <# } #> <# } #> } -} \ No newline at end of file +} diff --git a/src/MasterMemory.SourceGenerator/GeneratorCore/MemoryDatabaseTemplate.cs b/src/MasterMemory.SourceGenerator/GeneratorCore/MemoryDatabaseTemplate.cs index f4132f5..0efd478 100644 --- a/src/MasterMemory.SourceGenerator/GeneratorCore/MemoryDatabaseTemplate.cs +++ b/src/MasterMemory.SourceGenerator/GeneratorCore/MemoryDatabaseTemplate.cs @@ -1,12 +1,12 @@ -// ------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version: 17.0.0.0 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version: 16.0.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ namespace MasterMemory.GeneratorCore { using System.Linq; @@ -17,7 +17,7 @@ namespace MasterMemory.GeneratorCore /// /// Class to produce the template output /// - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "17.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "16.0.0.0")] public partial class MemoryDatabaseTemplate : MemoryDatabaseTemplateBase { /// @@ -25,197 +25,293 @@ public partial class MemoryDatabaseTemplate : MemoryDatabaseTemplateBase /// public virtual string TransformText() { - this.Write("// \r\n#pragma warning disable\r\n#nullable enable\r\n\r\n"); + this.Write("// \n#pragma warning disable\n#nullable enable\n\n"); + this.Write(this.ToStringHelper.ToStringWithCulture(Using)); - this.Write("\r\n\r\nnamespace "); + + #line default + #line hidden + this.Write("\n\nnamespace "); + this.Write(this.ToStringHelper.ToStringWithCulture(Namespace)); - this.Write("\r\n{\r\n public sealed class "); + + #line default + #line hidden + this.Write("\n{\n public sealed class "); + this.Write(this.ToStringHelper.ToStringWithCulture(ClassName)); - this.Write(" : MemoryDatabaseBase\r\n {\r\n"); + + #line default + #line hidden + this.Write(" : MemoryDatabaseBase\n {\n"); foreach(var item in GenerationContexts) { this.Write(" public "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.ClassName)); + + #line default + #line hidden this.Write("Table "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.ClassName)); - this.Write("Table { get; private set; } = default!;\r\n"); + + #line default + #line hidden + this.Write("Table { get; private set; } = default!;\n"); } - this.Write("\r\n public "); + this.Write("\n public "); + this.Write(this.ToStringHelper.ToStringWithCulture(ClassName)); - this.Write("(\r\n"); + + #line default + #line hidden + this.Write("(\n"); for(var i = 0; i < GenerationContexts.Length; i++) { var item = GenerationContexts[i]; this.Write(" "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.ClassName)); + + #line default + #line hidden this.Write("Table "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.ClassName)); + + #line default + #line hidden this.Write("Table"); + this.Write(this.ToStringHelper.ToStringWithCulture((i == GenerationContexts.Length - 1) ? "" : ",")); - this.Write("\r\n"); + + #line default + #line hidden + this.Write("\n"); } - this.Write(" )\r\n {\r\n"); + this.Write(" )\n {\n"); for(var i = 0; i < GenerationContexts.Length; i++) { var item = GenerationContexts[i]; this.Write(" this."); + this.Write(this.ToStringHelper.ToStringWithCulture(item.ClassName)); + + #line default + #line hidden this.Write("Table = "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.ClassName)); - this.Write("Table;\r\n"); + + #line default + #line hidden + this.Write("Table;\n"); } - this.Write(" }\r\n\r\n public "); + this.Write(" }\n\n public "); + this.Write(this.ToStringHelper.ToStringWithCulture(ClassName)); - this.Write(@"(byte[] databaseBinary, bool internString = true, MessagePack.IFormatterResolver? formatterResolver = null, int maxDegreeOfParallelism = 1) - : base(databaseBinary, internString, formatterResolver, maxDegreeOfParallelism) - { - } - - protected override void Init(Dictionary header, System.ReadOnlyMemory databaseBinary, MessagePack.MessagePackSerializerOptions options, int maxDegreeOfParallelism) - { - if (maxDegreeOfParallelism == 1) - { - InitSequential(header, databaseBinary, options, maxDegreeOfParallelism); - } - else - { - InitParallel(header, databaseBinary, options, maxDegreeOfParallelism); - } - } - - void InitSequential(Dictionary header, System.ReadOnlyMemory databaseBinary, MessagePack.MessagePackSerializerOptions options, int maxDegreeOfParallelism) - { -"); + + #line default + #line hidden + this.Write("(byte[] databaseBinary, bool internString = true, MessagePack.IFormatterResolver? formatterResolver = null, int maxDegreeOfParallelism = 1)\n : base(databaseBinary, internString, formatterResolver, maxDegreeOfParallelism)\n {\n }\n\n protected override void Init(Dictionary header, System.ReadOnlyMemory databaseBinary, MessagePack.MessagePackSerializerOptions options, int maxDegreeOfParallelism)\n {\n if (maxDegreeOfParallelism == 1)\n {\n InitSequential(header, databaseBinary, options, maxDegreeOfParallelism);\n }\n else\n {\n InitParallel(header, databaseBinary, options, maxDegreeOfParallelism);\n }\n }\n\n void InitSequential(Dictionary header, System.ReadOnlyMemory databaseBinary, MessagePack.MessagePackSerializerOptions options, int maxDegreeOfParallelism)\n {\n"); foreach(var item in GenerationContexts) { this.Write(" this."); + this.Write(this.ToStringHelper.ToStringWithCulture(item.ClassName)); + + #line default + #line hidden this.Write("Table = ExtractTableData<"); + this.Write(this.ToStringHelper.ToStringWithCulture(item.ClassName)); + + #line default + #line hidden this.Write(", "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.ClassName)); + + #line default + #line hidden this.Write("Table>(header, databaseBinary, options, xs => new "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.ClassName)); - this.Write("Table(xs));\r\n"); + + #line default + #line hidden + this.Write("Table(this, xs));\n"); } - this.Write(@" } - - void InitParallel(Dictionary header, System.ReadOnlyMemory databaseBinary, MessagePack.MessagePackSerializerOptions options, int maxDegreeOfParallelism) - { - var extracts = new Action[] - { -"); + this.Write(" }\n\n void InitParallel(Dictionary header, System.ReadOnlyMemory databaseBinary, MessagePack.MessagePackSerializerOptions options, int maxDegreeOfParallelism)\n {\n var extracts = new Action[]\n {\n"); foreach(var item in GenerationContexts) { this.Write(" () => this."); + this.Write(this.ToStringHelper.ToStringWithCulture(item.ClassName)); + + #line default + #line hidden this.Write("Table = ExtractTableData<"); + this.Write(this.ToStringHelper.ToStringWithCulture(item.ClassName)); + + #line default + #line hidden this.Write(", "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.ClassName)); + + #line default + #line hidden this.Write("Table>(header, databaseBinary, options, xs => new "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.ClassName)); - this.Write("Table(xs)),\r\n"); + + #line default + #line hidden + this.Write("Table(this, xs)),\n"); } - this.Write(@" }; + this.Write(" };\n\n System.Threading.Tasks.Parallel.Invoke(new System.Threading.Tasks.ParallelOptions\n {\n MaxDegreeOfParallelism = maxDegreeOfParallelism\n }, extracts);\n }\n\n public "); - System.Threading.Tasks.Parallel.Invoke(new System.Threading.Tasks.ParallelOptions - { - MaxDegreeOfParallelism = maxDegreeOfParallelism - }, extracts); - } - - public "); this.Write(this.ToStringHelper.ToStringWithCulture(PrefixClassName)); - this.Write("ImmutableBuilder ToImmutableBuilder()\r\n {\r\n return new "); + + #line default + #line hidden + this.Write("ImmutableBuilder ToImmutableBuilder()\n {\n return new "); + this.Write(this.ToStringHelper.ToStringWithCulture(PrefixClassName)); - this.Write("ImmutableBuilder(this);\r\n }\r\n\r\n public "); + + #line default + #line hidden + this.Write("ImmutableBuilder(this);\n }\n\n public "); + this.Write(this.ToStringHelper.ToStringWithCulture(PrefixClassName)); - this.Write("DatabaseBuilder ToDatabaseBuilder()\r\n {\r\n var builder = new "); + + #line default + #line hidden + this.Write("DatabaseBuilder ToDatabaseBuilder()\n {\n var builder = new "); + this.Write(this.ToStringHelper.ToStringWithCulture(PrefixClassName)); - this.Write("DatabaseBuilder();\r\n"); + + #line default + #line hidden + this.Write("DatabaseBuilder();\n"); foreach(var item in GenerationContexts) { this.Write(" builder.Append(this."); + this.Write(this.ToStringHelper.ToStringWithCulture(item.ClassName)); - this.Write("Table.GetRawDataUnsafe());\r\n"); + + #line default + #line hidden + this.Write("Table.GetRawDataUnsafe());\n"); } - this.Write(" return builder;\r\n }\r\n\r\n public "); + this.Write(" return builder;\n }\n\n public "); + this.Write(this.ToStringHelper.ToStringWithCulture(PrefixClassName)); - this.Write("DatabaseBuilder ToDatabaseBuilder(MessagePack.IFormatterResolver resolver)\r\n " + - " {\r\n var builder = new "); + + #line default + #line hidden + this.Write("DatabaseBuilder ToDatabaseBuilder(MessagePack.IFormatterResolver resolver)\n {\n var builder = new "); + this.Write(this.ToStringHelper.ToStringWithCulture(PrefixClassName)); - this.Write("DatabaseBuilder(resolver);\r\n"); + + #line default + #line hidden + this.Write("DatabaseBuilder(resolver);\n"); foreach(var item in GenerationContexts) { this.Write(" builder.Append(this."); + this.Write(this.ToStringHelper.ToStringWithCulture(item.ClassName)); - this.Write("Table.GetRawDataUnsafe());\r\n"); + + #line default + #line hidden + this.Write("Table.GetRawDataUnsafe());\n"); } - this.Write(@" return builder; - } - -#if !DISABLE_MASTERMEMORY_VALIDATOR - - public ValidateResult Validate() - { - var result = new ValidateResult(); - var database = new ValidationDatabase(new object[] - { -"); + this.Write(" return builder;\n }\n\n#if !DISABLE_MASTERMEMORY_VALIDATOR\n\n public ValidateResult Validate()\n {\n var result = new ValidateResult();\n var database = new ValidationDatabase(new object[]\n {\n"); foreach(var item in GenerationContexts) { this.Write(" "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.ClassName)); - this.Write("Table,\r\n"); + + #line default + #line hidden + this.Write("Table,\n"); } - this.Write(" });\r\n\r\n"); + this.Write(" });\n\n"); foreach(var item in GenerationContexts) { this.Write(" ((ITableUniqueValidate)"); + this.Write(this.ToStringHelper.ToStringWithCulture(item.ClassName)); - this.Write("Table).ValidateUnique(result);\r\n ValidateTable("); + + #line default + #line hidden + this.Write("Table).ValidateUnique(result);\n ValidateTable("); + this.Write(this.ToStringHelper.ToStringWithCulture(item.ClassName)); + + #line default + #line hidden this.Write("Table.All, database, \""); + this.Write(this.ToStringHelper.ToStringWithCulture(item.PrimaryKey.BuildPropertyTupleName())); + + #line default + #line hidden this.Write("\", "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.ClassName)); - this.Write("Table.PrimaryKeySelector, result);\r\n"); + + #line default + #line hidden + this.Write("Table.PrimaryKeySelector, result);\n"); } - this.Write("\r\n return result;\r\n }\r\n\r\n#endif\r\n\r\n static MasterMemory." + - "Meta.MetaDatabase? metaTable;\r\n\r\n public static object? GetTable("); + this.Write("\n return result;\n }\n\n#endif\n\n static MasterMemory.Meta.MetaDatabase? metaTable;\n\n public static object? GetTable("); + this.Write(this.ToStringHelper.ToStringWithCulture(ClassName)); - this.Write(" db, string tableName)\r\n {\r\n switch (tableName)\r\n {\r" + - "\n"); + + #line default + #line hidden + this.Write(" db, string tableName)\n {\n switch (tableName)\n {\n"); foreach(var item in GenerationContexts) { this.Write(" case \""); + this.Write(this.ToStringHelper.ToStringWithCulture(item.MemoryTableName)); - this.Write("\":\r\n return db."); + + #line default + #line hidden + this.Write("\":\n return db."); + this.Write(this.ToStringHelper.ToStringWithCulture(item.ClassName)); - this.Write("Table;\r\n"); + + #line default + #line hidden + this.Write("Table;\n"); } - this.Write(@" - default: - return null; - } - } - -#if !DISABLE_MASTERMEMORY_METADATABASE - - public static MasterMemory.Meta.MetaDatabase GetMetaDatabase() - { - if (metaTable != null) return metaTable; - - var dict = new Dictionary(); -"); + this.Write(" default:\n return null;\n }\n }\n\n#if !DISABLE_MASTERMEMORY_METADATABASE\n\n public static MasterMemory.Meta.MetaDatabase GetMetaDatabase()\n {\n if (metaTable != null) return metaTable;\n\n var dict = new Dictionary();\n"); foreach(var item in GenerationContexts) { this.Write(" dict.Add(\""); + this.Write(this.ToStringHelper.ToStringWithCulture(item.MemoryTableName)); + + #line default + #line hidden this.Write("\", "); + this.Write(this.ToStringHelper.ToStringWithCulture(Namespace)); + + #line default + #line hidden this.Write(".Tables."); + this.Write(this.ToStringHelper.ToStringWithCulture(item.ClassName)); - this.Write("Table.CreateMetaTable());\r\n"); + + #line default + #line hidden + this.Write("Table.CreateMetaTable());\n"); } - this.Write("\r\n metaTable = new MasterMemory.Meta.MetaDatabase(dict);\r\n " + - "return metaTable;\r\n }\r\n\r\n#endif\r\n }\r\n}"); + this.Write("\n metaTable = new MasterMemory.Meta.MetaDatabase(dict);\n return metaTable;\n }\n\n#endif\n }\n}\n"); return this.GenerationEnvironment.ToString(); } } - #region Base class - /// - /// Base class for this transformation - /// - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "17.0.0.0")] + #region Base class + /// + /// Base class for this transformation + /// + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "16.0.0.0")] public class MemoryDatabaseTemplateBase { #region Fields @@ -230,7 +326,7 @@ public class MemoryDatabaseTemplateBase /// /// The string builder that generation-time code is using to assemble generated output /// - public System.Text.StringBuilder GenerationEnvironment + protected System.Text.StringBuilder GenerationEnvironment { get { diff --git a/src/MasterMemory.SourceGenerator/GeneratorCore/MemoryDatabaseTemplate.tt b/src/MasterMemory.SourceGenerator/GeneratorCore/MemoryDatabaseTemplate.tt index a54c155..e60bb29 100644 --- a/src/MasterMemory.SourceGenerator/GeneratorCore/MemoryDatabaseTemplate.tt +++ b/src/MasterMemory.SourceGenerator/GeneratorCore/MemoryDatabaseTemplate.tt @@ -48,7 +48,7 @@ namespace <#= Namespace #> void InitSequential(Dictionary header, System.ReadOnlyMemory databaseBinary, MessagePack.MessagePackSerializerOptions options, int maxDegreeOfParallelism) { <# foreach(var item in GenerationContexts) { #> - this.<#= item.ClassName #>Table = ExtractTableData<<#= item.ClassName #>, <#= item.ClassName #>Table>(header, databaseBinary, options, xs => new <#= item.ClassName #>Table(xs)); + this.<#= item.ClassName #>Table = ExtractTableData<<#= item.ClassName #>, <#= item.ClassName #>Table>(header, databaseBinary, options, xs => new <#= item.ClassName #>Table(this, xs)); <# } #> } @@ -57,10 +57,10 @@ namespace <#= Namespace #> var extracts = new Action[] { <# foreach(var item in GenerationContexts) { #> - () => this.<#= item.ClassName #>Table = ExtractTableData<<#= item.ClassName #>, <#= item.ClassName #>Table>(header, databaseBinary, options, xs => new <#= item.ClassName #>Table(xs)), + () => this.<#= item.ClassName #>Table = ExtractTableData<<#= item.ClassName #>, <#= item.ClassName #>Table>(header, databaseBinary, options, xs => new <#= item.ClassName #>Table(this, xs)), <# } #> }; - + System.Threading.Tasks.Parallel.Invoke(new System.Threading.Tasks.ParallelOptions { MaxDegreeOfParallelism = maxDegreeOfParallelism @@ -121,7 +121,7 @@ namespace <#= Namespace #> <# foreach(var item in GenerationContexts) { #> case "<#= item.MemoryTableName #>": return db.<#= item.ClassName #>Table; -<# } #> +<# } #> default: return null; } @@ -144,4 +144,4 @@ namespace <#= Namespace #> #endif } -} \ No newline at end of file +} diff --git a/src/MasterMemory.SourceGenerator/GeneratorCore/TableTemplate.cs b/src/MasterMemory.SourceGenerator/GeneratorCore/TableTemplate.cs index b91fac6..3b0f839 100644 --- a/src/MasterMemory.SourceGenerator/GeneratorCore/TableTemplate.cs +++ b/src/MasterMemory.SourceGenerator/GeneratorCore/TableTemplate.cs @@ -1,12 +1,12 @@ -// ------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version: 17.0.0.0 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version: 16.0.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ namespace MasterMemory.GeneratorCore { using System.Linq; @@ -17,7 +17,7 @@ namespace MasterMemory.GeneratorCore /// /// Class to produce the template output /// - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "17.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "16.0.0.0")] public partial class TableTemplate : TableTemplateBase { /// @@ -25,277 +25,625 @@ public partial class TableTemplate : TableTemplateBase /// public virtual string TransformText() { - this.Write("// \r\n#pragma warning disable\r\n#nullable enable\r\n\r\n"); + this.Write("// \n#pragma warning disable\n#nullable enable\n\n"); + this.Write(this.ToStringHelper.ToStringWithCulture(Using)); - this.Write("\r\n\r\nnamespace "); + + #line default + #line hidden + this.Write("\n\nnamespace "); + this.Write(this.ToStringHelper.ToStringWithCulture(Namespace)); - this.Write(".Tables\r\n{\r\n public sealed partial class "); + + #line default + #line hidden + this.Write(".Tables\n{\n public sealed partial class "); + this.Write(this.ToStringHelper.ToStringWithCulture(GenerationContext.ClassName)); + + #line default + #line hidden this.Write("Table : TableBase<"); + this.Write(this.ToStringHelper.ToStringWithCulture(GenerationContext.ClassName)); - this.Write(">, ITableUniqueValidate\r\n {\r\n public Func<"); + + #line default + #line hidden + this.Write(">, ITableUniqueValidate\n {\n public Func<"); + this.Write(this.ToStringHelper.ToStringWithCulture(GenerationContext.ClassName)); + + #line default + #line hidden this.Write(", "); + this.Write(this.ToStringHelper.ToStringWithCulture(GenerationContext.PrimaryKey.BuildTypeName())); + + #line default + #line hidden this.Write("> PrimaryKeySelector => "); + this.Write(this.ToStringHelper.ToStringWithCulture(GenerationContext.PrimaryKey.SelectorName)); - this.Write(";\r\n readonly Func<"); + + #line default + #line hidden + this.Write(";\n readonly Func<"); + this.Write(this.ToStringHelper.ToStringWithCulture(GenerationContext.ClassName)); + + #line default + #line hidden this.Write(", "); + this.Write(this.ToStringHelper.ToStringWithCulture(GenerationContext.PrimaryKey.BuildTypeName())); + + #line default + #line hidden this.Write("> "); + this.Write(this.ToStringHelper.ToStringWithCulture(GenerationContext.PrimaryKey.SelectorName)); - this.Write(";\r\n\r\n"); + + #line default + #line hidden + this.Write(";\n\n"); for(var i = 0; i < GenerationContext.SecondaryKeys.Length; i++) { var item = GenerationContext.SecondaryKeys[i]; this.Write(" readonly "); + this.Write(this.ToStringHelper.ToStringWithCulture(GenerationContext.ClassName)); + + #line default + #line hidden this.Write("[] "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.TableName)); - this.Write(";\r\n readonly Func<"); + + #line default + #line hidden + this.Write(";\n readonly Func<"); + this.Write(this.ToStringHelper.ToStringWithCulture(GenerationContext.ClassName)); + + #line default + #line hidden this.Write(", "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildTypeName())); + + #line default + #line hidden this.Write("> "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.SelectorName)); - this.Write(";\r\n"); + + #line default + #line hidden + this.Write(";\n"); } - this.Write("\r\n public "); + this.Write("\n public "); + this.Write(this.ToStringHelper.ToStringWithCulture(GenerationContext.ClassName)); - this.Write("Table("); + + #line default + #line hidden + this.Write("Table(MemoryDatabaseBase db, "); + this.Write(this.ToStringHelper.ToStringWithCulture(GenerationContext.ClassName)); - this.Write("[] sortedData)\r\n : base(sortedData)\r\n {\r\n this."); + + #line default + #line hidden + this.Write("[] sortedData)\n : base(sortedData)\n {\n this."); + this.Write(this.ToStringHelper.ToStringWithCulture(GenerationContext.PrimaryKey.SelectorName)); + + #line default + #line hidden this.Write(" = x => "); + this.Write(this.ToStringHelper.ToStringWithCulture(GenerationContext.PrimaryKey.BuildKeyAccessor("x"))); - this.Write(";\r\n"); + + #line default + #line hidden + this.Write(";\n"); for(var i = 0; i < GenerationContext.SecondaryKeys.Length; i++) { var item = GenerationContext.SecondaryKeys[i]; this.Write(" this."); + this.Write(this.ToStringHelper.ToStringWithCulture(item.SelectorName)); + + #line default + #line hidden this.Write(" = x => "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildKeyAccessor("x"))); - this.Write(";\r\n this."); + + #line default + #line hidden + this.Write(";\n this."); + this.Write(this.ToStringHelper.ToStringWithCulture(item.TableName)); + + #line default + #line hidden this.Write(" = CloneAndSortBy(this.secondaryIndex"); + this.Write(this.ToStringHelper.ToStringWithCulture(item.IndexNo)); + + #line default + #line hidden this.Write("Selector, "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildComparer())); - this.Write(");\r\n"); + + #line default + #line hidden + this.Write(");\n"); } - this.Write(" OnAfterConstruct();\r\n }\r\n\r\n partial void OnAfterConstru" + - "ct();\r\n\r\n"); + this.Write(" OnAfterConstruct();\n OnAfterConstruct(db);\n }\n\n partial void OnAfterConstruct();\n\n partial void OnAfterConstruct(MemoryDatabaseBase db);\n\n"); for(var i = 0; i < GenerationContext.SecondaryKeys.Length; i++) { var item = GenerationContext.SecondaryKeys[i]; this.Write(" public RangeView<"); + this.Write(this.ToStringHelper.ToStringWithCulture(GenerationContext.ClassName)); + + #line default + #line hidden this.Write("> SortBy"); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildMethodName())); + + #line default + #line hidden this.Write(" => new RangeView<"); + this.Write(this.ToStringHelper.ToStringWithCulture(GenerationContext.ClassName)); + + #line default + #line hidden this.Write(">("); + this.Write(this.ToStringHelper.ToStringWithCulture(item.TableName)); + + #line default + #line hidden this.Write(", 0, "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.TableName)); - this.Write(".Length - 1, true);\r\n"); + + #line default + #line hidden + this.Write(".Length - 1, true);\n"); } - this.Write("\r\n"); + this.Write("\n"); foreach(var item in new KeyBase[] { GenerationContext.PrimaryKey }.Concat(GenerationContext.SecondaryKeys)) { if(item.CanInlineBinarySearch) { - this.Write(" [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServic" + - "es.MethodImplOptions.AggressiveInlining)]\r\n public "); + this.Write(" [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n public "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildReturnTypeName(GenerationContext.ClassName) + (ThrowKeyIfNotFound ? "" : "?"))); + + #line default + #line hidden this.Write(" FindBy"); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildMethodName())); + + #line default + #line hidden this.Write("("); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildTypeName())); - this.Write(" key)\r\n {\r\n var lo = 0;\r\n var hi = data.Length - 1;\r" + - "\n while (lo <= hi)\r\n {\r\n var mid = (int)(((" + - "uint)hi + (uint)lo) >> 1);\r\n var selected = data[mid]."); + + #line default + #line hidden + this.Write(" key)\n {\n var lo = 0;\n var hi = data.Length - 1;\n while (lo <= hi)\n {\n var mid = (int)(((uint)hi + (uint)lo) >> 1);\n var selected = data[mid]."); + this.Write(this.ToStringHelper.ToStringWithCulture(item.Properties[0].Name)); - this.Write(";\r\n var found = (selected < key) ? -1 : (selected > key) ? 1 : 0;\r" + - "\n if (found == 0) { return data[mid]; }\r\n if (foun" + - "d < 0) { lo = mid + 1; }\r\n else { hi = mid - 1; }\r\n }\r" + - "\n"); + + #line default + #line hidden + this.Write(";\n var found = (selected < key) ? -1 : (selected > key) ? 1 : 0;\n if (found == 0) { return data[mid]; }\n if (found < 0) { lo = mid + 1; }\n else { hi = mid - 1; }\n }\n"); if(ThrowKeyIfNotFound) { - this.Write(" return ThrowKeyNotFound(key);\r\n"); + this.Write(" return ThrowKeyNotFound(key);\n"); } else { - this.Write(" return default;\r\n"); + this.Write(" return default;\n"); } - this.Write(" }\r\n\r\n [System.Runtime.CompilerServices.MethodImpl(System.Runtime.C" + - "ompilerServices.MethodImplOptions.AggressiveInlining)]\r\n public bool TryF" + - "indBy"); + this.Write(" }\n\n [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n public bool TryFindBy"); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildMethodName())); + + #line default + #line hidden this.Write("("); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildTypeName())); + + #line default + #line hidden this.Write(" key, out "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildReturnTypeName(GenerationContext.ClassName))); - this.Write(" result)\r\n {\r\n var lo = 0;\r\n var hi = data.Length - " + - "1;\r\n while (lo <= hi)\r\n {\r\n var mid = (int)" + - "(((uint)hi + (uint)lo) >> 1);\r\n var selected = data[mid]."); + + #line default + #line hidden + this.Write(" result)\n {\n var lo = 0;\n var hi = data.Length - 1;\n while (lo <= hi)\n {\n var mid = (int)(((uint)hi + (uint)lo) >> 1);\n var selected = data[mid]."); + this.Write(this.ToStringHelper.ToStringWithCulture(item.Properties[0].Name)); - this.Write(@"; - var found = (selected < key) ? -1 : (selected > key) ? 1 : 0; - if (found == 0) { result = data[mid]; return true; } - if (found < 0) { lo = mid + 1; } - else { hi = mid - 1; } - } - result = default!; - return false; - } -"); + + #line default + #line hidden + this.Write(";\n var found = (selected < key) ? -1 : (selected > key) ? 1 : 0;\n if (found == 0) { result = data[mid]; return true; }\n if (found < 0) { lo = mid + 1; }\n else { hi = mid - 1; }\n }\n result = default!;\n return false;\n }\n"); } else { if (!item.IsNonUnique) { this.Write(" public "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildReturnTypeName(GenerationContext.ClassName))); + + #line default + #line hidden this.Write(" FindBy"); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildMethodName())); + + #line default + #line hidden this.Write("("); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildTypeName())); - this.Write(" key)\r\n {\r\n return "); + + #line default + #line hidden + this.Write(" key)\n {\n return "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildFindPrefix())); + + #line default + #line hidden this.Write("Core"); + this.Write(this.ToStringHelper.ToStringWithCulture(!item.IsNonUnique && item.IsIntType ? "Int" : "")); + + #line default + #line hidden this.Write("("); + this.Write(this.ToStringHelper.ToStringWithCulture(item.TableName)); + + #line default + #line hidden this.Write(", "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.SelectorName)); + + #line default + #line hidden this.Write(", "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildComparer())); + + #line default + #line hidden this.Write(", key, "); + this.Write(this.ToStringHelper.ToStringWithCulture(ThrowKeyIfNotFound.ToString().ToLower())); - this.Write(");\r\n }\r\n \r\n public bool TryFindBy"); + + #line default + #line hidden + this.Write(");\n }\n\n public bool TryFindBy"); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildMethodName())); + + #line default + #line hidden this.Write("("); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildTypeName())); + + #line default + #line hidden this.Write(" key, out "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildReturnTypeName(GenerationContext.ClassName))); - this.Write(" result)\r\n {\r\n return Try"); + + #line default + #line hidden + this.Write(" result)\n {\n return Try"); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildFindPrefix())); + + #line default + #line hidden this.Write("Core"); + this.Write(this.ToStringHelper.ToStringWithCulture(!item.IsNonUnique && item.IsIntType ? "Int" : "")); + + #line default + #line hidden this.Write("("); + this.Write(this.ToStringHelper.ToStringWithCulture(item.TableName)); + + #line default + #line hidden this.Write(", "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.SelectorName)); + + #line default + #line hidden this.Write(", "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildComparer())); - this.Write(", key, out result);\r\n }\r\n"); + + #line default + #line hidden + this.Write(", key, out result);\n }\n"); } else { this.Write(" public "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildReturnTypeName(GenerationContext.ClassName))); + + #line default + #line hidden this.Write(" FindBy"); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildMethodName())); + + #line default + #line hidden this.Write("("); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildTypeName())); - this.Write(" key)\r\n {\r\n return "); + + #line default + #line hidden + this.Write(" key)\n {\n return "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildFindPrefix())); + + #line default + #line hidden this.Write("Core"); + this.Write(this.ToStringHelper.ToStringWithCulture(!item.IsNonUnique && item.IsIntType ? "Int" : "")); + + #line default + #line hidden this.Write("("); + this.Write(this.ToStringHelper.ToStringWithCulture(item.TableName)); + + #line default + #line hidden this.Write(", "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.SelectorName)); + + #line default + #line hidden this.Write(", "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildComparer())); - this.Write(", key);\r\n }\r\n"); + + #line default + #line hidden + this.Write(", key);\n }\n"); } } - this.Write("\r\n public "); + this.Write("\n public "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildReturnTypeNameForClosest(GenerationContext.ClassName))); + + #line default + #line hidden this.Write(" FindClosestBy"); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildMethodName())); + + #line default + #line hidden this.Write("("); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildTypeName())); - this.Write(" key, bool selectLower = true)\r\n {\r\n return "); + + #line default + #line hidden + this.Write(" key, bool selectLower = true)\n {\n return "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildFindPrefix())); + + #line default + #line hidden this.Write("ClosestCore("); + this.Write(this.ToStringHelper.ToStringWithCulture(item.TableName)); + + #line default + #line hidden this.Write(", "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.SelectorName)); + + #line default + #line hidden this.Write(", "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildComparer())); - this.Write(", key, selectLower);\r\n }\r\n\r\n public RangeView<"); + + #line default + #line hidden + this.Write(", key, selectLower);\n }\n\n public RangeView<"); + this.Write(this.ToStringHelper.ToStringWithCulture(GenerationContext.ClassName)); + + #line default + #line hidden this.Write("> FindRangeBy"); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildMethodName())); + + #line default + #line hidden this.Write("("); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildTypeName())); + + #line default + #line hidden this.Write(" min, "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildTypeName())); - this.Write(" max, bool ascendant = true)\r\n {\r\n return "); + + #line default + #line hidden + this.Write(" max, bool ascendant = true)\n {\n return "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildFindPrefix())); + + #line default + #line hidden this.Write("RangeCore("); + this.Write(this.ToStringHelper.ToStringWithCulture(item.TableName)); + + #line default + #line hidden this.Write(", "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.SelectorName)); + + #line default + #line hidden this.Write(", "); + this.Write(this.ToStringHelper.ToStringWithCulture(item.BuildComparer())); - this.Write(", min, max, ascendant);\r\n }\r\n\r\n"); + + #line default + #line hidden + this.Write(", min, max, ascendant);\n }\n\n"); } - this.Write("\r\n void ITableUniqueValidate.ValidateUnique(ValidateResult resultSet)\r\n " + - " {\r\n#if !DISABLE_MASTERMEMORY_VALIDATOR\r\n\r\n"); + this.Write("\n void ITableUniqueValidate.ValidateUnique(ValidateResult resultSet)\n {\n#if !DISABLE_MASTERMEMORY_VALIDATOR\n\n"); if (!GenerationContext.PrimaryKey.IsNonUnique) { var key = GenerationContext.PrimaryKey; this.Write(" ValidateUniqueCore("); + this.Write(this.ToStringHelper.ToStringWithCulture(key.TableName)); + + #line default + #line hidden this.Write(", "); + this.Write(this.ToStringHelper.ToStringWithCulture(key.SelectorName)); + + #line default + #line hidden this.Write(", \""); + this.Write(this.ToStringHelper.ToStringWithCulture(key.BuildPropertyTupleName())); - this.Write("\", resultSet); \r\n"); + + #line default + #line hidden + this.Write("\", resultSet);\n"); } for(var i = 0; i < GenerationContext.SecondaryKeys.Length; i++) { var key = GenerationContext.SecondaryKeys[i]; if (!key.IsNonUnique) { this.Write(" ValidateUniqueCore("); + this.Write(this.ToStringHelper.ToStringWithCulture(key.TableName)); + + #line default + #line hidden this.Write(", "); + this.Write(this.ToStringHelper.ToStringWithCulture(key.SelectorName)); + + #line default + #line hidden this.Write(", \""); + this.Write(this.ToStringHelper.ToStringWithCulture(key.BuildPropertyTupleName())); - this.Write("\", resultSet); \r\n"); + + #line default + #line hidden + this.Write("\", resultSet);\n"); } } - this.Write("\r\n#endif\r\n }\r\n\r\n#if !DISABLE_MASTERMEMORY_METADATABASE\r\n\r\n public s" + - "tatic MasterMemory.Meta.MetaTable CreateMetaTable()\r\n {\r\n retu" + - "rn new MasterMemory.Meta.MetaTable(typeof("); + this.Write("\n#endif\n }\n\n#if !DISABLE_MASTERMEMORY_METADATABASE\n\n public static MasterMemory.Meta.MetaTable CreateMetaTable()\n {\n return new MasterMemory.Meta.MetaTable(typeof("); + this.Write(this.ToStringHelper.ToStringWithCulture(GenerationContext.ClassName)); + + #line default + #line hidden this.Write("), typeof("); + this.Write(this.ToStringHelper.ToStringWithCulture(GenerationContext.ClassName)); + + #line default + #line hidden this.Write("Table), \""); + this.Write(this.ToStringHelper.ToStringWithCulture(GenerationContext.MemoryTableName)); - this.Write("\",\r\n new MasterMemory.Meta.MetaProperty[]\r\n {\r\n"); + + #line default + #line hidden + this.Write("\",\n new MasterMemory.Meta.MetaProperty[]\n {\n"); foreach(var prop in GenerationContext.Properties) { this.Write(" new MasterMemory.Meta.MetaProperty(typeof("); + this.Write(this.ToStringHelper.ToStringWithCulture(GenerationContext.ClassName)); + + #line default + #line hidden this.Write(").GetProperty(\""); + this.Write(this.ToStringHelper.ToStringWithCulture(prop.Name)); - this.Write("\")!),\r\n"); + + #line default + #line hidden + this.Write("\")!),\n"); } - this.Write(" },\r\n new MasterMemory.Meta.MetaIndex[]{\r\n"); + this.Write(" },\n new MasterMemory.Meta.MetaIndex[]{\n"); foreach(var key in GenerationContext.Keys) { - this.Write(" new MasterMemory.Meta.MetaIndex(new System.Reflection.Propert" + - "yInfo[] {\r\n"); + this.Write(" new MasterMemory.Meta.MetaIndex(new System.Reflection.PropertyInfo[] {\n"); foreach(var keyProp in key.Properties) { this.Write(" typeof("); + this.Write(this.ToStringHelper.ToStringWithCulture(GenerationContext.ClassName)); + + #line default + #line hidden this.Write(").GetProperty(\""); + this.Write(this.ToStringHelper.ToStringWithCulture(keyProp.Name)); - this.Write("\")!,\r\n"); + + #line default + #line hidden + this.Write("\")!,\n"); } this.Write(" }, "); + this.Write(this.ToStringHelper.ToStringWithCulture(key.IsPrimary.ToString().ToLower())); + + #line default + #line hidden this.Write(", "); + this.Write(this.ToStringHelper.ToStringWithCulture((!key.IsNonUnique).ToString().ToLower())); + + #line default + #line hidden this.Write(", "); + this.Write(this.ToStringHelper.ToStringWithCulture(key.BuildComparer())); - this.Write("),\r\n"); + + #line default + #line hidden + this.Write("),\n"); } - this.Write(" });\r\n }\r\n\r\n#endif\r\n }\r\n}"); + this.Write(" });\n }\n\n#endif\n }\n}\n"); return this.GenerationEnvironment.ToString(); } } - #region Base class - /// - /// Base class for this transformation - /// - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "17.0.0.0")] + #region Base class + /// + /// Base class for this transformation + /// + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "16.0.0.0")] public class TableTemplateBase { #region Fields @@ -310,7 +658,7 @@ public class TableTemplateBase /// /// The string builder that generation-time code is using to assemble generated output /// - public System.Text.StringBuilder GenerationEnvironment + protected System.Text.StringBuilder GenerationEnvironment { get { diff --git a/src/MasterMemory.SourceGenerator/GeneratorCore/TableTemplate.tt b/src/MasterMemory.SourceGenerator/GeneratorCore/TableTemplate.tt index db90c55..617f963 100644 --- a/src/MasterMemory.SourceGenerator/GeneratorCore/TableTemplate.tt +++ b/src/MasterMemory.SourceGenerator/GeneratorCore/TableTemplate.tt @@ -21,7 +21,7 @@ namespace <#= Namespace #>.Tables readonly Func<<#= GenerationContext.ClassName #>, <#= item.BuildTypeName() #>> <#= item.SelectorName #>; <# } #> - public <#= GenerationContext.ClassName #>Table(<#= GenerationContext.ClassName #>[] sortedData) + public <#= GenerationContext.ClassName #>Table(MemoryDatabaseBase db, <#= GenerationContext.ClassName #>[] sortedData) : base(sortedData) { this.<#= GenerationContext.PrimaryKey.SelectorName #> = x => <#= GenerationContext.PrimaryKey.BuildKeyAccessor("x") #>; @@ -30,10 +30,13 @@ namespace <#= Namespace #>.Tables this.<#= item.TableName #> = CloneAndSortBy(this.secondaryIndex<#= item.IndexNo #>Selector, <#= item.BuildComparer() #>); <# } #> OnAfterConstruct(); + OnAfterConstruct(db); } partial void OnAfterConstruct(); + partial void OnAfterConstruct(MemoryDatabaseBase db); + <# for(var i = 0; i < GenerationContext.SecondaryKeys.Length; i++) { var item = GenerationContext.SecondaryKeys[i]; #> public RangeView<<#= GenerationContext.ClassName #>> SortBy<#= item.BuildMethodName() #> => new RangeView<<#= GenerationContext.ClassName #>>(<#= item.TableName #>, 0, <#= item.TableName #>.Length - 1, true); <# } #> @@ -84,7 +87,7 @@ namespace <#= Namespace #>.Tables { return <#= item.BuildFindPrefix() #>Core<#= !item.IsNonUnique && item.IsIntType ? "Int" : "" #>(<#= item.TableName #>, <#= item.SelectorName #>, <#= item.BuildComparer() #>, key, <#= ThrowKeyIfNotFound.ToString().ToLower() #>); } - + public bool TryFindBy<#= item.BuildMethodName() #>(<#= item.BuildTypeName() #> key, out <#= item.BuildReturnTypeName(GenerationContext.ClassName) #> result) { return Try<#= item.BuildFindPrefix() #>Core<#= !item.IsNonUnique && item.IsIntType ? "Int" : "" #>(<#= item.TableName #>, <#= item.SelectorName #>, <#= item.BuildComparer() #>, key, out result); @@ -114,11 +117,11 @@ namespace <#= Namespace #>.Tables #if !DISABLE_MASTERMEMORY_VALIDATOR <# if (!GenerationContext.PrimaryKey.IsNonUnique) { var key = GenerationContext.PrimaryKey; #> - ValidateUniqueCore(<#= key.TableName #>, <#= key.SelectorName #>, "<#= key.BuildPropertyTupleName() #>", resultSet); + ValidateUniqueCore(<#= key.TableName #>, <#= key.SelectorName #>, "<#= key.BuildPropertyTupleName() #>", resultSet); <# } #> <# for(var i = 0; i < GenerationContext.SecondaryKeys.Length; i++) { var key = GenerationContext.SecondaryKeys[i]; #> <# if (!key.IsNonUnique) { #> - ValidateUniqueCore(<#= key.TableName #>, <#= key.SelectorName #>, "<#= key.BuildPropertyTupleName() #>", resultSet); + ValidateUniqueCore(<#= key.TableName #>, <#= key.SelectorName #>, "<#= key.BuildPropertyTupleName() #>", resultSet); <# } #> <# } #> @@ -149,4 +152,4 @@ namespace <#= Namespace #>.Tables #endif } -} \ No newline at end of file +} diff --git a/tests/MasterMemory.Tests/MasterMemory.Tests.csproj b/tests/MasterMemory.Tests/MasterMemory.Tests.csproj index 3ba43b7..35efe37 100644 --- a/tests/MasterMemory.Tests/MasterMemory.Tests.csproj +++ b/tests/MasterMemory.Tests/MasterMemory.Tests.csproj @@ -1,7 +1,7 @@  - net9.0 + net10.0 diff --git a/tests/MasterMemory.Tests/RelationTest.cs b/tests/MasterMemory.Tests/RelationTest.cs new file mode 100644 index 0000000..62457b5 --- /dev/null +++ b/tests/MasterMemory.Tests/RelationTest.cs @@ -0,0 +1,58 @@ +using System.Linq; +using MasterMemory.Tests.TestStructures; + +namespace MasterMemory.Tests; + +public class RelationTest +{ + private MemoryDatabase PrepareDatabase() + { + var builder = new DatabaseBuilder(); + builder.Append(new PersonRelation[] + { + new (){ PersonId = 0, Name = "Dana Terry" }, + new (){ PersonId = 1, Name = "Kirk Obrien" }, + new (){ PersonId = 2, Name = "Wm Banks" }, + new (){ PersonId = 3, Name = "Karl Benson" }, + new (){ PersonId = 4, Name = "Jared Holland" }, + new (){ PersonId = 5, Name = "Jeanne Phelps" }, + new (){ PersonId = 6, Name = "Willie Rose" }, + new (){ PersonId = 7, Name = "Shari Gutierrez" }, + new (){ PersonId = 8, Name = "Lori Wilson" }, + new (){ PersonId = 9, Name = "Lena Ramsey" }, + }); + builder.Append(new RelationItem[] + { + new (){ ItemId = 1, Name = "Sword" }, + new (){ ItemId = 2, Name = "Shield" }, + new (){ ItemId = 3, Name = "Armor" }, + new (){ ItemId = 4, Name = "Spear" }, + new (){ ItemId = 5, Name = "Bow" }, + new (){ ItemId = 6, Name = "Axe" }, + new (){ ItemId = 7, Name = "Hammer" }, + new (){ ItemId = 8, Name = "Spear" }, + }); + builder.Append(new PersonRelationItem[] + { + new (){ PersonId = 1, ItemId = 4 }, + new (){ PersonId = 1, ItemId = 5 }, + new (){ PersonId = 1, ItemId = 6 }, + new (){ PersonId = 4, ItemId = 5 }, + new (){ PersonId = 4, ItemId = 6 }, + }); + + var build = builder.Build(); + + return new MemoryDatabase(build); + } + + [Fact] + public void GetRelation() + { + var db = PrepareDatabase(); + var items = db.PersonRelationTable.GetItemsFromPerson(1).ToArray(); + + items.Count().ShouldBe(3); + items.Select(x => x.Name).ShouldBe(new[] { "Spear", "Bow", "Axe" }); + } +} diff --git a/tests/MasterMemory.Tests/TestStructures/PersonRelations.cs b/tests/MasterMemory.Tests/TestStructures/PersonRelations.cs new file mode 100644 index 0000000..c4f7c61 --- /dev/null +++ b/tests/MasterMemory.Tests/TestStructures/PersonRelations.cs @@ -0,0 +1,58 @@ +using System.Collections.Generic; +using MasterMemory.Tests.TestStructures; +using MessagePack; + +namespace MasterMemory.Tests.TestStructures +{ + + [MemoryTable("person_rel"), MessagePackObject(true)] + public record PersonRelation + { + // index definition by attributes. + [PrimaryKey] public int PersonId { get; set; } + + public string Name { get; set; } + } + + [MemoryTable("person_rel_item"), MessagePackObject(true)] + public record PersonRelationItem + { + [PrimaryKey, NonUnique] + [SecondaryKey(0), NonUnique] + public int PersonId { get; set; } + + [PrimaryKey, NonUnique] + [SecondaryKey(1), NonUnique] + public int ItemId { get; set; } + } + + [MemoryTable("relation_item"), MessagePackObject(true)] + public record RelationItem + { + [PrimaryKey] public int ItemId { get; set; } + + public string Name { get; set; } + } +} + +namespace MasterMemory.Tests.Tables +{ + + public sealed partial class PersonRelationTable + { + private MemoryDatabase _database; + + partial void OnAfterConstruct(MemoryDatabaseBase db) + { + _database = (MemoryDatabase)db; + } + + public IEnumerable GetItemsFromPerson(int personId) + { + foreach (var item in _database.PersonRelationItemTable.FindByPersonId(personId)) + { + yield return _database.RelationItemTable.FindByItemId(item.ItemId); + } + } + } +}