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
Original file line number Diff line number Diff line change
Expand Up @@ -110,14 +110,14 @@
/// <summary>
/// Retrieves the existing operation that matches an operation for the provided entity.
/// </summary>
/// <param name="entity">The entity being processed.</param>

Check warning on line 113 in src/CommunityToolkit.Datasync.Client/Offline/OperationsQueue/OperationsQueueManager.cs

View workflow job for this annotation

GitHub Actions / build

XML comment has a param tag for 'entity', but there is no parameter by that name

Check warning on line 113 in src/CommunityToolkit.Datasync.Client/Offline/OperationsQueue/OperationsQueueManager.cs

View workflow job for this annotation

GitHub Actions / build

XML comment has a param tag for 'entity', but there is no parameter by that name
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to observe.</param>
/// <returns>The operation entity or null if one does not exist.</returns>
/// <exception cref="DatasyncException">Thrown if the entity ID of the provided entity is invalid.</exception>
internal async ValueTask<DatasyncOperation?> GetExistingOperationAsync(object entity, CancellationToken cancellationToken = default)
internal async ValueTask<DatasyncOperation?> GetExistingOperationAsync(EntityEntry entityEntry, CancellationToken cancellationToken = default)

Check warning on line 117 in src/CommunityToolkit.Datasync.Client/Offline/OperationsQueue/OperationsQueueManager.cs

View workflow job for this annotation

GitHub Actions / build

Parameter 'entityEntry' has no matching param tag in the XML comment for 'OperationsQueueManager.GetExistingOperationAsync(EntityEntry, CancellationToken)' (but other parameters do)

Check warning on line 117 in src/CommunityToolkit.Datasync.Client/Offline/OperationsQueue/OperationsQueueManager.cs

View workflow job for this annotation

GitHub Actions / build

Parameter 'entityEntry' has no matching param tag in the XML comment for 'OperationsQueueManager.GetExistingOperationAsync(EntityEntry, CancellationToken)' (but other parameters do)
{
Type entityType = entity.GetType();
EntityMetadata metadata = EntityResolver.GetEntityMetadata(entity, entityType);
Type entityType = entityEntry.Metadata.ClrType;
EntityMetadata metadata = EntityResolver.GetEntityMetadata(entityEntry.Entity, entityType);
if (!EntityResolver.EntityIdIsValid(metadata.Id))
{
throw new DatasyncException($"Entity ID for type {entityType.FullName} is invalid.");
Expand All @@ -143,7 +143,7 @@
/// <returns>The operation definition.</returns>
internal DatasyncOperation GetOperationForChangedEntity(EntityEntry entry)
{
Type entityType = entry.Entity.GetType();
Type entityType = entry.Metadata.ClrType;
EntityMetadata metadata = EntityResolver.GetEntityMetadata(entry.Entity, entityType);
if (!EntityResolver.EntityIdIsValid(metadata.Id))
{
Expand Down Expand Up @@ -432,7 +432,7 @@
foreach (EntityEntry entry in entitiesInScope)
{
DatasyncOperation newOperation = GetOperationForChangedEntity(entry);
DatasyncOperation? existingOperation = await GetExistingOperationAsync(entry.Entity, cancellationToken).ConfigureAwait(false);
DatasyncOperation? existingOperation = await GetExistingOperationAsync(entry, cancellationToken).ConfigureAwait(false);
if (existingOperation is null)
{
newOperation.Sequence = Interlocked.Increment(ref sequenceId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,22 @@ public abstract class BaseTest
/// </summary>
protected static TestDbContext CreateContext(Action<DbContextOptionsBuilder<TestDbContext>> configureOptions = null)
{
SqliteConnection connection = new("Data Source=:memory:");
connection.Open();
SqliteConnection connection = CreateAndOpenConnection();
DbContextOptionsBuilder<TestDbContext> optionsBuilder = new DbContextOptionsBuilder<TestDbContext>()
.UseSqlite(connection);
configureOptions?.Invoke(optionsBuilder);
TestDbContext context = new(optionsBuilder.Options) { Connection = connection };

// Ensure the database is created.
context.Database.EnsureCreated();
return context;
}

/// <summary>
/// Creates a version of the TestDbContext backed by the specified SQLite connection.
/// </summary>
protected static TestDbContext CreateContext(SqliteConnection connection, Action<DbContextOptionsBuilder<TestDbContext>> configureOptions = null)
{
DbContextOptionsBuilder<TestDbContext> optionsBuilder = new DbContextOptionsBuilder<TestDbContext>()
.UseSqlite(connection);
configureOptions?.Invoke(optionsBuilder);
Expand All @@ -37,6 +51,16 @@ protected static TestDbContext CreateContext(Action<DbContextOptionsBuilder<Test
return context;
}

/// <summary>
/// Creates and opens an in-memory SQLite database connection.
/// </summary>
protected static SqliteConnection CreateAndOpenConnection()
{
SqliteConnection connection = new("Data Source=:memory:");
connection.Open();
return connection;
}

/// <summary>
/// Creates a response message based on code and content.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using CommunityToolkit.Datasync.TestCommon.Databases;
using Microsoft.EntityFrameworkCore;
using System.Net;
using Microsoft.Data.Sqlite;
using TestData = CommunityToolkit.Datasync.TestCommon.TestData;

namespace CommunityToolkit.Datasync.Client.Test.Offline;
Expand Down Expand Up @@ -39,7 +40,7 @@
public async Task GetExistingOperationAsync_InvalidId_Throws()
{
ClientMovie movie = new() { Id = "###" };
Func<Task> act = async () => _ = await queueManager.GetExistingOperationAsync(movie);
Func<Task> act = async () => _ = await queueManager.GetExistingOperationAsync(context.Entry(movie));

Check warning on line 43 in tests/CommunityToolkit.Datasync.Client.Test/Offline/OperationsQueueManager_Tests.cs

View workflow job for this annotation

GitHub Actions / build

Add 'this' or 'Me' qualification (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0009)

Check warning on line 43 in tests/CommunityToolkit.Datasync.Client.Test/Offline/OperationsQueueManager_Tests.cs

View workflow job for this annotation

GitHub Actions / build

Add 'this' or 'Me' qualification (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0009)
await act.Should().ThrowAsync<DatasyncException>();
}
#endregion
Expand Down Expand Up @@ -482,5 +483,32 @@

llpContext.DatasyncOperationsQueue.Should().BeEmpty();
}

[Fact]
public async Task LLP_ModifyAfterInsertInNewContext_NoPush_ShouldUpdateOperationsQueue()
{
await using SqliteConnection connection = CreateAndOpenConnection();
string id = Guid.NewGuid().ToString("N");
await using (TestDbContext llpContext = CreateContext(connection, x => x.UseLazyLoadingProxies()))
{
ClientMovie clientMovie = new(TestData.Movies.MovieList[0].Title) { Id = id };
llpContext.Movies.Add(clientMovie);
llpContext.SaveChanges();
}

await using TestDbContext newLlpContext = CreateContext(connection, x => x.UseLazyLoadingProxies());

ClientMovie storedClientMovie = newLlpContext.Movies.First(m => m.Id == id);

// ensure that it is a lazy loading proxy and not exactly a ClientMovie
storedClientMovie.GetType().Should().NotBe(typeof(ClientMovie))
.And.Subject.Namespace.Should().Be("Castle.Proxies");

storedClientMovie.Title = TestData.Movies.MovieList[1].Title;
newLlpContext.SaveChanges();

newLlpContext.DatasyncOperationsQueue.Should().ContainSingle(op => op.ItemId == id)
.Which.EntityType.Should().NotContain("Castle.Proxies");
}
#endregion
}
Loading