diff --git a/Core/Models/TagDatabase/TagDatabase.Events.cs b/Core/Models/TagDatabase/TagDatabase.Events.cs index debafb6..0facf7f 100644 --- a/Core/Models/TagDatabase/TagDatabase.Events.cs +++ b/Core/Models/TagDatabase/TagDatabase.Events.cs @@ -7,16 +7,14 @@ public partial class TagDatabase /// public event EventHandler InitialisationComplete = delegate { }; - public event EventHandler TagAdded = delegate { }; + public sealed record DatabaseEditResult(List Added, List Updated, List<(int id, string name)> Deleted); - public event EventHandler TagUpdated = delegate { }; + public event EventHandler? TagsWritten; public event EventHandler<(int id, string name)> TagDeleted = delegate { }; public event EventHandler> TagsAdded = delegate { }; - public event EventHandler> TagsUpdated = delegate { }; - private void OnInitialisationComplete(EventArgs e) { this.Logger.Debug("OnInitialised invoked!"); diff --git a/Core/Models/TagDatabase/TagDatabase.WriteMethods.cs b/Core/Models/TagDatabase/TagDatabase.WriteMethods.cs index 2c758dd..b4e0ad1 100644 --- a/Core/Models/TagDatabase/TagDatabase.WriteMethods.cs +++ b/Core/Models/TagDatabase/TagDatabase.WriteMethods.cs @@ -6,62 +6,6 @@ namespace TagHierarchyManager.Models; public partial class TagDatabase { - // DEPRECATED: move to WriteTagsToDatabase. - /// - /// Saves the tag object to the database. - /// - /// The tag object. - /// The SqliteTransaction to execute queries on, will make its own if null. - /// Thrown if the tag already existed in the database. - public async Task WriteTagToDatabase(Tag tag, SqliteTransaction? transaction = null) - { - this.CheckInitialisation(); - bool isTransactionOwner = transaction == null; - transaction ??= (SqliteTransaction)await this.currentConnection.BeginTransactionAsync().ConfigureAwait(false); - - // a database-associated tag will have an ID, and the program will know to edit it. - bool alreadyOnDatabase = tag.Id != 0; - - try - { - SqliteCommand addCommand = this.currentConnection.CreateCommand(); - addCommand.Transaction = transaction; - QueryProcessorHandler.ProcessTagSaveCommand(addCommand, tag); - - if (await this.SelectTagFromDatabase(tag.Name) is not null && !alreadyOnDatabase) - throw new ArgumentException(ErrorMessages.TagAlreadyExists(tag.Name)); - - tag.Id = Convert.ToInt32(await addCommand.ExecuteScalarAsync().ConfigureAwait(false), - CultureInfo.InvariantCulture); - - await this.SaveTagAliases(transaction, tag.Id, tag.Aliases).ConfigureAwait(false); - await this.SaveTagParents(transaction, tag.Id, tag.Parents, tag).ConfigureAwait(false); - - if (isTransactionOwner) await transaction.CommitAsync().ConfigureAwait(false); - - int index = this.Tags.FindIndex(t => t.Id == tag.Id); - if (index != -1) - { - this.Tags[index] = tag; - TagUpdated.Invoke(this, tag); - } - else - { - this.Tags.Add(tag); - TagAdded.Invoke(this, tag); - } - } - catch (SqliteException) - { - await transaction.RollbackAsync().ConfigureAwait(false); - throw; - } - finally - { - if (isTransactionOwner) await transaction.DisposeAsync().ConfigureAwait(false); - } - } - /// /// Saves all tag objects to the database. /// @@ -79,7 +23,6 @@ public partial class TagDatabase try { - // technically, this supports bulk tag updates as well, but i ain't doing that rn. foreach (var tag in tags) { bool alreadyOnDatabase = tag.Id != 0; @@ -112,15 +55,7 @@ public partial class TagDatabase if (isTransactionOwner) await transaction.CommitAsync().ConfigureAwait(false); - if (updatedTags.Count > 0) - { - this.TagsUpdated.Invoke(this, updatedTags); - } - - if (newlyAddedTags.Count > 0) - { - this.TagsAdded.Invoke(this, newlyAddedTags); - } + TagsWritten?.Invoke(this, new DatabaseEditResult(newlyAddedTags, updatedTags, [])); } catch (SqliteException) { diff --git a/Tests/TagDatabaseSaveTests.cs b/Tests/TagDatabaseSaveTests.cs index 6147f1a..4b8745f 100644 --- a/Tests/TagDatabaseSaveTests.cs +++ b/Tests/TagDatabaseSaveTests.cs @@ -26,8 +26,7 @@ public class TagDatabaseWriteTests : TestBase public async Task ClearDatabaseAndAddSampleData() { this.Database.ClearTags(); - await this.Database.WriteTagToDatabase(TestSampleTags.Ambient); - await this.Database.WriteTagToDatabase(TestSampleTags.Electronic); + await this.Database.WriteTagsToDatabase([TestSampleTags.Ambient, TestSampleTags.Electronic]); } /// @@ -43,7 +42,7 @@ public class TagDatabaseWriteTests : TestBase Name = "DELETE ME", IsTopLevel = true, }; - await this.Database.WriteTagToDatabase(deletedTag); + await this.Database.WriteTagsToDatabase([deletedTag]); // Act await this.Database.DeleteTag(deletedTag.Id); @@ -94,9 +93,7 @@ public class TagDatabaseWriteTests : TestBase TagBindings = ["genre"], Parents = ["Test parent tag 1"], }; - await this.Database.WriteTagToDatabase(firstParentTag); - await this.Database.WriteTagToDatabase(secondParentTag); - await this.Database.WriteTagToDatabase(childTag); + await this.Database.WriteTagsToDatabase([firstParentTag, secondParentTag, childTag]); int childTagId = childTag.Id; List expectedParents = [firstParentTag.Id, secondParentTag.Id]; @@ -115,7 +112,7 @@ public class TagDatabaseWriteTests : TestBase childTag.Parents.Add(addedParentName); childTag.Notes = newNotes; childTag.Aliases = newAliases; - await this.Database.WriteTagToDatabase(childTag); + await this.Database.WriteTagsToDatabase([childTag]); // Assert Tag? editedChildTag = await this.Database.SelectTagFromDatabase(childTagId); @@ -143,7 +140,7 @@ public class TagDatabaseWriteTests : TestBase // Act/Assert ArgumentException? ex = - Assert.ThrowsAsync(async () => await this.Database.WriteTagToDatabase(ambient)); + Assert.ThrowsAsync(async () => await this.Database.WriteTagsToDatabase([ambient])); Assert.That(ex!.Message, Does.EndWith("already exists in the database.")); } @@ -160,7 +157,7 @@ public class TagDatabaseWriteTests : TestBase bool tagValidated = inputTag.Validate(); // Act - await this.Database.WriteTagToDatabase(inputTag); + await this.Database.WriteTagsToDatabase([inputTag]); Tag? savedTag = await this.Database.SelectTagFromDatabase(inputTag.Name); // Assert @@ -193,7 +190,7 @@ public class TagDatabaseWriteTests : TestBase // Arrange HashSet eventExpectedTags = []; List testTags = [TestSampleTags.Ambient, TestSampleTags.Electronic, TestSampleTags.SpaceAmbient]; - this.Database.TagsAdded += (_, tags) => eventExpectedTags.UnionWith(tags); + this.Database.TagsWritten += (_, tags) => eventExpectedTags.UnionWith(tags.Added); this.Database.ClearTags(); // Act diff --git a/Tests/TagDatabaseSearchTests.cs b/Tests/TagDatabaseSearchTests.cs index cd4f3e6..8f7d72f 100644 --- a/Tests/TagDatabaseSearchTests.cs +++ b/Tests/TagDatabaseSearchTests.cs @@ -124,7 +124,7 @@ public class TagDatabaseSearchTests : TestBase Parents = ["Ambient", "Electronic"], Aliases = ["áéíóúçýỷủ"], }; - await this.Database.WriteTagToDatabase(normalisedTest); + await this.Database.WriteTagsToDatabase([normalisedTest]); // Act List tags = this.Database.SearchWithAliases(query, mode); diff --git a/Tests/TestBase.cs b/Tests/TestBase.cs index 52436fe..01f3109 100644 --- a/Tests/TestBase.cs +++ b/Tests/TestBase.cs @@ -10,11 +10,6 @@ namespace TagHierarchyManager.Tests; /// public abstract class TestBase { - /// - /// The expected version value in the database. - /// - public const int ExpectedVersion = 1; - /// /// The expected default tag binding key in the database. /// @@ -68,7 +63,7 @@ public abstract class TestBase List sampleTags = TestSampleTags.AllTags(); this.Database.ClearTags(); - foreach (Tag inputTag in sampleTags) await this.Database.WriteTagToDatabase(inputTag); + await this.Database.WriteTagsToDatabase(sampleTags); } // do not use in Test1_Init. That needs to be tested at a lower level. diff --git a/UI/TagDatabaseService.cs b/UI/TagDatabaseService.cs index 6a84469..a1ea3d2 100644 --- a/UI/TagDatabaseService.cs +++ b/UI/TagDatabaseService.cs @@ -145,12 +145,6 @@ public class TagDatabaseService : ObservableObject StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).ToList(); this.NotifyDatabasePropertiesChanged(); } - - public async Task WriteTagToDatabase(List tag) - { - if (this.Database is null) return; - await this.Database.WriteTagsToDatabase(tag); - } public async Task WriteTagsToDatabase(List tags) { @@ -197,9 +191,7 @@ public class TagDatabaseService : ObservableObject private void SubscribeToEvents() { if (this.Database is null) return; - this.Database.TagAdded += this.TagDatabase_OnTagAdded; - this.Database.TagsAdded += this.TagDatabase_OnTagsAdded; - this.Database.TagsUpdated += this.TagDatabase_OnTagsUpdated; + this.Database.TagsWritten += this.TagDatabase_OnTagsWritten; this.Database.TagDeleted += this.TagDatabase_OnTagDeleted; } @@ -212,10 +204,10 @@ public class TagDatabaseService : ObservableObject this.InitialisationComplete?.Invoke(this, e); } - private void TagDatabase_OnTagAdded(object? sender, Tag newTag) + private void TagDatabase_OnTagsWritten(object? sender, TagDatabase.DatabaseEditResult editResult) { - this.TagsWritten?.Invoke(this, new TagWriteResult(new List {newTag}, [], [])); - this.NotifyDatabasePropertiesChanged(); + var resultConverted = new TagWriteResult(editResult.Added, editResult.Updated, []); + this.TagsWritten?.Invoke(this, resultConverted); } private void TagDatabase_OnTagDeleted(object? sender, (int id, string name) deletedTag) @@ -224,24 +216,10 @@ public class TagDatabaseService : ObservableObject this.NotifyDatabasePropertiesChanged(); } - private void TagDatabase_OnTagsAdded(object? sender, List newTags) - { - this.TagsWritten?.Invoke(this, new TagWriteResult(newTags, [], [])); - this.NotifyDatabasePropertiesChanged(); - } - - private void TagDatabase_OnTagsUpdated(object? sender, List updatedTags) - { - this.TagsWritten?.Invoke(this, new TagWriteResult([], updatedTags, [])); - this.NotifyDatabasePropertiesChanged(); - } - private void UnsubscribeFromEvents() { if (this.Database is null) return; - this.Database.TagAdded -= this.TagDatabase_OnTagAdded; - this.Database.TagsAdded -= this.TagDatabase_OnTagsAdded; - this.Database.TagsUpdated -= this.TagDatabase_OnTagsUpdated; + this.Database.TagsWritten -= this.TagDatabase_OnTagsWritten; this.Database.TagDeleted -= this.TagDatabase_OnTagDeleted; } } \ No newline at end of file