[backend/masto-client] Fix notification pagination (ISH-204)

This commit is contained in:
Laura Hausmann 2024-03-26 20:00:02 +01:00
parent 174064416a
commit 715f47cafc
No known key found for this signature in database
GPG key ID: D044E84C5BE01605
6 changed files with 6131 additions and 1 deletions

View file

@ -50,7 +50,7 @@ public class NotificationController(DatabaseContext db, NotificationRenderer not
.EnsureNoteVisibilityFor(p => p.Note, user) .EnsureNoteVisibilityFor(p => p.Note, user)
.FilterBlocked(p => p.Notifier, user) .FilterBlocked(p => p.Notifier, user)
.FilterBlocked(p => p.Note, user) .FilterBlocked(p => p.Note, user)
.Paginate(query, ControllerContext) .Paginate(p => p.MastoId, query, ControllerContext)
.PrecomputeNoteVisibilities(user) .PrecomputeNoteVisibilities(user)
.RenderAllForMastodonAsync(notificationRenderer, user); .RenderAllForMastodonAsync(notificationRenderer, user);

View file

@ -0,0 +1,27 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Iceshrimp.Backend.Core.Database.Migrations
{
/// <inheritdoc />
public partial class AddNotificationMastoIdIndex : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateIndex(
name: "IX_notification_masto_id",
table: "notification",
column: "masto_id");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "IX_notification_masto_id",
table: "notification");
}
}
}

View file

@ -2926,6 +2926,8 @@ namespace Iceshrimp.Backend.Core.Database.Migrations
b.HasIndex("IsRead"); b.HasIndex("IsRead");
b.HasIndex("MastoId");
b.HasIndex("NoteId"); b.HasIndex("NoteId");
b.HasIndex("NotifieeId"); b.HasIndex("NotifieeId");

View file

@ -12,6 +12,7 @@ namespace Iceshrimp.Backend.Core.Database.Tables;
[Index("NotifieeId")] [Index("NotifieeId")]
[Index("CreatedAt")] [Index("CreatedAt")]
[Index("AppAccessTokenId")] [Index("AppAccessTokenId")]
[Index("MastoId")]
public class Notification : IEntity public class Notification : IEntity
{ {
[PgName("notification_type_enum")] [PgName("notification_type_enum")]

View file

@ -85,6 +85,60 @@ public static class QueryableExtensions
return query.Take(Math.Min(pq.Limit ?? defaultLimit, maxLimit)); return query.Take(Math.Min(pq.Limit ?? defaultLimit, maxLimit));
} }
public static IQueryable<T> Paginate<T>(
this IQueryable<T> query,
Expression<Func<T, long>> predicate,
MastodonPaginationQuery pq,
int defaultLimit,
int maxLimit
) where T : IEntity
{
if (pq.Limit is < 1)
throw GracefulException.BadRequest("Limit cannot be less than 1");
if (pq is { SinceId: not null, MinId: not null })
throw GracefulException.BadRequest("Can't use sinceId and minId params simultaneously");
long? sinceId = null;
long? minId = null;
long? maxId = null;
if (pq.SinceId != null)
{
if (!long.TryParse(pq.SinceId, out var res))
throw GracefulException.BadRequest("sinceId must be an integer");
sinceId = res;
}
if (pq.MinId != null)
{
if (!long.TryParse(pq.MinId, out var res))
throw GracefulException.BadRequest("minId must be an integer");
minId = res;
}
if (pq.MaxId != null)
{
if (!long.TryParse(pq.MaxId, out var res))
throw GracefulException.BadRequest("maxId must be an integer");
maxId = res;
}
query = pq switch
{
{ SinceId: not null, MaxId: not null } => query.Where(predicate.Compose(id => id > sinceId && id < maxId))
.OrderByDescending(predicate),
{ MinId: not null, MaxId: not null } => query.Where(predicate.Compose(id => id > minId && id < maxId))
.OrderBy(predicate),
{ SinceId: not null } => query.Where(predicate.Compose(id => id > sinceId)).OrderByDescending(predicate),
{ MinId: not null } => query.Where(predicate.Compose(id => id > minId)).OrderBy(predicate),
{ MaxId: not null } => query.Where(predicate.Compose(id => id < maxId)).OrderByDescending(predicate),
_ => query.OrderByDescending(predicate)
};
return query.Take(Math.Min(pq.Limit ?? defaultLimit, maxLimit));
}
public static IQueryable<T> Paginate<T>( public static IQueryable<T> Paginate<T>(
this IQueryable<T> query, this IQueryable<T> query,
PaginationQuery pq, PaginationQuery pq,
@ -140,6 +194,22 @@ public static class QueryableExtensions
return Paginate(query, predicate, pq, filter.DefaultLimit, filter.MaxLimit); return Paginate(query, predicate, pq, filter.DefaultLimit, filter.MaxLimit);
} }
public static IQueryable<T> Paginate<T>(
this IQueryable<T> query,
Expression<Func<T, long>> predicate,
MastodonPaginationQuery pq,
ControllerContext context
) where T : IEntity
{
var filter = context.ActionDescriptor.FilterDescriptors.Select(p => p.Filter)
.OfType<LinkPaginationAttribute>()
.FirstOrDefault();
if (filter == null)
throw new GracefulException("Route doesn't have a LinkPaginationAttribute");
return Paginate(query, predicate, pq, filter.DefaultLimit, filter.MaxLimit);
}
public static IQueryable<T> Paginate<T>( public static IQueryable<T> Paginate<T>(
this IQueryable<T> query, this IQueryable<T> query,
PaginationQuery pq, PaginationQuery pq,