diff --git a/src/JasperFx/Events/CodeGeneration/CreateDocumentMethodCollection.cs b/src/JasperFx/Events/CodeGeneration/CreateDocumentMethodCollection.cs new file mode 100644 index 0000000..37fe696 --- /dev/null +++ b/src/JasperFx/Events/CodeGeneration/CreateDocumentMethodCollection.cs @@ -0,0 +1,35 @@ +namespace JasperFx.Events.CodeGeneration; + +/// +/// This would be a helper for the open ended EventProjection +/// +public class CreateDocumentMethodCollection: MethodCollection +{ + private readonly Type _operationsType; + public static readonly string MethodName = "Create"; + public static readonly string TransformMethodName = "Transform"; + + + + public CreateDocumentMethodCollection(Type projectionType, Type operationsType): base(new[] { MethodName, TransformMethodName }, + projectionType, null) + { + _operationsType = operationsType; + _validArgumentTypes.Add(operationsType); + } + + public override IEventHandlingFrame CreateEventTypeHandler(Type aggregateType, + IStorageMapping aggregateMapping, + MethodSlot slot) + { + return new CreateMethodFrame(_operationsType, slot); + } + + protected override void validateMethod(MethodSlot method) + { + if (method.ReturnType == typeof(void)) + { + method.AddError("The return value must be a new document"); + } + } +} \ No newline at end of file diff --git a/src/JasperFx/Events/CodeGeneration/CreateMethodFrame.cs b/src/JasperFx/Events/CodeGeneration/CreateMethodFrame.cs new file mode 100644 index 0000000..f4d0990 --- /dev/null +++ b/src/JasperFx/Events/CodeGeneration/CreateMethodFrame.cs @@ -0,0 +1,45 @@ +using System.Reflection; +using JasperFx.CodeGeneration; +using JasperFx.CodeGeneration.Frames; +using JasperFx.CodeGeneration.Model; + +namespace JasperFx.Events.CodeGeneration; + +internal class CreateMethodFrame: MethodCall, IEventHandlingFrame +{ + private readonly Type _operationsType; + private static int _counter; + + private Variable _operations; + + public CreateMethodFrame(Type operationsType, MethodSlot slot): base(slot.HandlerType, (MethodInfo)slot.Method) + { + _operationsType = operationsType; + EventType = Method.GetEventType(null); + ReturnVariable.OverrideName(ReturnVariable.Usage + ++_counter); + } + + public Type EventType { get; } + + public void Configure(EventProcessingFrame parent) + { + // Replace any arguments to IEvent + TrySetArgument(parent.SpecificEvent); + + // Replace any arguments to the specific T event type + TrySetArgument(parent.DataOnly); + } + + public override IEnumerable FindVariables(IMethodVariables chain) + { + foreach (var variable in base.FindVariables(chain)) yield return variable; + + _operations = chain.FindVariable(_operationsType); + } + + public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) + { + base.GenerateCode(method, writer); + writer.WriteLine($"{_operations.Usage}.Store({ReturnVariable.Usage});"); + } +} diff --git a/src/JasperFx/Events/CodeGeneration/NewGeneratedProjection.cs b/src/JasperFx/Events/CodeGeneration/NewGeneratedProjection.cs index 113243c..a81a39b 100644 --- a/src/JasperFx/Events/CodeGeneration/NewGeneratedProjection.cs +++ b/src/JasperFx/Events/CodeGeneration/NewGeneratedProjection.cs @@ -4,8 +4,45 @@ namespace JasperFx.Events.CodeGeneration; -/* + +public interface IStore +{ + TOptions Options { get; } + GenerationRules GenerationRules { get; } + IEventGraph Events { get; } +} + +public class GeneratedEventProjection : NewGeneratedProjection + where TStore : IStore +{ + private readonly ProjectMethodCollection _projectMethods; + private readonly CreateDocumentMethodCollection _createMethods; + + public GeneratedEventProjection(Type projectionType) : base(projectionType) + { + _projectMethods = new ProjectMethodCollection(projectionType, typeof(TOperations)); + _createMethods = new CreateDocumentMethodCollection(projectionType, typeof(TOperations)); + } + + protected override void assembleTypes(GeneratedAssembly assembly, TOptions options) + { + throw new NotImplementedException(); + } + + protected override bool tryAttachTypes(Assembly assembly, TOptions options) + { + throw new NotImplementedException(); + } + + protected override bool needsSettersGenerated() + { + throw new NotImplementedException(); + } +} + public abstract class NewGeneratedProjection : ICodeFile + where TStore : IStore { private readonly Type _projectionType; private bool _hasGenerated; @@ -71,9 +108,9 @@ private void generateIfNecessary(TStore store) void generateIfNecessaryLocked() { StoreOptions = store.Options; - var rules = store.Options.CreateGenerationRules(); + var rules = store.GenerationRules; rules.ReferenceTypes(GetType()); - this.As().InitializeSynchronously(rules, store.Options.EventGraph, null); + this.As().InitializeSynchronously(rules, store.Events, null); if (!needsSettersGenerated()) { @@ -98,4 +135,3 @@ void generateIfNecessaryLocked() } -*/ \ No newline at end of file diff --git a/src/JasperFx/Events/CodeGeneration/ProjectMethodCall.cs b/src/JasperFx/Events/CodeGeneration/ProjectMethodCall.cs new file mode 100644 index 0000000..c7246d8 --- /dev/null +++ b/src/JasperFx/Events/CodeGeneration/ProjectMethodCall.cs @@ -0,0 +1,25 @@ +using System.Reflection; +using JasperFx.CodeGeneration.Frames; + +namespace JasperFx.Events.CodeGeneration; + +internal class ProjectMethodCall: MethodCall, IEventHandlingFrame +{ + public ProjectMethodCall(MethodSlot slot): base(slot.HandlerType, (MethodInfo)slot.Method) + { + EventType = Method.GetEventType(null); + Target = slot.Setter; + } + + public Type EventType { get; } + + public void Configure(EventProcessingFrame parent) + { + // Replace any arguments to IEvent + + TrySetArgument(parent.SpecificEvent); + + // Replace any arguments to the specific T event type + TrySetArgument(parent.DataOnly); + } +} diff --git a/src/JasperFx/Events/CodeGeneration/ProjectMethodCollection.cs b/src/JasperFx/Events/CodeGeneration/ProjectMethodCollection.cs new file mode 100644 index 0000000..9b2e65b --- /dev/null +++ b/src/JasperFx/Events/CodeGeneration/ProjectMethodCollection.cs @@ -0,0 +1,36 @@ +using JasperFx.Core.Reflection; + +namespace JasperFx.Events.CodeGeneration; + +/// +/// This would be a helper for the open ended EventProjection +/// +public class ProjectMethodCollection: MethodCollection +{ + private readonly Type _operationsType; + public static readonly string MethodName = "Project"; + + + public ProjectMethodCollection(Type projectionType, Type operationsType): base(MethodName, projectionType, null) + { + _operationsType = operationsType; + _validArgumentTypes.Add(operationsType); + _validReturnTypes.Add(typeof(void)); + _validReturnTypes.Add(typeof(Task)); + } + + protected override void validateMethod(MethodSlot method) + { + if (method.Method.GetParameters().All(x => x.ParameterType != _operationsType)) + { + method.AddError($"{_operationsType.FullNameInCode()} is a required parameter"); + } + } + + public override IEventHandlingFrame CreateEventTypeHandler(Type aggregateType, + IStorageMapping aggregateMapping, + MethodSlot slot) + { + return new ProjectMethodCall(slot); + } +} diff --git a/src/JasperFx/Events/IEventGraph.cs b/src/JasperFx/Events/IEventGraph.cs index 7c03ae5..6843205 100644 --- a/src/JasperFx/Events/IEventGraph.cs +++ b/src/JasperFx/Events/IEventGraph.cs @@ -1,7 +1,9 @@ #nullable enable +using JasperFx.CodeGeneration; + namespace JasperFx.Events; -public interface IEventGraph +public interface IEventGraph : ICodeFileCollection { IEvent BuildEvent(object eventData); EventAppendMode AppendMode { get; set; }