diff --git a/Backend.Tests/Mocks/WordRepositoryMock.cs b/Backend.Tests/Mocks/WordRepositoryMock.cs index 11936493ac..56526460fa 100644 --- a/Backend.Tests/Mocks/WordRepositoryMock.cs +++ b/Backend.Tests/Mocks/WordRepositoryMock.cs @@ -163,6 +163,23 @@ public Task Add(Word word) return Task.FromResult(word); } + public Task CreateAndDeleteFrontier(Word newWord, string oldWordId) + { + newWord.Id = Guid.NewGuid().ToString(); + _words.Add(newWord.Clone()); + _frontier.Add(newWord.Clone()); + _frontier.RemoveAll(w => w.ProjectId == newWord.ProjectId && w.Id == oldWordId); + return Task.FromResult(newWord.Clone()); + } + + public Task AddAndDeleteFrontier(Word deletedWord, string wordId) + { + deletedWord.Id = Guid.NewGuid().ToString(); + _words.Add(deletedWord.Clone()); + _frontier.RemoveAll(w => w.ProjectId == deletedWord.ProjectId && w.Id == wordId); + return Task.FromResult(deletedWord.Clone()); + } + public Task CountFrontierWordsWithDomain(string projectId, string domainId) { var count = _frontier.Count( diff --git a/Backend/Interfaces/IWordRepository.cs b/Backend/Interfaces/IWordRepository.cs index 1aabed7bbd..3ee2e78e9b 100644 --- a/Backend/Interfaces/IWordRepository.cs +++ b/Backend/Interfaces/IWordRepository.cs @@ -12,6 +12,8 @@ public interface IWordRepository Task Create(Word word); Task> Create(List words); Task Add(Word word); + Task CreateAndDeleteFrontier(Word newWord, string oldWordId); + Task AddAndDeleteFrontier(Word deletedWord, string wordId); Task DeleteAllWords(string projectId); Task DeleteAllFrontierWords(string projectId); Task HasWords(string projectId); diff --git a/Backend/Repositories/WordRepository.cs b/Backend/Repositories/WordRepository.cs index 1492677079..60d204c124 100644 --- a/Backend/Repositories/WordRepository.cs +++ b/Backend/Repositories/WordRepository.cs @@ -190,6 +190,45 @@ public async Task Add(Word word) return word; } + /// + /// Adds a new to WordsCollection and Frontier, and removes the old word from Frontier. + /// + /// + /// If the Created or Modified time fields are blank, they will be automatically calculated using the current + /// time. This allows services to set or clear the values before creation to control these fields. + /// + /// The new word created. + public async Task CreateAndDeleteFrontier(Word newWord, string oldWordId) + { + using var activity = OtelService.StartActivityWithTag( + otelTagName, "creating word in WordsCollection and Frontier, deleting old word from Frontier"); + + PopulateBlankWordTimes(newWord); + await _words.InsertOneAsync(newWord); + await _frontier.InsertOneAsync(newWord); + await _frontier.FindOneAndDeleteAsync(GetProjectWordFilter(newWord.ProjectId, oldWordId)); + return newWord; + } + + /// + /// Adds a only to the WordsCollection and removes a word from the Frontier. + /// + /// + /// If the Created or Modified time fields are blank, they will be automatically calculated using the current + /// time. This allows services to set or clear the values before creation to control these fields. + /// + /// The word added. + public async Task AddAndDeleteFrontier(Word deletedWord, string wordId) + { + using var activity = OtelService.StartActivityWithTag( + otelTagName, "adding word to WordsCollection, deleting word from Frontier"); + + PopulateBlankWordTimes(deletedWord); + await _words.InsertOneAsync(deletedWord); + await _frontier.FindOneAndDeleteAsync(GetProjectWordFilter(deletedWord.ProjectId, wordId)); + return deletedWord; + } + /// Checks if Words collection for specified has any words. public async Task HasWords(string projectId) { diff --git a/Backend/Services/WordService.cs b/Backend/Services/WordService.cs index 5d55909e29..d8e23e797d 100644 --- a/Backend/Services/WordService.cs +++ b/Backend/Services/WordService.cs @@ -47,13 +47,6 @@ public async Task> Create(string userId, List words) return await _wordRepo.Create(words.Select(w => PrepEditedData(userId, w)).ToList()); } - /// Adds a new word with updated edited data. - /// The added word - private async Task Add(string userId, Word word) - { - return await _wordRepo.Add(PrepEditedData(userId, word)); - } - /// Removes audio with specified fileName from a Frontier word /// Updated word, or null if not found public async Task DeleteAudio(string projectId, string userId, string wordId, string fileName) @@ -85,10 +78,7 @@ private async Task Add(string userId, Word word) word.Accessibility = Status.Deleted; word.History.Add(wordId); - var deletedWord = await Add(userId, word); - - // Don't remove the Frontier word until the copy is successfully stored as deleted. - await _wordRepo.DeleteFrontier(projectId, wordId); + var deletedWord = await _wordRepo.AddAndDeleteFrontier(PrepEditedData(userId, word), wordId); return deletedWord.Id; } @@ -156,12 +146,7 @@ public async Task RestoreFrontierWords(string projectId, List word // only keep UsingCitationForm true if the Vernacular hasn't changed. word.UsingCitationForm &= word.Vernacular == oldWord.Vernacular; - var newWord = await Create(userId, word); - - // Don't remove the old Frontier word until the new word is successfully created. - await _wordRepo.DeleteFrontier(word.ProjectId, oldWordId); - - return newWord; + return await _wordRepo.CreateAndDeleteFrontier(PrepEditedData(userId, word), oldWordId); } /// Checks if a word being added is a duplicate of a preexisting word.