using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Runtime.InteropServices; using System.Threading.Tasks; using JetBrains.Annotations; using Kyoo.Models; namespace Kyoo.Controllers { /// /// Informations about the pagination. How many items should be displayed and where to start. /// public readonly struct Pagination { /// /// The count of items to return. /// public int Count { get; } /// /// Where to start? Using the given sort /// public int AfterID { get; } /// /// Create a new instance. /// /// Set the value /// Set the value. If not specified, it will start from the start public Pagination(int count, int afterID = 0) { Count = count; AfterID = afterID; } /// /// Implicitly create a new pagination from a limit number. /// /// Set the value /// A new instance public static implicit operator Pagination(int limit) => new(limit); } /// /// Informations about how a query should be sorted. What factor should decide the sort and in which order. /// /// For witch type this sort applies public readonly struct Sort { /// /// The sort key. This member will be used to sort the results. /// public Expression> Key { get; } /// /// If this is set to true, items will be sorted in descend order else, they will be sorted in ascendent order. /// public bool Descendant { get; } /// /// Create a new instance. /// /// The sort key given. It is assigned to . /// Should this be in descendant order? The default is false. /// If the given key is not a member. public Sort(Expression> key, bool descendant = false) { Key = key; Descendant = descendant; if (!Utility.IsPropertyExpression(Key)) throw new ArgumentException("The given sort key is not valid."); } /// /// Create a new instance from a key's name (case insensitive). /// /// A key name with an optional order specifier. Format: "key:asc", "key:desc" or "key". /// An invalid key or sort specifier as been given. public Sort(string sortBy) { if (string.IsNullOrEmpty(sortBy)) { Key = null; Descendant = false; return; } string key = sortBy.Contains(':') ? sortBy[..sortBy.IndexOf(':')] : sortBy; string order = sortBy.Contains(':') ? sortBy[(sortBy.IndexOf(':') + 1)..] : null; ParameterExpression param = Expression.Parameter(typeof(T), "x"); MemberExpression property = Expression.Property(param, key); Key = property.Type.IsValueType ? Expression.Lambda>(Expression.Convert(property, typeof(object)), param) : Expression.Lambda>(property, param); Descendant = order switch { "desc" => true, "asc" => false, null => false, _ => throw new ArgumentException($"The sort order, if set, should be :asc or :desc but it was :{order}.") }; } } /// /// A base class for repositories. Every service implementing this will be handled by the . /// public interface IBaseRepository : IDisposable, IAsyncDisposable { /// /// The type for witch this repository is responsible. /// Type RepositoryType { get; } } public interface IRepository : IBaseRepository where T : class, IResource { Task Get(int id); Task Get(string slug); Task Get(Expression> where); Task> Search(string query); Task> GetAll(Expression> where = null, Sort sort = default, Pagination limit = default); Task> GetAll([Optional] Expression> where, Expression> sort, Pagination limit = default ) => GetAll(where, new Sort(sort), limit); Task GetCount(Expression> where = null); Task Create([NotNull] T obj); Task CreateIfNotExists([NotNull] T obj, bool silentFail = false); Task Edit([NotNull] T edited, bool resetOld); Task Delete(int id); Task Delete(string slug); Task Delete([NotNull] T obj); Task DeleteRange(params T[] objs) => DeleteRange(objs.AsEnumerable()); Task DeleteRange(IEnumerable objs); Task DeleteRange(params int[] ids) => DeleteRange(ids.AsEnumerable()); Task DeleteRange(IEnumerable ids); Task DeleteRange(params string[] slugs) => DeleteRange(slugs.AsEnumerable()); Task DeleteRange(IEnumerable slugs); Task DeleteRange([NotNull] Expression> where); } public interface IShowRepository : IRepository { Task AddShowLink(int showID, int? libraryID, int? collectionID); Task GetSlug(int showID); } public interface ISeasonRepository : IRepository { Task Get(int showID, int seasonNumber); Task Get(string showSlug, int seasonNumber); Task Delete(string showSlug, int seasonNumber); } public interface IEpisodeRepository : IRepository { Task Get(int showID, int seasonNumber, int episodeNumber); Task Get(string showSlug, int seasonNumber, int episodeNumber); Task Get(int seasonID, int episodeNumber); Task GetAbsolute(int showID, int absoluteNumber); Task GetAbsolute(string showSlug, int absoluteNumber); Task Delete(string showSlug, int seasonNumber, int episodeNumber); } public interface ITrackRepository : IRepository { Task Get(string slug, StreamType type = StreamType.Unknown); } public interface ILibraryRepository : IRepository { } public interface ILibraryItemRepository : IRepository { public Task> GetFromLibrary(int id, Expression> where = null, Sort sort = default, Pagination limit = default); public Task> GetFromLibrary(int id, [Optional] Expression> where, Expression> sort, Pagination limit = default ) => GetFromLibrary(id, where, new Sort(sort), limit); public Task> GetFromLibrary(string librarySlug, Expression> where = null, Sort sort = default, Pagination limit = default); public Task> GetFromLibrary(string librarySlug, [Optional] Expression> where, Expression> sort, Pagination limit = default ) => GetFromLibrary(librarySlug, where, new Sort(sort), limit); } public interface ICollectionRepository : IRepository { } public interface IGenreRepository : IRepository { } public interface IStudioRepository : IRepository { } public interface IPeopleRepository : IRepository { Task> GetFromShow(int showID, Expression> where = null, Sort sort = default, Pagination limit = default); Task> GetFromShow(int showID, [Optional] Expression> where, Expression> sort, Pagination limit = default ) => GetFromShow(showID, where, new Sort(sort), limit); Task> GetFromShow(string showSlug, Expression> where = null, Sort sort = default, Pagination limit = default); Task> GetFromShow(string showSlug, [Optional] Expression> where, Expression> sort, Pagination limit = default ) => GetFromShow(showSlug, where, new Sort(sort), limit); Task> GetFromPeople(int showID, Expression> where = null, Sort sort = default, Pagination limit = default); Task> GetFromPeople(int showID, [Optional] Expression> where, Expression> sort, Pagination limit = default ) => GetFromPeople(showID, where, new Sort(sort), limit); Task> GetFromPeople(string showSlug, Expression> where = null, Sort sort = default, Pagination limit = default); Task> GetFromPeople(string showSlug, [Optional] Expression> where, Expression> sort, Pagination limit = default ) => GetFromPeople(showSlug, where, new Sort(sort), limit); } public interface IProviderRepository : IRepository { Task> GetMetadataID(Expression> where = null, Sort sort = default, Pagination limit = default); Task> GetMetadataID([Optional] Expression> where, Expression> sort, Pagination limit = default ) => GetMetadataID(where, new Sort(sort), limit); } }