mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-31 20:24:27 -04:00
Implement a base repository for dapper
This commit is contained in:
parent
179b79c926
commit
ba37786038
@ -174,19 +174,19 @@ namespace Kyoo.Abstractions.Models
|
|||||||
// language=PostgreSQL
|
// language=PostgreSQL
|
||||||
Sql = """
|
Sql = """
|
||||||
select
|
select
|
||||||
"pe".* -- Episode as pe
|
pe.* -- Episode as pe
|
||||||
from
|
from
|
||||||
episodes as "pe"
|
episodes as "pe"
|
||||||
where
|
where
|
||||||
"pe".show_id = "this".show_id
|
pe.show_id = "this".show_id
|
||||||
and ("pe".absolute_number < "this".absolute_number
|
and (pe.absolute_number < "this".absolute_number
|
||||||
or "pe".season_number < "this".season_number
|
or pe.season_number < "this".season_number
|
||||||
or ("pe".season_number = "this".season_number
|
or (pe.season_number = "this".season_number
|
||||||
and e.episode_number < "this".episode_number))
|
and e.episode_number < "this".episode_number))
|
||||||
order by
|
order by
|
||||||
"pe".absolute_number desc,
|
pe.absolute_number desc,
|
||||||
"pe".season_number desc,
|
pe.season_number desc,
|
||||||
"pe".episode_number desc
|
pe.episode_number desc
|
||||||
limit 1
|
limit 1
|
||||||
"""
|
"""
|
||||||
)]
|
)]
|
||||||
@ -210,19 +210,19 @@ namespace Kyoo.Abstractions.Models
|
|||||||
// language=PostgreSQL
|
// language=PostgreSQL
|
||||||
Sql = """
|
Sql = """
|
||||||
select
|
select
|
||||||
"ne".* -- Episode as ne
|
ne.* -- Episode as ne
|
||||||
from
|
from
|
||||||
episodes as "ne"
|
episodes as "ne"
|
||||||
where
|
where
|
||||||
"ne".show_id = "this".show_id
|
ne.show_id = "this".show_id
|
||||||
and ("ne".absolute_number > "this".absolute_number
|
and (ne.absolute_number > "this".absolute_number
|
||||||
or "ne".season_number > "this".season_number
|
or ne.season_number > "this".season_number
|
||||||
or ("ne".season_number = "this".season_number
|
or (ne.season_number = "this".season_number
|
||||||
and e.episode_number > "this".episode_number))
|
and e.episode_number > "this".episode_number))
|
||||||
order by
|
order by
|
||||||
"ne".absolute_number,
|
ne.absolute_number,
|
||||||
"ne".season_number,
|
ne.season_number,
|
||||||
"ne".episode_number
|
ne.episode_number
|
||||||
limit 1
|
limit 1
|
||||||
"""
|
"""
|
||||||
)]
|
)]
|
||||||
|
@ -158,7 +158,7 @@ namespace Kyoo.Abstractions.Models
|
|||||||
// language=PostgreSQL
|
// language=PostgreSQL
|
||||||
Sql = """
|
Sql = """
|
||||||
select
|
select
|
||||||
"fe".* -- Episode as fe
|
fe.* -- Episode as fe
|
||||||
from (
|
from (
|
||||||
select
|
select
|
||||||
e.*,
|
e.*,
|
||||||
@ -166,7 +166,7 @@ namespace Kyoo.Abstractions.Models
|
|||||||
from
|
from
|
||||||
episodes as e) as "fe"
|
episodes as e) as "fe"
|
||||||
where
|
where
|
||||||
"fe".number <= 1
|
fe.number <= 1
|
||||||
""",
|
""",
|
||||||
On = "show_id = \"this\".id"
|
On = "show_id = \"this\".id"
|
||||||
)]
|
)]
|
||||||
|
@ -48,11 +48,9 @@ public static class DapperHelper
|
|||||||
return $"coalesce({string.Join(", ", keys)})";
|
return $"coalesce({string.Join(", ", keys)})";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string ProcessSort<T>(Sort<T>? sort, bool reverse, Dictionary<string, Type> config, bool recurse = false)
|
public static string ProcessSort<T>(Sort<T> sort, bool reverse, Dictionary<string, Type> config, bool recurse = false)
|
||||||
where T : IQuery
|
where T : IQuery
|
||||||
{
|
{
|
||||||
sort ??= new Sort<T>.Default();
|
|
||||||
|
|
||||||
string ret = sort switch
|
string ret = sort switch
|
||||||
{
|
{
|
||||||
Sort<T>.Default(var value) => ProcessSort(value, reverse, config, true),
|
Sort<T>.Default(var value) => ProcessSort(value, reverse, config, true),
|
||||||
@ -78,7 +76,7 @@ public static class DapperHelper
|
|||||||
Dictionary<string, Type> retConfig = new();
|
Dictionary<string, Type> retConfig = new();
|
||||||
StringBuilder join = new();
|
StringBuilder join = new();
|
||||||
|
|
||||||
foreach (Include<T>.Metadata metadata in include.Metadatas)
|
foreach (Include.Metadata metadata in include.Metadatas)
|
||||||
{
|
{
|
||||||
relation++;
|
relation++;
|
||||||
switch (metadata)
|
switch (metadata)
|
||||||
@ -103,7 +101,7 @@ public static class DapperHelper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
T Map(T item, IEnumerable<object> relations)
|
T Map(T item, IEnumerable<object?> relations)
|
||||||
{
|
{
|
||||||
foreach ((string name, object? value) in include.Fields.Zip(relations))
|
foreach ((string name, object? value) in include.Fields.Zip(relations))
|
||||||
{
|
{
|
||||||
@ -177,7 +175,7 @@ public static class DapperHelper
|
|||||||
this IDbConnection db,
|
this IDbConnection db,
|
||||||
FormattableString command,
|
FormattableString command,
|
||||||
Dictionary<string, Type> config,
|
Dictionary<string, Type> config,
|
||||||
Func<object?[], T> mapper,
|
Func<List<object?>, T> mapper,
|
||||||
Func<int, Task<T>> get,
|
Func<int, Task<T>> get,
|
||||||
Include<T>? include,
|
Include<T>? include,
|
||||||
Filter<T>? filter,
|
Filter<T>? filter,
|
||||||
@ -205,7 +203,8 @@ public static class DapperHelper
|
|||||||
}
|
}
|
||||||
if (filter != null)
|
if (filter != null)
|
||||||
query += ProcessFilter(filter, config);
|
query += ProcessFilter(filter, config);
|
||||||
query += $"\norder by {ProcessSort(sort, limit.Reverse, config):raw}";
|
if (sort != null)
|
||||||
|
query += $"\norder by {ProcessSort(sort, limit.Reverse, config):raw}";
|
||||||
query += $"\nlimit {limit.Limit}";
|
query += $"\nlimit {limit.Limit}";
|
||||||
|
|
||||||
// Build query and prepare to do the query/projections
|
// Build query and prepare to do the query/projections
|
||||||
@ -260,7 +259,7 @@ public static class DapperHelper
|
|||||||
thumbs.Thumbnail = items[++i] as Image;
|
thumbs.Thumbnail = items[++i] as Image;
|
||||||
thumbs.Logo = items[++i] as Image;
|
thumbs.Logo = items[++i] as Image;
|
||||||
}
|
}
|
||||||
return mapIncludes(mapper(nItems.ToArray()), nItems.Skip(config.Count));
|
return mapIncludes(mapper(nItems), nItems.Skip(config.Count));
|
||||||
},
|
},
|
||||||
ParametersDictionary.LoadFrom(cmd),
|
ParametersDictionary.LoadFrom(cmd),
|
||||||
splitOn: string.Join(',', types.Select(x => x == typeof(Image) ? "source" : "id"))
|
splitOn: string.Join(',', types.Select(x => x == typeof(Image) ? "source" : "id"))
|
||||||
@ -269,4 +268,40 @@ public static class DapperHelper
|
|||||||
data = data.Reverse();
|
data = data.Reverse();
|
||||||
return data.ToList();
|
return data.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task<T?> QuerySingle<T>(
|
||||||
|
this IDbConnection db,
|
||||||
|
FormattableString command,
|
||||||
|
Dictionary<string, Type> config,
|
||||||
|
Func<List<object?>, T> mapper,
|
||||||
|
Include<T>? include,
|
||||||
|
Filter<T>? filter,
|
||||||
|
Sort<T>? sort = null)
|
||||||
|
where T : class, IResource, IQuery
|
||||||
|
{
|
||||||
|
ICollection<T> ret = await db.Query<T>(command, config, mapper, null!, include, filter, sort, new Pagination(1));
|
||||||
|
return ret.FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<int> Count<T>(
|
||||||
|
this IDbConnection db,
|
||||||
|
FormattableString command,
|
||||||
|
Dictionary<string, Type> config,
|
||||||
|
Filter<T>? filter)
|
||||||
|
where T : class, IResource
|
||||||
|
{
|
||||||
|
InterpolatedSql.Dapper.SqlBuilders.SqlBuilder query = new(db, command);
|
||||||
|
|
||||||
|
if (filter != null)
|
||||||
|
query += ProcessFilter(filter, config);
|
||||||
|
|
||||||
|
IDapperSqlCommand cmd = query.Build();
|
||||||
|
// language=postgreSQL
|
||||||
|
string sql = $"select count(*) from ({cmd.Sql})";
|
||||||
|
|
||||||
|
return await db.ExecuteAsync(
|
||||||
|
sql,
|
||||||
|
ParametersDictionary.LoadFrom(cmd)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,87 +18,156 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.Data.Common;
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kyoo.Abstractions.Controllers;
|
using Kyoo.Abstractions.Controllers;
|
||||||
using Kyoo.Abstractions.Models;
|
using Kyoo.Abstractions.Models;
|
||||||
|
using Kyoo.Abstractions.Models.Exceptions;
|
||||||
using Kyoo.Abstractions.Models.Utils;
|
using Kyoo.Abstractions.Models.Utils;
|
||||||
using Kyoo.Utils;
|
|
||||||
|
|
||||||
namespace Kyoo.Core.Controllers;
|
namespace Kyoo.Core.Controllers;
|
||||||
|
|
||||||
public class DapperRepository<T> : IRepository<T>
|
public abstract class DapperRepository<T> : IRepository<T>
|
||||||
where T : class, IResource, IQuery
|
where T : class, IResource, IQuery
|
||||||
{
|
{
|
||||||
public Type RepositoryType => typeof(T);
|
public Type RepositoryType => typeof(T);
|
||||||
|
|
||||||
|
protected abstract FormattableString Sql { get; }
|
||||||
|
|
||||||
|
protected abstract Dictionary<string, Type> Config { get; }
|
||||||
|
|
||||||
|
protected abstract T Mapper(List<object?> items);
|
||||||
|
|
||||||
|
protected DbConnection Database { get; init; }
|
||||||
|
|
||||||
|
public DapperRepository(DbConnection database)
|
||||||
|
{
|
||||||
|
Database = database;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public virtual async Task<T> Get(int id, Include<T>? include = default)
|
||||||
|
{
|
||||||
|
T? ret = await GetOrDefault(id, include);
|
||||||
|
if (ret == null)
|
||||||
|
throw new ItemNotFoundException($"No {typeof(T).Name} found with the id {id}");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public virtual async Task<T> Get(string slug, Include<T>? include = default)
|
||||||
|
{
|
||||||
|
T? ret = await GetOrDefault(slug, include);
|
||||||
|
if (ret == null)
|
||||||
|
throw new ItemNotFoundException($"No {typeof(T).Name} found with the slug {slug}");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public virtual async Task<T> Get(Filter<T> filter,
|
||||||
|
Include<T>? include = default)
|
||||||
|
{
|
||||||
|
T? ret = await GetOrDefault(filter, include: include);
|
||||||
|
if (ret == null)
|
||||||
|
throw new ItemNotFoundException($"No {typeof(T).Name} found with the given predicate.");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public Task<ICollection<T>> FromIds(IList<int> ids, Include<T>? include = null)
|
public Task<ICollection<T>> FromIds(IList<int> ids, Include<T>? include = null)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<T> Get(int id, Include<T>? include = null)
|
/// <inheritdoc />
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<T> Get(string slug, Include<T>? include = null)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<T> Get(Filter<T> filter, Include<T>? include = null)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<ICollection<T>> GetAll(Filter<T>? filter = null, Sort<T>? sort = null, Include<T>? include = null, Pagination? limit = null)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<int> GetCount(Filter<T>? filter = null)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<T?> GetOrDefault(int id, Include<T>? include = null)
|
public Task<T?> GetOrDefault(int id, Include<T>? include = null)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return Database.QuerySingle<T>(
|
||||||
|
Sql,
|
||||||
|
Config,
|
||||||
|
Mapper,
|
||||||
|
include,
|
||||||
|
new Filter<T>.Eq(nameof(IResource.Id), id)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public Task<T?> GetOrDefault(string slug, Include<T>? include = null)
|
public Task<T?> GetOrDefault(string slug, Include<T>? include = null)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return Database.QuerySingle<T>(
|
||||||
|
Sql,
|
||||||
|
Config,
|
||||||
|
Mapper,
|
||||||
|
include,
|
||||||
|
new Filter<T>.Eq(nameof(IResource.Slug), slug)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public Task<T?> GetOrDefault(Filter<T>? filter, Include<T>? include = null, Sort<T>? sortBy = null)
|
public Task<T?> GetOrDefault(Filter<T>? filter, Include<T>? include = null, Sort<T>? sortBy = null)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return Database.QuerySingle<T>(
|
||||||
|
Sql,
|
||||||
|
Config,
|
||||||
|
Mapper,
|
||||||
|
include,
|
||||||
|
filter,
|
||||||
|
sortBy
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<ICollection<T>> Search(string query, Include<T>? include = null)
|
/// <inheritdoc />
|
||||||
|
public Task<ICollection<T>> GetAll(Filter<T>? filter = default,
|
||||||
|
Sort<T>? sort = default,
|
||||||
|
Include<T>? include = default,
|
||||||
|
Pagination? limit = default)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return Database.Query<T>(
|
||||||
|
Sql,
|
||||||
|
Config,
|
||||||
|
Mapper,
|
||||||
|
(id) => Get(id),
|
||||||
|
include,
|
||||||
|
filter,
|
||||||
|
sort ?? new Sort<T>.Default(),
|
||||||
|
limit ?? new()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Task<int> GetCount(Filter<T>? filter = null)
|
||||||
|
{
|
||||||
|
return Database.Count(
|
||||||
|
Sql,
|
||||||
|
Config,
|
||||||
|
filter
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Task<ICollection<T>> Search(string query, Include<T>? include = null) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public Task<T> Create(T obj) => throw new NotImplementedException();
|
public Task<T> Create(T obj) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public Task<T> CreateIfNotExists(T obj) => throw new NotImplementedException();
|
public Task<T> CreateIfNotExists(T obj) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public Task Delete(int id) => throw new NotImplementedException();
|
public Task Delete(int id) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public Task Delete(string slug) => throw new NotImplementedException();
|
public Task Delete(string slug) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public Task Delete(T obj) => throw new NotImplementedException();
|
public Task Delete(T obj) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public Task DeleteAll(Filter<T> filter) => throw new NotImplementedException();
|
public Task DeleteAll(Filter<T> filter) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public Task<T> Edit(T edited) => throw new NotImplementedException();
|
public Task<T> Edit(T edited) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public Task<T> Patch(int id, Func<T, Task<bool>> patch) => throw new NotImplementedException();
|
public Task<T> Patch(int id, Func<T, Task<bool>> patch) => throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
@ -18,157 +18,63 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
using System.Data.Common;
|
using System.Data.Common;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Dapper;
|
|
||||||
using InterpolatedSql.Dapper;
|
|
||||||
using Kyoo.Abstractions.Controllers;
|
using Kyoo.Abstractions.Controllers;
|
||||||
using Kyoo.Abstractions.Models;
|
using Kyoo.Abstractions.Models;
|
||||||
using Kyoo.Abstractions.Models.Exceptions;
|
|
||||||
using Kyoo.Abstractions.Models.Utils;
|
using Kyoo.Abstractions.Models.Utils;
|
||||||
using Kyoo.Utils;
|
|
||||||
|
|
||||||
namespace Kyoo.Core.Controllers
|
namespace Kyoo.Core.Controllers
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A local repository to handle library items.
|
/// A local repository to handle library items.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class LibraryItemRepository : IRepository<ILibraryItem>
|
public class LibraryItemRepository : DapperRepository<ILibraryItem>
|
||||||
{
|
{
|
||||||
private readonly DbConnection _database;
|
// language=PostgreSQL
|
||||||
|
protected override FormattableString Sql => $"""
|
||||||
|
select
|
||||||
|
s.*, -- Show as s
|
||||||
|
m.*,
|
||||||
|
c.*
|
||||||
|
/* includes */
|
||||||
|
from
|
||||||
|
shows as s
|
||||||
|
full outer join (
|
||||||
|
select
|
||||||
|
* -- Movie
|
||||||
|
from
|
||||||
|
movies) as m on false
|
||||||
|
full outer join(
|
||||||
|
select
|
||||||
|
* -- Collection
|
||||||
|
from
|
||||||
|
collections) as c on false
|
||||||
|
""";
|
||||||
|
|
||||||
public Type RepositoryType => typeof(ILibraryItem);
|
protected override Dictionary<string, Type> Config => new()
|
||||||
|
{
|
||||||
|
{ "s", typeof(Show) },
|
||||||
|
{ "m", typeof(Movie) },
|
||||||
|
{ "c", typeof(Collection) }
|
||||||
|
};
|
||||||
|
|
||||||
|
protected override ILibraryItem Mapper(List<object?> items)
|
||||||
|
{
|
||||||
|
if (items[0] is Show show && show.Id != 0)
|
||||||
|
return show;
|
||||||
|
if (items[1] is Movie movie && movie.Id != 0)
|
||||||
|
return movie;
|
||||||
|
if (items[2] is Collection collection && collection.Id != 0)
|
||||||
|
return collection;
|
||||||
|
throw new InvalidDataException();
|
||||||
|
}
|
||||||
|
|
||||||
public LibraryItemRepository(DbConnection database)
|
public LibraryItemRepository(DbConnection database)
|
||||||
{
|
: base(database)
|
||||||
_database = database;
|
{ }
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public virtual async Task<ILibraryItem> Get(int id, Include<ILibraryItem>? include = default)
|
|
||||||
{
|
|
||||||
ILibraryItem? ret = await GetOrDefault(id, include);
|
|
||||||
if (ret == null)
|
|
||||||
throw new ItemNotFoundException($"No {nameof(ILibraryItem)} found with the id {id}");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public virtual async Task<ILibraryItem> Get(string slug, Include<ILibraryItem>? include = default)
|
|
||||||
{
|
|
||||||
ILibraryItem? ret = await GetOrDefault(slug, include);
|
|
||||||
if (ret == null)
|
|
||||||
throw new ItemNotFoundException($"No {nameof(ILibraryItem)} found with the slug {slug}");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public virtual async Task<ILibraryItem> Get(Filter<ILibraryItem> filter,
|
|
||||||
Include<ILibraryItem>? include = default)
|
|
||||||
{
|
|
||||||
ILibraryItem? ret = await GetOrDefault(filter, include: include);
|
|
||||||
if (ret == null)
|
|
||||||
throw new ItemNotFoundException($"No {nameof(ILibraryItem)} found with the given predicate.");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<ILibraryItem?> GetOrDefault(int id, Include<ILibraryItem>? include = null)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<ILibraryItem?> GetOrDefault(string slug, Include<ILibraryItem>? include = null)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<ILibraryItem?> GetOrDefault(Filter<ILibraryItem>? filter, Include<ILibraryItem>? include = default,
|
|
||||||
Sort<ILibraryItem>? sortBy = default)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<ICollection<ILibraryItem>> GetAll(
|
|
||||||
Filter<ILibraryItem>? filter = null,
|
|
||||||
Sort<ILibraryItem>? sort = default,
|
|
||||||
Include<ILibraryItem>? include = default,
|
|
||||||
Pagination? limit = default)
|
|
||||||
{
|
|
||||||
// language=PostgreSQL
|
|
||||||
FormattableString sql = $"""
|
|
||||||
select
|
|
||||||
s.*, -- Show as s
|
|
||||||
m.*,
|
|
||||||
c.*
|
|
||||||
/* includes */
|
|
||||||
from
|
|
||||||
shows as s
|
|
||||||
full outer join (
|
|
||||||
select
|
|
||||||
* -- Movie
|
|
||||||
from
|
|
||||||
movies) as m on false
|
|
||||||
full outer join (
|
|
||||||
select
|
|
||||||
* -- Collection
|
|
||||||
from
|
|
||||||
collections) as c on false
|
|
||||||
""";
|
|
||||||
|
|
||||||
return _database.Query<ILibraryItem>(sql, new()
|
|
||||||
{
|
|
||||||
{ "s", typeof(Show) },
|
|
||||||
{ "m", typeof(Movie) },
|
|
||||||
{ "c", typeof(Collection) }
|
|
||||||
},
|
|
||||||
items =>
|
|
||||||
{
|
|
||||||
if (items[0] is Show show && show.Id != 0)
|
|
||||||
return show;
|
|
||||||
if (items[1] is Movie movie && movie.Id != 0)
|
|
||||||
return movie;
|
|
||||||
if (items[2] is Collection collection && collection.Id != 0)
|
|
||||||
return collection;
|
|
||||||
throw new InvalidDataException();
|
|
||||||
},
|
|
||||||
(id) => Get(id),
|
|
||||||
include, filter, sort, limit ?? new()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<int> GetCount(Filter<ILibraryItem>? filter = null)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<ICollection<ILibraryItem>> FromIds(IList<int> ids, Include<ILibraryItem>? include = null)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task DeleteAll(Filter<ILibraryItem> filter)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public async Task<ICollection<ILibraryItem>> Search(string query, Include<ILibraryItem>? include = default)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
// return await Sort(
|
|
||||||
// AddIncludes(_database.LibraryItems, include)
|
|
||||||
// .Where(_database.Like<LibraryItem>(x => x.Name, $"%{query}%"))
|
|
||||||
// )
|
|
||||||
// .Take(20)
|
|
||||||
// .ToListAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<ICollection<ILibraryItem>> GetAllOfCollection(
|
public async Task<ICollection<ILibraryItem>> GetAllOfCollection(
|
||||||
Expression<Func<Collection, bool>> selector,
|
Expression<Func<Collection, bool>> selector,
|
||||||
@ -193,33 +99,5 @@ namespace Kyoo.Core.Controllers
|
|||||||
// limit,
|
// limit,
|
||||||
// include);
|
// include);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public Task<ILibraryItem> Create(ILibraryItem obj)
|
|
||||||
=> throw new InvalidOperationException();
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public Task<ILibraryItem> CreateIfNotExists(ILibraryItem obj)
|
|
||||||
=> throw new InvalidOperationException();
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public Task<ILibraryItem> Edit(ILibraryItem edited)
|
|
||||||
=> throw new InvalidOperationException();
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public Task<ILibraryItem> Patch(int id, Func<ILibraryItem, Task<bool>> patch)
|
|
||||||
=> throw new InvalidOperationException();
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public Task Delete(int id)
|
|
||||||
=> throw new InvalidOperationException();
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public Task Delete(string slug)
|
|
||||||
=> throw new InvalidOperationException();
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public Task Delete(ILibraryItem obj)
|
|
||||||
=> throw new InvalidOperationException();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user