Skip to content

Commit

Permalink
feat: add endpoints to load aggregates globally and for a specific co…
Browse files Browse the repository at this point in the history
…untry within a year
  • Loading branch information
alsami committed Oct 23, 2020
1 parent a9aaa12 commit 8670d77
Show file tree
Hide file tree
Showing 39 changed files with 264 additions and 66 deletions.
2 changes: 0 additions & 2 deletions src/Covid19Api.Controllers/Covid19Api.Controllers.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@

<ItemGroup>
<ProjectReference Include="..\Covid19Api.Presentation\Covid19Api.Presentation.csproj" />
<ProjectReference Include="..\Covid19Api.Repositories\Covid19Api.Repositories.csproj" />
<ProjectReference Include="..\Covid19Api.Services\Covid19Api.Services.csproj" />
<ProjectReference Include="..\Covid19Api.UseCases.Abstractions\Covid19Api.UseCases.Abstractions.csproj" />
</ItemGroup>

Expand Down
4 changes: 2 additions & 2 deletions src/Covid19Api.Controllers/V1/CountryStatisticsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Covid19Api.Presentation.Response;
using Covid19Api.UseCases.Abstractions.Queries;
using Covid19Api.UseCases.Abstractions.Queries.CountryStatistics;
using MediatR;
using Microsoft.AspNetCore.Mvc;

Expand Down Expand Up @@ -33,6 +33,6 @@ public Task<CountryStatisticsDto> LoadLatestForCountryAsync(string country) =>

[HttpGet("{country}/history")]
public Task<IEnumerable<CountryStatisticsDto>> LoadHistoryForCountryAsync(string country) =>
this.mediator.Send(new LoadHistoricalStatisticsForCountryQuery(country));
this.mediator.Send(new LoadHistoricalCountryStatisticsForCountryQuery(country));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Covid19Api.Presentation.Response;
using Covid19Api.UseCases.Abstractions.Queries.CountryStatisticsAggregates;
using MediatR;
using Microsoft.AspNetCore.Mvc;

namespace Covid19Api.Controllers.V1
{
[ApiController]
[Route("api/v1/countries/{country}/aggregates")]
public class CountryStatisticsCountryAggregatesController : ControllerBase
{
[HttpGet("{year:int}")]
public Task<IEnumerable<CountryStatisticsAggregateDto>> LoadAggregatesForCountryInYearAsync(
[FromServices] IMediator mediator, string country, int year)
{
var query = new LoadCountryStatisticsAggregatesForCountryInYearQuery(country, year);
return mediator.Send(query);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Covid19Api.Presentation.Response;
using Covid19Api.UseCases.Abstractions.Queries.GlobalStatisticsAggregates;
using MediatR;
using Microsoft.AspNetCore.Mvc;

namespace Covid19Api.Controllers.V1
{
[ApiController]
[Route("api/v1/global/aggregates")]
public class GlobalStatisticsAggregatesController
{
[HttpGet("{year:int}")]
public Task<IEnumerable<GlobalStatisticsAggregateDto>> LoadForYearAsync([FromServices] IMediator mediator,
int year)
{
var query = new LoadGlobalStatisticsAggregatesForYearQuery(year);
return mediator.Send(query);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Covid19Api.Presentation.Response;
using Covid19Api.UseCases.Abstractions.Queries;
using Covid19Api.UseCases.Abstractions.Queries.GlobalStatistics;
using MediatR;
using Microsoft.AspNetCore.Mvc;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public static ContainerBuilder RegisterWorker(this ContainerBuilder builder)
builder.RegisterType<GlobalStatisticsAggregationWorker>()
.As<IHostedService>()
.InstancePerDependency();

builder.RegisterType<CountryStatisticsAggregateWorker>()
.As<IHostedService>()
.InstancePerDependency();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ protected DatabaseMigration(ILogger logger)
{
this.logger = logger;
}

public abstract int Number { get; }

protected abstract string Name { get; }

public async Task ExecuteUpdateAsync()
{
this.logger.LogInformation("Executing migration {number}-{migration}", this.Number, this.Name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using Covid19Api.Mongo.Migrator.Abstractions;
using Covid19Api.Mongo.Migrator.Configuration;
using Covid19Api.UseCases.Abstractions.Commands;
using Covid19Api.UseCases.Abstractions.Queries;
using Covid19Api.UseCases.Abstractions.Queries.GlobalStatisticsAggregates;
using MediatR;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
Expand All @@ -23,7 +23,7 @@ public GlobalAggregatesMigration(ILogger<GlobalAggregatesMigration> logger,
this.mediator = mediator;
this.options = options?.Value ?? throw new ArgumentNullException(nameof(options));
}

public override int Number => 0;
protected override string Name => nameof(GlobalAggregatesMigration);

Expand All @@ -36,16 +36,16 @@ protected override async Task ExecuteAsync()
{
if (next.Month > end.Month && next.Year >= end.Year)
break;

var query = new LoadGlobalStatisticsAggregate(next.Month, next.Year);
var aggregate = await this.mediator.Send(query);

if (aggregate is {})
{
next = next.AddMonths(1);
continue;
}

var command = new AggregateGlobalStatisticsCommand(next.Month, next.Year);
await this.mediator.Send(command);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
using Covid19Api.Mongo.Migrator.Abstractions;
using Covid19Api.Mongo.Migrator.Configuration;
using Covid19Api.UseCases.Abstractions.Commands;
using Covid19Api.UseCases.Abstractions.Queries;
using Covid19Api.UseCases.Abstractions.Queries.CountryStatistics;
using Covid19Api.UseCases.Abstractions.Queries.CountryStatisticsAggregates;
using MediatR;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
Expand All @@ -24,7 +25,7 @@ public CountryAggregatesMigration(ILogger<CountryAggregatesMigration> logger,
this.mediator = mediator;
this.options = options?.Value ?? throw new ArgumentNullException(nameof(options));
}

public override int Number => 1;
protected override string Name => nameof(CountryAggregatesMigration);

Expand All @@ -37,7 +38,7 @@ protected override async Task ExecuteAsync()
{
if (next.Month > end.Month && next.Year >= end.Year)
break;

var loadCountriesStatisticsQuery = new LoadLatestCountriesStatisticsQuery();
var countries = (await this.mediator.Send(loadCountriesStatisticsQuery))
.Select(country => country.Country).ToList();
Expand All @@ -59,7 +60,7 @@ protected override async Task ExecuteAsync()
await Task.Delay(100);
continue;
}

var command = new AggregateCountryStatisticsCommand(countries.ToArray(), next.Month, next.Year);
await this.mediator.Send(command);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,20 @@ protected override async Task ExecuteAsync()
{
await this.databaseContext.Database.CreateCollectionIfNotExistsAsync(CollectionNames
.CountryStatisticsAggregates);

var collection =
this.databaseContext.Database.GetCollection<CountryStatisticsAggregate>(CollectionNames
.CountryStatisticsAggregates);

var countryIndex = Builders<CountryStatisticsAggregate>
.IndexKeys
.Ascending(statistics => statistics.Country);

var countryIndexModel = new CreateIndexModel<CountryStatisticsAggregate>(countryIndex, new CreateIndexOptions
{
Name = $"{CollectionNames.CountryStatisticsAggregates}_country"
});
var countryIndexModel = new CreateIndexModel<CountryStatisticsAggregate>(countryIndex,
new CreateIndexOptions
{
Name = $"{CollectionNames.CountryStatisticsAggregates}_country"
});

await collection.Indexes.CreateOneAsync(countryIndexModel);

Expand All @@ -49,7 +50,7 @@ await this.databaseContext.Database.CreateCollectionIfNotExistsAsync(CollectionN
{
Name = $"{CollectionNames.CountryStatisticsAggregates}_month_descending"
});

await collection.Indexes.CreateOneAsync(monthIndexModel);

var yearIndex = Builders<CountryStatisticsAggregate>
Expand All @@ -60,7 +61,7 @@ await this.databaseContext.Database.CreateCollectionIfNotExistsAsync(CollectionN
{
Name = $"{CollectionNames.CountryStatisticsAggregates}_year_descending"
});

await collection.Indexes.CreateOneAsync(yearIndexModel);

var yearMonthIndex = Builders<CountryStatisticsAggregate>
Expand All @@ -72,9 +73,9 @@ await this.databaseContext.Database.CreateCollectionIfNotExistsAsync(CollectionN
{
Name = $"{CollectionNames.CountryStatisticsAggregates}_year_month",
});

await collection.Indexes.CreateOneAsync(yearMonthIndexModel);

var countryYearMonthIndex = Builders<CountryStatisticsAggregate>
.IndexKeys
.Combine(countryIndex, yearIndex, monthIndex);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Covid19Api.Domain;

Expand All @@ -8,5 +9,7 @@ public interface ICountryStatisticsAggregatesRepository
Task StoreAsync(CountryStatisticsAggregate countryStatisticsAggregate);

Task<CountryStatisticsAggregate?> FindAsync(string country, int month, int year);

Task<IList<CountryStatisticsAggregate>> FindForCountryInYearAsync(string country, int year);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public interface ICountryStatisticsRepository

Task<CountryStatistics?> FindInRangeAsync(string country, DateTime inclusiveStart,
DateTime exclusiveEnd);

Task StoreManyAsync(IEnumerable<CountryStatistics> countryStats);
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Covid19Api.Domain;

Expand All @@ -8,5 +9,7 @@ public interface IGlobalStatisticsAggregatesRepository
Task StoreAsync(GlobalStatisticsAggregate globalStatisticsAggregate);

Task<GlobalStatisticsAggregate?> FindAsync(int month, int year);

Task<IList<GlobalStatisticsAggregate>> FindInYearAsync(int year);
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Covid19Api.Domain;
using Covid19Api.Mongo;
Expand Down Expand Up @@ -48,6 +49,25 @@ public Task StoreAsync(CountryStatisticsAggregate countryStatisticsAggregate)
return await cursor.SingleOrDefaultAsync();
}

public async Task<IList<CountryStatisticsAggregate>> FindForCountryInYearAsync(string country, int year)
{
// ReSharper disable once SpecifyStringComparison
var countryFilter =
Builders<CountryStatisticsAggregate>.Filter.Where(statistics =>
statistics.Country.ToLower() == country.ToLower());

var yearFilter =
Builders<CountryStatisticsAggregate>.Filter.Where(statistics => statistics.Year == year);

var filter = countryFilter & yearFilter;

var collection = this.GetCollection();

var cursor = await collection.FindAsync(filter);

return await cursor.ToListAsync();
}

private IMongoCollection<CountryStatisticsAggregate> GetCollection()
=> this.context.Database.GetCollection<CountryStatisticsAggregate>(CollectionNames
.CountryStatisticsAggregates);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Covid19Api.Domain;
using Covid19Api.Mongo;
Expand Down Expand Up @@ -38,6 +39,15 @@ public Task StoreAsync(GlobalStatisticsAggregate globalStatisticsAggregate)
return await cursor.SingleOrDefaultAsync();
}

public async Task<IList<GlobalStatisticsAggregate>> FindInYearAsync(int year)
{
var collection = this.GetCollection();

var cursor = await collection.FindAsync(aggregate => aggregate.Year == year);

return await cursor.ToListAsync();
}

private IMongoCollection<GlobalStatisticsAggregate> GetCollection()
=> this.context.Database.GetCollection<GlobalStatisticsAggregate>(CollectionNames
.GlobalStatisticsAggregates);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ public CountryMetaDataLoaderDecorator(IDistributedCache distributedCache,
this.countryMetaDataLoader = countryMetaDataLoader;
this.compressionService = compressionService;
}


public void Dispose()
{
Mutex.Dispose();
Expand Down
4 changes: 2 additions & 2 deletions src/Covid19Api.Services/Loader/CountryMetaDataLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class CountryMetaDataLoader : ICountryMetaDataLoader
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};

private readonly ILogger<CountryMetaDataLoader> logger;
private readonly IHttpClientFactory httpClientFactory;

Expand All @@ -38,7 +38,7 @@ public async Task<CountryMetaData[]> LoadCountryMetaDataAsync()
{
var deserialized = await JsonSerializer.DeserializeAsync<CountryMetaData[]>(
await response.Content.ReadAsStreamAsync(), SerializerOptions);

return deserialized ?? Array.Empty<CountryMetaData>();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
using Covid19Api.UseCases.Abstractions.Models;
using MediatR;

namespace Covid19Api.UseCases.Abstractions.Queries
namespace Covid19Api.UseCases.Abstractions.Queries.CountryStatistics
{
public class LoadHistoricalCountriesStatisticsQuery : ICacheableRequest, IRequest<IEnumerable<CountryStatisticsDto>>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,20 @@
using Covid19Api.UseCases.Abstractions.Models;
using MediatR;

namespace Covid19Api.UseCases.Abstractions.Queries
namespace Covid19Api.UseCases.Abstractions.Queries.CountryStatistics
{
public class LoadHistoricalStatisticsForCountryQuery : ICacheableRequest,
public class LoadHistoricalCountryStatisticsForCountryQuery : ICacheableRequest,
IRequest<IEnumerable<CountryStatisticsDto>>
{
public LoadHistoricalStatisticsForCountryQuery(string country)
public LoadHistoricalCountryStatisticsForCountryQuery(string country)
{
this.Country = country;
}

public string Country { get; }

public CacheConfiguration GetCacheConfiguration() =>
new CacheConfiguration($"{nameof(LoadHistoricalStatisticsForCountryQuery)}_{Country}",
new CacheConfiguration($"{nameof(LoadHistoricalCountryStatisticsForCountryQuery)}_{this.Country}",
TimeSpan.FromMinutes(30));
}
}
Loading

0 comments on commit 8670d77

Please sign in to comment.