< Summary

Information
Class: Elsa.Identity.Services.MemoryApplicationStore
Assembly: Elsa.Identity
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Identity/Services/MemoryApplicationStore.cs
Line coverage
100%
Covered lines: 36
Uncovered lines: 0
Coverable lines: 36
Total lines: 91
Line coverage: 100%
Branch coverage
100%
Covered branches: 6
Total branches: 6
Branch coverage: 100%
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%11100%
DeleteAsync(...)100%22100%
FindAsync(...)100%11100%
Filter(...)100%11100%
IsVisible(...)100%11100%
ApplyCurrentTenant(...)100%44100%
Clone(...)100%11100%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Identity/Services/MemoryApplicationStore.cs

#LineLine coverage
 1using Elsa.Common.Entities;
 2using Elsa.Common.Multitenancy;
 3using Elsa.Common.Services;
 4using Elsa.Identity.Contracts;
 5using Elsa.Identity.Entities;
 6using Elsa.Identity.Models;
 7
 8namespace Elsa.Identity.Services;
 9
 10/// <summary>
 11/// Represents an in-memory application store.
 12/// </summary>
 13/// <remarks>
 14/// Ambient tenant is applied here rather than in callers.
 15/// EF owns that via <c>SetTenantIdFilter</c> / <c>ApplyTenantId</c>; Memory must compensate.
 16/// Application contracts have no TenantAgnostic flag, so isolation always applies (EF query filter).
 17/// </remarks>
 18public class MemoryApplicationStore : IApplicationStore
 19{
 20    private readonly MemoryStore<Application> _store;
 21    private readonly ITenantAccessor _tenantAccessor;
 22
 23    /// <summary>
 24    /// Initializes a new instance of the <see cref="MemoryApplicationStore"/> class.
 25    /// </summary>
 1826    public MemoryApplicationStore(MemoryStore<Application> store, ITenantAccessor tenantAccessor)
 27    {
 1828        _store = store;
 1829        _tenantAccessor = tenantAccessor;
 1830    }
 31
 32    /// <inheritdoc />
 33    public Task SaveAsync(Application application, CancellationToken cancellationToken = default)
 34    {
 2835        lock (_store.Sync)
 36        {
 2837            ApplyCurrentTenant(application);
 6138            MemoryIdentityUniqueness.EnsureAvailable(_store, application, x => x.Name, "name");
 5239            MemoryIdentityUniqueness.EnsureAvailable(_store, application, x => x.ClientId, "client id");
 4840            _store.Save(application, x => x.Id);
 2441        }
 42
 2443        return Task.CompletedTask;
 44    }
 45
 46    /// <inheritdoc />
 47    public Task DeleteAsync(ApplicationFilter filter, CancellationToken cancellationToken = default)
 48    {
 249        lock (_store.Sync)
 50        {
 251            _store.DeleteWhere(application =>
 652                IsVisible(application) && filter.Apply(new[] { application }.AsQueryable()).Any());
 253        }
 54
 255        return Task.CompletedTask;
 56    }
 57
 58    /// <inheritdoc />
 59    public Task<Application?> FindAsync(ApplicationFilter filter, CancellationToken cancellationToken = default)
 60    {
 4461        var result = _store.Query(query => Filter(query, filter)).Select(Clone).FirstOrDefault();
 2262        return Task.FromResult(result);
 63    }
 64
 65    private IQueryable<Application> Filter(IQueryable<Application> queryable, ApplicationFilter filter) =>
 2266        filter.Apply(queryable.WhereVisibleToTenant(_tenantAccessor.TenantId));
 67
 468    private bool IsVisible(Entity entity) => TenantVisibility.IsVisible(entity.TenantId, _tenantAccessor.TenantId);
 69
 70    private void ApplyCurrentTenant(Entity entity)
 71    {
 2872        if (entity.TenantId == Tenant.AgnosticTenantId)
 473            return;
 74
 2475        entity.TenantId ??= _tenantAccessor.TenantId;
 2476    }
 77
 78    private static Application Clone(Application application) =>
 1879        new()
 1880        {
 1881            Id = application.Id,
 1882            Name = application.Name,
 1883            ClientId = application.ClientId,
 1884            TenantId = application.TenantId,
 1885            HashedApiKey = application.HashedApiKey,
 1886            HashedApiKeySalt = application.HashedApiKeySalt,
 1887            HashedClientSecret = application.HashedClientSecret,
 1888            HashedClientSecretSalt = application.HashedClientSecretSalt,
 1889            Roles = application.Roles.ToList()
 1890        };
 91}