♻️ Refactor the publisher loading in posts
This commit is contained in:
parent
7656a8b298
commit
c3095f2a9b
@ -3,6 +3,7 @@ using DysonNetwork.Sphere.Permission;
|
|||||||
using DysonNetwork.Sphere.Publisher;
|
using DysonNetwork.Sphere.Publisher;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Design;
|
using Microsoft.EntityFrameworkCore.Design;
|
||||||
|
using Microsoft.EntityFrameworkCore.Query;
|
||||||
using NodaTime;
|
using NodaTime;
|
||||||
using Npgsql;
|
using Npgsql;
|
||||||
using Quartz;
|
using Quartz;
|
||||||
@ -49,7 +50,7 @@ public class AppDatabase(
|
|||||||
public DbSet<PublisherMember> PublisherMembers { get; set; }
|
public DbSet<PublisherMember> PublisherMembers { get; set; }
|
||||||
public DbSet<PublisherSubscription> PublisherSubscriptions { get; set; }
|
public DbSet<PublisherSubscription> PublisherSubscriptions { get; set; }
|
||||||
public DbSet<PublisherFeature> PublisherFeatures { get; set; }
|
public DbSet<PublisherFeature> PublisherFeatures { get; set; }
|
||||||
|
|
||||||
public DbSet<Post.Post> Posts { get; set; }
|
public DbSet<Post.Post> Posts { get; set; }
|
||||||
public DbSet<Post.PostReaction> PostReactions { get; set; }
|
public DbSet<Post.PostReaction> PostReactions { get; set; }
|
||||||
public DbSet<Post.PostTag> PostTags { get; set; }
|
public DbSet<Post.PostTag> PostTags { get; set; }
|
||||||
@ -64,10 +65,10 @@ public class AppDatabase(
|
|||||||
public DbSet<Chat.Message> ChatMessages { get; set; }
|
public DbSet<Chat.Message> ChatMessages { get; set; }
|
||||||
public DbSet<Chat.RealtimeCall> ChatRealtimeCall { get; set; }
|
public DbSet<Chat.RealtimeCall> ChatRealtimeCall { get; set; }
|
||||||
public DbSet<Chat.MessageReaction> ChatReactions { get; set; }
|
public DbSet<Chat.MessageReaction> ChatReactions { get; set; }
|
||||||
|
|
||||||
public DbSet<Sticker.Sticker> Stickers { get; set; }
|
public DbSet<Sticker.Sticker> Stickers { get; set; }
|
||||||
public DbSet<Sticker.StickerPack> StickerPacks { get; set; }
|
public DbSet<Sticker.StickerPack> StickerPacks { get; set; }
|
||||||
|
|
||||||
public DbSet<Wallet.Wallet> Wallets { get; set; }
|
public DbSet<Wallet.Wallet> Wallets { get; set; }
|
||||||
public DbSet<Wallet.WalletPocket> WalletPockets { get; set; }
|
public DbSet<Wallet.WalletPocket> WalletPockets { get; set; }
|
||||||
public DbSet<Wallet.Order> PaymentOrders { get; set; }
|
public DbSet<Wallet.Order> PaymentOrders { get; set; }
|
||||||
@ -75,14 +76,14 @@ public class AppDatabase(
|
|||||||
|
|
||||||
public DbSet<Developer.CustomApp> CustomApps { get; set; }
|
public DbSet<Developer.CustomApp> CustomApps { get; set; }
|
||||||
public DbSet<Developer.CustomAppSecret> CustomAppSecrets { get; set; }
|
public DbSet<Developer.CustomAppSecret> CustomAppSecrets { get; set; }
|
||||||
|
|
||||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
{
|
{
|
||||||
var dataSourceBuilder = new NpgsqlDataSourceBuilder(configuration.GetConnectionString("App"));
|
var dataSourceBuilder = new NpgsqlDataSourceBuilder(configuration.GetConnectionString("App"));
|
||||||
dataSourceBuilder.EnableDynamicJson();
|
dataSourceBuilder.EnableDynamicJson();
|
||||||
dataSourceBuilder.UseNetTopologySuite();
|
dataSourceBuilder.UseNetTopologySuite();
|
||||||
dataSourceBuilder.UseNodaTime();
|
dataSourceBuilder.UseNodaTime();
|
||||||
|
|
||||||
if (configuration.GetValue<bool>("Debug"))
|
if (configuration.GetValue<bool>("Debug"))
|
||||||
optionsBuilder.EnableSensitiveDataLogging();
|
optionsBuilder.EnableSensitiveDataLogging();
|
||||||
|
|
||||||
@ -104,20 +105,20 @@ public class AppDatabase(
|
|||||||
{
|
{
|
||||||
Key = "default",
|
Key = "default",
|
||||||
Nodes = new List<string>
|
Nodes = new List<string>
|
||||||
{
|
{
|
||||||
"posts.create",
|
"posts.create",
|
||||||
"posts.react",
|
"posts.react",
|
||||||
"publishers.create",
|
"publishers.create",
|
||||||
"files.create",
|
"files.create",
|
||||||
"chat.create",
|
"chat.create",
|
||||||
"chat.messages.create",
|
"chat.messages.create",
|
||||||
"chat.realtime.create",
|
"chat.realtime.create",
|
||||||
"accounts.statuses.create",
|
"accounts.statuses.create",
|
||||||
"accounts.statuses.update",
|
"accounts.statuses.update",
|
||||||
"stickers.packs.create",
|
"stickers.packs.create",
|
||||||
"stickers.create"
|
"stickers.create"
|
||||||
}.Select(permission =>
|
}.Select(permission =>
|
||||||
PermissionService.NewPermissionNode("group:default", "global", permission, true))
|
PermissionService.NewPermissionNode("group:default", "global", permission, true))
|
||||||
.ToList()
|
.ToList()
|
||||||
});
|
});
|
||||||
await context.SaveChangesAsync(cancellationToken);
|
await context.SaveChangesAsync(cancellationToken);
|
||||||
@ -359,4 +360,36 @@ public class AppDatabaseFactory : IDesignTimeDbContextFactory<AppDatabase>
|
|||||||
var optionsBuilder = new DbContextOptionsBuilder<AppDatabase>();
|
var optionsBuilder = new DbContextOptionsBuilder<AppDatabase>();
|
||||||
return new AppDatabase(optionsBuilder.Options, configuration);
|
return new AppDatabase(optionsBuilder.Options, configuration);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class OptionalQueryExtensions
|
||||||
|
{
|
||||||
|
public static IQueryable<T> If<T>(
|
||||||
|
this IQueryable<T> source,
|
||||||
|
bool condition,
|
||||||
|
Func<IQueryable<T>, IQueryable<T>> transform
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return condition ? transform(source) : source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IQueryable<T> If<T, TP>(
|
||||||
|
this IIncludableQueryable<T, TP> source,
|
||||||
|
bool condition,
|
||||||
|
Func<IIncludableQueryable<T, TP>, IQueryable<T>> transform
|
||||||
|
)
|
||||||
|
where T : class
|
||||||
|
{
|
||||||
|
return condition ? transform(source) : source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IQueryable<T> If<T, TP>(
|
||||||
|
this IIncludableQueryable<T, IEnumerable<TP>> source,
|
||||||
|
bool condition,
|
||||||
|
Func<IIncludableQueryable<T, IEnumerable<TP>>, IQueryable<T>> transform
|
||||||
|
)
|
||||||
|
where T : class
|
||||||
|
{
|
||||||
|
return condition ? transform(source) : source;
|
||||||
|
}
|
||||||
}
|
}
|
@ -40,7 +40,7 @@ public class PostController(
|
|||||||
.FilterWithVisibility(currentUser, userFriends, isListing: true)
|
.FilterWithVisibility(currentUser, userFriends, isListing: true)
|
||||||
.CountAsync();
|
.CountAsync();
|
||||||
var posts = await query
|
var posts = await query
|
||||||
.Include(e => e.Publisher)
|
.Include(e => e.RepliedPost)
|
||||||
.Include(e => e.ThreadedPost)
|
.Include(e => e.ThreadedPost)
|
||||||
.Include(e => e.ForwardedPost)
|
.Include(e => e.ForwardedPost)
|
||||||
.Include(e => e.Attachments)
|
.Include(e => e.Attachments)
|
||||||
@ -53,6 +53,7 @@ public class PostController(
|
|||||||
.Take(take)
|
.Take(take)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
posts = PostService.TruncatePostContent(posts);
|
posts = PostService.TruncatePostContent(posts);
|
||||||
|
posts = await ps.LoadPublishers(posts);
|
||||||
|
|
||||||
var postsId = posts.Select(e => e.Id).ToList();
|
var postsId = posts.Select(e => e.Id).ToList();
|
||||||
var reactionMaps = await ps.GetPostReactionMapBatch(postsId);
|
var reactionMaps = await ps.GetPostReactionMapBatch(postsId);
|
||||||
@ -106,7 +107,6 @@ public class PostController(
|
|||||||
.CountAsync();
|
.CountAsync();
|
||||||
var posts = await db.Posts
|
var posts = await db.Posts
|
||||||
.Where(e => e.RepliedPostId == id)
|
.Where(e => e.RepliedPostId == id)
|
||||||
.Include(e => e.Publisher)
|
|
||||||
.Include(e => e.ThreadedPost)
|
.Include(e => e.ThreadedPost)
|
||||||
.Include(e => e.ForwardedPost)
|
.Include(e => e.ForwardedPost)
|
||||||
.Include(e => e.Attachments)
|
.Include(e => e.Attachments)
|
||||||
@ -118,6 +118,7 @@ public class PostController(
|
|||||||
.Take(take)
|
.Take(take)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
posts = PostService.TruncatePostContent(posts);
|
posts = PostService.TruncatePostContent(posts);
|
||||||
|
posts = await ps.LoadPublishers(posts);
|
||||||
|
|
||||||
var postsId = posts.Select(e => e.Id).ToList();
|
var postsId = posts.Select(e => e.Id).ToList();
|
||||||
var reactionMaps = await ps.GetPostReactionMapBatch(postsId);
|
var reactionMaps = await ps.GetPostReactionMapBatch(postsId);
|
||||||
|
@ -271,6 +271,47 @@ public class PostService(
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<List<Post>> LoadPublishers(List<Post> posts)
|
||||||
|
{
|
||||||
|
var publisherIds = posts
|
||||||
|
.Where(e => e.Publisher.AccountId != null)
|
||||||
|
.SelectMany<Post, Guid?>(e =>
|
||||||
|
[
|
||||||
|
e.Publisher.Id,
|
||||||
|
e.RepliedPost?.Publisher.Id,
|
||||||
|
e.ForwardedPost?.Publisher.Id,
|
||||||
|
e.ThreadedPost?.Publisher.Id
|
||||||
|
])
|
||||||
|
.Where(e => e != null)
|
||||||
|
.Distinct()
|
||||||
|
.ToList();
|
||||||
|
if (publisherIds.Count == 0) return posts;
|
||||||
|
|
||||||
|
var publishers = await db.Publishers
|
||||||
|
.Where(e => e.AccountId != null && publisherIds.Contains(e.AccountId.Value))
|
||||||
|
.ToDictionaryAsync(e => e.AccountId!.Value);
|
||||||
|
|
||||||
|
foreach (var post in posts)
|
||||||
|
{
|
||||||
|
if (publishers.TryGetValue(post.Publisher.Id, out var publisher))
|
||||||
|
post.Publisher = publisher;
|
||||||
|
|
||||||
|
if (post.RepliedPost?.Publisher.Id != null &&
|
||||||
|
publishers.TryGetValue(post.RepliedPost.Publisher.Id, out var repliedPublisher))
|
||||||
|
post.RepliedPost.Publisher = repliedPublisher;
|
||||||
|
|
||||||
|
if (post.ForwardedPost?.Publisher.Id != null &&
|
||||||
|
publishers.TryGetValue(post.ForwardedPost.Publisher.Id, out var forwardedPublisher))
|
||||||
|
post.ForwardedPost.Publisher = forwardedPublisher;
|
||||||
|
|
||||||
|
if (post.ThreadedPost?.Publisher.Id != null &&
|
||||||
|
publishers.TryGetValue(post.ThreadedPost.Publisher.Id, out var threadedPublisher))
|
||||||
|
post.ThreadedPost.Publisher = threadedPublisher;
|
||||||
|
}
|
||||||
|
|
||||||
|
return posts;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class PostQueryExtensions
|
public static class PostQueryExtensions
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEntityFrameworkQueryableExtensions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fcb0587797ea44bd6915ede69888c6766291038_003F55_003F277f2d4c_003FEntityFrameworkQueryableExtensions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEntityFrameworkQueryableExtensions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fcb0587797ea44bd6915ede69888c6766291038_003F55_003F277f2d4c_003FEntityFrameworkQueryableExtensions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEntityFrameworkServiceCollectionExtensions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F4a28847852ee9ba45fd3107526c0a749a733bd4f4ebf33aa3c9a59737a3f758_003FEntityFrameworkServiceCollectionExtensions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEntityFrameworkServiceCollectionExtensions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F4a28847852ee9ba45fd3107526c0a749a733bd4f4ebf33aa3c9a59737a3f758_003FEntityFrameworkServiceCollectionExtensions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEnumerable_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F832399abc13b45b6bdbabfa022e4a28487e00_003F7f_003F7aece4dd_003FEnumerable_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEnumerable_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F832399abc13b45b6bdbabfa022e4a28487e00_003F7f_003F7aece4dd_003FEnumerable_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEnumerable_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fadcd336f9cde4e71998a851d7eb945bb87e00_003F0c_003F96dc130e_003FEnumerable_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEvents_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F8bb08a178b5b43c5bac20a5a54159a5b2a800_003F20_003F86914b63_003FEvents_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEvents_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F8bb08a178b5b43c5bac20a5a54159a5b2a800_003F20_003F86914b63_003FEvents_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AExceptionDispatchInfo_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F109293935a4844d5aa1610150b96edcde55000_003Fb7_003F8b7e5594_003FExceptionDispatchInfo_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AExceptionDispatchInfo_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F109293935a4844d5aa1610150b96edcde55000_003Fb7_003F8b7e5594_003FExceptionDispatchInfo_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AExceptionDispatchInfo_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb6f0571a6bc744b0b551fd4578292582e54c00_003Fbf_003F44af6d95_003FExceptionDispatchInfo_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AExceptionDispatchInfo_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb6f0571a6bc744b0b551fd4578292582e54c00_003Fbf_003F44af6d95_003FExceptionDispatchInfo_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user