RSCG – corecraft
RSCG – corecraft
name | corecraft |
nuget | https://www.nuget.org/packages/corecraft/ |
link | https://github.com/AlexNav73/CoreCraft |
author |
Decomposing properties and class into Domain Models. Seems however too complicated to use
This is how you can use corecraft .
The code that you start with is
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net8.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> <PropertyGroup> <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles> <CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath> </PropertyGroup> <ItemGroup> <None Remove="Person.model.json" /> </ItemGroup> <ItemGroup> <AdditionalFiles Include="Person.model.json"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </AdditionalFiles> </ItemGroup> <ItemGroup> <PackageReference Include="CoreCraft" Version="0.6.0" /> <PackageReference Include="CoreCraft.Generators" Version="0.6.0"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> </ItemGroup> </Project>
The code that you will use is
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net8.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> <PropertyGroup> <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles> <CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath> </PropertyGroup> <ItemGroup> <None Remove="Person.model.json" /> </ItemGroup> <ItemGroup> <AdditionalFiles Include="Person.model.json"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </AdditionalFiles> </ItemGroup> <ItemGroup> <PackageReference Include="CoreCraft" Version="0.6.0" /> <PackageReference Include="CoreCraft.Generators" Version="0.6.0"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> </ItemGroup> </Project>
using CoreCraft; using CoreCraft.ChangesTracking; using CoreCraft.Subscription; using Json2Code.Person; using Json2Code.Person.Entities; var model = new DomainModel(new[] { new Json2Code.Person.PersonShardModelShard() }); // Subscribe to Items collection change events using var subscription = model.For<IPersonShardChangesFrame>() .With(x => x.Persons) .Subscribe(OnItemChanged); // Observe changes void OnItemChanged(Change<ICollectionChangeSet<Person, PersonProperties>> changes) { foreach (var c in changes.Hunk) { Console.WriteLine($"Entity [{c.Entity}] has been {c.Action}ed."); Console.WriteLine($" Old data: {c.OldData}"); Console.WriteLine($" New data: {c.NewData}"); } } await model.Run<IMutablePersonShardModelShard> ( (shard, _) => { shard.Persons.Add(new() { FirstName = "A", LastName = "B" }); //shard.Persons.Remove(shard.Persons.First()); }); await model.Run<IMutablePersonShardModelShard>( (shard, _) => { shard.Persons.Modify(shard.Persons.First(), p => p with { FirstName = "C" }); }); await model.Run<IMutablePersonShardModelShard>( (shard, _) => { shard.Persons.Remove(shard.Persons.First()); }); Console.WriteLine("Press any key to exit..."); Console.ReadKey();
{ "shards": [ { "name": "PersonShard", "entities": [ { "name": "Person", "properties": [ { "name": "FirstName", "type": "string", "defaultValue": "\"Andrei\"" }, { "name": "LastName", "type": "string", "defaultValue": "\"Ignat\"" } ] } ], "collections": [ { "name": "Persons", "entityType": "Person" } ], "relations": [] } ] }
The code that is generated is
//------------------------------------------------------------------------------ // <auto-generated> // This code was generated by the tool. // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // </auto-generated> //------------------------------------------------------------------------------ #nullable enable namespace Json2Code.Person { using CoreCraft.Core; using CoreCraft.ChangesTracking; using CoreCraft.Persistence; using Json2Code.Person.Entities; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("C# Source Generator", "1.0.0.0")] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public interface IPersonShardModelShard : IModelShard { ICollection<Person, PersonProperties> Persons { get; } } [global::System.CodeDom.Compiler.GeneratedCodeAttribute("C# Source Generator", "1.0.0.0")] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public interface IMutablePersonShardModelShard : IModelShard { IMutableCollection<Person, PersonProperties> Persons { get; } } [global::System.CodeDom.Compiler.GeneratedCodeAttribute("C# Source Generator", "1.0.0.0")] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute()] internal static class PersonShardModelShardInfo { public static readonly CollectionInfo PersonsInfo = new("PersonShard", "Persons", new PropertyInfo[] { new("FirstName", typeof(string), false), new("LastName", typeof(string), false) }); } [global::System.CodeDom.Compiler.GeneratedCodeAttribute("C# Source Generator", "1.0.0.0")] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute()] internal sealed partial class PersonShardModelShard : IPersonShardModelShard { public const string PersonsId = "Json2Code.Person.PersonShard.Persons"; public PersonShardModelShard() { Persons = new Collection<Person, PersonProperties>( PersonsId, static id => new Person(id), static () => new PersonProperties()); } internal PersonShardModelShard(IMutablePersonShardModelShard mutable) { Persons = ((IMutableState<ICollection<Person, PersonProperties>>)mutable.Persons).AsReadOnly(); } public ICollection<Person, PersonProperties> Persons { get; init; } = null!; } internal sealed partial class PersonShardModelShard : IReadOnlyState<IMutablePersonShardModelShard> { public IMutablePersonShardModelShard AsMutable(global::System.Collections.Generic.IEnumerable<IFeature> features) { var persons = (IMutableCollection<Person, PersonProperties>)Persons; foreach (var feature in features) { persons = feature.Decorate(this, persons); } return new MutablePersonShardModelShard() { Persons = persons, }; } } internal sealed partial class PersonShardModelShard : ICanBeSaved { public void Save(IRepository repository) { repository.Save(PersonShardModelShardInfo.PersonsInfo, Persons); } } internal sealed partial class PersonShardModelShard : IFeatureContext { IChangesFrame IFeatureContext.GetOrAddFrame(IMutableModelChanges modelChanges) { return modelChanges.Register(static () => new PersonShardChangesFrame()); } } [global::System.CodeDom.Compiler.GeneratedCodeAttribute("C# Source Generator", "1.0.0.0")] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public interface IPersonShardChangesFrame : IChangesFrame { ICollectionChangeSet<Person, PersonProperties> Persons { get; } } [global::System.CodeDom.Compiler.GeneratedCodeAttribute("C# Source Generator", "1.0.0.0")] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute()] internal sealed class PersonShardChangesFrame : IPersonShardChangesFrame, IChangesFrameEx, ICanBeSaved { public PersonShardChangesFrame() { Persons = new CollectionChangeSet<Person, PersonProperties>(PersonShardModelShard.PersonsId); } public ICollectionChangeSet<Person, PersonProperties> Persons { get; private set; } ICollectionChangeSet<TEntity, TProperty>? IChangesFrame.Get<TEntity, TProperty>(ICollection<TEntity, TProperty> collection) { if (Persons.Id == collection.Id) return Persons as ICollectionChangeSet<TEntity, TProperty>; throw new System.InvalidOperationException("Unable to find collection's changes set"); } IRelationChangeSet<TParent, TChild>? IChangesFrame.Get<TParent, TChild>(IRelation<TParent, TChild> relation) { throw new System.InvalidOperationException($"Unable to find relation's change set"); } IChangesFrame IChangesFrame.Invert() { return new PersonShardChangesFrame() { Persons = Persons.Invert(), }; } public void Apply(IModel model) { var modelShard = model.Shard<IMutablePersonShardModelShard>(); Persons.Apply(modelShard.Persons); } public bool HasChanges() { return Persons.HasChanges(); } public IChangesFrame Merge(IChangesFrame frame) { var typedFrame = (PersonShardChangesFrame)frame; return new PersonShardChangesFrame() { Persons = Persons.Merge(typedFrame.Persons), }; } public void Save(IRepository repository) { repository.Save(PersonShardModelShardInfo.PersonsInfo, Persons); } } [global::System.CodeDom.Compiler.GeneratedCodeAttribute("C# Source Generator", "1.0.0.0")] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute()] internal sealed class MutablePersonShardModelShard : IMutablePersonShardModelShard, IMutableState<IPersonShardModelShard>, ICanBeLoaded { public IMutableCollection<Person, PersonProperties> Persons { get; init; } = null!; public IPersonShardModelShard AsReadOnly() { return new PersonShardModelShard(this); } public void Load(IRepository repository) { repository.Load(PersonShardModelShardInfo.PersonsInfo, Persons); } } } namespace Json2Code.Person.Entities { using CoreCraft.Core; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("C# Source Generator", "1.0.0.0")] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute()] public sealed record Person(global::System.Guid Id) : Entity(Id) { internal Person() : this(global::System.Guid.NewGuid()) { } } [global::System.CodeDom.Compiler.GeneratedCodeAttribute("C# Source Generator", "1.0.0.0")] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute()] public sealed partial record PersonProperties : Properties { public PersonProperties() { FirstName = "Andrei"; LastName = "Ignat"; } public string FirstName { get; init; } public string LastName { get; init; } #if NET5_0_OR_GREATER public override PersonProperties ReadFrom(IPropertiesBag bag) #else public override Properties ReadFrom(IPropertiesBag bag) #endif { return new PersonProperties() { FirstName = bag.Read<string>("FirstName"), LastName = bag.Read<string>("LastName"), }; } public override void WriteTo(IPropertiesBag bag) { bag.Write("FirstName", FirstName); bag.Write("LastName", LastName); } } }
Code and pdf at
https://ignatandrei.github.io/RSCG_Examples/v2/docs/corecraft
Leave a Reply