Skip to content
2 changes: 1 addition & 1 deletion src/SIL.Harmony.Tests/Adapter/CustomObjectAdapterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,6 @@ await dataModel.AddChange(Guid.NewGuid(),
myClass2.MyNumber.Should().Be(123.45m);
myClass2.DeletedTime.Should().BeNull();

dataModel.QueryLatest<MyClass>().Should().NotBeEmpty();
dataModel.QueryLatest<MyClass>().ToBlockingEnumerable().Should().NotBeEmpty();
}
}
7 changes: 3 additions & 4 deletions src/SIL.Harmony.Tests/DataModelReferenceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
using SIL.Harmony.Changes;
using SIL.Harmony.Sample.Changes;
using SIL.Harmony.Sample.Models;
using SIL.Harmony.Tests;

namespace Tests;
namespace SIL.Harmony.Tests;

public class DataModelReferenceTests : DataModelTestBase
{
Expand Down Expand Up @@ -158,7 +157,7 @@ public async Task CanCreate2TagsWithTheSameNameOutOfOrder()
var commitA = await WriteNextChange(SetTag(Guid.NewGuid(), tagText));
//represents someone syncing in a tag with the same name
await WriteChangeBefore(commitA, SetTag(Guid.NewGuid(), tagText));
DataModel.QueryLatest<Tag>().Where(t => t.Text == tagText).Should().ContainSingle();
DataModel.QueryLatest<Tag>().ToBlockingEnumerable().Where(t => t.Text == tagText).Should().ContainSingle();
}

[Fact]
Expand All @@ -170,6 +169,6 @@ public async Task CanUpdateTagWithTheSameNameOutOfOrder()
var commitA = await WriteNextChange(SetTag(Guid.NewGuid(), tagText));
//represents someone syncing in a tag with the same name
await WriteNextChange(SetTag(renameTagId, tagText));
DataModel.QueryLatest<Tag>().Where(t => t.Text == tagText).Should().ContainSingle();
DataModel.QueryLatest<Tag>().ToBlockingEnumerable().Where(t => t.Text == tagText).Should().ContainSingle();
}
}
6 changes: 2 additions & 4 deletions src/SIL.Harmony.Tests/DataModelSimpleChanges.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
using SIL.Harmony;
using SIL.Harmony.Changes;
using SIL.Harmony.Db;
using SIL.Harmony.Sample.Changes;
using SIL.Harmony.Sample.Models;
using SIL.Harmony.Tests;
using Microsoft.EntityFrameworkCore;

namespace Tests;
namespace SIL.Harmony.Tests;

public class DataModelSimpleChanges : DataModelTestBase
{
Expand Down Expand Up @@ -79,7 +77,7 @@ public async Task WriteMultipleCommits()

await WriteNextChange(SetWord(Guid.NewGuid(), "change 3"));
DbContext.Snapshots.Should().HaveCount(3);
DataModel.QueryLatest<Word>().Should().HaveCount(3);
DataModel.QueryLatest<Word>().ToBlockingEnumerable().Should().HaveCount(3);
}

[Fact]
Expand Down
3 changes: 1 addition & 2 deletions src/SIL.Harmony.Tests/DataModelTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ public class DataModelTestBase : IAsyncLifetime
private readonly bool _performanceTest;
public readonly DataModel DataModel;
public readonly SampleDbContext DbContext;
internal readonly CrdtRepository CrdtRepository;
protected readonly MockTimeProvider MockTimeProvider = new();

public DataModelTestBase(bool saveToDisk = false, bool alwaysValidate = true,
Expand Down Expand Up @@ -47,7 +46,6 @@ public DataModelTestBase(SqliteConnection connection, bool alwaysValidate = true
DbContext.Database.OpenConnection();
DbContext.Database.EnsureCreated();
DataModel = _services.GetRequiredService<DataModel>();
CrdtRepository = _services.GetRequiredService<CrdtRepository>();
}

public DataModelTestBase ForkDatabase(bool alwaysValidate = true)
Expand Down Expand Up @@ -170,6 +168,7 @@ public virtual Task InitializeAsync()

public async Task DisposeAsync()
{

await _services.DisposeAsync();
}

Expand Down
2 changes: 1 addition & 1 deletion src/SIL.Harmony.Tests/PersistExtraDataTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public async Task CanPersistExtraData()
{
var entityId = Guid.NewGuid();
var commit = await _dataModelTestBase.WriteNextChange(new CreateExtraDataModelChange(entityId));
var extraDataModel = _dataModelTestBase.DataModel.QueryLatest<ExtraDataModel>().Should().ContainSingle().Subject;
var extraDataModel = _dataModelTestBase.DataModel.QueryLatest<ExtraDataModel>().ToBlockingEnumerable().Should().ContainSingle().Subject;
extraDataModel.Id.Should().Be(entityId);
extraDataModel.CommitId.Should().Be(commit.Id);
extraDataModel.DateTime.Should().Be(commit.HybridDateTime.DateTime);
Expand Down
3 changes: 2 additions & 1 deletion src/SIL.Harmony.Tests/RepositoryTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public RepositoryTests()
.AddCrdtDataSample(":memory:")
.BuildServiceProvider();

_repository = _services.GetRequiredService<CrdtRepository>();
_repository = _services.GetRequiredService<CrdtRepositoryFactory>().CreateRepositorySync();
Comment thread
hahn-kev marked this conversation as resolved.
_crdtDbContext = _services.GetRequiredService<SampleDbContext>();
}

Expand All @@ -34,6 +34,7 @@ public async Task InitializeAsync()

public async Task DisposeAsync()
{
await _repository.DisposeAsync();
await _services.DisposeAsync();
}

Expand Down
8 changes: 4 additions & 4 deletions src/SIL.Harmony.Tests/SnapshotTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,8 @@ await WriteNextChange(
TagWord(wordId, tagId),
]);

var word = await DataModel.QueryLatest<Word>().Include(w => w.Tags)
.Where(w => w.Id == wordId).FirstOrDefaultAsync();
var word = await DataModel.QueryLatest<Word>(q => q.Include(w => w.Tags)
.Where(w => w.Id == wordId)).FirstOrDefaultAsync();
word.Should().NotBeNull();
word.Tags.Should().BeEquivalentTo([new Tag { Id = tagId, Text = "tag-1" }]);
}
Expand All @@ -135,8 +135,8 @@ await WriteNextChange(
var tagCreation = await WriteNextChange(TagWord(wordId, tagId));
await WriteChangeBefore(tagCreation, TagWord(wordId, tagId));

var word = await DataModel.QueryLatest<Word>().Include(w => w.Tags)
.Where(w => w.Id == wordId).FirstOrDefaultAsync();
var word = await DataModel.QueryLatest<Word>(q=> q.Include(w => w.Tags)
.Where(w => w.Id == wordId)).FirstOrDefaultAsync();
word.Should().NotBeNull();
word.Tags.Should().BeEquivalentTo([new Tag { Id = tagId, Text = "tag-1" }]);
}
Expand Down
4 changes: 2 additions & 2 deletions src/SIL.Harmony.Tests/SyncTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ public async Task CanSync_AddDependentWithMultipleChanges()

await _client2.DataModel.SyncWith(_client1.DataModel);

_client2.DataModel.QueryLatest<Definition>().Should()
.BeEquivalentTo(_client1.DataModel.QueryLatest<Definition>());
_client2.DataModel.QueryLatest<Definition>().ToBlockingEnumerable().Should()
.BeEquivalentTo(_client1.DataModel.QueryLatest<Definition>().ToBlockingEnumerable());
}
}
35 changes: 26 additions & 9 deletions src/SIL.Harmony/CrdtKernel.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Text.Json;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
Expand All @@ -8,29 +9,42 @@ namespace SIL.Harmony;

public static class CrdtKernel
{
public static IServiceCollection AddCrdtDataDbFactory<TContext>(this IServiceCollection services,
Action<CrdtConfig> configureCrdt) where TContext : DbContext, ICrdtDbContext
{

services.AddCrdtDataCore(configureCrdt);
services.AddScoped<ICrdtDbContextFactory, CrdtDbContextFactory<TContext>>();
return services;
}

public static IServiceCollection AddCrdtData<TContext>(this IServiceCollection services,
Action<CrdtConfig> configureCrdt) where TContext: ICrdtDbContext
Action<CrdtConfig> configureCrdt) where TContext : DbContext, ICrdtDbContext
{
services.AddCrdtDataCore(configureCrdt);
services.AddScoped<ICrdtDbContextFactory, CrdtDbContextNoDisposeFactory<TContext>>();
return services;
}
public static IServiceCollection AddCrdtDataCore(this IServiceCollection services, Action<CrdtConfig> configureCrdt)
{
services.AddLogging();
services.AddOptions<CrdtConfig>().Configure(configureCrdt).PostConfigure(crdtConfig => crdtConfig.ObjectTypeListBuilder.Freeze());
services.AddOptions<CrdtConfig>().Configure(configureCrdt)
.PostConfigure(crdtConfig => crdtConfig.ObjectTypeListBuilder.Freeze());
services.AddSingleton(sp => sp.GetRequiredService<IOptions<CrdtConfig>>().Value.JsonSerializerOptions);
services.AddSingleton(TimeProvider.System);
services.AddScoped<IHybridDateTimeProvider>(NewTimeProvider);
//must use factory, otherwise one context will be created for this registration, and one for the application.
//we want to have one context per application
services.AddScoped<ICrdtDbContext>(p => p.GetRequiredService<TContext>());
services.AddScoped<CrdtRepository>();
services.AddScoped<CrdtRepositoryFactory>();
//must use factory method because DataModel constructor is internal
services.AddScoped<DataModel>(provider => new DataModel(
provider.GetRequiredService<CrdtRepository>(),
provider.GetRequiredService<CrdtRepositoryFactory>(),
provider.GetRequiredService<JsonSerializerOptions>(),
provider.GetRequiredService<IHybridDateTimeProvider>(),
provider.GetRequiredService<IOptions<CrdtConfig>>(),
provider.GetRequiredService<ILogger<DataModel>>()
));
//must use factory method because ResourceService constructor is internal
services.AddScoped<ResourceService>(provider => new ResourceService(
provider.GetRequiredService<CrdtRepository>(),
provider.GetRequiredService<CrdtRepositoryFactory>(),
provider.GetRequiredService<IOptions<CrdtConfig>>(),
provider.GetRequiredService<DataModel>(),
provider.GetRequiredService<ILogger<ResourceService>>()
Expand All @@ -43,8 +57,11 @@ public static HybridDateTimeProvider NewTimeProvider(IServiceProvider servicePro
//todo, if this causes issues getting the order correct, we can update the last date time after the db is created
//as long as it's before we get a date time from the provider
//todo use IMemoryCache to store the last date time, possibly based on the current project
var hybridDateTime = serviceProvider.GetRequiredService<CrdtRepository>().GetLatestDateTime();
using var repo = serviceProvider.GetRequiredService<CrdtRepositoryFactory>().CreateRepositorySync();
var hybridDateTime = repo.GetLatestDateTime();
hybridDateTime ??= HybridDateTimeProvider.DefaultLastDateTime;
return ActivatorUtilities.CreateInstance<HybridDateTimeProvider>(serviceProvider, hybridDateTime);
}
}


Loading
Loading