Skip to content

Commit

Permalink
feat: build aggregates
Browse files Browse the repository at this point in the history
  • Loading branch information
alsami committed Oct 21, 2020
1 parent 4519be4 commit d65e7c9
Show file tree
Hide file tree
Showing 40 changed files with 741 additions and 22 deletions.
30 changes: 30 additions & 0 deletions Covid19Api.sln
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{EBCCA0C8-4
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Covid19Api.Tests", "test\Covid19Api.Tests\Covid19Api.Tests.csproj", "{663655F5-2BFE-4154-AF3F-BB8BF36C2165}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Covid19Api.Mongo.Migrator", "src\Covid19Api.Mongo.Migrator\Covid19Api.Mongo.Migrator.csproj", "{9C4F9DEA-77E9-42E7-8991-C5227AAC0119}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Covid19Api.AutoMapper", "src\Covid19Api.AutoMapper\Covid19Api.AutoMapper.csproj", "{2DEC9058-1FD3-457F-A0B2-DF053371DF34}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -258,6 +262,30 @@ Global
{663655F5-2BFE-4154-AF3F-BB8BF36C2165}.Release|x64.Build.0 = Release|Any CPU
{663655F5-2BFE-4154-AF3F-BB8BF36C2165}.Release|x86.ActiveCfg = Release|Any CPU
{663655F5-2BFE-4154-AF3F-BB8BF36C2165}.Release|x86.Build.0 = Release|Any CPU
{9C4F9DEA-77E9-42E7-8991-C5227AAC0119}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9C4F9DEA-77E9-42E7-8991-C5227AAC0119}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9C4F9DEA-77E9-42E7-8991-C5227AAC0119}.Debug|x64.ActiveCfg = Debug|Any CPU
{9C4F9DEA-77E9-42E7-8991-C5227AAC0119}.Debug|x64.Build.0 = Debug|Any CPU
{9C4F9DEA-77E9-42E7-8991-C5227AAC0119}.Debug|x86.ActiveCfg = Debug|Any CPU
{9C4F9DEA-77E9-42E7-8991-C5227AAC0119}.Debug|x86.Build.0 = Debug|Any CPU
{9C4F9DEA-77E9-42E7-8991-C5227AAC0119}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9C4F9DEA-77E9-42E7-8991-C5227AAC0119}.Release|Any CPU.Build.0 = Release|Any CPU
{9C4F9DEA-77E9-42E7-8991-C5227AAC0119}.Release|x64.ActiveCfg = Release|Any CPU
{9C4F9DEA-77E9-42E7-8991-C5227AAC0119}.Release|x64.Build.0 = Release|Any CPU
{9C4F9DEA-77E9-42E7-8991-C5227AAC0119}.Release|x86.ActiveCfg = Release|Any CPU
{9C4F9DEA-77E9-42E7-8991-C5227AAC0119}.Release|x86.Build.0 = Release|Any CPU
{2DEC9058-1FD3-457F-A0B2-DF053371DF34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2DEC9058-1FD3-457F-A0B2-DF053371DF34}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2DEC9058-1FD3-457F-A0B2-DF053371DF34}.Debug|x64.ActiveCfg = Debug|Any CPU
{2DEC9058-1FD3-457F-A0B2-DF053371DF34}.Debug|x64.Build.0 = Debug|Any CPU
{2DEC9058-1FD3-457F-A0B2-DF053371DF34}.Debug|x86.ActiveCfg = Debug|Any CPU
{2DEC9058-1FD3-457F-A0B2-DF053371DF34}.Debug|x86.Build.0 = Debug|Any CPU
{2DEC9058-1FD3-457F-A0B2-DF053371DF34}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2DEC9058-1FD3-457F-A0B2-DF053371DF34}.Release|Any CPU.Build.0 = Release|Any CPU
{2DEC9058-1FD3-457F-A0B2-DF053371DF34}.Release|x64.ActiveCfg = Release|Any CPU
{2DEC9058-1FD3-457F-A0B2-DF053371DF34}.Release|x64.Build.0 = Release|Any CPU
{2DEC9058-1FD3-457F-A0B2-DF053371DF34}.Release|x86.ActiveCfg = Release|Any CPU
{2DEC9058-1FD3-457F-A0B2-DF053371DF34}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{1A670B81-08F0-4F15-81AF-4DDD12E765D6} = {2A35F3E7-12D1-4F74-8867-F5882FB47009}
Expand All @@ -276,5 +304,7 @@ Global
{3FAF620F-B417-43EF-8540-B0DDBA932DC8} = {2A35F3E7-12D1-4F74-8867-F5882FB47009}
{CC6C9309-C452-4C12-9783-35B5298781AF} = {2A35F3E7-12D1-4F74-8867-F5882FB47009}
{663655F5-2BFE-4154-AF3F-BB8BF36C2165} = {EBCCA0C8-4218-490F-A131-E8DF265DC415}
{9C4F9DEA-77E9-42E7-8991-C5227AAC0119} = {2A35F3E7-12D1-4F74-8867-F5882FB47009}
{2DEC9058-1FD3-457F-A0B2-DF053371DF34} = {2A35F3E7-12D1-4F74-8867-F5882FB47009}
EndGlobalSection
EndGlobal
16 changes: 16 additions & 0 deletions src/Covid19Api.AutoMapper/Covid19Api.AutoMapper.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="AutoMapper" Version="10.1.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Covid19Api.Domain\Covid19Api.Domain.csproj" />
<ProjectReference Include="..\Covid19Api.Presentation\Covid19Api.Presentation.csproj" />
</ItemGroup>

</Project>
16 changes: 16 additions & 0 deletions src/Covid19Api.AutoMapper/GlobalStatisticsAggregateProfile.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using AutoMapper;
using Covid19Api.Domain;
using Covid19Api.Presentation.Response;

namespace Covid19Api.AutoMapper
{
public class GlobalStatisticsAggregateProfile : Profile
{
public GlobalStatisticsAggregateProfile()
{
this.CreateMap<GlobalStatisticsAggregate, GlobalStatisticsAggregateDto>()
.ConstructUsing(source => new GlobalStatisticsAggregateDto(source.Id, source.Total, source.Recovered,
source.Deaths, source.Month, source.Year));
}
}
}
1 change: 0 additions & 1 deletion src/Covid19Api.Domain/CountryStatistics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ public class CountryStatistics

public DateTime FetchedAt { get; private set; }


public CountryStatistics(string country, string? countryCode, int totalCases, int newCases, int totalDeaths,
int newDeaths,
int recoveredCases, int activeCases, int seriousCases, DateTime fetchedAt)
Expand Down
8 changes: 8 additions & 0 deletions src/Covid19Api.Domain/Enums/AggregateType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Covid19Api.Domain.Enums
{
public enum AggregateType
{
Month = 0,
Year = 1,
}
}
39 changes: 39 additions & 0 deletions src/Covid19Api.Domain/GlobalStatisticsAggregate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System;
using System.Security.Cryptography;
using System.Text;

namespace Covid19Api.Domain
{
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Local
// ReSharper disable UnusedAutoPropertyAccessor.Global
public class GlobalStatisticsAggregate
{
public GlobalStatisticsAggregate(int total, int recovered, int deaths, int month, int year)
{
this.Total = total;
this.Recovered = recovered;
this.Deaths = deaths;
this.Month = month;
this.Year = year;
this.Id = this.Generate();
}

public Guid Id { get; private set; }
public int Total { get; private set; }
public int Recovered { get; private set; }
public int Deaths { get; private set; }
public int Month { get; private set; }
public int Year { get; private set; }

private Guid Generate()
{
using var hasher = MD5.Create();

var unhashed = $"{nameof(GlobalStatisticsAggregate)}_{this.Month}.{this.Year}";

var hashed = hasher.ComputeHash(Encoding.UTF8.GetBytes(unhashed));

return new Guid(hashed);
}
}
}
10 changes: 9 additions & 1 deletion src/Covid19Api.IoC/Extensions/ContainerBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ public static ContainerBuilder RegisterRepositories(this ContainerBuilder builde
.As<IGlobalStatisticsRepository>()
.InstancePerLifetimeScope();

builder.RegisterType<GlobalStatisticsAggregatesRepository>()
.As<IGlobalStatisticsAggregatesRepository>()
.InstancePerLifetimeScope();

builder.RegisterType<CountryStatisticsRepository>()
.As<ICountryStatisticsRepository>()
.InstancePerLifetimeScope();
Expand All @@ -39,7 +43,7 @@ public static ContainerBuilder RegisterServices(this ContainerBuilder builder)
builder.RegisterType<BrotliCompressionService>()
.As<ICompressionService>()
.SingleInstance();

builder.RegisterType<CountryStatisticsLoader>()
.As<ICountryStatisticsLoader>()
.SingleInstance();
Expand Down Expand Up @@ -74,6 +78,10 @@ public static ContainerBuilder RegisterWorker(this ContainerBuilder builder)
.As<IHostedService>()
.InstancePerDependency();

builder.RegisterType<GlobalStatisticsAggregationWorker>()
.As<IHostedService>()
.InstancePerDependency();

return builder;
}
}
Expand Down
27 changes: 27 additions & 0 deletions src/Covid19Api.Mongo.Migrator/Abstractions/DatabaseMigration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;

namespace Covid19Api.Mongo.Migrator.Abstractions
{
public abstract class DatabaseMigration
{
private readonly ILogger logger;

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);
await ExecuteAsync();
this.logger.LogInformation("Executed migration {number}-{migration}", this.Number, this.Name);
}

protected abstract Task ExecuteAsync();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Covid19Api.Mongo.Migrator.Configuration
{
public class GlobalAggregatesStartConfiguration
{
public int Month { get; set; } = 9;

public int Year { get; set; } = 2020;
}
}
36 changes: 36 additions & 0 deletions src/Covid19Api.Mongo.Migrator/Covid19Api.Mongo.Migrator.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Covid19Api.AutoMapper\Covid19Api.AutoMapper.csproj" />
<ProjectReference Include="..\Covid19Api.IoC\Covid19Api.IoC.csproj" />
<ProjectReference Include="..\Covid19Api.UseCases\Covid19Api.UseCases.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="AutoMapper.Contrib.Autofac.DependencyInjection" Version="5.1.0" />
<PackageReference Include="MediatR.Extensions.Autofac.DependencyInjection" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0-rc.2.20475.5" />
<PackageReference Include="Serilog.Extensions.Hosting" Version="3.1.0" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.1.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
</ItemGroup>

<ItemGroup>
<Content Include="appsettings.json">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="Properties\launchSettings.json">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</Content>
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System;
using System.Threading.Tasks;
using Covid19Api.Mongo.Migrator.Abstractions;
using Covid19Api.Mongo.Migrator.Configuration;
using Covid19Api.UseCases.Abstractions.Commands;
using Covid19Api.UseCases.Abstractions.Queries;
using MediatR;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace Covid19Api.Mongo.Migrator.Migrations
{
public class GlobalAggregatesMigration : DatabaseMigration
{
private readonly GlobalAggregatesStartConfiguration options;
private readonly IMediator mediator;

// ReSharper disable once SuggestBaseTypeForParameter
public GlobalAggregatesMigration(ILogger<GlobalAggregatesMigration> logger,
IOptions<GlobalAggregatesStartConfiguration> options, IMediator mediator) : base(logger)
{
this.mediator = mediator;
this.options = options?.Value ?? throw new ArgumentNullException(nameof(options));
}

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

protected override async Task ExecuteAsync()
{
var next = new DateTime(this.options.Year, this.options.Month, 1, 0, 0, 0, DateTimeKind.Utc);
var end = DateTime.UtcNow.Date;

while (true)
{
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);

next = next.AddMonths(1);
}
}
}
}
70 changes: 70 additions & 0 deletions src/Covid19Api.Mongo.Migrator/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Autofac;
using Autofac.Extensions.DependencyInjection;
using AutoMapper.Contrib.Autofac.DependencyInjection;
using Covid19Api.AutoMapper;
using Covid19Api.IoC.Extensions;
using Covid19Api.Mongo.Migrator.Abstractions;
using Covid19Api.Mongo.Migrator.Configuration;
using Covid19Api.UseCases.Commands;
using MediatR.Extensions.Autofac.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog;

namespace Covid19Api.Mongo.Migrator
{
public static class Program
{
public static async Task Main(string[] args)
{
using var host = CreateHost(args);

await host.StartAsync();

var migrations = host.Services.GetServices<DatabaseMigration>();

foreach (var databaseMigration in migrations.OrderBy(migration => migration.Number))
await databaseMigration.ExecuteUpdateAsync();

await host.StopAsync();
}

private static IHost CreateHost(string[] args)
=> Host.CreateDefaultBuilder(args)
.UseContentRoot(AppContext.BaseDirectory)
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.UseSerilog(ConfigureLogger)
.ConfigureServices(ConfigureServices)
.ConfigureContainer<ContainerBuilder>(ConfigureContainer)
.Build();

private static void ConfigureServices(HostBuilderContext hostBuilderContext, IServiceCollection services)
{
services.AddOptions();
services.Configure<GlobalAggregatesStartConfiguration>(options =>
hostBuilderContext.Configuration.GetSection(nameof(GlobalAggregatesStartConfiguration)).Bind(options));
}

private static void ConfigureLogger(HostBuilderContext context, LoggerConfiguration loggerConfiguration)
{
loggerConfiguration.ReadFrom.Configuration(context.Configuration);
}

private static void ConfigureContainer(HostBuilderContext context, ContainerBuilder builder)
{
builder.RegisterAssemblyTypes(typeof(Program).Assembly)
.AssignableTo(typeof(DatabaseMigration))
.As<DatabaseMigration>()
.InstancePerLifetimeScope();

builder.RegisterRepositories(context.HostingEnvironment, context.Configuration)
.RegisterServices()
.RegisterMediatR(typeof(RefreshGlobalStatisticsCommandHandler).Assembly)
.RegisterAutoMapper(typeof(CountryStatsProfile).Assembly);
}
}
}
11 changes: 11 additions & 0 deletions src/Covid19Api.Mongo.Migrator/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"profiles": {
"Covid19Api.Mongo.Migrator": {
"commandName": "Project",
"environmentVariables": {
"DOTNET_ENVIRONMENT": "Development"
}
}
}
}
Loading

0 comments on commit d65e7c9

Please sign in to comment.