refactor: do not serialize compact post for tag and category (#2483)

#### What type of PR is this?
/kind improvement
/area core
/milestone 2.0

#### What this PR does / why we need it:
标签和分类的 status 中的 posts 字段不序列化,只提供文章 postCount 代替
#### Which issue(s) this PR fixes:

Fixes #

#### Special notes for your reviewer:
/cc @halo-dev/sig-halo 
#### Does this PR introduce a user-facing change?

```release-note
None
```
pull/2493/head
guqing 2022-09-28 22:10:17 +08:00 committed by GitHub
parent 565c8340e9
commit 2d87a95193
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 55 additions and 155 deletions

View File

@ -67,8 +67,13 @@ public class Category extends AbstractExtension {
private String permalink; private String permalink;
/** /**
* name (depth=max). * (depth=max).
*/ */
private List<Post.CompactPost> posts; public Integer postCount;
/**
* (depth=max).
*/
public Integer visiblePostCount;
} }
} }

View File

@ -2,7 +2,6 @@ package run.halo.app.core.extension;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.ToString; import lombok.ToString;
@ -69,6 +68,8 @@ public class Tag extends AbstractExtension {
private String permalink; private String permalink;
private List<Post.CompactPost> posts; public Integer visiblePostCount;
public Integer postCount;
} }
} }

View File

@ -7,6 +7,7 @@ import java.util.Deque;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -131,7 +132,13 @@ public class CategoryReconciler implements Reconciler<Reconciler.Request> {
.published(post.isPublished()) .published(post.isPublished())
.build()) .build())
.toList(); .toList();
category.getStatusOrDefault().setPosts(compactPosts); category.getStatusOrDefault().setPostCount(compactPosts.size());
long visiblePostCount = compactPosts.stream()
.filter(post -> Objects.equals(true, post.getPublished())
&& Post.VisibleEnum.PUBLIC.equals(post.getVisible()))
.count();
category.getStatusOrDefault().setVisiblePostCount((int) visiblePostCount);
} }
/** /**

View File

@ -3,6 +3,7 @@ package run.halo.app.core.extension.reconciler;
import java.time.Duration; import java.time.Duration;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import run.halo.app.content.permalinks.TagPermalinkPolicy; import run.halo.app.content.permalinks.TagPermalinkPolicy;
import run.halo.app.core.extension.Post; import run.halo.app.core.extension.Post;
@ -115,7 +116,13 @@ public class TagReconciler implements Reconciler<Reconciler.Request> {
.visible(post.getSpec().getVisible()) .visible(post.getSpec().getVisible())
.build()) .build())
.toList(); .toList();
tag.getStatusOrDefault().setPosts(compactPosts); tag.getStatusOrDefault().setPostCount(compactPosts.size());
long visiblePostCount = compactPosts.stream()
.filter(post -> Objects.equals(true, post.getPublished())
&& Post.VisibleEnum.PUBLIC.equals(post.getVisible()))
.count();
tag.getStatusOrDefault().setVisiblePostCount((int) visiblePostCount);
} }
private boolean includes(List<String> tags, String tagName) { private boolean includes(List<String> tags, String tagName) {

View File

@ -1,14 +1,12 @@
package run.halo.app.theme.finders.vo; package run.halo.app.theme.finders.vo;
import java.util.List; import java.util.List;
import java.util.Objects;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.ToString; import lombok.ToString;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import run.halo.app.core.extension.Category; import run.halo.app.core.extension.Category;
import run.halo.app.core.extension.Post;
import run.halo.app.extension.MetadataOperator; import run.halo.app.extension.MetadataOperator;
/** /**
@ -33,6 +31,8 @@ public class CategoryTreeVo {
private String parentName; private String parentName;
private Integer postCount;
/** /**
* Convert {@link CategoryVo} to {@link CategoryTreeVo}. * Convert {@link CategoryVo} to {@link CategoryTreeVo}.
* *
@ -46,21 +46,7 @@ public class CategoryTreeVo {
.spec(category.getSpec()) .spec(category.getSpec())
.status(category.getStatus()) .status(category.getStatus())
.children(List.of()) .children(List.of())
.postCount(category.getPostCount())
.build(); .build();
} }
/**
* Gets the number of posts under the current category and its sub categories.
*
* @return the number of posts
*/
public long postCount() {
if (this.status == null || this.status.getPosts() == null) {
return 0;
}
return this.status.getPosts().stream()
.filter(post -> Objects.equals(true, post.getPublished())
&& Post.VisibleEnum.PUBLIC.equals(post.getVisible()))
.count();
}
} }

View File

@ -1,11 +1,9 @@
package run.halo.app.theme.finders.vo; package run.halo.app.theme.finders.vo;
import java.util.Objects;
import lombok.Builder; import lombok.Builder;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Value; import lombok.Value;
import run.halo.app.core.extension.Category; import run.halo.app.core.extension.Category;
import run.halo.app.core.extension.Post;
import run.halo.app.extension.MetadataOperator; import run.halo.app.extension.MetadataOperator;
/** /**
@ -25,6 +23,8 @@ public class CategoryVo {
Category.CategoryStatus status; Category.CategoryStatus status;
Integer postCount;
/** /**
* Convert {@link Category} to {@link CategoryVo}. * Convert {@link Category} to {@link CategoryVo}.
* *
@ -36,21 +36,7 @@ public class CategoryVo {
.metadata(category.getMetadata()) .metadata(category.getMetadata())
.spec(category.getSpec()) .spec(category.getSpec())
.status(category.getStatus()) .status(category.getStatus())
.postCount(category.getStatusOrDefault().visiblePostCount)
.build(); .build();
} }
/**
* Gets the number of posts under the current category and its sub categories.
*
* @return the number of posts
*/
public long postCount() {
if (this.status == null || this.status.getPosts() == null) {
return 0;
}
return this.status.getPosts().stream()
.filter(post -> Objects.equals(true, post.getPublished())
&& Post.VisibleEnum.PUBLIC.equals(post.getVisible()))
.count();
}
} }

View File

@ -1,9 +1,7 @@
package run.halo.app.theme.finders.vo; package run.halo.app.theme.finders.vo;
import java.util.Objects;
import lombok.Builder; import lombok.Builder;
import lombok.Value; import lombok.Value;
import run.halo.app.core.extension.Post;
import run.halo.app.core.extension.Tag; import run.halo.app.core.extension.Tag;
import run.halo.app.extension.MetadataOperator; import run.halo.app.extension.MetadataOperator;
@ -20,6 +18,8 @@ public class TagVo {
Tag.TagStatus status; Tag.TagStatus status;
Integer postCount;
/** /**
* Convert {@link Tag} to {@link TagVo}. * Convert {@link Tag} to {@link TagVo}.
* *
@ -33,22 +33,7 @@ public class TagVo {
.metadata(tag.getMetadata()) .metadata(tag.getMetadata())
.spec(spec) .spec(spec)
.status(status) .status(status)
.postCount(tag.getStatusOrDefault().getVisiblePostCount())
.build(); .build();
} }
/**
* Gets the number of posts under the current tag.
*
* @return the number of posts
*/
public long postCount() {
if (this.status == null || this.status.getPosts() == null) {
return 0;
}
return this.status.getPosts()
.stream()
.filter(post -> Objects.equals(true, post.getPublished())
&& Post.VisibleEnum.PUBLIC.equals(post.getVisible()))
.count();
}
} }

View File

@ -17,7 +17,6 @@ import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import org.skyscreamer.jsonassert.JSONAssert;
import run.halo.app.content.TestPost; import run.halo.app.content.TestPost;
import run.halo.app.content.permalinks.CategoryPermalinkPolicy; import run.halo.app.content.permalinks.CategoryPermalinkPolicy;
import run.halo.app.core.extension.Category; import run.halo.app.core.extension.Category;
@ -25,7 +24,6 @@ import run.halo.app.core.extension.Post;
import run.halo.app.extension.ExtensionClient; import run.halo.app.extension.ExtensionClient;
import run.halo.app.extension.Metadata; import run.halo.app.extension.Metadata;
import run.halo.app.extension.controller.Reconciler; import run.halo.app.extension.controller.Reconciler;
import run.halo.app.infra.utils.JsonUtils;
/** /**
* Tests for {@link CategoryReconciler}. * Tests for {@link CategoryReconciler}.
@ -50,32 +48,9 @@ class CategoryReconcilerTest {
ArgumentCaptor<Category> captor = ArgumentCaptor.forClass(Category.class); ArgumentCaptor<Category> captor = ArgumentCaptor.forClass(Category.class);
verify(client, times(2)).update(captor.capture()); verify(client, times(2)).update(captor.capture());
JSONAssert.assertEquals(""" assertThat(captor.getAllValues().get(1).getStatusOrDefault().getPostCount()).isEqualTo(4);
[ assertThat(
{ captor.getAllValues().get(1).getStatusOrDefault().getVisiblePostCount()).isEqualTo(0);
"name": "post-1",
"visible": "PUBLIC",
"published": false
},
{
"name": "post-2",
"visible": "PUBLIC",
"published": false
},
{
"name": "post-3",
"visible": "PUBLIC",
"published": false
},
{
"name": "post-4",
"visible": "PUBLIC",
"published": false
}
]
""",
JsonUtils.objectToJson(captor.getAllValues().get(1).getStatusOrDefault().getPosts()),
true);
} }
@Test @Test
@ -83,27 +58,9 @@ class CategoryReconcilerTest {
reconcileStatusPostPilling("category-B"); reconcileStatusPostPilling("category-B");
ArgumentCaptor<Category> captor = ArgumentCaptor.forClass(Category.class); ArgumentCaptor<Category> captor = ArgumentCaptor.forClass(Category.class);
verify(client, times(2)).update(captor.capture()); verify(client, times(2)).update(captor.capture());
JSONAssert.assertEquals(""" Category category = captor.getAllValues().get(1);
[ assertThat(category.getStatusOrDefault().getPostCount()).isEqualTo(3);
{ assertThat(category.getStatusOrDefault().getVisiblePostCount()).isEqualTo(0);
"name": "post-1",
"visible": "PUBLIC",
"published": false
},
{
"name": "post-2",
"visible": "PUBLIC",
"published": false
},
{
"name": "post-3",
"visible": "PUBLIC",
"published": false
}
]
""",
JsonUtils.objectToJson(captor.getAllValues().get(1).getStatusOrDefault().getPosts()),
true);
} }
@Test @Test
@ -111,22 +68,9 @@ class CategoryReconcilerTest {
reconcileStatusPostPilling("category-C"); reconcileStatusPostPilling("category-C");
ArgumentCaptor<Category> captor = ArgumentCaptor.forClass(Category.class); ArgumentCaptor<Category> captor = ArgumentCaptor.forClass(Category.class);
verify(client, times(2)).update(captor.capture()); verify(client, times(2)).update(captor.capture());
JSONAssert.assertEquals(""" assertThat(captor.getAllValues().get(1).getStatusOrDefault().getPostCount()).isEqualTo(2);
[ assertThat(
{ captor.getAllValues().get(1).getStatusOrDefault().getVisiblePostCount()).isEqualTo(0);
"name": "post-1",
"visible": "PUBLIC",
"published": false
},
{
"name": "post-2",
"visible": "PUBLIC",
"published": false
}
]
""",
JsonUtils.objectToJson(captor.getAllValues().get(1).getStatusOrDefault().getPosts()),
true);
} }
@Test @Test
@ -134,17 +78,8 @@ class CategoryReconcilerTest {
reconcileStatusPostPilling("category-D"); reconcileStatusPostPilling("category-D");
ArgumentCaptor<Category> captor = ArgumentCaptor.forClass(Category.class); ArgumentCaptor<Category> captor = ArgumentCaptor.forClass(Category.class);
verify(client, times(2)).update(captor.capture()); verify(client, times(2)).update(captor.capture());
JSONAssert.assertEquals(""" assertThat(captor.getAllValues().get(1).getStatusOrDefault().postCount).isEqualTo(1);
[ assertThat(captor.getAllValues().get(1).getStatusOrDefault().visiblePostCount).isEqualTo(0);
{
"name": "post-1",
"visible": "PUBLIC",
"published": false
}
]
""",
JsonUtils.objectToJson(captor.getAllValues().get(1).getStatusOrDefault().getPosts()),
true);
} }

View File

@ -10,21 +10,18 @@ import static org.mockito.Mockito.when;
import java.time.Instant; import java.time.Instant;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import org.json.JSONException;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import org.skyscreamer.jsonassert.JSONAssert;
import run.halo.app.content.TestPost; import run.halo.app.content.TestPost;
import run.halo.app.content.permalinks.TagPermalinkPolicy; import run.halo.app.content.permalinks.TagPermalinkPolicy;
import run.halo.app.core.extension.Post; import run.halo.app.core.extension.Post;
import run.halo.app.core.extension.Tag; import run.halo.app.core.extension.Tag;
import run.halo.app.extension.ExtensionClient; import run.halo.app.extension.ExtensionClient;
import run.halo.app.extension.Metadata; import run.halo.app.extension.Metadata;
import run.halo.app.infra.utils.JsonUtils;
/** /**
* Tests for {@link TagReconciler}. * Tests for {@link TagReconciler}.
@ -85,7 +82,7 @@ class TagReconcilerTest {
} }
@Test @Test
void reconcileStatusPosts() throws JSONException { void reconcileStatusPosts() {
Tag tag = tag(); Tag tag = tag();
when(client.fetch(eq(Tag.class), eq("fake-tag"))) when(client.fetch(eq(Tag.class), eq("fake-tag")))
.thenReturn(Optional.of(tag)); .thenReturn(Optional.of(tag));
@ -95,20 +92,8 @@ class TagReconcilerTest {
tagReconciler.reconcile(new TagReconciler.Request("fake-tag")); tagReconciler.reconcile(new TagReconciler.Request("fake-tag"));
verify(client, times(2)).update(captor.capture()); verify(client, times(2)).update(captor.capture());
List<Tag> allValues = captor.getAllValues(); List<Tag> allValues = captor.getAllValues();
List<Post.CompactPost> posts = allValues.get(1).getStatusOrDefault().getPosts(); assertThat(allValues.get(1).getStatusOrDefault().getPostCount()).isEqualTo(2);
JSONAssert.assertEquals(""" assertThat(allValues.get(1).getStatusOrDefault().getVisiblePostCount()).isEqualTo(0);
[{
"name": "fake-post-1",
"published": false,
"visible": "PUBLIC"
},
{
"name": "fake-post-3",
"published": false,
"visible": "PRIVATE"
}]
""",
JsonUtils.objectToJson(posts), true);
} }
Tag tag() { Tag tag() {

View File

@ -65,8 +65,10 @@ class TagFinderImplTest {
}, },
"status": { "status": {
"permalink": "permalink-1", "permalink": "permalink-1",
"posts": [] "postCount": 2,
} "visiblePostCount": 1
},
"postCount": 1
} }
""", """,
JsonUtils.objectToJson(tagVo), JsonUtils.objectToJson(tagVo),
@ -117,7 +119,8 @@ class TagFinderImplTest {
Tag.TagStatus tagStatus = new Tag.TagStatus(); Tag.TagStatus tagStatus = new Tag.TagStatus();
tagStatus.setPermalink("permalink-" + i); tagStatus.setPermalink("permalink-" + i);
tagStatus.setPosts(List.of()); tagStatus.setPostCount(2);
tagStatus.setVisiblePostCount(1);
tag.setStatus(tagStatus); tag.setStatus(tagStatus);
return tag; return tag;
} }