Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Serval.sln
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{1DB5E6D1-1
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SIL.ServiceToolkit.Tests", "src\ServiceToolkit\test\SIL.ServiceToolkit.Tests\SIL.ServiceToolkit.Tests.csproj", "{C50ED15A-876D-42BF-980A-388E8C49C78D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Serval.IntegrationTests", "src\Serval\test\Serval.IntegrationTests\Serval.IntegrationTests.csproj", "{5FC2A081-9C4A-4761-BCE1-9753C942D597}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Serval.Machine.IntegrationTests", "src\Machine\test\Serval.Machine.IntegrationTests\Serval.Machine.IntegrationTests.csproj", "{D6C99413-E63C-40EE-8A25-1D3EE78EE5B0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -194,6 +198,14 @@ Global
{C50ED15A-876D-42BF-980A-388E8C49C78D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C50ED15A-876D-42BF-980A-388E8C49C78D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C50ED15A-876D-42BF-980A-388E8C49C78D}.Release|Any CPU.Build.0 = Release|Any CPU
{5FC2A081-9C4A-4761-BCE1-9753C942D597}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5FC2A081-9C4A-4761-BCE1-9753C942D597}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5FC2A081-9C4A-4761-BCE1-9753C942D597}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5FC2A081-9C4A-4761-BCE1-9753C942D597}.Release|Any CPU.Build.0 = Release|Any CPU
{D6C99413-E63C-40EE-8A25-1D3EE78EE5B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D6C99413-E63C-40EE-8A25-1D3EE78EE5B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D6C99413-E63C-40EE-8A25-1D3EE78EE5B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D6C99413-E63C-40EE-8A25-1D3EE78EE5B0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -232,6 +244,8 @@ Global
{5E3D2BC3-9A98-4106-A2BF-B1F3641DC6F5} = {3E753B99-7C31-42AC-B02E-012B802F58DB}
{1DB5E6D1-17A8-4FF2-B90A-C5DFBEF63126} = {EA69B41C-49EF-4017-A687-44B9DF37FF98}
{C50ED15A-876D-42BF-980A-388E8C49C78D} = {1DB5E6D1-17A8-4FF2-B90A-C5DFBEF63126}
{5FC2A081-9C4A-4761-BCE1-9753C942D597} = {3E753B99-7C31-42AC-B02E-012B802F58DB}
{D6C99413-E63C-40EE-8A25-1D3EE78EE5B0} = {40C225C2-1EEF-4D1D-9D14-1CBB86C8A1CB}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {9F18C25E-E140-43C3-B177-D562E1628370}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ public static IMongoDataAccessConfigurator AddRepository<T>(
this IMongoDataAccessConfigurator configurator,
string collectionName,
Action<BsonClassMap<T>>? mapSetup = null,
Func<IMongoCollection<T>, Task>? init = null
IReadOnlyList<Func<IMongoCollection<T>, Task>>? init = null
)
where T : IEntity
{
Expand All @@ -16,7 +16,27 @@ public static IMongoDataAccessConfigurator AddRepository<T>(
{
configurator.Services.Configure<MongoDataAccessOptions>(options =>
{
options.Initializers.Add(database => init(database.GetCollection<T>(collectionName)));
options.Initializers.Add(
async (serviceProvider, database) =>
{
using IServiceScope scope = serviceProvider.CreateScope();
var schemaVersions = scope.ServiceProvider.GetRequiredService<IRepository<SchemaVersion>>();
SchemaVersion? schemaVersion = await schemaVersions.GetAsync(s =>
s.Collection == collectionName
);
int currentVersion = schemaVersion?.Version ?? 0;
IMongoCollection<T> collection = database.GetCollection<T>(collectionName);
for (int i = currentVersion + 1; i <= init.Count; i++)
{
await init[i - 1](collection);
await schemaVersions.UpdateAsync(
s => s.Collection == collectionName,
u => u.Set(s => s.Version, i),
upsert: true
);
}
}
);
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,17 @@ Action<IMongoDataAccessConfigurator> configure
new ObjectRefConvention()
);

// Configure conventions for schema_versions
DataAccessClassMap.RegisterConventions(
"SIL.DataAccess.Models",
new StringIdStoredAsObjectIdConvention(),
new CamelCaseElementNameConvention(),
new EnumRepresentationConvention(BsonType.String),
new IgnoreExtraElementsConvention(true),
new IgnoreIfNullConvention(true),
new ObjectRefConvention()
);

services.Configure<MongoDataAccessOptions>(options => options.Url = new MongoUrl(connectionString));
services.TryAddTransient<SIL.DataAccess.IIdGenerator, ObjectIdGenerator>();
services.TryAddSingleton<IMongoClient>(sp =>
Expand All @@ -45,7 +56,23 @@ Action<IMongoDataAccessConfigurator> configure
services.TryAddScoped<IMongoDataAccessContext, MongoDataAccessContext>();
services.TryAddScoped<IDataAccessContext>(sp => sp.GetRequiredService<IMongoDataAccessContext>());
services.AddHostedService<MongoDataAccessInitializeService>();
configure(new MongoDataAccessConfigurator(services));
var configurator = new MongoDataAccessConfigurator(services);

// Configure the schema_versions repository
configurator.AddRepository<SchemaVersion>(
"schema_versions",
init:
[
c =>
c.Indexes.CreateOrUpdateAsync(
new CreateIndexModel<SchemaVersion>(
Builders<SchemaVersion>.IndexKeys.Ascending(p => p.Collection)
)
),
]
);

configure(configurator);
return services;
}
}
9 changes: 9 additions & 0 deletions src/DataAccess/src/SIL.DataAccess/Models/SchemaVersion.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace SIL.DataAccess.Models;

public class SchemaVersion : IEntity
{
public required string Id { get; set; }
public int Revision { get; set; }
public required string Collection { get; set; }
public int Version { get; set; }
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
namespace SIL.DataAccess;

public class MongoDataAccessInitializeService(IMongoDatabase database, IOptions<MongoDataAccessOptions> options)
: IHostedService
public class MongoDataAccessInitializeService(
IServiceProvider provider,
IMongoDatabase database,
IOptions<MongoDataAccessOptions> options
) : IHostedService
{
private readonly IMongoDatabase _database = database;
private readonly IOptions<MongoDataAccessOptions> _options = options;

public async Task StartAsync(CancellationToken cancellationToken)
{
foreach (Func<IMongoDatabase, Task> initializer in _options.Value.Initializers)
await initializer(_database).ConfigureAwait(false);
foreach (Func<IServiceProvider, IMongoDatabase, Task> initializer in options.Value.Initializers)
await initializer(provider, database).ConfigureAwait(false);
}

public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
public class MongoDataAccessOptions
{
public MongoUrl Url { get; set; } = new MongoUrl("mongodb://localhost:27017");
public IList<Func<IMongoDatabase, Task>> Initializers { get; } = new List<Func<IMongoDatabase, Task>>();
public IList<Func<IServiceProvider, IMongoDatabase, Task>> Initializers { get; } = [];
}
1 change: 1 addition & 0 deletions src/DataAccess/src/SIL.DataAccess/Usings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@
global using Newtonsoft.Json.Serialization;
global using Nito.AsyncEx;
global using SIL.DataAccess;
global using SIL.DataAccess.Models;
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.4">
<PackageReference Include="coverlet.collector" Version="8.0.1">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
<PackageReference Include="NSubstitute" Version="5.3.0" />
<PackageReference Include="NSubstitute.Analyzers.CSharp" Version="1.0.17">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="NUnit" Version="4.4.0" />
<PackageReference Include="NUnit" Version="4.5.1" />
<PackageReference Include="NUnit3TestAdapter" Version="6.1.0" />
<PackageReference Include="NUnit.Analyzers" Version="4.11.2">
<PackageReference Include="NUnit.Analyzers" Version="4.12.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,45 +215,54 @@ public static IMachineBuilder AddMongoDataAccess(this IMachineBuilder builder)
{
o.AddRepository<TranslationEngine>(
"translation_engines",
init: async c =>
{
await c.Indexes.CreateOrUpdateAsync(
new CreateIndexModel<TranslationEngine>(
Builders<TranslationEngine>.IndexKeys.Ascending(e => e.EngineId)
)
);
await c.Indexes.CreateOrUpdateAsync(
new CreateIndexModel<TranslationEngine>(
Builders<TranslationEngine>.IndexKeys.Ascending(e => e.CurrentBuild!.BuildJobRunner)
)
);
}
init:
[
c =>
c.Indexes.CreateOrUpdateAsync(
new CreateIndexModel<TranslationEngine>(
Builders<TranslationEngine>.IndexKeys.Ascending(e => e.EngineId)
)
),
c =>
c.Indexes.CreateOrUpdateAsync(
new CreateIndexModel<TranslationEngine>(
Builders<TranslationEngine>.IndexKeys.Ascending(e => e.CurrentBuild!.BuildJobRunner)
)
),
]
);
o.AddRepository<WordAlignmentEngine>(
"word_alignment_engines",
init: async c =>
{
await c.Indexes.CreateOrUpdateAsync(
new CreateIndexModel<WordAlignmentEngine>(
Builders<WordAlignmentEngine>.IndexKeys.Ascending(e => e.EngineId)
)
);
await c.Indexes.CreateOrUpdateAsync(
new CreateIndexModel<WordAlignmentEngine>(
Builders<WordAlignmentEngine>.IndexKeys.Ascending(e => e.CurrentBuild!.BuildJobRunner)
)
);
}
init:
[
c =>
c.Indexes.CreateOrUpdateAsync(
new CreateIndexModel<WordAlignmentEngine>(
Builders<WordAlignmentEngine>.IndexKeys.Ascending(e => e.EngineId)
)
),
c =>
c.Indexes.CreateOrUpdateAsync(
new CreateIndexModel<WordAlignmentEngine>(
Builders<WordAlignmentEngine>.IndexKeys.Ascending(e =>
e.CurrentBuild!.BuildJobRunner
)
)
),
]
);
o.AddRepository<RWLock>("locks");
o.AddRepository<TrainSegmentPair>(
"train_segment_pairs",
init: c =>
c.Indexes.CreateOrUpdateAsync(
new CreateIndexModel<TrainSegmentPair>(
Builders<TrainSegmentPair>.IndexKeys.Ascending(p => p.TranslationEngineRef)
)
)
init:
[
c =>
c.Indexes.CreateOrUpdateAsync(
new CreateIndexModel<TrainSegmentPair>(
Builders<TrainSegmentPair>.IndexKeys.Ascending(p => p.TranslationEngineRef)
)
),
]
);
}
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace Microsoft.Extensions.DependencyInjection;

internal class MachineBuilder(IServiceCollection services, IConfiguration configuration) : IMachineBuilder
public class MachineBuilder(IServiceCollection services, IConfiguration configuration) : IMachineBuilder
{
public IServiceCollection Services { get; } = services;
public IConfiguration Configuration { get; } = configuration;
Expand Down
4 changes: 0 additions & 4 deletions src/Machine/src/Serval.Machine.Shared/Usings.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
global using System.Collections.Concurrent;
global using System.Collections.Generic;
global using System.Collections.Immutable;
global using System.ComponentModel;
global using System.Data;
global using System.Diagnostics;
global using System.Formats.Tar;
global using System.Globalization;
Expand All @@ -24,7 +22,6 @@
global using Amazon.S3;
global using Amazon.S3.Model;
global using Bugsnag.AspNet.Core;
global using CommunityToolkit.HighPerformance;
global using Grpc.Core;
global using Grpc.Core.Interceptors;
global using Grpc.Net.Client.Configuration;
Expand All @@ -43,7 +40,6 @@
global using Microsoft.Extensions.Logging;
global using Microsoft.Extensions.Options;
global using MongoDB.Driver;
global using MongoDB.Driver.Linq;
global using Nito.AsyncEx;
global using Nito.AsyncEx.Synchronous;
global using Polly;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);CS1591;CS1573</NoWarn>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="coverlet.collector" Version="8.0.1">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
<PackageReference Include="NSubstitute" Version="5.3.0" />
<PackageReference Include="NSubstitute.Analyzers.CSharp" Version="1.0.17">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="NUnit" Version="4.5.1" />
<PackageReference Include="NUnit3TestAdapter" Version="6.1.0" />
<PackageReference Include="NUnit.Analyzers" Version="4.12.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\DataAccess\src\SIL.DataAccess\SIL.DataAccess.csproj" />
<ProjectReference Include="..\..\src\Serval.Machine.Shared\Serval.Machine.Shared.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
namespace Serval.Machine.IntegrationTests;

[TestFixture]
[Category("Integration")]
public class ServalMachineSharedTests
{
private TestEnvironment _env;

[SetUp]
public void SetUp()
{
_env = new TestEnvironment();
}

[Test]
public async Task InitializesRepositories()
{
// Setup
IMachineBuilder machineBuilder = new MachineBuilder(_env.Services, _env.Configuration);
machineBuilder.AddMongoDataAccess();

// SUT
await _env.InitializeDatabaseAsync();

// Verify schema versioning
SchemaVersion? schemaVersion = await _env.SchemaVersions!.GetAsync(s => s.Collection == "schema_versions");
Assert.That(schemaVersion!.Version, Is.EqualTo(1));
}

[TearDown]
public void TearDown()
{
_env.Dispose();
}
}
Loading
Loading