diff --git a/DysonNetwork.Sphere/AppDatabase.cs b/DysonNetwork.Sphere/AppDatabase.cs index 3393ab7..ff7c5b7 100644 --- a/DysonNetwork.Sphere/AppDatabase.cs +++ b/DysonNetwork.Sphere/AppDatabase.cs @@ -135,6 +135,7 @@ public class AppDatabase( .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() + .HasGeneratedTsVectorColumn(p => p.SearchVector, "simple", p => new { p.Title, p.Description, p.Content }) .HasIndex(p => p.SearchVector) .HasMethod("GIN"); modelBuilder.Entity() @@ -199,7 +200,7 @@ public class AppDatabase( .HasForeignKey(m => m.ForwardedMessageId) .OnDelete(DeleteBehavior.Restrict); modelBuilder.Entity() - .HasOne(m => m.RepliedMessage) + .HasOne(m => m.RepliedMessage) .WithMany() .HasForeignKey(m => m.RepliedMessageId) .OnDelete(DeleteBehavior.Restrict); diff --git a/DysonNetwork.Sphere/Migrations/20250503124624_InitialMigration.Designer.cs b/DysonNetwork.Sphere/Migrations/20250504170705_InitialMigration.Designer.cs similarity index 99% rename from DysonNetwork.Sphere/Migrations/20250503124624_InitialMigration.Designer.cs rename to DysonNetwork.Sphere/Migrations/20250504170705_InitialMigration.Designer.cs index 1d91f30..6351f5b 100644 --- a/DysonNetwork.Sphere/Migrations/20250503124624_InitialMigration.Designer.cs +++ b/DysonNetwork.Sphere/Migrations/20250504170705_InitialMigration.Designer.cs @@ -16,7 +16,7 @@ using NpgsqlTypes; namespace DysonNetwork.Sphere.Migrations { [DbContext(typeof(AppDatabase))] - [Migration("20250503124624_InitialMigration")] + [Migration("20250504170705_InitialMigration")] partial class InitialMigration { /// @@ -1080,8 +1080,8 @@ namespace DysonNetwork.Sphere.Migrations NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - b.Property("Content") - .HasColumnType("jsonb") + b.Property("Content") + .HasColumnType("text") .HasColumnName("content"); b.Property("CreatedAt") @@ -1131,8 +1131,12 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnName("replied_post_id"); b.Property("SearchVector") + .IsRequired() + .ValueGeneratedOnAddOrUpdate() .HasColumnType("tsvector") - .HasColumnName("search_vector"); + .HasColumnName("search_vector") + .HasAnnotation("Npgsql:TsVectorConfig", "simple") + .HasAnnotation("Npgsql:TsVectorProperties", new[] { "Title", "Description", "Content" }); b.Property("ThreadedPostId") .HasColumnType("bigint") diff --git a/DysonNetwork.Sphere/Migrations/20250503124624_InitialMigration.cs b/DysonNetwork.Sphere/Migrations/20250504170705_InitialMigration.cs similarity index 99% rename from DysonNetwork.Sphere/Migrations/20250503124624_InitialMigration.cs rename to DysonNetwork.Sphere/Migrations/20250504170705_InitialMigration.cs index 8304822..cdbcb8a 100644 --- a/DysonNetwork.Sphere/Migrations/20250503124624_InitialMigration.cs +++ b/DysonNetwork.Sphere/Migrations/20250504170705_InitialMigration.cs @@ -709,7 +709,7 @@ namespace DysonNetwork.Sphere.Migrations edited_at = table.Column(type: "timestamp with time zone", nullable: true), published_at = table.Column(type: "timestamp with time zone", nullable: true), visibility = table.Column(type: "integer", nullable: false), - content = table.Column(type: "jsonb", nullable: true), + content = table.Column(type: "text", nullable: true), type = table.Column(type: "integer", nullable: false), meta = table.Column>(type: "jsonb", nullable: true), views_unique = table.Column(type: "integer", nullable: false), @@ -719,7 +719,9 @@ namespace DysonNetwork.Sphere.Migrations threaded_post_id = table.Column(type: "bigint", nullable: true), replied_post_id = table.Column(type: "bigint", nullable: true), forwarded_post_id = table.Column(type: "bigint", nullable: true), - search_vector = table.Column(type: "tsvector", nullable: true), + search_vector = table.Column(type: "tsvector", nullable: false) + .Annotation("Npgsql:TsVectorConfig", "simple") + .Annotation("Npgsql:TsVectorProperties", new[] { "title", "description", "content" }), publisher_id = table.Column(type: "bigint", nullable: false), created_at = table.Column(type: "timestamp with time zone", nullable: false), updated_at = table.Column(type: "timestamp with time zone", nullable: false), diff --git a/DysonNetwork.Sphere/Migrations/AppDatabaseModelSnapshot.cs b/DysonNetwork.Sphere/Migrations/AppDatabaseModelSnapshot.cs index ce445a2..a4450ae 100644 --- a/DysonNetwork.Sphere/Migrations/AppDatabaseModelSnapshot.cs +++ b/DysonNetwork.Sphere/Migrations/AppDatabaseModelSnapshot.cs @@ -1077,8 +1077,8 @@ namespace DysonNetwork.Sphere.Migrations NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - b.Property("Content") - .HasColumnType("jsonb") + b.Property("Content") + .HasColumnType("text") .HasColumnName("content"); b.Property("CreatedAt") @@ -1128,8 +1128,12 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnName("replied_post_id"); b.Property("SearchVector") + .IsRequired() + .ValueGeneratedOnAddOrUpdate() .HasColumnType("tsvector") - .HasColumnName("search_vector"); + .HasColumnName("search_vector") + .HasAnnotation("Npgsql:TsVectorConfig", "simple") + .HasAnnotation("Npgsql:TsVectorProperties", new[] { "Title", "Description", "Content" }); b.Property("ThreadedPostId") .HasColumnType("bigint") diff --git a/DysonNetwork.Sphere/Post/Post.cs b/DysonNetwork.Sphere/Post/Post.cs index 7411367..289aaf7 100644 --- a/DysonNetwork.Sphere/Post/Post.cs +++ b/DysonNetwork.Sphere/Post/Post.cs @@ -32,8 +32,9 @@ public class Post : ModelBase public Instant? EditedAt { get; set; } public Instant? PublishedAt { get; set; } public PostVisibility Visibility { get; set; } = PostVisibility.Public; - - [Column(TypeName = "jsonb")] public JsonDocument? Content { get; set; } + + // ReSharper disable once EntityFramework.ModelValidation.UnlimitedStringLength + public string? Content { get; set; } public PostType Type { get; set; } [Column(TypeName = "jsonb")] public Dictionary? Meta { get; set; } @@ -51,8 +52,8 @@ public class Post : ModelBase public long? ForwardedPostId { get; set; } public Post? ForwardedPost { get; set; } public ICollection Attachments { get; set; } = new List(); - - [JsonIgnore] public NpgsqlTsVector? SearchVector { get; set; } + + [JsonIgnore] public NpgsqlTsVector SearchVector { get; set; } = null!; public Publisher Publisher { get; set; } = null!; public ICollection Reactions { get; set; } = new List(); diff --git a/DysonNetwork.Sphere/Post/PostController.cs b/DysonNetwork.Sphere/Post/PostController.cs index e358822..dc447a3 100644 --- a/DysonNetwork.Sphere/Post/PostController.cs +++ b/DysonNetwork.Sphere/Post/PostController.cs @@ -119,7 +119,7 @@ public class PostController(AppDatabase db, PostService ps, RelationshipService { [MaxLength(1024)] public string? Title { get; set; } [MaxLength(4096)] public string? Description { get; set; } - public JsonDocument? Content { get; set; } + public string? Content { get; set; } public PostVisibility? Visibility { get; set; } public PostType? Type { get; set; } [MaxLength(16)] public List? Tags { get; set; } diff --git a/DysonNetwork.Sphere/Post/PostService.cs b/DysonNetwork.Sphere/Post/PostService.cs index 778c82d..502b99f 100644 --- a/DysonNetwork.Sphere/Post/PostService.cs +++ b/DysonNetwork.Sphere/Post/PostService.cs @@ -10,57 +10,12 @@ public class PostService(AppDatabase db, FileService fs, ActivityService act) { public static List TruncatePostContent(List input) { - // This truncate post content is designed for quill delta const int maxLength = 256; foreach (var item in input) { - if (item.Content is not { RootElement: var rootElement }) continue; - - if (rootElement.ValueKind != JsonValueKind.Array) continue; - var totalLength = 0; - var truncatedArrayElements = new List(); - - foreach (var element in rootElement.EnumerateArray()) - { - if (element is { ValueKind: JsonValueKind.Object } && - element.TryGetProperty("insert", out var insertProperty)) - { - if (insertProperty is { ValueKind: JsonValueKind.String }) - { - var textContent = insertProperty.GetString()!; - if (totalLength + textContent.Length <= maxLength) - { - truncatedArrayElements.Add(element); - totalLength += textContent.Length; - } - else - { - var remainingLength = maxLength - totalLength; - if (remainingLength > 0) - { - using var truncatedElementDocument = - JsonDocument.Parse( - $@"{{ ""insert"": ""{textContent.Substring(0, remainingLength)}"" }}" - ); - truncatedArrayElements.Add(truncatedElementDocument.RootElement.Clone()); - totalLength = maxLength; - } - - break; - } - } - else - truncatedArrayElements.Add(element); - } - else - truncatedArrayElements.Add(element); - - if (totalLength >= maxLength) - break; - } - - var newDocument = JsonDocument.Parse(JsonSerializer.Serialize(truncatedArrayElements)); - item.Content = newDocument; + if (!(item.Content?.Length > maxLength)) continue; + item.Content = item.Content[..maxLength]; + item.IsTruncated = true; } return input; @@ -121,29 +76,6 @@ public class PostService(AppDatabase db, FileService fs, ActivityService act) throw new InvalidOperationException("Categories contains one or more categories that wasn't exists."); } - // Vectorize the quill delta content - if (post.Content?.RootElement is { ValueKind: JsonValueKind.Array }) - { - var searchTextBuilder = new System.Text.StringBuilder(); - - if (!string.IsNullOrWhiteSpace(post.Title)) - searchTextBuilder.AppendLine(post.Title); - if (!string.IsNullOrWhiteSpace(post.Description)) - searchTextBuilder.AppendLine(post.Description); - - foreach (var element in post.Content.RootElement.EnumerateArray()) - { - if (element is { ValueKind: JsonValueKind.Object } && - element.TryGetProperty("insert", out var insertProperty) && - insertProperty.ValueKind == JsonValueKind.String) - { - searchTextBuilder.Append(insertProperty.GetString()); - } - } - - post.SearchVector = EF.Functions.ToTsVector(searchTextBuilder.ToString().Trim()); - } - // TODO Notify the subscribers db.Posts.Add(post); @@ -222,29 +154,6 @@ public class PostService(AppDatabase db, FileService fs, ActivityService act) throw new InvalidOperationException("Categories contains one or more categories that wasn't exists."); } - // Vectorize the quill delta content - if (post.Content?.RootElement is { ValueKind: JsonValueKind.Array }) - { - var searchTextBuilder = new System.Text.StringBuilder(); - - if (!string.IsNullOrWhiteSpace(post.Title)) - searchTextBuilder.AppendLine(post.Title); - if (!string.IsNullOrWhiteSpace(post.Description)) - searchTextBuilder.AppendLine(post.Description); - - foreach (var element in post.Content.RootElement.EnumerateArray()) - { - if (element is { ValueKind: JsonValueKind.Object } && - element.TryGetProperty("insert", out var insertProperty) && - insertProperty.ValueKind == JsonValueKind.String) - { - searchTextBuilder.Append(insertProperty.GetString()); - } - } - - post.SearchVector = EF.Functions.ToTsVector(searchTextBuilder.ToString().Trim()); - } - db.Update(post); await db.SaveChangesAsync(); diff --git a/DysonNetwork.sln.DotSettings.user b/DysonNetwork.sln.DotSettings.user index 10180ba..2668fd3 100644 --- a/DysonNetwork.sln.DotSettings.user +++ b/DysonNetwork.sln.DotSettings.user @@ -40,6 +40,7 @@ ForceIncluded ForceIncluded ForceIncluded + ForceIncluded ForceIncluded ForceIncluded ForceIncluded