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); }