Skip to content

Commit f47bcf1

Browse files
authored
(#36) OfflineDbContext with operations queue. (#63)
- Adds an OfflineDbContext - Adds an OperationsQueue - When SaveChanges() is called, OperationsQueue is updated. - Optional bypass of the operations queue. - Full test coverage.
1 parent d0bbbed commit f47bcf1

File tree

16 files changed

+1955
-18
lines changed

16 files changed

+1955
-18
lines changed

src/CommunityToolkit.Datasync.Client/CommunityToolkit.Datasync.Client.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55

66
<ItemGroup>
77
<InternalsVisibleTo Include="CommunityToolkit.Datasync.Client.Test" />
8-
<InternalsVisibleTo Include="DynamicProxyGenAssembly2"/>
8+
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" />
99
</ItemGroup>
1010

1111
<ItemGroup>
1212
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.7" />
13+
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.7" />
1314
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
1415
<PackageReference Include="Microsoft.Azure.Core.Spatial" Version="1.1.0" />
1516
</ItemGroup>

src/CommunityToolkit.Datasync.Client/Exceptions/DatasyncException.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,32 @@ public DatasyncException(string? message) : base(message)
2626
public DatasyncException(string? message, Exception? innerException) : base(message, innerException)
2727
{
2828
}
29+
30+
/// <summary>
31+
/// A helper method to throw the <see cref="DatasyncException"/> if the value is null.
32+
/// </summary>
33+
/// <param name="value">The value to check.</param>
34+
/// <param name="message">The message for this exception.</param>
35+
/// <exception cref="DatasyncException">Thrown if <paramref name="value"/> is null.</exception>
36+
internal static void ThrowIfNull(object? value, string? message)
37+
{
38+
if (value is null)
39+
{
40+
throw new DatasyncException(message);
41+
}
42+
}
43+
44+
/// <summary>
45+
/// A helper method to throw the <see cref="DatasyncException"/> if the value is null or empty.
46+
/// </summary>
47+
/// <param name="value">The value to check.</param>
48+
/// <param name="message">The message for this exception.</param>
49+
/// <exception cref="DatasyncException">Thrown if <paramref name="value"/> is null or empty.</exception>
50+
internal static void ThrowIfNullOrEmpty(string? value, string? message)
51+
{
52+
if (string.IsNullOrEmpty(value))
53+
{
54+
throw new DatasyncException(message);
55+
}
56+
}
2957
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using Microsoft.EntityFrameworkCore.Metadata.Internal;
6+
7+
namespace CommunityToolkit.Datasync.Client.Offline;
8+
9+
/// <summary>
10+
/// The kind of operation represented by a <see cref="DatasyncOperation"/> entity.
11+
/// </summary>
12+
public enum OperationKind
13+
{
14+
/// <summary>The operation represents an addition to the entity set.</summary>
15+
Add,
16+
/// <summary>The operation represents a deletion from the entity set.</summary>
17+
Delete,
18+
/// <summary>The operation represents a replacement of the entity within the entity set.</summary>
19+
Replace
20+
}
21+
22+
/// <summary>
23+
/// The current state of the pending operation.
24+
/// </summary>
25+
public enum OperationState
26+
{
27+
/// <summary>The operation has not been completed yet.</summary>
28+
Pending,
29+
/// <summary>The operation has been completed successfully.</summary>
30+
Completed,
31+
/// <summary>The operation failed.</summary>
32+
Failed
33+
}
34+
35+
/// <summary>
36+
/// An entity representing a pending operation against an entity set.
37+
/// </summary>
38+
public class DatasyncOperation
39+
{
40+
/// <summary>
41+
/// A unique ID for the operation.
42+
/// </summary>
43+
public required string Id { get; set; }
44+
45+
/// <summary>
46+
/// The kind of operation that this entity represents.
47+
/// </summary>
48+
public required OperationKind Kind { get; set; }
49+
50+
/// <summary>
51+
/// The current state of the operation.
52+
/// </summary>
53+
public required OperationState State { get; set; }
54+
55+
/// <summary>
56+
/// The fully qualified name of the entity type.
57+
/// </summary>
58+
public required string EntityType { get; set; }
59+
60+
/// <summary>
61+
/// The globally unique ID of the entity.
62+
/// </summary>
63+
public required string ItemId { get; set; }
64+
65+
/// <summary>
66+
/// The JSON-encoded representation of the Item.
67+
/// </summary>
68+
public required string Item { get; set; }
69+
70+
/// <summary>
71+
/// The sequence number for the operation. This is incremented for each
72+
/// new operation to a different entity.
73+
/// </summary>
74+
public required long Sequence { get; set; }
75+
76+
/// <summary>
77+
/// The version number for the operation. This is incremented as multiple
78+
/// changes to the same entity are performed in between pushes.
79+
/// </summary>
80+
public required int Version { get; set; }
81+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
namespace CommunityToolkit.Datasync.Client.Offline;
6+
7+
/// <summary>
8+
/// An error occurred when updating the Datasync Operations Queue.
9+
/// </summary>
10+
public class DatasyncQueueException : DatasyncException
11+
{
12+
/// <summary>
13+
/// Creates a new <see cref="DatasyncQueueException"/> based on the original and updated operations.
14+
/// </summary>
15+
/// <param name="originalOperation"></param>
16+
/// <param name="updatedOperation"></param>
17+
public DatasyncQueueException(DatasyncOperation originalOperation, DatasyncOperation updatedOperation)
18+
: base("The operation could not be updated due to an invalid state change.")
19+
{
20+
OriginalOperation = originalOperation;
21+
UpdatedOperation = updatedOperation;
22+
}
23+
24+
/// <summary>
25+
/// The original operation definition.
26+
/// </summary>
27+
public DatasyncOperation OriginalOperation { get; }
28+
29+
/// <summary>
30+
/// The updated operation definition.
31+
/// </summary>
32+
public DatasyncOperation UpdatedOperation { get; }
33+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
namespace CommunityToolkit.Datasync.Client.Offline;
6+
7+
/// <summary>
8+
/// An attribute for signifying that the DbSet should not be synchronized with
9+
/// a remote datasync service.
10+
/// </summary>
11+
[AttributeUsage(AttributeTargets.Property)]
12+
public class DoNotSynchronizeAttribute : Attribute
13+
{
14+
/// <summary>
15+
/// Creates a new <see cref="DoNotSynchronizeAttribute"/> instance.
16+
/// </summary>
17+
public DoNotSynchronizeAttribute()
18+
{
19+
}
20+
}

0 commit comments

Comments
 (0)