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