Creating views for library items

This commit is contained in:
Zoe Roux 2021-06-28 21:59:08 +02:00
parent 531abee95b
commit 0c537e1cc1
7 changed files with 68 additions and 40 deletions

View File

@ -74,6 +74,14 @@ namespace Kyoo
/// Episodes with a watch percentage. See <see cref="WatchedEpisode"/>
/// </summary>
public DbSet<WatchedEpisode> WatchedEpisodes { get; set; }
/// <summary>
/// The list of library items (shows and collections that are part of a library - or the global one)
/// </summary>
/// <remarks>
/// This set is ready only, on most database this will be a view.
/// </remarks>
public DbSet<LibraryItem> LibraryItems { get; set; }
/// <summary>
/// Get all metadataIDs (ExternalIDs) of a given resource. See <see cref="MetadataID{T}"/>.
@ -322,6 +330,8 @@ namespace Kyoo
modelBuilder.Entity<Track>()
.Property(x => x.Slug)
.ValueGeneratedOnAddOrUpdate();
// modelBuilder.Ignore<LibraryItem>();
}
/// <summary>

View File

@ -74,6 +74,25 @@ namespace Kyoo.Postgresql.Migrations
migrationBuilder.Sql(@"
CREATE TRIGGER show_slug_trigger AFTER UPDATE OF slug ON shows
FOR EACH ROW EXECUTE PROCEDURE show_slug_update();");
// language=PostgreSQL
migrationBuilder.Sql(@"
CREATE VIEW library_items AS
SELECT s.id, s.slug, s.title, s.overview, s.status, s.start_air, s.end_air, s.poster, CASE
WHEN s.is_movie THEN 'movie'::item_type
ELSE 'show'::item_type
END AS type
FROM shows AS s
WHERE NOT (EXISTS (
SELECT 1
FROM link_collection_show AS l
INNER JOIN collections AS c ON l.first_id = c.id
WHERE s.id = l.second_id))
UNION ALL
SELECT -c0.id, c0.slug, c0.name AS title, c0.overview, 'unknown'::status AS status,
NULL AS start_air, NULL AS end_air, c0.poster, 'collection'::item_type AS type
FROM collections AS c0");
}
protected override void Down(MigrationBuilder migrationBuilder)
@ -90,6 +109,8 @@ namespace Kyoo.Postgresql.Migrations
migrationBuilder.Sql("DROP TRIGGER episode_slug_trigger ON episodes;");
// language=PostgreSQL
migrationBuilder.Sql(@"DROP FUNCTION episode_slug_update;");
// language=PostgreSQL
migrationBuilder.Sql(@"DROP VIEW library_items;");
}
}
}

View File

@ -91,6 +91,10 @@ namespace Kyoo.Postgresql
modelBuilder.HasPostgresEnum<ItemType>();
modelBuilder.HasPostgresEnum<StreamType>();
modelBuilder.Entity<LibraryItem>()
.ToView("library_items")
.HasKey(x => x.ID);
modelBuilder.Entity<User>()
.Property(x => x.ExtraData)
.HasColumnType("jsonb");

View File

@ -61,6 +61,25 @@ namespace Kyoo.SqLite.Migrations
END
WHERE ShowID = new.ID;
END;");
// language=SQLite
migrationBuilder.Sql(@"
CREATE VIEW LibraryItems AS
SELECT s.ID, s.Slug, s.Title, s.Overview, s.Status, s.StartAir, s.EndAir, s.Poster, CASE
WHEN s.IsMovie THEN 1
ELSE 0
END AS Type
FROM Shows AS s
WHERE NOT (EXISTS (
SELECT 1
FROM 'Link<Collection, Show>' AS l
INNER JOIN Collections AS c ON l.FirstID = c.ID
WHERE s.ID = l.SecondID))
UNION ALL
SELECT -c0.ID, c0.Slug, c0.Name AS Title, c0.Overview, 3 AS Status,
NULL AS StartAir, NULL AS EndAir, c0.Poster, 2 AS Type
FROM collections AS c0");
}
protected override void Down(MigrationBuilder migrationBuilder)

View File

@ -108,6 +108,10 @@ namespace Kyoo.SqLite
modelBuilder.Entity<User>()
.Property(x => x.ExtraData)
.HasConversion(jsonConvertor);
modelBuilder.Entity<LibraryItem>()
.ToView("LibraryItems")
.HasKey(x => x.ID);
base.OnModelCreating(modelBuilder);
}

View File

@ -30,9 +30,7 @@ namespace Kyoo.Tests
ShowRepository show = new(_database, studio, people, genre, provider);
SeasonRepository season = new(_database, provider);
LibraryItemRepository libraryItem = new(_database,
new Lazy<ILibraryRepository>(() => LibraryManager.LibraryRepository),
new Lazy<IShowRepository>(() => LibraryManager.ShowRepository),
new Lazy<ICollectionRepository>(() => LibraryManager.CollectionRepository));
new Lazy<ILibraryRepository>(() => LibraryManager.LibraryRepository));
TrackRepository track = new(_database);
EpisodeRepository episode = new(_database, provider, track);

View File

@ -22,15 +22,7 @@ namespace Kyoo.Controllers
/// A lazy loaded library repository to validate queries (check if a library does exist)
/// </summary>
private readonly Lazy<ILibraryRepository> _libraries;
/// <summary>
/// A lazy loaded show repository to get a show from it's id.
/// </summary>
private readonly Lazy<IShowRepository> _shows;
/// <summary>
/// A lazy loaded collection repository to get a collection from it's id.
/// </summary>
private readonly Lazy<ICollectionRepository> _collections;
/// <inheritdoc />
protected override Expression<Func<LibraryItem, object>> DefaultSort => x => x.Title;
@ -38,60 +30,41 @@ namespace Kyoo.Controllers
/// <summary>
/// Create a new <see cref="LibraryItemRepository"/>.
/// </summary>
/// <param name="database">The databse instance</param>
/// <param name="database">The database instance</param>
/// <param name="libraries">A lazy loaded library repository</param>
/// <param name="shows">A lazy loaded show repository</param>
/// <param name="collections">A lazy loaded collection repository</param>
public LibraryItemRepository(DatabaseContext database,
Lazy<ILibraryRepository> libraries,
Lazy<IShowRepository> shows,
Lazy<ICollectionRepository> collections)
Lazy<ILibraryRepository> libraries)
: base(database)
{
_database = database;
_libraries = libraries;
_shows = shows;
_collections = collections;
}
/// <inheritdoc />
public override async Task<LibraryItem> GetOrDefault(int id)
public override Task<LibraryItem> GetOrDefault(int id)
{
return id > 0
? new LibraryItem(await _shows.Value.GetOrDefault(id))
: new LibraryItem(await _collections.Value.GetOrDefault(-id));
return _database.LibraryItems.FirstOrDefaultAsync(x => x.ID == id);
}
/// <inheritdoc />
public override Task<LibraryItem> GetOrDefault(string slug)
{
throw new InvalidOperationException("You can't get a library item by a slug.");
return _database.LibraryItems.SingleOrDefaultAsync(x => x.Slug == slug);
}
/// <summary>
/// Get a basic queryable with the right mapping from shows & collections.
/// Shows contained in a collection are excluded.
/// </summary>
private IQueryable<LibraryItem> ItemsQuery
=> _database.Shows
.Where(x => !x.Collections.Any())
.Select(LibraryItem.FromShow)
.Concat(_database.Collections
.Select(LibraryItem.FromCollection));
/// <inheritdoc />
public override Task<ICollection<LibraryItem>> GetAll(Expression<Func<LibraryItem, bool>> where = null,
Sort<LibraryItem> sort = default,
Pagination limit = default)
{
return ApplyFilters(ItemsQuery, where, sort, limit);
return ApplyFilters(_database.LibraryItems, where, sort, limit);
}
/// <inheritdoc />
public override Task<int> GetCount(Expression<Func<LibraryItem, bool>> where = null)
{
IQueryable<LibraryItem> query = ItemsQuery;
IQueryable<LibraryItem> query = _database.LibraryItems;
if (where != null)
query = query.Where(where);
return query.CountAsync();
@ -100,7 +73,7 @@ namespace Kyoo.Controllers
/// <inheritdoc />
public override async Task<ICollection<LibraryItem>> Search(string query)
{
return await ItemsQuery
return await _database.LibraryItems
.Where(_database.Like<LibraryItem>(x => x.Title, $"%{query}%"))
.OrderBy(DefaultSort)
.Take(20)
@ -109,7 +82,6 @@ namespace Kyoo.Controllers
/// <inheritdoc />
public override Task<LibraryItem> Create(LibraryItem obj) => throw new InvalidOperationException();
/// <inheritdoc />
public override Task<LibraryItem> CreateIfNotExists(LibraryItem obj) => throw new InvalidOperationException();
/// <inheritdoc />