spring-boot-realworld-examp.../src/main/java/io/spring/graphql/users/ArticleDatafetcher.java
2021-03-23 15:54:04 +08:00

391 lines
15 KiB
Java

package io.spring.graphql.users;
import com.netflix.graphql.dgs.DgsComponent;
import com.netflix.graphql.dgs.DgsData;
import com.netflix.graphql.dgs.DgsDataFetchingEnvironment;
import com.netflix.graphql.dgs.InputArgument;
import graphql.execution.DataFetcherResult;
import graphql.relay.DefaultConnectionCursor;
import graphql.relay.DefaultPageInfo;
import graphql.schema.DataFetchingEnvironment;
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;
import io.spring.core.user.UserRepository;
import io.spring.graphql.DgsConstants;
import io.spring.graphql.DgsConstants.ARTICLEPAYLOAD;
import io.spring.graphql.DgsConstants.COMMENT;
import io.spring.graphql.DgsConstants.PROFILE;
import io.spring.graphql.DgsConstants.QUERY;
import io.spring.graphql.types.Article;
import io.spring.graphql.types.ArticleEdge;
import io.spring.graphql.types.ArticlesConnection;
import io.spring.graphql.types.Profile;
import java.util.HashMap;
import java.util.stream.Collectors;
import org.joda.time.format.ISODateTimeFormat;
import org.springframework.beans.factory.annotation.Autowired;
@DgsComponent
public class ArticleDatafetcher {
private ArticleQueryService articleQueryService;
private UserRepository userRepository;
@Autowired
public ArticleDatafetcher(
ArticleQueryService articleQueryService, UserRepository userRepository) {
this.articleQueryService = articleQueryService;
this.userRepository = userRepository;
}
@DgsData(parentType = DgsConstants.QUERY_TYPE, field = QUERY.Feed)
public DataFetcherResult<ArticlesConnection> getFeed(
@InputArgument("first") Integer first,
@InputArgument("after") String after,
@InputArgument("last") Integer last,
@InputArgument("before") String before,
DgsDataFetchingEnvironment dfe) {
if (first == null && last == null) {
throw new IllegalArgumentException("first 和 last 必须只存在一个");
}
User current = SecurityUtil.getCurrentUser().orElse(null);
CursorPager<ArticleData> articles;
if (first != null) {
articles =
articleQueryService.findUserFeedWithCursor(
current,
new CursorPageParameter<>(DateTimeCursor.parse(after), first, Direction.NEXT));
} else {
articles =
articleQueryService.findUserFeedWithCursor(
current,
new CursorPageParameter<>(DateTimeCursor.parse(before), last, Direction.PREV));
}
graphql.relay.PageInfo pageInfo = buildArticlePageInfo(articles);
ArticlesConnection articlesConnection =
ArticlesConnection.newBuilder()
.pageInfo(pageInfo)
.edges(
articles.getData().stream()
.map(
a ->
ArticleEdge.newBuilder()
.cursor(a.getCursor().toString())
.node(buildArticleResult(a))
.build())
.collect(Collectors.toList()))
.build();
return DataFetcherResult.<ArticlesConnection>newResult()
.data(articlesConnection)
.localContext(
articles.getData().stream().collect(Collectors.toMap(ArticleData::getSlug, a -> a)))
.build();
}
@DgsData(parentType = PROFILE.TYPE_NAME, field = PROFILE.Feed)
public DataFetcherResult<ArticlesConnection> userFeed(
@InputArgument("first") Integer first,
@InputArgument("after") String after,
@InputArgument("last") Integer last,
@InputArgument("before") String before,
DgsDataFetchingEnvironment dfe) {
if (first == null && last == null) {
throw new IllegalArgumentException("first 和 last 必须只存在一个");
}
Profile profile = dfe.getSource();
User target =
userRepository
.findByUsername(profile.getUsername())
.orElseThrow(ResourceNotFoundException::new);
CursorPager<ArticleData> articles;
if (first != null) {
articles =
articleQueryService.findUserFeedWithCursor(
target,
new CursorPageParameter<>(DateTimeCursor.parse(after), first, Direction.NEXT));
} else {
articles =
articleQueryService.findUserFeedWithCursor(
target,
new CursorPageParameter<>(DateTimeCursor.parse(before), last, Direction.PREV));
}
graphql.relay.PageInfo pageInfo = buildArticlePageInfo(articles);
ArticlesConnection articlesConnection =
ArticlesConnection.newBuilder()
.pageInfo(pageInfo)
.edges(
articles.getData().stream()
.map(
a ->
ArticleEdge.newBuilder()
.cursor(a.getCursor().toString())
.node(buildArticleResult(a))
.build())
.collect(Collectors.toList()))
.build();
return DataFetcherResult.<ArticlesConnection>newResult()
.data(articlesConnection)
.localContext(
articles.getData().stream().collect(Collectors.toMap(ArticleData::getSlug, a -> a)))
.build();
}
@DgsData(parentType = PROFILE.TYPE_NAME, field = PROFILE.Favorites)
public DataFetcherResult<ArticlesConnection> userFavorites(
@InputArgument("first") Integer first,
@InputArgument("after") String after,
@InputArgument("last") Integer last,
@InputArgument("before") String before,
DgsDataFetchingEnvironment dfe) {
if (first == null && last == null) {
throw new IllegalArgumentException("first 和 last 必须只存在一个");
}
User current = SecurityUtil.getCurrentUser().orElse(null);
Profile profile = dfe.getSource();
CursorPager<ArticleData> articles;
if (first != null) {
articles =
articleQueryService.findRecentArticlesWithCursor(
null,
null,
profile.getUsername(),
new CursorPageParameter<>(DateTimeCursor.parse(after), first, Direction.NEXT),
current);
} else {
articles =
articleQueryService.findRecentArticlesWithCursor(
null,
null,
profile.getUsername(),
new CursorPageParameter<>(DateTimeCursor.parse(before), last, Direction.PREV),
current);
}
graphql.relay.PageInfo pageInfo = buildArticlePageInfo(articles);
ArticlesConnection articlesConnection =
ArticlesConnection.newBuilder()
.pageInfo(pageInfo)
.edges(
articles.getData().stream()
.map(
a ->
ArticleEdge.newBuilder()
.cursor(a.getCursor().toString())
.node(buildArticleResult(a))
.build())
.collect(Collectors.toList()))
.build();
return DataFetcherResult.<ArticlesConnection>newResult()
.data(articlesConnection)
.localContext(
articles.getData().stream().collect(Collectors.toMap(ArticleData::getSlug, a -> a)))
.build();
}
@DgsData(parentType = PROFILE.TYPE_NAME, field = PROFILE.Articles)
public DataFetcherResult<ArticlesConnection> userArticles(
@InputArgument("first") Integer first,
@InputArgument("after") String after,
@InputArgument("last") Integer last,
@InputArgument("before") String before,
DgsDataFetchingEnvironment dfe) {
if (first == null && last == null) {
throw new IllegalArgumentException("first 和 last 必须只存在一个");
}
User current = SecurityUtil.getCurrentUser().orElse(null);
Profile profile = dfe.getSource();
CursorPager<ArticleData> articles;
if (first != null) {
articles =
articleQueryService.findRecentArticlesWithCursor(
null,
profile.getUsername(),
null,
new CursorPageParameter<>(DateTimeCursor.parse(after), first, Direction.NEXT),
current);
} else {
articles =
articleQueryService.findRecentArticlesWithCursor(
null,
profile.getUsername(),
null,
new CursorPageParameter<>(DateTimeCursor.parse(before), last, Direction.PREV),
current);
}
graphql.relay.PageInfo pageInfo = buildArticlePageInfo(articles);
ArticlesConnection articlesConnection =
ArticlesConnection.newBuilder()
.pageInfo(pageInfo)
.edges(
articles.getData().stream()
.map(
a ->
ArticleEdge.newBuilder()
.cursor(a.getCursor().toString())
.node(buildArticleResult(a))
.build())
.collect(Collectors.toList()))
.build();
return DataFetcherResult.<ArticlesConnection>newResult()
.data(articlesConnection)
.localContext(
articles.getData().stream().collect(Collectors.toMap(ArticleData::getSlug, a -> a)))
.build();
}
@DgsData(parentType = DgsConstants.QUERY_TYPE, field = QUERY.Articles)
public DataFetcherResult<ArticlesConnection> getArticles(
@InputArgument("first") Integer first,
@InputArgument("after") String after,
@InputArgument("last") Integer last,
@InputArgument("before") String before,
@InputArgument("authoredBy") String authoredBy,
@InputArgument("favoritedBy") String favoritedBy,
@InputArgument("withTag") String withTag,
DgsDataFetchingEnvironment dfe) {
if (first == null && last == null) {
throw new IllegalArgumentException("first 和 last 必须只存在一个");
}
User current = SecurityUtil.getCurrentUser().orElse(null);
CursorPager<ArticleData> articles;
if (first != null) {
articles =
articleQueryService.findRecentArticlesWithCursor(
withTag,
authoredBy,
favoritedBy,
new CursorPageParameter<>(DateTimeCursor.parse(after), first, Direction.NEXT),
current);
} else {
articles =
articleQueryService.findRecentArticlesWithCursor(
withTag,
authoredBy,
favoritedBy,
new CursorPageParameter<>(DateTimeCursor.parse(before), last, Direction.PREV),
current);
}
graphql.relay.PageInfo pageInfo = buildArticlePageInfo(articles);
ArticlesConnection articlesConnection =
ArticlesConnection.newBuilder()
.pageInfo(pageInfo)
.edges(
articles.getData().stream()
.map(
a ->
ArticleEdge.newBuilder()
.cursor(a.getCursor().toString())
.node(buildArticleResult(a))
.build())
.collect(Collectors.toList()))
.build();
return DataFetcherResult.<ArticlesConnection>newResult()
.data(articlesConnection)
.localContext(
articles.getData().stream().collect(Collectors.toMap(ArticleData::getSlug, a -> a)))
.build();
}
@DgsData(parentType = ARTICLEPAYLOAD.TYPE_NAME, field = ARTICLEPAYLOAD.Article)
public DataFetcherResult<Article> getArticle(DataFetchingEnvironment dfe) {
io.spring.core.article.Article article = dfe.getLocalContext();
User current = SecurityUtil.getCurrentUser().orElse(null);
ArticleData articleData =
articleQueryService
.findById(article.getId(), current)
.orElseThrow(ResourceNotFoundException::new);
Article articleResult = buildArticleResult(articleData);
return DataFetcherResult.<Article>newResult()
.localContext(
new HashMap<String, Object>() {
{
put(articleData.getSlug(), articleData);
}
})
.data(articleResult)
.build();
}
@DgsData(parentType = COMMENT.TYPE_NAME, field = COMMENT.Article)
public DataFetcherResult<Article> getCommentArticle(
DataFetchingEnvironment dataFetchingEnvironment) {
CommentData comment = dataFetchingEnvironment.getLocalContext();
User current = SecurityUtil.getCurrentUser().orElse(null);
ArticleData articleData =
articleQueryService
.findById(comment.getArticleId(), current)
.orElseThrow(ResourceNotFoundException::new);
Article articleResult = buildArticleResult(articleData);
return DataFetcherResult.<Article>newResult()
.localContext(
new HashMap<String, Object>() {
{
put(articleData.getSlug(), articleData);
}
})
.data(articleResult)
.build();
}
@DgsData(parentType = DgsConstants.QUERY_TYPE, field = QUERY.Article)
public DataFetcherResult<Article> findArticleBySlug(@InputArgument("slug") String slug) {
User current = SecurityUtil.getCurrentUser().orElse(null);
ArticleData articleData =
articleQueryService.findBySlug(slug, current).orElseThrow(ResourceNotFoundException::new);
Article articleResult = buildArticleResult(articleData);
return DataFetcherResult.<Article>newResult()
.localContext(
new HashMap<String, Object>() {
{
put(articleData.getSlug(), articleData);
}
})
.data(articleResult)
.build();
}
private DefaultPageInfo buildArticlePageInfo(CursorPager<ArticleData> articles) {
return new DefaultPageInfo(
articles.getStartCursor() == null
? null
: new DefaultConnectionCursor(articles.getStartCursor().toString()),
articles.getEndCursor() == null
? null
: new DefaultConnectionCursor(articles.getEndCursor().toString()),
articles.hasPrevious(),
articles.hasNext());
}
private Article buildArticleResult(ArticleData articleData) {
return Article.newBuilder()
.body(articleData.getBody())
.createdAt(ISODateTimeFormat.dateTime().withZoneUTC().print(articleData.getCreatedAt()))
.description(articleData.getDescription())
.favorited(articleData.isFavorited())
.favoritesCount(articleData.getFavoritesCount())
.slug(articleData.getSlug())
.tagList(articleData.getTagList())
.title(articleData.getTitle())
.updatedAt(ISODateTimeFormat.dateTime().withZoneUTC().print(articleData.getUpdatedAt()))
.build();
}
}