feat: use joda time for cursor process
This commit is contained in:
parent
7478515067
commit
7b7016e569
@ -16,6 +16,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import org.joda.time.DateTime;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@ -60,7 +61,11 @@ public class ArticleQueryService {
|
||||
}
|
||||
|
||||
public CursorPager<ArticleData> findRecentArticlesWithCursor(
|
||||
String tag, String author, String favoritedBy, CursorPageParameter page, User currentUser) {
|
||||
String tag,
|
||||
String author,
|
||||
String favoritedBy,
|
||||
CursorPageParameter<DateTime> page,
|
||||
User currentUser) {
|
||||
List<String> articleIds =
|
||||
articleReadService.findArticlesWithCursor(tag, author, favoritedBy, page);
|
||||
if (articleIds.size() == 0) {
|
||||
@ -81,7 +86,8 @@ public class ArticleQueryService {
|
||||
}
|
||||
}
|
||||
|
||||
public CursorPager<ArticleData> findUserFeedWithCursor(User user, CursorPageParameter page) {
|
||||
public CursorPager<ArticleData> findUserFeedWithCursor(
|
||||
User user, CursorPageParameter<DateTime> page) {
|
||||
List<String> followdUsers = userRelationshipQueryService.followedUsers(user.getId());
|
||||
if (followdUsers.size() == 0) {
|
||||
return new CursorPager<>(new ArrayList<>(), page.getDirection(), false);
|
||||
|
@ -10,6 +10,7 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.joda.time.DateTime;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@ -58,7 +59,7 @@ public class CommentQueryService {
|
||||
}
|
||||
|
||||
public CursorPager<CommentData> findByArticleIdWithCursor(
|
||||
String articleId, User user, CursorPageParameter page) {
|
||||
String articleId, User user, CursorPageParameter<DateTime> page) {
|
||||
List<CommentData> comments = commentReadService.findByArticleIdWithCursor(articleId, page);
|
||||
if (comments.isEmpty()) {
|
||||
return new CursorPager<>(new ArrayList<>(), page.getDirection(), false);
|
||||
|
@ -6,13 +6,13 @@ import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class CursorPageParameter {
|
||||
public class CursorPageParameter<T> {
|
||||
private static final int MAX_LIMIT = 1000;
|
||||
private int limit = 20;
|
||||
private String cursor;
|
||||
private T cursor;
|
||||
private Direction direction;
|
||||
|
||||
public CursorPageParameter(String cursor, int limit, Direction direction) {
|
||||
public CursorPageParameter(T cursor, int limit, Direction direction) {
|
||||
setLimit(limit);
|
||||
setCursor(cursor);
|
||||
setDirection(direction);
|
||||
@ -26,13 +26,9 @@ public class CursorPageParameter {
|
||||
return limit + 1;
|
||||
}
|
||||
|
||||
private void setCursor(String cursor) {
|
||||
if (cursor == null) {
|
||||
this.cursor = "";
|
||||
} else {
|
||||
private void setCursor(T cursor) {
|
||||
this.cursor = cursor;
|
||||
}
|
||||
}
|
||||
|
||||
private void setLimit(int limit) {
|
||||
if (limit > MAX_LIMIT) {
|
||||
|
@ -29,12 +29,12 @@ public class CursorPager<T extends Node> {
|
||||
return previous;
|
||||
}
|
||||
|
||||
public String getStartCursor() {
|
||||
return data.isEmpty() ? "" : data.get(0).getCursor();
|
||||
public PageCursor getStartCursor() {
|
||||
return data.isEmpty() ? null : data.get(0).getCursor();
|
||||
}
|
||||
|
||||
public String getEndCursor() {
|
||||
return data.isEmpty() ? "" : data.get(data.size() - 1).getCursor();
|
||||
public PageCursor getEndCursor() {
|
||||
return data.isEmpty() ? null : data.get(data.size() - 1).getCursor();
|
||||
}
|
||||
|
||||
public enum Direction {
|
||||
|
23
src/main/java/io/spring/application/DateTimeCursor.java
Normal file
23
src/main/java/io/spring/application/DateTimeCursor.java
Normal file
@ -0,0 +1,23 @@
|
||||
package io.spring.application;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
|
||||
public class DateTimeCursor extends PageCursor<DateTime> {
|
||||
|
||||
public DateTimeCursor(DateTime data) {
|
||||
super(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.valueOf(getData().getMillis());
|
||||
}
|
||||
|
||||
public static DateTime parse(String cursor) {
|
||||
if (cursor == null) {
|
||||
return null;
|
||||
}
|
||||
return new DateTime().withMillis(Long.parseLong(cursor)).withZone(DateTimeZone.UTC);
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
package io.spring.application;
|
||||
|
||||
public interface Node {
|
||||
String getCursor();
|
||||
PageCursor getCursor();
|
||||
}
|
||||
|
18
src/main/java/io/spring/application/PageCursor.java
Normal file
18
src/main/java/io/spring/application/PageCursor.java
Normal file
@ -0,0 +1,18 @@
|
||||
package io.spring.application;
|
||||
|
||||
public abstract class PageCursor<T> {
|
||||
private T data;
|
||||
|
||||
public PageCursor(T data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public T getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return data.toString();
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package io.spring.application.data;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import io.spring.application.DateTimeCursor;
|
||||
import java.util.List;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
@ -26,7 +27,7 @@ public class ArticleData implements io.spring.application.Node {
|
||||
private ProfileData profileData;
|
||||
|
||||
@Override
|
||||
public String getCursor() {
|
||||
return String.valueOf(getUpdatedAt().getMillis());
|
||||
public DateTimeCursor getCursor() {
|
||||
return new DateTimeCursor(updatedAt);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package io.spring.application.data;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import io.spring.application.DateTimeCursor;
|
||||
import io.spring.application.Node;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
@ -22,7 +23,7 @@ public class CommentData implements Node {
|
||||
private ProfileData profileData;
|
||||
|
||||
@Override
|
||||
public String getCursor() {
|
||||
return String.valueOf(createdAt.getMillis());
|
||||
public DateTimeCursor getCursor() {
|
||||
return new DateTimeCursor(createdAt);
|
||||
}
|
||||
}
|
||||
|
@ -8,12 +8,12 @@ import graphql.execution.DataFetcherResult;
|
||||
import graphql.relay.DefaultConnectionCursor;
|
||||
import graphql.relay.DefaultPageInfo;
|
||||
import graphql.schema.DataFetchingEnvironment;
|
||||
import io.spring.Util;
|
||||
import io.spring.api.exception.ResourceNotFoundException;
|
||||
import io.spring.application.ArticleQueryService;
|
||||
import io.spring.application.CursorPageParameter;
|
||||
import io.spring.application.CursorPager;
|
||||
import io.spring.application.CursorPager.Direction;
|
||||
import io.spring.application.DateTimeCursor;
|
||||
import io.spring.application.data.ArticleData;
|
||||
import io.spring.application.data.CommentData;
|
||||
import io.spring.core.user.User;
|
||||
@ -62,11 +62,13 @@ public class ArticleDatafetcher {
|
||||
if (first != null) {
|
||||
articles =
|
||||
articleQueryService.findUserFeedWithCursor(
|
||||
current, new CursorPageParameter(after, first, Direction.NEXT));
|
||||
current,
|
||||
new CursorPageParameter<>(DateTimeCursor.parse(after), first, Direction.NEXT));
|
||||
} else {
|
||||
articles =
|
||||
articleQueryService.findUserFeedWithCursor(
|
||||
current, new CursorPageParameter(before, last, Direction.PREV));
|
||||
current,
|
||||
new CursorPageParameter<>(DateTimeCursor.parse(before), last, Direction.PREV));
|
||||
}
|
||||
graphql.relay.PageInfo pageInfo = buildArticlePageInfo(articles);
|
||||
ArticlesConnection articlesConnection =
|
||||
@ -77,7 +79,7 @@ public class ArticleDatafetcher {
|
||||
.map(
|
||||
a ->
|
||||
ArticleEdge.newBuilder()
|
||||
.cursor(a.getCursor())
|
||||
.cursor(a.getCursor().toString())
|
||||
.node(buildArticleResult(a))
|
||||
.build())
|
||||
.collect(Collectors.toList()))
|
||||
@ -110,11 +112,13 @@ public class ArticleDatafetcher {
|
||||
if (first != null) {
|
||||
articles =
|
||||
articleQueryService.findUserFeedWithCursor(
|
||||
target, new CursorPageParameter(after, first, Direction.NEXT));
|
||||
target,
|
||||
new CursorPageParameter<>(DateTimeCursor.parse(after), first, Direction.NEXT));
|
||||
} else {
|
||||
articles =
|
||||
articleQueryService.findUserFeedWithCursor(
|
||||
target, new CursorPageParameter(before, last, Direction.PREV));
|
||||
target,
|
||||
new CursorPageParameter<>(DateTimeCursor.parse(before), last, Direction.PREV));
|
||||
}
|
||||
graphql.relay.PageInfo pageInfo = buildArticlePageInfo(articles);
|
||||
ArticlesConnection articlesConnection =
|
||||
@ -125,7 +129,7 @@ public class ArticleDatafetcher {
|
||||
.map(
|
||||
a ->
|
||||
ArticleEdge.newBuilder()
|
||||
.cursor(a.getCursor())
|
||||
.cursor(a.getCursor().toString())
|
||||
.node(buildArticleResult(a))
|
||||
.build())
|
||||
.collect(Collectors.toList()))
|
||||
@ -158,7 +162,7 @@ public class ArticleDatafetcher {
|
||||
null,
|
||||
null,
|
||||
profile.getUsername(),
|
||||
new CursorPageParameter(after, first, Direction.NEXT),
|
||||
new CursorPageParameter<>(DateTimeCursor.parse(after), first, Direction.NEXT),
|
||||
current);
|
||||
} else {
|
||||
articles =
|
||||
@ -166,7 +170,7 @@ public class ArticleDatafetcher {
|
||||
null,
|
||||
null,
|
||||
profile.getUsername(),
|
||||
new CursorPageParameter(before, last, Direction.PREV),
|
||||
new CursorPageParameter<>(DateTimeCursor.parse(before), last, Direction.PREV),
|
||||
current);
|
||||
}
|
||||
graphql.relay.PageInfo pageInfo = buildArticlePageInfo(articles);
|
||||
@ -179,7 +183,7 @@ public class ArticleDatafetcher {
|
||||
.map(
|
||||
a ->
|
||||
ArticleEdge.newBuilder()
|
||||
.cursor(a.getCursor())
|
||||
.cursor(a.getCursor().toString())
|
||||
.node(buildArticleResult(a))
|
||||
.build())
|
||||
.collect(Collectors.toList()))
|
||||
@ -212,7 +216,7 @@ public class ArticleDatafetcher {
|
||||
null,
|
||||
profile.getUsername(),
|
||||
null,
|
||||
new CursorPageParameter(after, first, Direction.NEXT),
|
||||
new CursorPageParameter<>(DateTimeCursor.parse(after), first, Direction.NEXT),
|
||||
current);
|
||||
} else {
|
||||
articles =
|
||||
@ -220,7 +224,7 @@ public class ArticleDatafetcher {
|
||||
null,
|
||||
profile.getUsername(),
|
||||
null,
|
||||
new CursorPageParameter(before, last, Direction.PREV),
|
||||
new CursorPageParameter<>(DateTimeCursor.parse(before), last, Direction.PREV),
|
||||
current);
|
||||
}
|
||||
graphql.relay.PageInfo pageInfo = buildArticlePageInfo(articles);
|
||||
@ -232,7 +236,7 @@ public class ArticleDatafetcher {
|
||||
.map(
|
||||
a ->
|
||||
ArticleEdge.newBuilder()
|
||||
.cursor(a.getCursor())
|
||||
.cursor(a.getCursor().toString())
|
||||
.node(buildArticleResult(a))
|
||||
.build())
|
||||
.collect(Collectors.toList()))
|
||||
@ -267,7 +271,7 @@ public class ArticleDatafetcher {
|
||||
withTag,
|
||||
authoredBy,
|
||||
favoritedBy,
|
||||
new CursorPageParameter(after, first, Direction.NEXT),
|
||||
new CursorPageParameter<>(DateTimeCursor.parse(after), first, Direction.NEXT),
|
||||
current);
|
||||
} else {
|
||||
articles =
|
||||
@ -275,7 +279,7 @@ public class ArticleDatafetcher {
|
||||
withTag,
|
||||
authoredBy,
|
||||
favoritedBy,
|
||||
new CursorPageParameter(before, last, Direction.PREV),
|
||||
new CursorPageParameter<>(DateTimeCursor.parse(before), last, Direction.PREV),
|
||||
current);
|
||||
}
|
||||
graphql.relay.PageInfo pageInfo = buildArticlePageInfo(articles);
|
||||
@ -287,7 +291,7 @@ public class ArticleDatafetcher {
|
||||
.map(
|
||||
a ->
|
||||
ArticleEdge.newBuilder()
|
||||
.cursor(a.getCursor())
|
||||
.cursor(a.getCursor().toString())
|
||||
.node(buildArticleResult(a))
|
||||
.build())
|
||||
.collect(Collectors.toList()))
|
||||
@ -360,12 +364,12 @@ public class ArticleDatafetcher {
|
||||
|
||||
private DefaultPageInfo buildArticlePageInfo(CursorPager<ArticleData> articles) {
|
||||
return new DefaultPageInfo(
|
||||
Util.isEmpty(articles.getStartCursor())
|
||||
articles.getStartCursor() == null
|
||||
? null
|
||||
: new DefaultConnectionCursor(articles.getStartCursor()),
|
||||
Util.isEmpty(articles.getEndCursor())
|
||||
: new DefaultConnectionCursor(articles.getStartCursor().toString()),
|
||||
articles.getEndCursor() == null
|
||||
? null
|
||||
: new DefaultConnectionCursor(articles.getEndCursor()),
|
||||
: new DefaultConnectionCursor(articles.getEndCursor().toString()),
|
||||
articles.hasPrevious(),
|
||||
articles.hasNext());
|
||||
}
|
||||
|
@ -7,11 +7,11 @@ import com.netflix.graphql.dgs.InputArgument;
|
||||
import graphql.execution.DataFetcherResult;
|
||||
import graphql.relay.DefaultConnectionCursor;
|
||||
import graphql.relay.DefaultPageInfo;
|
||||
import io.spring.Util;
|
||||
import io.spring.application.CommentQueryService;
|
||||
import io.spring.application.CursorPageParameter;
|
||||
import io.spring.application.CursorPager;
|
||||
import io.spring.application.CursorPager.Direction;
|
||||
import io.spring.application.DateTimeCursor;
|
||||
import io.spring.application.data.ArticleData;
|
||||
import io.spring.application.data.CommentData;
|
||||
import io.spring.core.user.User;
|
||||
@ -72,11 +72,15 @@ public class CommentDatafetcher {
|
||||
if (first != null) {
|
||||
comments =
|
||||
commentQueryService.findByArticleIdWithCursor(
|
||||
articleData.getId(), current, new CursorPageParameter(after, first, Direction.NEXT));
|
||||
articleData.getId(),
|
||||
current,
|
||||
new CursorPageParameter<>(DateTimeCursor.parse(after), first, Direction.NEXT));
|
||||
} else {
|
||||
comments =
|
||||
commentQueryService.findByArticleIdWithCursor(
|
||||
articleData.getId(), current, new CursorPageParameter(before, last, Direction.PREV));
|
||||
articleData.getId(),
|
||||
current,
|
||||
new CursorPageParameter<>(DateTimeCursor.parse(before), last, Direction.PREV));
|
||||
}
|
||||
graphql.relay.PageInfo pageInfo = buildCommentPageInfo(comments);
|
||||
CommentsConnection result =
|
||||
@ -87,7 +91,7 @@ public class CommentDatafetcher {
|
||||
.map(
|
||||
a ->
|
||||
CommentEdge.newBuilder()
|
||||
.cursor(a.getCursor())
|
||||
.cursor(a.getCursor().toString())
|
||||
.node(buildCommentResult(a))
|
||||
.build())
|
||||
.collect(Collectors.toList()))
|
||||
@ -101,12 +105,12 @@ public class CommentDatafetcher {
|
||||
|
||||
private DefaultPageInfo buildCommentPageInfo(CursorPager<CommentData> comments) {
|
||||
return new DefaultPageInfo(
|
||||
Util.isEmpty(comments.getStartCursor())
|
||||
comments.getStartCursor() == null
|
||||
? null
|
||||
: new DefaultConnectionCursor(comments.getStartCursor()),
|
||||
Util.isEmpty(comments.getEndCursor())
|
||||
: new DefaultConnectionCursor(comments.getStartCursor().toString()),
|
||||
comments.getEndCursor() == null
|
||||
? null
|
||||
: new DefaultConnectionCursor(comments.getEndCursor()),
|
||||
: new DefaultConnectionCursor(comments.getEndCursor().toString()),
|
||||
comments.hasPrevious(),
|
||||
comments.hasNext());
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import io.spring.application.data.CommentData;
|
||||
import java.util.List;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
@Mapper
|
||||
public interface CommentReadService {
|
||||
@ -13,5 +14,5 @@ public interface CommentReadService {
|
||||
List<CommentData> findByArticleId(@Param("articleId") String articleId);
|
||||
|
||||
List<CommentData> findByArticleIdWithCursor(
|
||||
@Param("articleId") String articleId, @Param("page") CursorPageParameter page);
|
||||
@Param("articleId") String articleId, @Param("page") CursorPageParameter<DateTime> page);
|
||||
}
|
||||
|
@ -116,10 +116,10 @@
|
||||
<if test="favoritedBy != null">
|
||||
AND AFU.username = #{favoritedBy}
|
||||
</if>
|
||||
<if test='page.cursor != "" and page.direction.name() == "NEXT"'>
|
||||
<if test='page.cursor != null and page.direction.name() == "NEXT"'>
|
||||
AND A.created_at < #{page.cursor}
|
||||
</if>
|
||||
<if test='page.cursor != "" and page.direction.name() == "PREV"'>
|
||||
<if test='page.cursor != null and page.direction.name() == "PREV"'>
|
||||
AND A.created_at > #{page.cursor}
|
||||
</if>
|
||||
</where>
|
||||
@ -138,10 +138,10 @@
|
||||
<foreach index="index" collection="authors" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
<if test='page.cursor != "" and page.direction.name() == "NEXT"'>
|
||||
<if test='page.cursor != null and page.direction.name() == "NEXT"'>
|
||||
AND A.created_at < #{page.cursor}
|
||||
</if>
|
||||
<if test='page.cursor != "" and page.direction.name() == "PREV"'>
|
||||
<if test='page.cursor != null and page.direction.name() == "PREV"'>
|
||||
AND A.created_at > #{page.cursor}
|
||||
</if>
|
||||
<if test='page.direction.name() == "NEXT"'>
|
||||
|
@ -25,10 +25,10 @@
|
||||
<include refid="selectCommentData"/>
|
||||
<where>
|
||||
C.article_id = #{articleId}
|
||||
<if test='page.cursor != "" and page.direction.name() == "NEXT"'>
|
||||
<if test='page.cursor != null and page.direction.name() == "NEXT"'>
|
||||
AND C.created_at < #{page.cursor}
|
||||
</if>
|
||||
<if test='page.cursor != "" and page.direction.name() == "PREV"'>
|
||||
<if test='page.cursor != null and page.direction.name() == "PREV"'>
|
||||
AND C.created_at > #{page.cursor}
|
||||
</if>
|
||||
</where>
|
||||
|
@ -9,6 +9,7 @@ import io.spring.application.ArticleQueryService;
|
||||
import io.spring.application.CursorPageParameter;
|
||||
import io.spring.application.CursorPager;
|
||||
import io.spring.application.CursorPager.Direction;
|
||||
import io.spring.application.DateTimeCursor;
|
||||
import io.spring.application.Page;
|
||||
import io.spring.application.data.ArticleData;
|
||||
import io.spring.application.data.ArticleDataList;
|
||||
@ -124,7 +125,7 @@ public class ArticleQueryServiceTest extends DbTestBase {
|
||||
|
||||
CursorPager<ArticleData> recentArticles =
|
||||
queryService.findRecentArticlesWithCursor(
|
||||
null, null, null, new CursorPageParameter("", 20, Direction.NEXT), user);
|
||||
null, null, null, new CursorPageParameter<>(null, 20, Direction.NEXT), user);
|
||||
assertEquals(recentArticles.getData().size(), 2);
|
||||
assertEquals(recentArticles.getData().get(0).getId(), article.getId());
|
||||
|
||||
@ -133,14 +134,15 @@ public class ArticleQueryServiceTest extends DbTestBase {
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
new CursorPageParameter(recentArticles.getEndCursor(), 20, Direction.NEXT),
|
||||
new CursorPageParameter<DateTime>(
|
||||
DateTimeCursor.parse(recentArticles.getEndCursor().toString()), 20, Direction.NEXT),
|
||||
user);
|
||||
assertEquals(nodata.getData().size(), 0);
|
||||
assertEquals(nodata.getStartCursor(), "");
|
||||
assertEquals(nodata.getStartCursor(), null);
|
||||
|
||||
CursorPager<ArticleData> prevArticles =
|
||||
queryService.findRecentArticlesWithCursor(
|
||||
null, null, null, new CursorPageParameter("", 20, Direction.PREV), user);
|
||||
null, null, null, new CursorPageParameter<>(null, 20, Direction.PREV), user);
|
||||
assertEquals(prevArticles.getData().size(), 2);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user