Skip to content

Commit e41617e

Browse files
committed
Tests for new table options.
1 parent bce3024 commit e41617e

File tree

6 files changed

+160
-35
lines changed

6 files changed

+160
-35
lines changed

PowerSync/PowerSync.Common/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# PowerSync.Common Changelog
22

3+
## 0.0.6-alpha.1
4+
- Add `trackPreviousValues` option on `TableOptions` which sets `CrudEntry.PreviousValues` to previous values on updates.
5+
- Add `trackMetadata` option on `TableOptions` which adds a `_metadata` column that can be used for updates. The configured metadata is available through `CrudEntry.Metadata`.
6+
- Add `ignoreEmptyUpdates` option on `TableOptions` which skips creating CRUD entries for updates that don't change any values.
7+
8+
39
## 0.0.5-alpha.1
410
- Using the latest (0.4.9) version of the core extension, it introduces support for the Rust Sync implementation and also makes it the default - users can still opt out and use the legacy C# sync implementation as option when calling `connect()`.
511

PowerSync/PowerSync.Common/DB/Crud/CrudEntry.cs

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -48,28 +48,6 @@ public class CrudEntryDataJSON
4848
public string? Metadata { get; set; }
4949
}
5050

51-
public class CrudEntryOutputJSON
52-
{
53-
[JsonProperty("op_id")]
54-
public int OpId { get; set; }
55-
56-
[JsonProperty("op")]
57-
public UpdateType Op { get; set; }
58-
59-
[JsonProperty("type")]
60-
public string Type { get; set; } = null!;
61-
62-
[JsonProperty("id")]
63-
public string Id { get; set; } = null!;
64-
65-
[JsonProperty("tx_id")]
66-
public long? TransactionId { get; set; }
67-
68-
[JsonProperty("data")]
69-
public Dictionary<string, object>? Data { get; set; }
70-
}
71-
72-
7351
public class CrudEntry(
7452
int clientId,
7553
UpdateType op,
@@ -84,6 +62,7 @@ public class CrudEntry(
8462
public int ClientId { get; private set; } = clientId;
8563
public string Id { get; private set; } = id;
8664
public UpdateType Op { get; private set; } = op;
65+
8766
public Dictionary<string, object>? OpData { get; private set; } = opData;
8867
public string Table { get; private set; } = table;
8968
public long? TransactionId { get; private set; } = transactionId;

PowerSync/PowerSync.Common/DB/Schema/Table.cs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ public class TableOptions(
99
bool? insertOnly = null,
1010
string? viewName = null,
1111
bool? trackMetadata = null,
12-
TrackPreviousOptions? trackPreviousOptions = null,
12+
TrackPreviousOptions? trackPreviousValues = null,
1313
bool? ignoreEmptyUpdates = null
1414
)
1515
{
@@ -25,18 +25,18 @@ public class TableOptions(
2525
/// Whether to add a hidden `_metadata` column that will be enabled for updates to attach custom
2626
/// information about writes that will be reported through [CrudEntry.metadata].
2727
/// </summary>
28-
public bool TrackMetadata { get; } = trackMetadata ?? false;
28+
public bool TrackMetadata { get; set; } = trackMetadata ?? false;
2929

3030
/// <summary>
3131
/// When set to a non-null value, track old values of columns
3232
/// </summary>
33-
public TrackPreviousOptions? TrackPreviousOptions { get; } = trackPreviousOptions ?? null;
33+
public TrackPreviousOptions? TrackPreviousValues { get; set; } = trackPreviousValues ?? null;
3434

3535
/// <summary>
3636
/// Whether an `UPDATE` statement that doesn't change any values should be ignored when creating
3737
/// CRUD entries.
3838
/// </summary>
39-
public bool IgnoreEmptyUpdates { get; } = ignoreEmptyUpdates ?? false;
39+
public bool IgnoreEmptyUpdates { get; set; } = ignoreEmptyUpdates ?? false;
4040
}
4141

4242
/// <summary>
@@ -53,8 +53,7 @@ public class TrackPreviousOptions
5353
public List<string>? Columns { get; set; }
5454

5555
/// <summary>
56-
/// Whether to only include old values when they were changed by an update, instead of always
57-
/// including all old values,
56+
/// When enabled, only include values that have actually been changed by an update.
5857
/// </summary>
5958
[JsonProperty("onlyWhenChanged")]
6059
public bool? OnlyWhenChanged { get; set; }
@@ -117,7 +116,7 @@ public void Validate()
117116
throw new Exception("Can't include metadata for local-only tables.");
118117
}
119118

120-
if (Options.TrackPreviousOptions != null && Options.LocalOnly)
119+
if (Options.TrackPreviousValues != null && Options.LocalOnly)
121120
{
122121
throw new Exception("Can't include old values for local-only tables.");
123122
}
@@ -161,7 +160,7 @@ public void Validate()
161160

162161
public string ToJSON(string Name = "")
163162
{
164-
var trackPrevious = Options.TrackPreviousOptions;
163+
var trackPrevious = Options.TrackPreviousValues;
165164

166165
var jsonObject = new
167166
{

PowerSync/PowerSync.Maui/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# PowerSync.Maui Changelog
22

3+
## 0.0.4-alpha.1
4+
- Upstream PowerSync.Common version bump
5+
36
## 0.0.3-alpha.1
47
- Upstream PowerSync.Common version bump
58
- Using the latest (0.4.9) version of the core extension, it introduces support for the Rust Sync implementation and also makes it the default - users can still opt out and use the legacy C# sync implementation as option when calling `connect()`.

Tests/PowerSync/PowerSync.Common.Tests/Client/Sync/CRUDTests.cs

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ namespace PowerSync.Common.Tests.Client.Sync;
99
using PowerSync.Common.DB.Schema;
1010
using PowerSync.Common.Tests.Utils;
1111

12+
13+
/// <summary>
14+
/// dotnet test -v n --framework net8.0 --filter "CRUDTests"
15+
/// </summary>
1216
public class CRUDTests : IAsyncLifetime
1317
{
1418
private PowerSyncDatabase db = default!;
@@ -32,6 +36,127 @@ public async Task DisposeAsync()
3236
DatabaseUtils.CleanDb(dbName);
3337
}
3438

39+
private async Task ResetDB(PowerSyncDatabase db)
40+
{
41+
await db.DisconnectAndClear();
42+
DatabaseUtils.CleanDb(db.Database.Name);
43+
}
44+
45+
[Fact]
46+
public async Task IncludeMetadataTest()
47+
{
48+
var db = new PowerSyncDatabase(new PowerSyncDatabaseOptions
49+
{
50+
Database = new SQLOpenOptions { DbFilename = "IncludeMetadataTest.db" },
51+
Schema = TestSchema.GetSchemaWithCustomAssetOptions(new TableOptions
52+
{
53+
TrackMetadata = true
54+
}),
55+
});
56+
await ResetDB(db);
57+
58+
await db.Execute("INSERT INTO assets (id, description, _metadata) VALUES(uuid(), 'xxxx', 'so meta');");
59+
60+
var batch = await db.GetNextCrudTransaction();
61+
Assert.Equal("so meta", batch?.Crud[0].Metadata);
62+
}
63+
64+
[Fact]
65+
public async Task IncludeOldValuesTest()
66+
{
67+
var db = new PowerSyncDatabase(new PowerSyncDatabaseOptions
68+
{
69+
Database = new SQLOpenOptions { DbFilename = "IncludeOldValuesTest.db" },
70+
Schema = TestSchema.GetSchemaWithCustomAssetOptions(new TableOptions
71+
{
72+
TrackPreviousValues = new TrackPreviousOptions()
73+
}),
74+
});
75+
await ResetDB(db);
76+
77+
await db.Execute("INSERT INTO assets (id, description) VALUES(?, ?);", ["a185b7e1-dffa-4a9a-888c-15c0f0cac4b3", "entry"]);
78+
await db.Execute("DELETE FROM ps_crud;");
79+
await db.Execute("UPDATE assets SET description = ?", ["new name"]);
80+
81+
var batch = await db.GetNextCrudTransaction();
82+
Assert.True(batch?.Crud[0].PreviousValues?.ContainsKey("description"));
83+
Assert.Equal("entry", batch?.Crud[0].PreviousValues?["description"]);
84+
}
85+
86+
[Fact]
87+
public async Task IncludeOldValuesWithColumnFilterTest()
88+
{
89+
var db = new PowerSyncDatabase(new PowerSyncDatabaseOptions
90+
{
91+
Database = new SQLOpenOptions { DbFilename = "IncludeOldValuesWithColumnFilterTest.db" },
92+
Schema = TestSchema.GetSchemaWithCustomAssetOptions(new TableOptions
93+
{
94+
TrackPreviousValues = new TrackPreviousOptions
95+
{
96+
Columns = new List<string> { "description" }
97+
}
98+
}),
99+
});
100+
await ResetDB(db);
101+
102+
await db.Execute("INSERT INTO assets (id, description, make) VALUES(?, ?, ?);", ["a185b7e1-dffa-4a9a-888c-15c0f0cac4b3", "entry", "make1"]);
103+
await db.Execute("DELETE FROM ps_crud;");
104+
await db.Execute("UPDATE assets SET description = ?, make = ?", ["new name", "make2"]);
105+
106+
var batch = await db.GetNextCrudTransaction();
107+
Assert.NotNull(batch?.Crud[0].PreviousValues);
108+
Assert.Equal("entry", batch?.Crud[0].PreviousValues?["description"]);
109+
Assert.False(batch?.Crud[0].PreviousValues!.ContainsKey("make"));
110+
}
111+
112+
113+
[Fact]
114+
public async Task IncludeOldValuesWhenChangedTest()
115+
{
116+
var db = new PowerSyncDatabase(new PowerSyncDatabaseOptions
117+
{
118+
Database = new SQLOpenOptions { DbFilename = "oldValuesDb" },
119+
Schema = TestSchema.GetSchemaWithCustomAssetOptions(new TableOptions
120+
{
121+
TrackPreviousValues = new TrackPreviousOptions
122+
{
123+
OnlyWhenChanged = true
124+
}
125+
}),
126+
});
127+
await ResetDB(db);
128+
129+
await db.Execute("INSERT INTO assets (id, description, make) VALUES(uuid(), ?, ?);", ["name", "make1"]);
130+
await db.Execute("DELETE FROM ps_crud;");
131+
await db.Execute("UPDATE assets SET description = ?", ["new name"]);
132+
133+
var batch = await db.GetNextCrudTransaction();
134+
Assert.Single(batch!.Crud);
135+
Assert.NotNull(batch.Crud[0].PreviousValues);
136+
Assert.Equal("name", batch.Crud[0].PreviousValues!["description"]);
137+
Assert.False(batch.Crud[0].PreviousValues!.ContainsKey("make"));
138+
}
139+
140+
[Fact]
141+
public async Task IgnoreEmptyUpdateTest()
142+
{
143+
var db = new PowerSyncDatabase(new PowerSyncDatabaseOptions
144+
{
145+
Database = new SQLOpenOptions { DbFilename = "IgnoreEmptyUpdateTest.db" },
146+
Schema = TestSchema.GetSchemaWithCustomAssetOptions(new TableOptions
147+
{
148+
IgnoreEmptyUpdates = true
149+
}),
150+
});
151+
await ResetDB(db);
152+
await db.Execute("INSERT INTO assets (id, description) VALUES(?, ?);", [testId, "name"]);
153+
await db.Execute("DELETE FROM ps_crud;");
154+
await db.Execute("UPDATE assets SET description = ?", ["name"]);
155+
156+
var batch = await db.GetNextCrudTransaction();
157+
Assert.Null(batch);
158+
}
159+
35160
[Fact]
36161
public async Task Insert_RecordCrudEntryTest()
37162
{

Tests/PowerSync/PowerSync.Common.Tests/TestSchema.cs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ namespace PowerSync.Common.Tests;
44

55
public class TestSchema
66
{
7-
public static readonly Table Assets = new Table(new Dictionary<string, ColumnType>
7+
public static readonly Dictionary<string, ColumnType> AssetsColumns = new Dictionary<string, ColumnType>
88
{
99
{ "created_at", ColumnType.TEXT },
1010
{ "make", ColumnType.TEXT },
@@ -14,10 +14,12 @@ public class TestSchema
1414
{ "user_id", ColumnType.TEXT },
1515
{ "customer_id", ColumnType.TEXT },
1616
{ "description", ColumnType.TEXT },
17-
}, new TableOptions
18-
{
19-
Indexes = new Dictionary<string, List<string>> { { "makemodel", new List<string> { "make", "model" } } }
20-
});
17+
};
18+
19+
public static readonly Table Assets = new Table(AssetsColumns, new TableOptions
20+
{
21+
Indexes = new Dictionary<string, List<string>> { { "makemodel", new List<string> { "make", "model" } } },
22+
});
2123

2224
public static readonly Table Customers = new Table(new Dictionary<string, ColumnType>
2325
{
@@ -30,4 +32,15 @@ public class TestSchema
3032
{ "assets", Assets },
3133
{ "customers", Customers }
3234
});
35+
36+
public static Schema GetSchemaWithCustomAssetOptions(TableOptions? assetOptions = null)
37+
{
38+
var customAssets = new Table(AssetsColumns, assetOptions);
39+
40+
return new Schema(new Dictionary<string, Table>
41+
{
42+
{ "assets", customAssets },
43+
// { "customers", Customers }
44+
});
45+
}
3346
}

0 commit comments

Comments
 (0)