< Summary

Information
Class: Elsa.Workflows.Management.Stores.CachingWorkflowDefinitionStore
Assembly: Elsa.Workflows.Management
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Management/Stores/CachingWorkflowDefinitionStore.cs
Line coverage
59%
Covered lines: 42
Uncovered lines: 29
Coverable lines: 71
Total lines: 172
Line coverage: 59.1%
Branch coverage
50%
Covered branches: 2
Total branches: 4
Branch coverage: 50%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
.cctor()100%11100%
GetTenantReconciliationTokenKey(...)100%11100%
FindAsync()100%11100%
FindAsync()100%11100%
FindManyAsync()100%210%
FindManyAsync()100%11100%
FindManyAsync()100%11100%
<FindManyAsync()100%11100%
FindManyAsync()100%210%
<FindManyAsync()100%210%
FindSummariesAsync()100%210%
FindSummariesAsync()100%210%
FindSummariesAsync()100%11100%
FindSummariesAsync()100%210%
FindLastVersionAsync()100%11100%
SaveAsync()100%11100%
TryUpdateLatestAsync()0%620%
SaveManyAsync()100%11100%
DeleteAsync()100%11100%
AnyAsync()100%210%
CountDistinctAsync()100%210%
GetIsNameUnique()100%210%
GetOrCreateAsync()100%22100%
<GetOrCreateAsync()100%11100%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Management/Stores/CachingWorkflowDefinitionStore.cs

#LineLine coverage
 1using Elsa.Caching;
 2using Elsa.Common.Models;
 3using Elsa.Common.Multitenancy;
 4using Elsa.Workflows.Management.Entities;
 5using Elsa.Workflows.Management.Filters;
 6using Elsa.Workflows.Management.Models;
 7using Microsoft.Extensions.Caching.Memory;
 8
 9namespace Elsa.Workflows.Management.Stores;
 10
 11/// <summary>
 12/// A decorator for <see cref="IWorkflowDefinitionStore"/> that caches workflow definitions.
 13/// </summary>
 43614public class CachingWorkflowDefinitionStore(IWorkflowDefinitionStore decoratedStore, ICacheManager cacheManager, IHasher
 15{
 216    private static readonly string CacheInvalidationTokenKey = typeof(CachingWorkflowDefinitionStore).FullName!;
 17
 18    /// <summary>
 19    /// Gets the local reconciliation token for a tenant's workflow-definition view.
 20    /// </summary>
 929921    internal static string GetTenantReconciliationTokenKey(string tenantId) => $"{CacheInvalidationTokenKey}:Reconcile:{
 22
 23    /// <inheritdoc />
 24    public async Task<WorkflowDefinition?> FindAsync(WorkflowDefinitionFilter filter, CancellationToken cancellationToke
 25    {
 332826        var cacheKey = hasher.Hash(filter);
 665427        return await GetOrCreateAsync(cacheKey, () => decoratedStore.FindAsync(filter, cancellationToken));
 332828    }
 29
 30    /// <inheritdoc />
 31    public async Task<WorkflowDefinition?> FindAsync<TOrderBy>(WorkflowDefinitionFilter filter, WorkflowDefinitionOrder<
 32    {
 1133        var cacheKey = hasher.Hash(filter, order);
 2234        return await GetOrCreateAsync(cacheKey, () => decoratedStore.FindAsync(filter, order, cancellationToken));
 1135    }
 36
 37    /// <inheritdoc />
 38    public async Task<Page<WorkflowDefinition>> FindManyAsync(WorkflowDefinitionFilter filter, PageArgs pageArgs, Cancel
 39    {
 040        var cacheKey = hasher.Hash(filter, pageArgs);
 041        return (await GetOrCreateAsync(cacheKey, () => decoratedStore.FindManyAsync(filter, pageArgs, cancellationToken)
 042    }
 43
 44    /// <inheritdoc />
 45    public async Task<Page<WorkflowDefinition>> FindManyAsync<TOrderBy>(WorkflowDefinitionFilter filter, WorkflowDefinit
 46    {
 247        var cacheKey = hasher.Hash(filter, order, pageArgs);
 448        return (await GetOrCreateAsync(cacheKey, () => decoratedStore.FindManyAsync(filter, order, pageArgs, cancellatio
 249    }
 50
 51    /// <inheritdoc />
 52    public async Task<IEnumerable<WorkflowDefinition>> FindManyAsync(WorkflowDefinitionFilter filter, CancellationToken 
 53    {
 585754        var cacheKey = hasher.Hash(filter);
 1160455        return (await GetOrCreateAsync(cacheKey, async () => (await decoratedStore.FindManyAsync(filter, cancellationTok
 585756    }
 57
 58    /// <inheritdoc />
 59    public async Task<IEnumerable<WorkflowDefinition>> FindManyAsync<TOrderBy>(WorkflowDefinitionFilter filter, Workflow
 60    {
 061        var cacheKey = hasher.Hash(filter, order);
 062        return (await GetOrCreateAsync(cacheKey, async () => (await decoratedStore.FindManyAsync(filter, order, cancella
 063    }
 64
 65    /// <inheritdoc />
 66    public async Task<Page<WorkflowDefinitionSummary>> FindSummariesAsync(WorkflowDefinitionFilter filter, PageArgs page
 67    {
 068        var cacheKey = hasher.Hash(filter, pageArgs);
 069        return (await GetOrCreateAsync(cacheKey, () => decoratedStore.FindSummariesAsync(filter, pageArgs, cancellationT
 070    }
 71
 72    /// <inheritdoc />
 73    public async Task<Page<WorkflowDefinitionSummary>> FindSummariesAsync<TOrderBy>(WorkflowDefinitionFilter filter, Wor
 74    {
 075        var cacheKey = hasher.Hash(filter, order, pageArgs);
 076        return (await GetOrCreateAsync(cacheKey, () => decoratedStore.FindSummariesAsync(filter, order, pageArgs, cancel
 077    }
 78
 79    /// <inheritdoc />
 80    public async Task<IEnumerable<WorkflowDefinitionSummary>> FindSummariesAsync(WorkflowDefinitionFilter filter, Cancel
 81    {
 1682        var cacheKey = hasher.Hash(filter);
 2383        return (await GetOrCreateAsync(cacheKey, () => decoratedStore.FindSummariesAsync(filter, cancellationToken)))!;
 1684    }
 85
 86    /// <inheritdoc />
 87    public async Task<IEnumerable<WorkflowDefinitionSummary>> FindSummariesAsync<TOrderBy>(WorkflowDefinitionFilter filt
 88    {
 089        var cacheKey = hasher.Hash(filter, order);
 090        return (await GetOrCreateAsync(cacheKey, () => decoratedStore.FindSummariesAsync(filter, order, cancellationToke
 091    }
 92
 93    /// <inheritdoc />
 94    public async Task<WorkflowDefinition?> FindLastVersionAsync(WorkflowDefinitionFilter filter, CancellationToken cance
 95    {
 2196        var cacheKey = hasher.Hash(filter);
 3897        return await GetOrCreateAsync(cacheKey, () => decoratedStore.FindLastVersionAsync(filter, cancellationToken));
 2198    }
 99
 100    /// <inheritdoc />
 101    public async Task SaveAsync(WorkflowDefinition definition, CancellationToken cancellationToken = default)
 102    {
 27103        await decoratedStore.SaveAsync(definition, cancellationToken);
 27104        await cacheManager.TriggerTokenAsync(CacheInvalidationTokenKey, cancellationToken);
 27105    }
 106
 107    /// <inheritdoc />
 108    public async Task<WorkflowDefinitionUpdateResult> TryUpdateLatestAsync(
 109        WorkflowDefinitionFilter filter,
 110        Func<WorkflowDefinition, bool> matchesExpected,
 111        Func<WorkflowDefinition, WorkflowDefinition> update,
 112        CancellationToken cancellationToken = default)
 113    {
 0114        var result = await decoratedStore.TryUpdateLatestAsync(filter, matchesExpected, update, cancellationToken);
 115
 0116        if (result.Outcome == WorkflowDefinitionUpdateOutcome.Updated)
 0117            await cacheManager.TriggerTokenAsync(CacheInvalidationTokenKey, cancellationToken);
 118
 0119        return result;
 0120    }
 121
 122    /// <inheritdoc />
 123    public async Task SaveManyAsync(IEnumerable<WorkflowDefinition> definitions, CancellationToken cancellationToken = d
 124    {
 2760125        await decoratedStore.SaveManyAsync(definitions, cancellationToken);
 2760126        await cacheManager.TriggerTokenAsync(CacheInvalidationTokenKey, cancellationToken);
 2760127    }
 128
 129    /// <inheritdoc />
 130    public async Task<long> DeleteAsync(WorkflowDefinitionFilter filter, CancellationToken cancellationToken = default)
 131    {
 7132        var result = await decoratedStore.DeleteAsync(filter, cancellationToken);
 7133        await cacheManager.TriggerTokenAsync(CacheInvalidationTokenKey, cancellationToken);
 7134        return result;
 7135    }
 136
 137    /// <inheritdoc />
 138    public async Task<bool> AnyAsync(WorkflowDefinitionFilter filter, CancellationToken cancellationToken = default)
 139    {
 0140        var cacheKey = hasher.Hash(nameof(AnyAsync), filter);
 0141        return await GetOrCreateAsync(cacheKey, () => decoratedStore.AnyAsync(filter, cancellationToken));
 0142    }
 143
 144    /// <inheritdoc />
 145    public async Task<long> CountDistinctAsync(CancellationToken cancellationToken = default)
 146    {
 0147        var cacheKey = hasher.Hash(nameof(CountDistinctAsync));
 0148        return await GetOrCreateAsync(cacheKey, () => decoratedStore.CountDistinctAsync(cancellationToken));
 0149    }
 150
 151    /// <inheritdoc />
 152    public async Task<bool> GetIsNameUnique(string name, string? definitionId = null, CancellationToken cancellationToke
 153    {
 0154        var cacheKey = hasher.Hash(nameof(GetIsNameUnique), name, definitionId);
 0155        return await GetOrCreateAsync(cacheKey, () => decoratedStore.GetIsNameUnique(name, definitionId, cancellationTok
 0156    }
 157
 158    private async Task<T?> GetOrCreateAsync<T>(string key, Func<Task<T>> factory)
 159    {
 9235160        var tenantId = tenantAccessor.TenantId;
 9235161        var tenantIdPrefix = !string.IsNullOrEmpty(tenantId) ? $"{tenantId}:" : string.Empty;
 9235162        var internalKey = $"{tenantIdPrefix}{typeof(T).Name}:{key}";
 9235163        return await cacheManager.FindOrCreateAsync(internalKey, async entry =>
 9235164        {
 9110165            entry.AddExpirationToken(cacheManager.GetToken(CacheInvalidationTokenKey));
 9110166            entry.AddExpirationToken(cacheManager.GetToken(GetTenantReconciliationTokenKey(tenantId)));
 9110167            entry.SetSlidingExpiration(cacheManager.CachingOptions.Value.CacheDuration);
 9110168            return await factory();
 18345169        });
 9235170    }
 171
 172}