Skip to content

Commit

Permalink
Merge branch 'projection-configuration' into quick-append-revision-fix
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremydmiller committed Jul 19, 2024
2 parents 55acdf2 + a1b96f8 commit 70c352e
Show file tree
Hide file tree
Showing 12 changed files with 161 additions and 2 deletions.
7 changes: 7 additions & 0 deletions src/DocumentDbTests/Configuration/DocumentMappingTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ public void can_replace_hilo_def_settings()
sequence.MaxLo.ShouldBe(newDef.MaxLo);
}

[Fact]
public void use_revision_from_stream_is_false_by_default()
{
var mapping = DocumentMapping.For<LongId>();
mapping.UseVersionFromMatchingStream.ShouldBeFalse();
}

[Fact]
public void concrete_type_with_subclasses_is_hierarchy()
{
Expand Down
32 changes: 32 additions & 0 deletions src/EventSourcingTests/Aggregation/CustomProjectionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
using System.Threading;
using System.Threading.Tasks;
using JasperFx.Core.Reflection;
using Marten.Events;
using Marten.Events.Aggregation;
using Marten.Events.Projections;
using Marten.Exceptions;
using Marten.Internal.Sessions;
using Marten.Metadata;
using Marten.Schema;
using Marten.Testing.Documents;
using Marten.Testing.Harness;
using Shouldly;
Expand All @@ -16,6 +18,22 @@ namespace EventSourcingTests.Aggregation;

public class CustomProjectionTests
{
[Theory]
[InlineData(true, EventAppendMode.Quick, true)]
[InlineData(true, EventAppendMode.Rich, false)]
[InlineData(false, EventAppendMode.Rich, false)]
[InlineData(false, EventAppendMode.Quick, false)]
public void configure_mapping(bool isSingleGrouper, EventAppendMode appendMode, bool useVersionFromStream)
{
var projection = isSingleGrouper ? (IAggregateProjection)new MySingleStreamProjection() : new MyCustomProjection();
var mapping = DocumentMapping.For<MyAggregate>();
mapping.StoreOptions.Events.AppendMode = appendMode;

projection.ConfigureAggregateMapping(mapping, mapping.StoreOptions);

mapping.UseVersionFromMatchingStream.ShouldBe(useVersionFromStream);
}

[Fact]
public void default_projection_name_is_type_name()
{
Expand Down Expand Up @@ -247,6 +265,20 @@ public override ValueTask ApplyChangesAsync(DocumentSessionBase session, EventSl
}
}

public class MySingleStreamProjection: CustomProjection<CustomAggregate, Guid>
{
public MySingleStreamProjection()
{
AggregateByStream();
}

public override async ValueTask ApplyChangesAsync(DocumentSessionBase session, EventSlice<CustomAggregate, Guid> slice, CancellationToken cancellation,
ProjectionLifecycle lifecycle = ProjectionLifecycle.Inline)
{
throw new NotImplementedException();
}
}

public class MyCustomProjection: CustomProjection<CustomAggregate, int>
{
public MyCustomProjection()
Expand Down
38 changes: 38 additions & 0 deletions src/EventSourcingTests/Projections/SingleStreamProjectionTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using Marten;
using Marten.Events;
using Marten.Events.Aggregation;
using Marten.Schema;
using Marten.Testing.Documents;
using Shouldly;
using Xunit;

namespace EventSourcingTests.Projections;

public class SingleStreamProjectionTests
{
[Fact]
public void set_mapping_to_UseVersionFromMatchingStream_when_quick_append()
{
var projection = new SingleStreamProjection<User>();
var mapping = DocumentMapping.For<User>();

mapping.StoreOptions.EventGraph.AppendMode = EventAppendMode.Quick;

projection.ConfigureAggregateMapping(mapping, mapping.StoreOptions);

mapping.UseVersionFromMatchingStream.ShouldBeTrue();
}

[Fact]
public void do_not_set_mapping_to_UseVersionFromMatchingStream_when_rich_append()
{
var projection = new SingleStreamProjection<User>();
var mapping = DocumentMapping.For<User>();

mapping.StoreOptions.EventGraph.AppendMode = EventAppendMode.Rich;

projection.ConfigureAggregateMapping(mapping, mapping.StoreOptions);

mapping.UseVersionFromMatchingStream.ShouldBeFalse();
}
}
51 changes: 49 additions & 2 deletions src/Marten/Events/Aggregation/CustomProjection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Marten.Exceptions;
using Marten.Internal.Sessions;
using Marten.Internal.Storage;
using Marten.Schema;
using Marten.Services;
using Marten.Sessions;
using Marten.Storage;
Expand All @@ -21,7 +22,7 @@ namespace Marten.Events.Aggregation;
/// </summary>
/// <typeparam name="TDoc"></typeparam>
/// <typeparam name="TId"></typeparam>
public abstract class CustomProjection<TDoc, TId>: ProjectionBase, IAggregationRuntime<TDoc, TId>, IProjectionSource
public abstract class CustomProjection<TDoc, TId>: ProjectionBase, IAggregationRuntime<TDoc, TId>, IProjectionSource, IAggregateProjection
{
private IDocumentStorage<TDoc, TId> _storage;

Expand Down Expand Up @@ -128,7 +129,6 @@ public ValueTask<IReadOnlyList<TenantSliceGroup<TDoc, TId>>> GroupEventRange(Doc
}

Type IReadOnlyProjectionData.ProjectionType => GetType();
AsyncOptions IProjectionSource.Options { get; } = new();

IEnumerable<Type> IProjectionSource.PublishedTypes()
{
Expand Down Expand Up @@ -225,5 +225,52 @@ public void AggregateByStream()
$"Invalid identity type {typeof(TId).NameInCode()} for aggregating by stream in projection {GetType().FullNameInCode()}");
}
}

public Type AggregateType
{
get => typeof(TDoc);
}

public Type[] AllEventTypes { get; set; }
public bool MatchesAnyDeleteType(StreamAction action)
{
return false; // just no way of knowing
}

public bool MatchesAnyDeleteType(IEventSlice slice)
{
return false; // just no way of knowing
}

public bool AppliesTo(IEnumerable<Type> eventTypes)
{
return true; // just no way of knowing
}

public AsyncOptions Options { get; } = new();
public object ApplyMetadata(object aggregate, IEvent lastEvent)
{
if (aggregate is TDoc t) return ApplyMetadata(t, lastEvent);

return aggregate;
}

/// <summary>
/// Template method that is called on the last event in a slice of events that
/// are updating an aggregate. This was added specifically to add metadata like "LastModifiedBy"
/// from the last event to an aggregate with user-defined logic. Override this for your own specific logic
/// </summary>
/// <param name="aggregate"></param>
/// <param name="lastEvent"></param>
public virtual TDoc ApplyMetadata(TDoc aggregate, IEvent lastEvent)
{
return aggregate;
}

public void ConfigureAggregateMapping(DocumentMapping mapping, StoreOptions storeOptions)
{
mapping.UseVersionFromMatchingStream =
storeOptions.Events.AppendMode == EventAppendMode.Quick && Slicer is ISingleStreamSlicer;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -151,4 +151,9 @@ protected virtual Type[] determineEventTypes()
.Concat(DeleteEvents).Concat(TransformedEvents).Distinct().ToArray();
return eventTypes;
}

public virtual void ConfigureAggregateMapping(DocumentMapping mapping, StoreOptions storeOptions)
{
// nothing
}
}
9 changes: 9 additions & 0 deletions src/Marten/Events/Aggregation/IAggregateProjection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Collections.Generic;
using Marten.Events.Daemon;
using Marten.Events.Projections;
using Marten.Schema;

namespace Marten.Events.Aggregation;

Expand Down Expand Up @@ -33,4 +34,12 @@ public interface IAggregateProjection // THIS NEEDS TO REMAIN PUBLIC
uint ProjectionVersion { get; set; }

object ApplyMetadata(object aggregate, IEvent lastEvent);

/// <summary>
/// Apply any necessary configuration to the document mapping to work with the projection and append
/// mode
/// </summary>
/// <param name="mapping"></param>
/// <param name="storeOptions"></param>
void ConfigureAggregateMapping(DocumentMapping mapping, StoreOptions storeOptions);
}
5 changes: 5 additions & 0 deletions src/Marten/Events/Aggregation/SingleStreamProjection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ protected sealed override object buildEventSlicer(StoreOptions documentMapping)
return Activator.CreateInstance(slicerType);
}

public override void ConfigureAggregateMapping(DocumentMapping mapping, StoreOptions storeOptions)
{
mapping.UseVersionFromMatchingStream = storeOptions.Events.AppendMode == EventAppendMode.Quick;
}

protected sealed override Type baseTypeForAggregationRuntime()
{
return typeof(AggregationRuntime<,>).MakeGenericType(typeof(T), _aggregateMapping.IdType);
Expand Down
1 change: 1 addition & 0 deletions src/Marten/Events/EventMapping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ protected EventMapping(EventGraph parent, Type eventType)
public TenancyStyle TenancyStyle { get; } = TenancyStyle.Single;
public IReadOnlyList<DuplicatedField> DuplicatedFields { get; }
public DeleteStyle DeleteStyle { get; }
public bool UseVersionFromMatchingStream { get; set; }

public PropertySearching PropertySearching { get; } = PropertySearching.JSON_Locator_Only;

Expand Down
2 changes: 2 additions & 0 deletions src/Marten/Events/Projections/ProjectionDocumentPolicy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ public void Apply(DocumentMapping mapping)
mapping.Metadata.Version.Enabled = false;
mapping.UseNumericRevisions = true;
mapping.Metadata.Revision.Enabled = true;

projection.ConfigureAggregateMapping(mapping, mapping.StoreOptions);
}
}
}
6 changes: 6 additions & 0 deletions src/Marten/Schema/DocumentMapping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,12 @@ public DocumentMapping(Type documentType, StoreOptions storeOptions)

internal DocumentSchema Schema => _schema.Value;

/// <summary>
/// This is a workaround for the quick append + inline projection
/// issue
/// </summary>
public bool UseVersionFromMatchingStream { get; set; }

public HiloSettings HiloSettings
{
get => _hiloSettings;
Expand Down
6 changes: 6 additions & 0 deletions src/Marten/Schema/IDocumentMapping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,10 @@ internal interface IDocumentMapping

public PropertySearching PropertySearching { get; }
public DeleteStyle DeleteStyle { get; }

/// <summary>
/// This is a workaround for the quick append + inline projection
/// issue
/// </summary>
bool UseVersionFromMatchingStream { get; set; }
}
1 change: 1 addition & 0 deletions src/Marten/Schema/SubClassMapping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ public SubClassMapping(Type documentType, DocumentMapping parent, StoreOptions s


public DeleteStyle DeleteStyle => Parent.DeleteStyle;
public bool UseVersionFromMatchingStream { get; set; }

public MemberInfo IdMember => Parent.IdMember;

Expand Down

0 comments on commit 70c352e

Please sign in to comment.