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 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 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.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 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 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.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 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 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.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 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 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.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 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 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.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
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.
newResult() .localContext( new HashMap() { { put(articleData.getSlug(), articleData); } }) .data(articleResult) .build(); } @DgsData(parentType = COMMENT.TYPE_NAME, field = COMMENT.Article) public DataFetcherResult
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.
newResult() .localContext( new HashMap() { { put(articleData.getSlug(), articleData); } }) .data(articleResult) .build(); } @DgsData(parentType = DgsConstants.QUERY_TYPE, field = QUERY.Article) public DataFetcherResult
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.
newResult() .localContext( new HashMap() { { put(articleData.getSlug(), articleData); } }) .data(articleResult) .build(); } private DefaultPageInfo buildArticlePageInfo(CursorPager 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(); } }