book-hub-umsp / book-hub-api

1 stars 0 forks source link

[Book/Repository] Модели отношения между книгами/репозиториями и авторами #23

Closed AlexBimlnk closed 6 days ago

AlexBimlnk commented 3 weeks ago

В этой задаче нужно добавить модели, описывающие разное отношение репозиториев и авторов. Во-первых это отношение контрибьютеров к книги (помимо основного автора). Также сюда можно отнести "избранное"

Code snippets you can use:

UserFavourite.cs

/// <summary>
/// Избранное из книг у пользователя.
/// </summary>
public sealed class UserFavourite
{
    public Id<User> UserId { get; }

    public HashSet<UserFavouriteBookLink> Links { get; private set; } = [];

    public UserFavourite(
        Id<User> userId, 
        IReadOnlySet<UserFavouriteBookLink> links)
    {
        UserId = userId ?? throw new ArgumentNullException(nameof(userId));

        AddLinks(userId, links);
    }

    public void ChangeLinks(IReadOnlySet<UserFavouriteBookLink> links)
    {
        AddLinks(UserId, links);
    }

    public void RemoveLinks(IReadOnlySet<Id<Book>> booksIds)
    {
        ArgumentNullException.ThrowIfNull(booksIds);

        foreach (var bookId in booksIds)
        {
            var linkToRemove = new UserFavouriteBookLink(UserId, bookId);

            if (Links.Contains(linkToRemove))
            {
                Links.Remove(linkToRemove);
            }
        }
    }

    private void AddLinks(
        Id<User> userId,
        IReadOnlySet<UserFavouriteBookLink> links)
    {
        ArgumentNullException.ThrowIfNull(links);

        try
        {
            var linksDistinctByUser = links
                .DistinctBy(l => l.UserId)
                .Single(l => l.UserId == userId);
        }
        catch (InvalidOperationException)
        {
            throw new InvalidOperationException(
                $"All links should be related only for user {userId}.");
        }

        foreach (var link in links)
        {
            _ = Links.Add(link);
        }
    }
}

UserFavouriteBookLink.cs

/// <summary>
/// Одиночный линк к пользователю и книге из избранного.
/// </summary>
public sealed class UserFavouriteBookLink : IEquatable<UserFavouriteBookLink>
{
    public Id<User> UserId { get; }

    public Id<Book> BookId { get; }

    public DateTimeOffset AddingTime { get; }

    public UserFavouriteBookLink(
        Id<User> userId, 
        Id<Book> bookId)
    {
        UserId = userId ?? throw new ArgumentNullException(nameof(userId));
        BookId = bookId ?? throw new ArgumentNullException(nameof(bookId));

        AddingTime = DateTimeOffset.UtcNow;
    }

    public bool Equals(UserFavouriteBookLink? other) =>
        other is not null
            ? UserId == other.UserId && BookId == other.BookId
            : false;
    public override int GetHashCode() => HashCode.Combine(UserId, BookId);
}