2023-05-09 13:56:57 +00:00
|
|
|
|
using Microsoft.EntityFrameworkCore;
|
2022-06-06 21:51:25 +00:00
|
|
|
|
using VoidCat.Model;
|
|
|
|
|
using VoidCat.Services.Abstractions;
|
|
|
|
|
|
|
|
|
|
namespace VoidCat.Services.Files;
|
|
|
|
|
|
2022-06-08 16:17:53 +00:00
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
public class PostgresFileMetadataStore : IFileMetadataStore
|
2022-06-06 21:51:25 +00:00
|
|
|
|
{
|
2023-05-09 13:56:57 +00:00
|
|
|
|
private readonly VoidContext _db;
|
|
|
|
|
private readonly IServiceScopeFactory _scopeFactory;
|
2022-06-06 21:51:25 +00:00
|
|
|
|
|
2023-05-09 13:56:57 +00:00
|
|
|
|
public PostgresFileMetadataStore(VoidContext db, IServiceScopeFactory scopeFactory)
|
2022-06-06 21:51:25 +00:00
|
|
|
|
{
|
2023-05-09 13:56:57 +00:00
|
|
|
|
_db = db;
|
|
|
|
|
_scopeFactory = scopeFactory;
|
2022-06-06 21:51:25 +00:00
|
|
|
|
}
|
2023-05-09 13:56:57 +00:00
|
|
|
|
|
2022-07-25 17:59:32 +00:00
|
|
|
|
public string? Key => "postgres";
|
2022-06-06 21:51:25 +00:00
|
|
|
|
|
2022-06-08 16:17:53 +00:00
|
|
|
|
/// <inheritdoc />
|
2023-05-09 13:56:57 +00:00
|
|
|
|
public async ValueTask<Database.File?> Get(Guid id)
|
2022-06-08 16:17:53 +00:00
|
|
|
|
{
|
2023-05-09 13:56:57 +00:00
|
|
|
|
return await _db.Files
|
|
|
|
|
.AsNoTracking()
|
|
|
|
|
.Include(a => a.Paywall)
|
|
|
|
|
.SingleOrDefaultAsync(a => a.Id == id);
|
2022-06-08 16:17:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-05-09 13:56:57 +00:00
|
|
|
|
public async ValueTask Add(Database.File f)
|
2022-06-06 21:51:25 +00:00
|
|
|
|
{
|
2023-05-09 13:56:57 +00:00
|
|
|
|
_db.Files.Add(f);
|
|
|
|
|
await _db.SaveChangesAsync();
|
2022-06-06 21:51:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-06-08 16:17:53 +00:00
|
|
|
|
/// <inheritdoc />
|
2022-06-06 21:51:25 +00:00
|
|
|
|
public async ValueTask Delete(Guid id)
|
|
|
|
|
{
|
2023-05-09 13:56:57 +00:00
|
|
|
|
await _db.Files
|
|
|
|
|
.Where(a => a.Id == id)
|
|
|
|
|
.ExecuteDeleteAsync();
|
2022-06-06 21:51:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-06-08 16:17:53 +00:00
|
|
|
|
/// <inheritdoc />
|
2023-05-09 13:56:57 +00:00
|
|
|
|
public async ValueTask<IReadOnlyList<Database.File>> Get(Guid[] ids)
|
2022-06-06 21:51:25 +00:00
|
|
|
|
{
|
2023-05-09 13:56:57 +00:00
|
|
|
|
return await _db.Files
|
|
|
|
|
.Include(a => a.Paywall)
|
|
|
|
|
.Where(a => ids.Contains(a.Id))
|
|
|
|
|
.ToArrayAsync();
|
2022-06-06 21:51:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-06-08 16:17:53 +00:00
|
|
|
|
/// <inheritdoc />
|
2023-05-09 13:56:57 +00:00
|
|
|
|
public async ValueTask Update(Guid id, Database.File obj)
|
2022-06-06 21:51:25 +00:00
|
|
|
|
{
|
2023-05-09 13:56:57 +00:00
|
|
|
|
var existing = await _db.Files.FindAsync(id);
|
|
|
|
|
if (existing == default)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-06-06 21:51:25 +00:00
|
|
|
|
|
2023-05-09 13:56:57 +00:00
|
|
|
|
existing.Patch(obj);
|
|
|
|
|
await _db.SaveChangesAsync();
|
2022-06-06 21:51:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-06-08 16:17:53 +00:00
|
|
|
|
/// <inheritdoc />
|
2023-05-09 13:56:57 +00:00
|
|
|
|
public async ValueTask<PagedResult<Database.File>> ListFiles(PagedRequest request)
|
2022-06-08 16:17:53 +00:00
|
|
|
|
{
|
2023-05-09 13:56:57 +00:00
|
|
|
|
var count = await _db.Files.CountAsync();
|
2022-06-08 16:17:53 +00:00
|
|
|
|
|
2023-05-09 13:56:57 +00:00
|
|
|
|
async IAsyncEnumerable<Database.File> Enumerate()
|
2022-06-08 16:17:53 +00:00
|
|
|
|
{
|
2023-05-09 13:56:57 +00:00
|
|
|
|
using var scope = _scopeFactory.CreateScope();
|
|
|
|
|
var db = scope.ServiceProvider.GetRequiredService<VoidContext>();
|
|
|
|
|
var q = db.Files.AsNoTracking().AsQueryable();
|
|
|
|
|
switch (request.SortBy, request.SortOrder)
|
2022-06-09 14:15:28 +00:00
|
|
|
|
{
|
2023-05-09 13:56:57 +00:00
|
|
|
|
case (PagedSortBy.Id, PageSortOrder.Asc):
|
|
|
|
|
q = q.OrderBy(a => a.Id);
|
|
|
|
|
break;
|
|
|
|
|
case (PagedSortBy.Id, PageSortOrder.Dsc):
|
|
|
|
|
q = q.OrderByDescending(a => a.Id);
|
|
|
|
|
break;
|
|
|
|
|
case (PagedSortBy.Name, PageSortOrder.Asc):
|
|
|
|
|
q = q.OrderBy(a => a.Name);
|
|
|
|
|
break;
|
|
|
|
|
case (PagedSortBy.Name, PageSortOrder.Dsc):
|
|
|
|
|
q = q.OrderByDescending(a => a.Name);
|
|
|
|
|
break;
|
|
|
|
|
case (PagedSortBy.Date, PageSortOrder.Asc):
|
|
|
|
|
q = q.OrderBy(a => a.Uploaded);
|
|
|
|
|
break;
|
|
|
|
|
case (PagedSortBy.Date, PageSortOrder.Dsc):
|
|
|
|
|
q = q.OrderByDescending(a => a.Uploaded);
|
|
|
|
|
break;
|
|
|
|
|
case (PagedSortBy.Size, PageSortOrder.Asc):
|
|
|
|
|
q = q.OrderBy(a => a.Size);
|
|
|
|
|
break;
|
|
|
|
|
case (PagedSortBy.Size, PageSortOrder.Dsc):
|
|
|
|
|
q = q.OrderByDescending(a => a.Size);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await foreach (var r in q.Skip(request.Page * request.PageSize).Take(request.PageSize).AsAsyncEnumerable())
|
2022-06-08 16:17:53 +00:00
|
|
|
|
{
|
2023-05-09 13:56:57 +00:00
|
|
|
|
yield return r;
|
2022-06-08 16:17:53 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return new()
|
|
|
|
|
{
|
|
|
|
|
TotalResults = count,
|
|
|
|
|
PageSize = request.PageSize,
|
|
|
|
|
Page = request.Page,
|
|
|
|
|
Results = Enumerate()
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
2022-06-06 21:51:25 +00:00
|
|
|
|
public async ValueTask<IFileMetadataStore.StoreStats> Stats()
|
|
|
|
|
{
|
2023-05-09 13:56:57 +00:00
|
|
|
|
var size = await _db.Files
|
|
|
|
|
.AsNoTracking()
|
|
|
|
|
.SumAsync(a => (long)a.Size);
|
|
|
|
|
|
|
|
|
|
var count = await _db.Files.CountAsync();
|
|
|
|
|
return new(count, (ulong)size);
|
2022-06-06 21:51:25 +00:00
|
|
|
|
}
|
2023-05-09 13:56:57 +00:00
|
|
|
|
}
|