-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Moved most of the projection codegen work to JasperFx
- Loading branch information
1 parent
61177ca
commit adf72ac
Showing
21 changed files
with
1,419 additions
and
20 deletions.
There are no files selected for viewing
57 changes: 57 additions & 0 deletions
57
src/JasperFx/Events/CodeGeneration/AggregateConstructorFrame.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
using JasperFx.CodeGeneration; | ||
using JasperFx.CodeGeneration.Frames; | ||
using JasperFx.CodeGeneration.Model; | ||
using JasperFx.Core.Reflection; | ||
|
||
namespace JasperFx.Events.CodeGeneration; | ||
|
||
/// <summary> | ||
/// Calls the aggregate's single argument constructor for a specific | ||
/// event type | ||
/// </summary> | ||
public class AggregateConstructorFrame: SyncFrame, IEventHandlingFrame | ||
{ | ||
private readonly Type _argType; | ||
private readonly MethodSlot _slot; | ||
private Variable _aggregate; | ||
private Variable _arg; | ||
|
||
public AggregateConstructorFrame(MethodSlot slot) | ||
{ | ||
_slot = slot; | ||
_argType = slot.Method.GetParameters().Single().ParameterType; | ||
} | ||
|
||
public void Configure(EventProcessingFrame parent) | ||
{ | ||
_arg = parent.SpecificEvent.VariableType == _argType ? parent.SpecificEvent : parent.DataOnly; | ||
_aggregate = parent.Aggregate; | ||
} | ||
|
||
public Type EventType => _slot.EventType; | ||
|
||
public override IEnumerable<Variable> FindVariables(IMethodVariables chain) | ||
{ | ||
if (_aggregate != null) | ||
{ | ||
yield return _aggregate; | ||
} | ||
|
||
yield return _arg; | ||
} | ||
|
||
public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) | ||
{ | ||
if (_aggregate == null) | ||
{ | ||
writer.WriteLine($"return new {_slot.ReturnType.FullNameInCode()}({_arg.Usage});"); | ||
} | ||
else | ||
{ | ||
writer.WriteLine($"{_aggregate.Usage} ??= new {_slot.ReturnType.FullNameInCode()}({_arg.Usage});"); | ||
} | ||
|
||
|
||
Next?.GenerateCode(method, writer); | ||
} | ||
} |
109 changes: 109 additions & 0 deletions
109
src/JasperFx/Events/CodeGeneration/AggregateEventProcessingFrame.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
using JasperFx.CodeGeneration; | ||
using JasperFx.CodeGeneration.Frames; | ||
using JasperFx.Core.Reflection; | ||
|
||
namespace JasperFx.Events.CodeGeneration; | ||
|
||
public class AggregateEventProcessingFrame: EventProcessingFrame | ||
{ | ||
private ApplyMethodCall _apply; | ||
|
||
private Frame _creation; | ||
private ShouldDeleteFrame _deletion; | ||
|
||
public AggregateEventProcessingFrame(Type aggregateType, Type eventType): base(true, aggregateType, eventType) | ||
{ | ||
} | ||
|
||
public bool AlwaysDeletes { get; set; } | ||
|
||
public Frame CreationFrame | ||
{ | ||
get => _creation; | ||
set | ||
{ | ||
if (value is not IEventHandlingFrame) | ||
{ | ||
throw new ArgumentOutOfRangeException( | ||
$"The CreationFrame must implement {nameof(IEventHandlingFrame)}"); | ||
} | ||
|
||
_inner.Add(value); | ||
_creation = value; | ||
} | ||
} | ||
|
||
public ShouldDeleteFrame Deletion | ||
{ | ||
get => _deletion; | ||
set | ||
{ | ||
_deletion = value; | ||
_inner.Add(value); | ||
} | ||
} | ||
|
||
public ApplyMethodCall Apply | ||
{ | ||
get => _apply; | ||
set | ||
{ | ||
_apply = value; | ||
_inner.Add(value); | ||
} | ||
} | ||
|
||
public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) | ||
{ | ||
writer.Write($"case {SpecificEvent.VariableType.FullNameInCode()} {SpecificEvent.Usage}:"); | ||
|
||
writer.IndentionLevel++; | ||
|
||
|
||
if (AlwaysDeletes) | ||
{ | ||
writer.Write("return null;"); | ||
} | ||
|
||
if (Apply == null) | ||
{ | ||
if (CreationFrame != null) | ||
{ | ||
CreationFrame.GenerateCode(method, writer); | ||
} | ||
else | ||
{ | ||
writer.Write($"{Aggregate.Usage} ??= CreateDefault(evt);"); | ||
} | ||
} | ||
else if (CreationFrame != null) | ||
{ | ||
writer.Write($"BLOCK:if ({Aggregate.Usage} == null)"); | ||
|
||
CreationFrame.GenerateCode(method, writer); | ||
|
||
writer.FinishBlock(); | ||
writer.WriteElse(); | ||
Apply.GenerateCode(method, writer); | ||
writer.FinishBlock(); | ||
} | ||
else // Have an Apply() method and no Create() | ||
{ | ||
writer.Write($"{Aggregate.Usage} ??= CreateDefault(evt);"); | ||
Apply.GenerateCode(method, writer); | ||
} | ||
|
||
if (Deletion != null) | ||
{ | ||
writer.Write($"if ({Aggregate.Usage} == null) return null;"); | ||
|
||
Deletion.GenerateCode(method, writer); | ||
} | ||
|
||
writer.Write($"return {Aggregate.Usage};"); | ||
|
||
writer.IndentionLevel--; | ||
|
||
Next?.GenerateCode(method, writer); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
using System.Reflection; | ||
using JasperFx.CodeGeneration.Frames; | ||
|
||
namespace JasperFx.Events.CodeGeneration; | ||
|
||
public class ApplyMethodCall: MethodCall, IEventHandlingFrame | ||
{ | ||
public ApplyMethodCall(Type handlerType, string methodName, Type aggregateType): base(handlerType, methodName) | ||
{ | ||
EventType = Method.GetEventType(aggregateType); | ||
} | ||
|
||
public ApplyMethodCall(MethodSlot slot): base(slot.HandlerType, (MethodInfo)slot.Method) | ||
{ | ||
EventType = slot.EventType; | ||
if (slot.Setter != null) | ||
{ | ||
Target = slot.Setter; | ||
} | ||
} | ||
|
||
public Type EventType { get; } | ||
|
||
public void Configure(EventProcessingFrame parent) | ||
{ | ||
// Replace any arguments to IEvent<T> | ||
TrySetArgument(parent.SpecificEvent); | ||
|
||
// Replace any arguments to the specific T event type | ||
TrySetArgument(parent.DataOnly); | ||
|
||
if (ReturnType == parent.AggregateType) | ||
{ | ||
AssignResultTo(parent.Aggregate); | ||
} | ||
} | ||
} |
68 changes: 68 additions & 0 deletions
68
src/JasperFx/Events/CodeGeneration/ApplyMethodCollection.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
using JasperFx.CodeGeneration; | ||
using JasperFx.CodeGeneration.Frames; | ||
using JasperFx.CodeGeneration.Model; | ||
using JasperFx.Core.Reflection; | ||
|
||
namespace JasperFx.Events.CodeGeneration; | ||
|
||
public class ApplyMethodCollection: MethodCollection | ||
{ | ||
public static readonly string MethodName = "Apply"; | ||
|
||
public ApplyMethodCollection(Type projectionType, Type aggregateType, Type querySessionType): base(MethodName, projectionType, | ||
aggregateType) | ||
{ | ||
QuerySessionType = querySessionType; | ||
LambdaName = "ProjectEvent"; | ||
_validArgumentTypes.Add(querySessionType); | ||
_validArgumentTypes.Add(aggregateType); | ||
|
||
_validReturnTypes.Add(typeof(Task)); | ||
_validReturnTypes.Add(typeof(void)); | ||
_validReturnTypes.Add(aggregateType); | ||
_validReturnTypes.Add(typeof(Task<>).MakeGenericType(aggregateType)); | ||
} | ||
|
||
public Type QuerySessionType { get; } | ||
|
||
protected override void validateMethod(MethodSlot method) | ||
{ | ||
if (!method.DeclaredByAggregate && method.Method.GetParameters().All(x => x.ParameterType != AggregateType)) | ||
{ | ||
method.AddError($"Aggregate type '{AggregateType.FullNameInCode()}' is required as a parameter"); | ||
} | ||
} | ||
|
||
public override IEventHandlingFrame CreateEventTypeHandler(Type aggregateType, | ||
IStorageMapping aggregateMapping, MethodSlot slot) | ||
{ | ||
return new ApplyMethodCall(slot); | ||
} | ||
|
||
public void BuildApplyMethod(GeneratedType generatedType, IStorageMapping aggregateMapping) | ||
{ | ||
var returnType = IsAsync | ||
? typeof(ValueTask<>).MakeGenericType(AggregateType) | ||
: AggregateType; | ||
|
||
var args = new[] | ||
{ | ||
new Argument(typeof(IEvent), "@event"), new Argument(AggregateType, "aggregate"), | ||
new Argument(QuerySessionType, "session") | ||
}; | ||
|
||
if (IsAsync) | ||
{ | ||
args = args.Concat(new[] { new Argument(typeof(CancellationToken), "cancellation") }).ToArray(); | ||
} | ||
|
||
var method = new GeneratedMethod(MethodName, returnType, args); | ||
generatedType.AddMethod(method); | ||
|
||
var eventHandling = AddEventHandling(AggregateType, aggregateMapping, this); | ||
method.Frames.Add(eventHandling); | ||
|
||
|
||
method.Frames.Code("return {0};", new Use(AggregateType)); | ||
} | ||
} |
78 changes: 78 additions & 0 deletions
78
src/JasperFx/Events/CodeGeneration/CallApplyAggregateFrame.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
using JasperFx.CodeGeneration; | ||
using JasperFx.CodeGeneration.Frames; | ||
using JasperFx.CodeGeneration.Model; | ||
using JasperFx.Core.Reflection; | ||
|
||
namespace JasperFx.Events.CodeGeneration; | ||
|
||
public class CallApplyAggregateFrame: Frame | ||
{ | ||
private readonly Type _fullSessionType; | ||
private Variable _aggregate; | ||
private Variable _cancellation; | ||
private Variable _session; | ||
private Variable _usedEventOnCreate; | ||
private readonly Type _querySessionType; | ||
|
||
/// <summary> | ||
/// | ||
/// </summary> | ||
/// <param name="methods"></param> | ||
/// <param name="fullSessionType">"Fuller" session type just in case we need that</param> | ||
public CallApplyAggregateFrame(ApplyMethodCollection methods, Type fullSessionType): base(methods.IsAsync) | ||
{ | ||
_fullSessionType = fullSessionType; | ||
AggregateType = methods.AggregateType; | ||
_querySessionType = methods.QuerySessionType; | ||
} | ||
|
||
public Type AggregateType { get; } | ||
public bool InsideForEach { get; set; } | ||
|
||
public override IEnumerable<Variable> FindVariables(IMethodVariables chain) | ||
{ | ||
_aggregate = chain.FindVariable(AggregateType); | ||
|
||
_session = chain.TryFindVariable(_querySessionType, VariableSource.All) ?? | ||
chain.FindVariable(_fullSessionType); | ||
|
||
_usedEventOnCreate = chain.FindVariableByName(typeof(bool), CallCreateAggregateFrame.UsedEventOnCreateName); | ||
|
||
yield return _session; | ||
|
||
if (IsAsync) | ||
{ | ||
_cancellation = chain.TryFindVariable(typeof(CancellationToken), VariableSource.All) ?? | ||
new Variable(typeof(CancellationToken), | ||
$"{typeof(CancellationToken).FullNameInCode()}.None"); | ||
|
||
yield return _cancellation; | ||
} | ||
} | ||
|
||
public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) | ||
{ | ||
if (InsideForEach) | ||
{ | ||
writer.Write($"BLOCK:foreach (var @event in events.Skip({_usedEventOnCreate.Usage} ? 1 : 0))"); | ||
} | ||
|
||
if (IsAsync) | ||
{ | ||
writer.WriteLine( | ||
$"{_aggregate.Usage} = await {ApplyMethodCollection.MethodName}(@event, {_aggregate.Usage}, {_session.Usage}, {_cancellation.Usage});"); | ||
} | ||
else | ||
{ | ||
writer.WriteLine( | ||
$"{_aggregate.Usage} = {ApplyMethodCollection.MethodName}(@event, {_aggregate.Usage}, {_session.Usage});"); | ||
} | ||
|
||
if (InsideForEach) | ||
{ | ||
writer.FinishBlock(); | ||
} | ||
|
||
Next?.GenerateCode(method, writer); | ||
} | ||
} |
Oops, something went wrong.