< Summary

Information
Class: Api.Utils.GeneralUtils
Assembly: Api
File(s): /home/runner/work/ProjectRead.ing/ProjectRead.ing/Api/Utils/GeneralUtils.cs
Line coverage
90%
Covered lines: 29
Uncovered lines: 3
Coverable lines: 32
Total lines: 86
Line coverage: 90.6%
Branch coverage
100%
Covered branches: 12
Total branches: 12
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
WithQueryContext<T>(...)100%22100%
ToPageWithDataLoaderAsync()100%22100%
GetManyToManyIds()100%44100%
NormalizeEmail(...)100%11100%
Now()100%11100%
TryParseGuid(...)100%22100%
TryDeserialize<T>(...)100%1157.14%

File(s)

/home/runner/work/ProjectRead.ing/ProjectRead.ing/Api/Utils/GeneralUtils.cs

#LineLine coverage
 1// SPDX-FileCopyrightText: 2026 Alper Çelik <alper@alper-celik.dev>
 2//
 3// SPDX-License-Identifier: AGPL-3.0-or-later
 4using System.Linq.Expressions;
 5using System.Text.Json;
 6using GreenDonut.Data;
 7using LinqKit;
 8using Microsoft.EntityFrameworkCore;
 9
 10namespace Api.Utils;
 11
 12public static class GeneralUtils
 13{
 14    // Mostly Ai Generated - Start
 15    public static IQueryable<T> WithQueryContext<T>(
 16        this IQueryable<T> query,
 17        QueryContext<T> qc
 18    )
 19        where T : IEntityMetadata =>
 120        query.With(
 121            qc with
 122            {
 123                Selector = null,
 124            },
 125            sort => sort.Operations.Length == 0 ? sort.AddAscending(t => t.Id) : sort
 126        );
 27
 28    // Mostly Ai Generated - End
 29    public static async Task<Page<T>> ToPageWithDataLoaderAsync<T>(
 30        this IQueryable<T> table,
 31        PagingArguments pg,
 32        IDataLoader<Guid, T> dataLoader,
 33        CancellationToken ct
 34    )
 35        where T : IEntityMetadata
 136    {
 137        var page = await table.ToPageAsync(pg, includeTotalCount: true, ct);
 38
 139        foreach (var item in page)
 140        {
 141            dataLoader.SetCacheEntry(item.Id, item);
 142        }
 143        return page;
 144    }
 45
 46    public static async Task<IDictionary<Guid, Guid[]>> GetManyToManyIds<T>(
 47        this IQueryable<T> table,
 48        IReadOnlyList<Guid> tableIds,
 49        Guid userId,
 50        Expression<Func<T, IEnumerable<Guid>>> manyIdSelector,
 51        CancellationToken ct
 52    )
 53        where T : IDbEntityMetadata
 154    {
 155        return await table
 156            .Where(t => t.OwnerId == userId)
 157            .Where(t => tableIds.Contains(t.Id))
 158            .Select(t => new { t.Id, ManyIds = manyIdSelector.Invoke(t) })
 159            .ToDictionaryAsync(ids => ids.Id, ids => ids.ManyIds.ToArray(), ct);
 160    }
 61
 62    public static string NormalizeEmail(this string email) =>
 163        email.Trim().Normalize().ToLowerInvariant();
 64
 65    public static NodaTime.Instant Now() =>
 166        NodaTime.SystemClock.Instance.GetCurrentInstant();
 67
 68    public static Guid? TryParseGuid(this ReadOnlySpan<char> s) =>
 169        Guid.TryParse(s, out Guid g) ? g : null;
 70
 71    public static T? TryDeserialize<T>(
 72        this JsonDocument doc,
 73        JsonSerializerOptions? opt = null
 74    )
 75        where T : class
 176    {
 77        try
 178        {
 179            return doc.Deserialize<T>(opt);
 80        }
 081        catch (JsonException)
 082        {
 083            return null;
 84        }
 185    }
 86}