< Summary

Information
Class: Elsa.Persistence.EFCore.Modules.Runtime.EFCoreActivityExecutionStore
Assembly: Elsa.Persistence.EFCore
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Persistence.EFCore/Modules/Runtime/ActivityExecutionLogStore.cs
Line coverage
44%
Covered lines: 47
Uncovered lines: 59
Coverable lines: 106
Total lines: 209
Line coverage: 44.3%
Branch coverage
64%
Covered branches: 9
Total branches: 14
Branch coverage: 64.2%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
SaveAsync()100%210%
SaveManyAsync()100%11100%
AddManyAsync()100%210%
FindAsync()100%11100%
FindManyAsync()100%11100%
FindManyAsync()100%11100%
FindManySummariesAsync()100%210%
FindManySummariesAsync()100%210%
CountAsync()100%210%
DeleteManyAsync()100%11100%
OnSaveAsync(...)50%2290.9%
OnLoadAsync()50%2288.88%
DeserializeActivityState()66.66%66100%
Deserialize(...)100%22100%
DeserializePayload(...)100%22100%
Filter(...)100%11100%
FromRecordExpression()100%210%
Map(...)100%210%
Map(...)0%620%
get_WorkflowInstanceId()100%210%
get_ActivityId()100%210%
get_ActivityNodeId()100%210%
get_ActivityType()100%210%
get_ActivityTypeVersion()100%210%
get_ActivityName()100%210%
get_StartedAt()100%210%
get_HasBookmarks()100%210%
get_Status()100%210%
get_SerializedProperties()100%210%
get_SerializedMetadata()100%210%
get_AggregateFaultCount()100%210%
get_CompletedAt()100%210%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Persistence.EFCore/Modules/Runtime/ActivityExecutionLogStore.cs

#LineLine coverage
 1using System.Diagnostics.CodeAnalysis;
 2using System.Linq.Expressions;
 3using System.Text.Json;
 4using Elsa.Common;
 5using Elsa.Common.Codecs;
 6using Elsa.Common.Entities;
 7using Elsa.Extensions;
 8using Elsa.Workflows;
 9using Elsa.Workflows.Runtime;
 10using Elsa.Workflows.Runtime.Entities;
 11using Elsa.Workflows.Runtime.Extensions;
 12using Elsa.Workflows.Runtime.Filters;
 13using Elsa.Workflows.Runtime.OrderDefinitions;
 14using Elsa.Workflows.State;
 15using JetBrains.Annotations;
 16using Microsoft.EntityFrameworkCore;
 17using Open.Linq.AsyncExtensions;
 18
 19namespace Elsa.Persistence.EFCore.Modules.Runtime;
 20
 21/// <summary>
 22/// An EF Core implementation of <see cref="IActivityExecutionStore"/>.
 23/// </summary>
 24[UsedImplicitly]
 32425public class EFCoreActivityExecutionStore(
 32426    EntityStore<RuntimeElsaDbContext, ActivityExecutionRecord> store,
 32427    IPayloadSerializer payloadSerializer,
 32428    ICompressionCodecResolver compressionCodecResolver) : IActivityExecutionStore
 29{
 30    /// <inheritdoc />
 031    public async Task SaveAsync(ActivityExecutionRecord record, CancellationToken cancellationToken = default) => await 
 32
 33    /// <inheritdoc />
 32334    public async Task SaveManyAsync(IEnumerable<ActivityExecutionRecord> records, CancellationToken cancellationToken = 
 35
 36    /// <inheritdoc />
 037    public async Task AddManyAsync(IEnumerable<ActivityExecutionRecord> records, CancellationToken cancellationToken = d
 38
 39    /// <inheritdoc />
 40    [RequiresUnreferencedCode("Calls Elsa.Persistence.EFCore.Modules.Runtime.EFCoreActivityExecutionStore.DeserializeAct
 41    public async Task<ActivityExecutionRecord?> FindAsync(ActivityExecutionRecordFilter filter, CancellationToken cancel
 42    {
 243        return await store.QueryAsync(queryable => Filter(queryable, filter), OnLoadAsync, cancellationToken).FirstOrDef
 144    }
 45
 46    /// <inheritdoc />
 47    public async Task<IEnumerable<ActivityExecutionRecord>> FindManyAsync<TOrderBy>(ActivityExecutionRecordFilter filter
 48    {
 449        return await store.QueryAsync(queryable => Filter(queryable, filter).OrderBy(order), OnLoadAsync, cancellationTo
 250    }
 51
 52    /// <inheritdoc />
 53    [RequiresUnreferencedCode("Calls Elsa.Persistence.EFCore.Modules.Runtime.EFCoreActivityExecutionStore.DeserializeAct
 54    public async Task<IEnumerable<ActivityExecutionRecord>> FindManyAsync(ActivityExecutionRecordFilter filter, Cancella
 55    {
 1656        return await store.QueryAsync(queryable => Filter(queryable, filter), OnLoadAsync, cancellationToken).ToList();
 857    }
 58
 59    /// <inheritdoc />
 60    public async Task<IEnumerable<ActivityExecutionRecordSummary>> FindManySummariesAsync<TOrderBy>(ActivityExecutionRec
 61    {
 062        var shadowRecords = await store.QueryAsync(query => Filter(query, filter), FromRecordExpression(), cancellationT
 063        return Map(shadowRecords);
 064    }
 65
 66    /// <inheritdoc />
 67    public async Task<IEnumerable<ActivityExecutionRecordSummary>> FindManySummariesAsync(ActivityExecutionRecordFilter 
 68    {
 069        var shadowRecords = await store.QueryAsync(query => Filter(query, filter), FromRecordExpression(), cancellationT
 070        return Map(shadowRecords);
 071    }
 72
 73    /// <inheritdoc />
 74    public async Task<long> CountAsync(ActivityExecutionRecordFilter filter, CancellationToken cancellationToken = defau
 75    {
 076        return await store.CountAsync(queryable => Filter(queryable, filter), cancellationToken);
 077    }
 78
 79    /// <inheritdoc />
 80    public async Task<long> DeleteManyAsync(ActivityExecutionRecordFilter filter, CancellationToken cancellationToken = 
 81    {
 2682        return await store.DeleteWhereAsync(queryable => Filter(queryable, filter), cancellationToken);
 1383    }
 84
 85    private ValueTask OnSaveAsync(RuntimeElsaDbContext dbContext, ActivityExecutionRecord entity, CancellationToken canc
 86    {
 248187        var snapshot = entity.SerializedSnapshot;
 88
 248189        if (snapshot is null)
 090            return ValueTask.CompletedTask;
 91
 248192        dbContext.Entry(entity).Property("SerializedActivityState").CurrentValue = snapshot.SerializedActivityState;
 248193        dbContext.Entry(entity).Property("SerializedActivityStateCompressionAlgorithm").CurrentValue = snapshot.Serializ
 248194        dbContext.Entry(entity).Property("SerializedOutputs").CurrentValue = snapshot.SerializedOutputs;
 248195        dbContext.Entry(entity).Property("SerializedProperties").CurrentValue = snapshot.SerializedProperties;
 248196        dbContext.Entry(entity).Property("SerializedMetadata").CurrentValue = snapshot.SerializedMetadata;
 248197        dbContext.Entry(entity).Property("SerializedException").CurrentValue = snapshot.SerializedException;
 248198        dbContext.Entry(entity).Property("SerializedPayload").CurrentValue = snapshot.SerializedPayload;
 248199        return ValueTask.CompletedTask;
 100    }
 101
 102    [RequiresUnreferencedCode("Calls Elsa.Persistence.EFCore.Modules.Runtime.EFCoreActivityExecutionStore.DeserializeAct
 103    private async ValueTask OnLoadAsync(RuntimeElsaDbContext dbContext, ActivityExecutionRecord? entity, CancellationTok
 104    {
 33105        if (entity is null)
 0106            return;
 107
 33108        entity.ActivityState = await DeserializeActivityState(dbContext, entity, cancellationToken);
 33109        entity.Outputs = Deserialize<IDictionary<string, object?>>(dbContext, entity, "SerializedOutputs");
 33110        entity.Properties = DeserializePayload<IDictionary<string, object>?>(dbContext, entity, "SerializedProperties");
 33111        entity.Metadata = DeserializePayload<IDictionary<string, object>?>(dbContext, entity, "SerializedMetadata");
 33112        entity.Exception = DeserializePayload<ExceptionState>(dbContext, entity, "SerializedException");
 33113        entity.Payload = DeserializePayload<IDictionary<string, object>>(dbContext, entity, "SerializedPayload");
 33114    }
 115
 116    [RequiresUnreferencedCode("Calls System.Text.Json.JsonSerializer.Deserialize<TValue>(String, JsonSerializerOptions)"
 117    private async Task<IDictionary<string, object?>?> DeserializeActivityState(RuntimeElsaDbContext dbContext, ActivityE
 118    {
 33119        var json = dbContext.Entry(entity).Property<string>("SerializedActivityState").CurrentValue;
 120
 33121        if (!string.IsNullOrWhiteSpace(json))
 122        {
 16123            var compressionAlgorithm = (string?)dbContext.Entry(entity).Property("SerializedActivityStateCompressionAlgo
 16124            var compressionStrategy = compressionCodecResolver.Resolve(compressionAlgorithm);
 16125            json = await compressionStrategy.DecompressAsync(json, cancellationToken);
 16126            var dictionary = JsonSerializer.Deserialize<IDictionary<string, object?>>(json);
 48127            return dictionary?.ToDictionary(x => x.Key, x => x.Value);
 128        }
 129
 17130        return null;
 33131    }
 132
 133    [RequiresUnreferencedCode("Calls System.Text.Json.JsonSerializer.Deserialize<TValue>(String, JsonSerializerOptions)"
 134    private T Deserialize<T>(RuntimeElsaDbContext dbContext, ActivityExecutionRecord entity, string propertyName)
 135    {
 33136        var json = dbContext.Entry(entity).Property<string>(propertyName).CurrentValue;
 33137        var value = !string.IsNullOrEmpty(json) ? JsonSerializer.Deserialize<T>(json) : default;
 6138        return value!;
 139    }
 140
 141    private T DeserializePayload<T>(RuntimeElsaDbContext dbContext, ActivityExecutionRecord entity, string propertyName)
 142    {
 132143        var json = dbContext.Entry(entity).Property<string>(propertyName).CurrentValue;
 132144        var payload = !string.IsNullOrEmpty(json) ? payloadSerializer.Deserialize<T>(json) : default;
 59145        return payload!;
 146    }
 147
 24148    private static IQueryable<ActivityExecutionRecord> Filter(IQueryable<ActivityExecutionRecord> queryable, ActivityExe
 149
 150    private static Expression<Func<ActivityExecutionRecord, ShadowActivityExecutionRecordSummary>> FromRecordExpression(
 151    {
 0152        return record => new()
 0153        {
 0154            Id = record.Id,
 0155            WorkflowInstanceId = record.WorkflowInstanceId,
 0156            ActivityId = record.ActivityId,
 0157            ActivityNodeId = record.ActivityNodeId,
 0158            ActivityType = record.ActivityType,
 0159            ActivityTypeVersion = record.ActivityTypeVersion,
 0160            ActivityName = record.ActivityName,
 0161            StartedAt = record.StartedAt,
 0162            HasBookmarks = record.HasBookmarks,
 0163            Status = record.Status,
 0164            AggregateFaultCount = record.AggregateFaultCount,
 0165            SerializedProperties = EF.Property<string>(record, "SerializedProperties"),
 0166            SerializedMetadata = EF.Property<string>(record, "SerializedMetadata"),
 0167            CompletedAt = record.CompletedAt
 0168        };
 169    }
 170
 0171    private IEnumerable<ActivityExecutionRecordSummary> Map(IEnumerable<ShadowActivityExecutionRecordSummary> source) =>
 172
 173    private ActivityExecutionRecordSummary Map(ShadowActivityExecutionRecordSummary source)
 174    {
 0175        return new()
 0176        {
 0177            Id = source.Id,
 0178            WorkflowInstanceId = source.WorkflowInstanceId,
 0179            ActivityId = source.ActivityId,
 0180            ActivityNodeId = source.ActivityNodeId,
 0181            ActivityType = source.ActivityType,
 0182            ActivityTypeVersion = source.ActivityTypeVersion,
 0183            ActivityName = source.ActivityName,
 0184            StartedAt = source.StartedAt,
 0185            HasBookmarks = source.HasBookmarks,
 0186            Status = source.Status,
 0187            AggregateFaultCount = source.AggregateFaultCount,
 0188            CompletedAt = source.CompletedAt,
 0189            Metadata = source.SerializedMetadata is null ? null : payloadSerializer.Deserialize<IDictionary<string, obje
 0190        };
 191    }
 192
 193    private class ShadowActivityExecutionRecordSummary : Entity
 194    {
 0195        public string WorkflowInstanceId { get; set; } = null!;
 0196        public string ActivityId { get; set; } = null!;
 0197        public string ActivityNodeId { get; set; } = null!;
 0198        public string ActivityType { get; set; } = null!;
 0199        public int ActivityTypeVersion { get; set; }
 0200        public string? ActivityName { get; set; }
 0201        public DateTimeOffset StartedAt { get; set; }
 0202        public bool HasBookmarks { get; set; }
 0203        public ActivityStatus Status { get; set; }
 0204        public string? SerializedProperties { get; set; }
 0205        public string? SerializedMetadata { get; set; }
 0206        public int AggregateFaultCount { get; set; }
 0207        public DateTimeOffset? CompletedAt { get; set; }
 208    }
 209}

Methods/Properties

.ctor(Elsa.Persistence.EFCore.EntityStore`2<Elsa.Persistence.EFCore.Modules.Runtime.RuntimeElsaDbContext,Elsa.Workflows.Runtime.Entities.ActivityExecutionRecord>,Elsa.Workflows.IPayloadSerializer,Elsa.Common.ICompressionCodecResolver)
SaveAsync()
SaveManyAsync()
AddManyAsync()
FindAsync()
FindManyAsync()
FindManyAsync()
FindManySummariesAsync()
FindManySummariesAsync()
CountAsync()
DeleteManyAsync()
OnSaveAsync(Elsa.Persistence.EFCore.Modules.Runtime.RuntimeElsaDbContext,Elsa.Workflows.Runtime.Entities.ActivityExecutionRecord,System.Threading.CancellationToken)
OnLoadAsync()
DeserializeActivityState()
Deserialize(Elsa.Persistence.EFCore.Modules.Runtime.RuntimeElsaDbContext,Elsa.Workflows.Runtime.Entities.ActivityExecutionRecord,System.String)
DeserializePayload(Elsa.Persistence.EFCore.Modules.Runtime.RuntimeElsaDbContext,Elsa.Workflows.Runtime.Entities.ActivityExecutionRecord,System.String)
Filter(System.Linq.IQueryable`1<Elsa.Workflows.Runtime.Entities.ActivityExecutionRecord>,Elsa.Workflows.Runtime.Filters.ActivityExecutionRecordFilter)
FromRecordExpression()
Map(System.Collections.Generic.IEnumerable`1<Elsa.Persistence.EFCore.Modules.Runtime.EFCoreActivityExecutionStore/ShadowActivityExecutionRecordSummary>)
Map(Elsa.Persistence.EFCore.Modules.Runtime.EFCoreActivityExecutionStore/ShadowActivityExecutionRecordSummary)
get_WorkflowInstanceId()
get_ActivityId()
get_ActivityNodeId()
get_ActivityType()
get_ActivityTypeVersion()
get_ActivityName()
get_StartedAt()
get_HasBookmarks()
get_Status()
get_SerializedProperties()
get_SerializedMetadata()
get_AggregateFaultCount()
get_CompletedAt()