From 6b5d51fbf738043f6784397a3eff13ae2d3bc072 Mon Sep 17 00:00:00 2001 From: riza_ramadan Date: Tue, 12 Jan 2021 10:50:30 +0700 Subject: [PATCH] article by tag's done the previously introduced TagArticles grain is done, serving articles query by tag. And also some refactor of mediator handle. This is still not in the final form yet, as I think the final form should be map of enum and function. --- src/Conduit/Features/Articles/GetArticles.cs | 57 ++++++++++++++------ src/Contracts/Articles/ITagArticlesGrain.cs | 2 +- src/Grains/Articles/ArticlesGrain.cs | 43 ++------------- src/Grains/Articles/BaseArticleGrain.cs | 46 ++++++++++++++++ src/Grains/Articles/TagArticlesGrain.cs | 15 +++--- 5 files changed, 98 insertions(+), 65 deletions(-) create mode 100644 src/Grains/Articles/BaseArticleGrain.cs diff --git a/src/Conduit/Features/Articles/GetArticles.cs b/src/Conduit/Features/Articles/GetArticles.cs index 1f2d572..fbee5e9 100644 --- a/src/Conduit/Features/Articles/GetArticles.cs +++ b/src/Conduit/Features/Articles/GetArticles.cs @@ -6,21 +6,22 @@ using MediatR; using Orleans; using System; + using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; public class GetArticlesInput : IRequest<(GetArticlesOutput Output, Error Error)> { - public const int MaxLimit = 20; + public const int MaxLimit = 10; public string Tag { get; set; } - public string Autor { get; set; } + public string Author { get; set; } public string Favorited { get; set; } private int? _limit; public int? Limit { - get => _limit.HasValue ? _limit : 0; + get => _limit.HasValue ? _limit : MaxLimit; set => _limit = value > MaxLimit ? MaxLimit : value; } private int? _offset; @@ -29,6 +30,16 @@ public int? Offset get => _offset.HasValue ? _offset : 0; set => _offset = value; } + + public bool AllAtricles() => + string.IsNullOrWhiteSpace(Tag) + && string.IsNullOrWhiteSpace(Author) + && string.IsNullOrWhiteSpace(Favorited); + + internal bool ExistTagOnly() => + !string.IsNullOrWhiteSpace(Tag) + && string.IsNullOrWhiteSpace(Author) + && string.IsNullOrWhiteSpace(Favorited); } public class GetArticlesHandler : IRequestHandler _client = c; public async Task<(GetArticlesOutput Output, Error Error)> Handle(GetArticlesInput req, CancellationToken ct) { try { - var articlesGrain = _client.GetGrain(0); - var result = await articlesGrain.GetHomeGuestArticles(req.Limit.Value, req.Offset.Value); - if (result.Error.Exist()) + (List Articles, ulong Count, Error Error) result = + req.AllAtricles() ? + await GetAllArticles(req.Limit.Value, req.Offset.Value) + : req.ExistTagOnly() ? + await GetArticlesByTag(req) + : (null, 0, Error.None); + + if (result.Error.Exist()) { return (null, result.Error); } @@ -94,5 +105,21 @@ public GetArticlesHandler(IClusterClient c, IMediator m) return (null, new Error("7f9cef3e-ec24-45d9-b59d-f188ed1c6e5b", ex.Message)); } } + + private async Task<(List Articles, ulong Count, Error Error)> + GetAllArticles(int limit, int offset) + { + var grains = _client.GetGrain(0); + var result = await grains.GetHomeGuestArticles(limit, offset); + return result; + } + + private async Task<(List Articles, ulong Count, Error Error)> + GetArticlesByTag(GetArticlesInput req) + { + var grains = _client.GetGrain(req.Tag); + var result = await grains.GetArticlesByTag(req.Limit.Value, req.Offset.Value); + return result; + } } } diff --git a/src/Contracts/Articles/ITagArticlesGrain.cs b/src/Contracts/Articles/ITagArticlesGrain.cs index 8813f49..0a1337e 100644 --- a/src/Contracts/Articles/ITagArticlesGrain.cs +++ b/src/Contracts/Articles/ITagArticlesGrain.cs @@ -7,6 +7,6 @@ public interface ITagArticlesGrain : IGrainWithStringKey { public Task<(List Articles, ulong Count, Error Error)> - GetArticlesByTag(string tag, int limit, int offset); + GetArticlesByTag(int limit, int offset); } } diff --git a/src/Grains/Articles/ArticlesGrain.cs b/src/Grains/Articles/ArticlesGrain.cs index 220c9c2..51e879d 100644 --- a/src/Grains/Articles/ArticlesGrain.cs +++ b/src/Grains/Articles/ArticlesGrain.cs @@ -14,7 +14,7 @@ [StatelessWorker] [Reentrant] - public class ArticlesGrain : Grain, IArticlesGrain + public class ArticlesGrain : BaseArticleGrain, IArticlesGrain { private const string Query = @" @@ -28,20 +28,15 @@ LIMIT @limit private const string LimitParam = "@limit"; private const string OffsetParam = "@offset"; - private readonly IGrainFactory _factory; - public ArticlesGrain(IGrainFactory f) - { - _factory = f; - } + public ArticlesGrain(IGrainFactory f) : base(f) { } - #region Get Home Guest Articles public async Task<(List Articles, ulong Count, Error Error)> GetHomeGuestArticles(int limit, int offset) { try { var articlesAndAuthors = await GetArticlesId(limit, offset); - var cleanArticles = await GetArticlesData(_factory, articlesAndAuthors); + var cleanArticles = await GetArticlesData(articlesAndAuthors); var allArticlesCounter = _factory.GetGrain(nameof(IArticleGrain)); var count = await allArticlesCounter.Get(); return (cleanArticles, count, Error.None); @@ -71,37 +66,5 @@ public ArticlesGrain(IGrainFactory f) } return idAuthor; } - - public static async Task> - GetArticlesData(IGrainFactory _factory, List<(long, string)> idAuthors) - { - - var articleTasks = new List>(idAuthors.Count); - var authorTasks = new List>(idAuthors.Count); - var authorSet = new HashSet(); - foreach (var each in idAuthors) - { - var articleId = each.Item1; - var authorId = each.Item2; - var articleGrain = _factory.GetGrain(articleId, authorId); - articleTasks.Add(articleGrain.GetArticle()); - if (!authorSet.Contains(authorId)) - { - authorSet.Add(authorId); - var userGrain = _factory.GetGrain(authorId); - authorTasks.Add(userGrain.Get()); - } - } - - var articles = (await Task.WhenAll(articleTasks)).ToList(); - var authors = (await Task.WhenAll(authorTasks)).ToDictionary(x => x.User.Username, y => y.User); - - return articles.Where(x => !x.error.Exist()) - .Select(x => new ArticleUserPair(x.article, authors[x.article.Author])) - .ToList(); - } - - #endregion - } } diff --git a/src/Grains/Articles/BaseArticleGrain.cs b/src/Grains/Articles/BaseArticleGrain.cs new file mode 100644 index 0000000..08868db --- /dev/null +++ b/src/Grains/Articles/BaseArticleGrain.cs @@ -0,0 +1,46 @@ +namespace Grains.Articles +{ + using Contracts; + using Contracts.Articles; + using Contracts.Users; + using Orleans; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + + public class BaseArticleGrain : Grain + { + protected readonly IGrainFactory _factory; + public BaseArticleGrain(IGrainFactory f) + { + _factory = f; + } + + protected async Task> + GetArticlesData(List<(long ArticleId, string Author)> list) + { + + var articleTasks = new List>(list.Count); + var authorTasks = new List>(list.Count); + var authorSet = new HashSet(); + foreach (var each in list) + { + var articleGrain = _factory.GetGrain(each.ArticleId, each.Author); + articleTasks.Add(articleGrain.GetArticle()); + if (!authorSet.Contains(each.Author)) + { + authorSet.Add(each.Author); + var userGrain = _factory.GetGrain(each.Author); + authorTasks.Add(userGrain.Get()); + } + } + + var articles = (await Task.WhenAll(articleTasks)).ToList(); + var authors = (await Task.WhenAll(authorTasks)).ToDictionary(x => x.User.Username, y => y.User); + + return articles.Where(x => !x.error.Exist()) + .Select(x => new ArticleUserPair(x.article, authors[x.article.Author])) + .ToList(); + } + } +} diff --git a/src/Grains/Articles/TagArticlesGrain.cs b/src/Grains/Articles/TagArticlesGrain.cs index 5bc3d50..d238fe2 100644 --- a/src/Grains/Articles/TagArticlesGrain.cs +++ b/src/Grains/Articles/TagArticlesGrain.cs @@ -11,25 +11,22 @@ using System.Text; using System.Threading.Tasks; - public class TagArticlesGrain : Grain, ITagArticlesGrain + public class TagArticlesGrain : BaseArticleGrain, ITagArticlesGrain { - private readonly IGrainFactory _factory; - - public TagArticlesGrain(IGrainFactory f) => _factory = f; - + public TagArticlesGrain(IGrainFactory f) : base(f) { } public async Task<(List Articles, ulong Count, Error Error)> - GetArticlesByTag(string tag, int limit, int offset) + GetArticlesByTag(int limit, int offset) { - var tagGrain = _factory.GetGrain(tag); - (List<(long, string)> ArticleIds, Error Error) tags = + var tagGrain = _factory.GetGrain(this.GetPrimaryKeyString()); + (List<(long ArticleId, string Author)> ArticleIds, Error Error) tags = await tagGrain.GetArticles(); var latest = tags.ArticleIds.OrderByDescending(x => x) .Skip(offset) .Take(limit) .ToList(); - var result = await ArticlesGrain.GetArticlesData(_factory, latest); + var result = await GetArticlesData(latest); var count = Convert.ToUInt64(tags.ArticleIds.Count); return (result, count, Error.None); }