[backend/masto-client] Expose AccountEntity.last_status_at

For performance reasons (it's set on the same query as the one that
increments the user notes counter) this does not take renotes into
account
This commit is contained in:
Kopper 2025-02-23 12:42:37 +03:00 committed by Laura Hausmann
parent ec7056f11a
commit 5d27233d08
No known key found for this signature in database
GPG key ID: D044E84C5BE01605
6 changed files with 46 additions and 1 deletions

View file

@ -61,6 +61,7 @@ public class UserRenderer(
FullyQualifiedName = $"{user.Username}@{user.Host ?? config.Value.AccountDomain}", FullyQualifiedName = $"{user.Username}@{user.Host ?? config.Value.AccountDomain}",
IsLocked = user.IsLocked, IsLocked = user.IsLocked,
CreatedAt = user.CreatedAt.ToStringIso8601Like(), CreatedAt = user.CreatedAt.ToStringIso8601Like(),
LastStatusAt = user.LastNoteAt?.ToStringIso8601Like(),
FollowersCount = user.FollowersCount, FollowersCount = user.FollowersCount,
FollowingCount = user.FollowingCount, FollowingCount = user.FollowingCount,
StatusesCount = user.NotesCount, StatusesCount = user.NotesCount,

View file

@ -28,6 +28,7 @@ public class AccountEntity : IIdentifiable
[J("source")] public AccountSource? Source { get; set; } [J("source")] public AccountSource? Source { get; set; }
[J("emojis")] public required List<EmojiEntity> Emoji { get; set; } [J("emojis")] public required List<EmojiEntity> Emoji { get; set; }
[J("id")] public required string Id { get; set; } [J("id")] public required string Id { get; set; }
[J("last_status_at")] public string? LastStatusAt { get; set; }
[J("avatar_description")] public required string AvatarDescription { get; set; } [J("avatar_description")] public required string AvatarDescription { get; set; }
[J("header_description")] public required string HeaderDescription { get; set; } [J("header_description")] public required string HeaderDescription { get; set; }

View file

@ -4180,6 +4180,10 @@ namespace Iceshrimp.Backend.Core.Database.Migrations
.HasColumnType("timestamp with time zone") .HasColumnType("timestamp with time zone")
.HasColumnName("lastFetchedAt"); .HasColumnName("lastFetchedAt");
b.Property<DateTime?>("LastNoteAt")
.HasColumnType("timestamp with time zone")
.HasColumnName("lastNoteAt");
b.Property<string>("MovedToUri") b.Property<string>("MovedToUri")
.HasMaxLength(512) .HasMaxLength(512)
.HasColumnType("character varying(512)") .HasColumnType("character varying(512)")

View file

@ -0,0 +1,34 @@
using System;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Iceshrimp.Backend.Core.Database.Migrations
{
/// <inheritdoc />
[DbContext(typeof(DatabaseContext))]
[Migration("20250223092435_AddUserLastNoteAt")]
public partial class AddUserLastNoteAt : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<DateTime>(
name: "lastNoteAt",
table: "user",
type: "timestamp with time zone",
nullable: true);
migrationBuilder.Sql("""UPDATE "user" SET "lastNoteAt" = (SELECT note."createdAt" FROM "note" WHERE "note"."userId" = "user"."id" ORDER BY "note"."createdAt" DESC LIMIT 1);""");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "lastNoteAt",
table: "user");
}
}
}

View file

@ -41,6 +41,7 @@ public class User : IIdentifiable
[Column("lastFetchedAt")] public DateTime? LastFetchedAt { get; set; } [Column("lastFetchedAt")] public DateTime? LastFetchedAt { get; set; }
[Column("outboxFetchedAt")] public DateTime? OutboxFetchedAt { get; set; } [Column("outboxFetchedAt")] public DateTime? OutboxFetchedAt { get; set; }
[Column("lastNoteAt")] public DateTime? LastNoteAt { get; set; }
[NotMapped] [NotMapped]
[Projectable] [Projectable]

View file

@ -480,8 +480,12 @@ public class NoteService(
} }
else else
{ {
var updateLastNoteTimestamp = create && (note.User.LastNoteAt == null || note.CreatedAt > note.User.LastNoteAt);
await db.Users.Where(p => p.Id == note.User.Id) await db.Users.Where(p => p.Id == note.User.Id)
.ExecuteUpdateAsync(p => p.SetProperty(u => u.NotesCount, u => u.NotesCount + diff)); .ExecuteUpdateAsync(p => p
.SetProperty(u => u.NotesCount, u => u.NotesCount + diff)
.SetProperty(u => u.LastNoteAt, u => updateLastNoteTimestamp ? note.CreatedAt : u.LastNoteAt));
} }
if (note.Reply != null) if (note.Reply != null)