Skip to content

Commit

Permalink
article by tag's done
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
riza_ramadan committed Jan 12, 2021
1 parent d43d379 commit 6b5d51f
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 65 deletions.
57 changes: 42 additions & 15 deletions src/Conduit/Features/Articles/GetArticles.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<GetArticlesInput,
Expand All @@ -50,31 +61,31 @@ public class GetArticlesHandler : IRequestHandler<GetArticlesInput,
FavoritesCount = x.Article.FavoritesCount,
Author = new ArticleAuthor
{
Username = x.User.Username,
Bio = x.User.Bio,
Image = x.User.Image
Username = x.User.Username,
Bio = x.User.Bio,
Image = x.User.Image
}
};
return output;
};

private readonly IClusterClient _client;
private readonly IMediator _mediator;

public GetArticlesHandler(IClusterClient c, IMediator m)
{
_client = c;
_mediator = m;
}
public GetArticlesHandler(IClusterClient c) => _client = c;

public async Task<(GetArticlesOutput Output, Error Error)>
Handle(GetArticlesInput req, CancellationToken ct)
{
try
{
var articlesGrain = _client.GetGrain<IArticlesGrain>(0);
var result = await articlesGrain.GetHomeGuestArticles(req.Limit.Value, req.Offset.Value);
if (result.Error.Exist())
(List<ArticleUserPair> 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);
}
Expand All @@ -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<ArticleUserPair> Articles, ulong Count, Error Error)>
GetAllArticles(int limit, int offset)
{
var grains = _client.GetGrain<IArticlesGrain>(0);
var result = await grains.GetHomeGuestArticles(limit, offset);
return result;
}

private async Task<(List<ArticleUserPair> Articles, ulong Count, Error Error)>
GetArticlesByTag(GetArticlesInput req)
{
var grains = _client.GetGrain<ITagArticlesGrain>(req.Tag);
var result = await grains.GetArticlesByTag(req.Limit.Value, req.Offset.Value);
return result;
}
}
}
2 changes: 1 addition & 1 deletion src/Contracts/Articles/ITagArticlesGrain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
public interface ITagArticlesGrain : IGrainWithStringKey
{
public Task<(List<ArticleUserPair> Articles, ulong Count, Error Error)>
GetArticlesByTag(string tag, int limit, int offset);
GetArticlesByTag(int limit, int offset);
}
}
43 changes: 3 additions & 40 deletions src/Grains/Articles/ArticlesGrain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

[StatelessWorker]
[Reentrant]
public class ArticlesGrain : Grain, IArticlesGrain
public class ArticlesGrain : BaseArticleGrain, IArticlesGrain
{
private const string Query =
@"
Expand All @@ -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<ArticleUserPair> 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<ICounterGrain>(nameof(IArticleGrain));
var count = await allArticlesCounter.Get();
return (cleanArticles, count, Error.None);
Expand Down Expand Up @@ -71,37 +66,5 @@ public ArticlesGrain(IGrainFactory f)
}
return idAuthor;
}

public static async Task<List<ArticleUserPair>>
GetArticlesData(IGrainFactory _factory, List<(long, string)> idAuthors)
{

var articleTasks = new List<Task<(Article article, Error error)>>(idAuthors.Count);
var authorTasks = new List<Task<(User User, Error Error)>>(idAuthors.Count);
var authorSet = new HashSet<string>();
foreach (var each in idAuthors)
{
var articleId = each.Item1;
var authorId = each.Item2;
var articleGrain = _factory.GetGrain<IArticleGrain>(articleId, authorId);
articleTasks.Add(articleGrain.GetArticle());
if (!authorSet.Contains(authorId))
{
authorSet.Add(authorId);
var userGrain = _factory.GetGrain<IUserGrain>(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

}
}
46 changes: 46 additions & 0 deletions src/Grains/Articles/BaseArticleGrain.cs
Original file line number Diff line number Diff line change
@@ -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<List<ArticleUserPair>>
GetArticlesData(List<(long ArticleId, string Author)> list)
{

var articleTasks = new List<Task<(Article article, Error error)>>(list.Count);
var authorTasks = new List<Task<(User User, Error Error)>>(list.Count);
var authorSet = new HashSet<string>();
foreach (var each in list)
{
var articleGrain = _factory.GetGrain<IArticleGrain>(each.ArticleId, each.Author);
articleTasks.Add(articleGrain.GetArticle());
if (!authorSet.Contains(each.Author))
{
authorSet.Add(each.Author);
var userGrain = _factory.GetGrain<IUserGrain>(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();
}
}
}
15 changes: 6 additions & 9 deletions src/Grains/Articles/TagArticlesGrain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<ArticleUserPair> Articles, ulong Count, Error Error)>
GetArticlesByTag(string tag, int limit, int offset)
GetArticlesByTag(int limit, int offset)
{
var tagGrain = _factory.GetGrain<ITagGrain>(tag);
(List<(long, string)> ArticleIds, Error Error) tags =
var tagGrain = _factory.GetGrain<ITagGrain>(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);
}
Expand Down

0 comments on commit 6b5d51f

Please sign in to comment.