diff --git a/Wino.Services/MailService.cs b/Wino.Services/MailService.cs index a543ff66..faf8d556 100644 --- a/Wino.Services/MailService.cs +++ b/Wino.Services/MailService.cs @@ -117,14 +117,9 @@ public class MailService : BaseDatabaseService, IMailService public async Task> GetMailsByFolderIdAsync(Guid folderId) { - var mails = await Connection.QueryAsync("SELECT * FROM MailCopy WHERE FolderId = ?", folderId); + var mails = await Connection.QueryAsync("SELECT * FROM MailCopy WHERE FolderId = ?", folderId).ConfigureAwait(false); - foreach (var mail in mails) - { - await LoadAssignedPropertiesAsync(mail).ConfigureAwait(false); - } - - return mails; + return await HydrateMailCopiesAsync(mails).ConfigureAwait(false); } public async Task HasAccountAnyDraftAsync(Guid accountId) @@ -141,14 +136,9 @@ public class MailService : BaseDatabaseService, IMailService public async Task> GetUnreadMailsByFolderIdAsync(Guid folderId) { - var unreadMails = await Connection.QueryAsync("SELECT * FROM MailCopy WHERE FolderId = ? AND IsRead = 0", folderId); + var unreadMails = await Connection.QueryAsync("SELECT * FROM MailCopy WHERE FolderId = ? AND IsRead = 0", folderId).ConfigureAwait(false); - foreach (var mail in unreadMails) - { - await LoadAssignedPropertiesAsync(mail).ConfigureAwait(false); - } - - return unreadMails; + return await HydrateMailCopiesAsync(unreadMails).ConfigureAwait(false); } public async Task GetMailCopyByMessageIdAsync(Guid accountId, string messageId) @@ -165,10 +155,7 @@ public class MailService : BaseDatabaseService, IMailService accountId, normalizedMessageId).ConfigureAwait(false); - if (mailCopy != null) - await LoadAssignedPropertiesAsync(mailCopy).ConfigureAwait(false); - - return mailCopy; + return await HydrateMailCopyAsync(mailCopy).ConfigureAwait(false); } private static (string Query, object[] Parameters) BuildMailFetchQuery(MailListInitializationOptions options) @@ -517,10 +504,12 @@ public class MailService : BaseDatabaseService, IMailService } } - private async Task PopulateAssignedPropertiesAsync(List mails) + // AssignedAccount is loaded through AccountService so IMAP server information, + // preferences, and other account-side ignored properties are populated as well. + private async Task> HydrateMailCopiesAsync(List mails) { if (mails == null || mails.Count == 0) - return; + return mails ?? []; var folderIds = mails .Select(m => m.FolderId) @@ -528,7 +517,7 @@ public class MailService : BaseDatabaseService, IMailService .ToList(); if (folderIds.Count == 0) - return; + return mails; var folders = await Task.WhenAll(folderIds.Select(id => _folderService.GetFolderAsync(id))).ConfigureAwait(false); var folderCache = folders @@ -536,7 +525,7 @@ public class MailService : BaseDatabaseService, IMailService .ToDictionary(f => f.Id); if (folderCache.Count == 0) - return; + return mails; var accountIds = folderCache.Values .Select(f => f.MailAccountId) @@ -562,6 +551,17 @@ public class MailService : BaseDatabaseService, IMailService AssignPropertiesFromCaches(mails, folderCache, accountCache, contactCache); await _sentMailReceiptService.PopulateReceiptStatesAsync(mails).ConfigureAwait(false); + + return mails; + } + + private async Task HydrateMailCopyAsync(MailCopy mailCopy) + { + if (mailCopy == null) + return null; + + var hydratedMails = await HydrateMailCopiesAsync([mailCopy]).ConfigureAwait(false); + return hydratedMails.FirstOrDefault(); } private async Task> GetMailsByThreadIdsAsync(List threadIds, HashSet excludeMailIds) @@ -610,14 +610,6 @@ public class MailService : BaseDatabaseService, IMailService } } - private async Task> GetMailItemsAsync(string mailCopyId) - { - var mailCopies = await GetMailCopiesByIdAsync([mailCopyId]).ConfigureAwait(false); - await PopulateAssignedPropertiesAsync(mailCopies).ConfigureAwait(false); - - return mailCopies; - } - private async Task> GetMailCopiesByIdAsync(IEnumerable mailCopyIds) { var distinctMailCopyIds = mailCopyIds? @@ -642,7 +634,7 @@ public class MailService : BaseDatabaseService, IMailService mailCopies.AddRange(batch); } - return mailCopies; + return await HydrateMailCopiesAsync(mailCopies).ConfigureAwait(false); } private Task GetSenderContactForAccountAsync(MailAccount account, string fromAddress) @@ -669,35 +661,11 @@ public class MailService : BaseDatabaseService, IMailService }; } - private async Task LoadAssignedPropertiesAsync(MailCopy mailCopy) - { - if (mailCopy == null) return; - - // Load AssignedAccount, AssignedFolder and SenderContact. - - var folder = await _folderService.GetFolderAsync(mailCopy.FolderId); - - if (folder == null) return; - - var account = await _accountService.GetAccountAsync(folder.MailAccountId); - - if (account == null) return; - - mailCopy.AssignedAccount = account; - mailCopy.AssignedFolder = folder; - mailCopy.SenderContact = await GetSenderContactForAccountAsync(account, mailCopy.FromAddress).ConfigureAwait(false); - await _sentMailReceiptService.PopulateReceiptStateAsync(mailCopy).ConfigureAwait(false); - } - public async Task GetSingleMailItemWithoutFolderAssignmentAsync(string mailCopyId) { - var mailCopy = await Connection.Table().FirstOrDefaultAsync(a => a.Id == mailCopyId); + var mailCopy = await Connection.Table().FirstOrDefaultAsync(a => a.Id == mailCopyId).ConfigureAwait(false); - if (mailCopy == null) return null; - - await LoadAssignedPropertiesAsync(mailCopy).ConfigureAwait(false); - - return mailCopy; + return await HydrateMailCopyAsync(mailCopy).ConfigureAwait(false); } /// @@ -710,43 +678,32 @@ public class MailService : BaseDatabaseService, IMailService { var mailCopy = await Connection.FindWithQueryAsync( "SELECT MailCopy.* FROM MailCopy WHERE MailCopy.Id = ?", - mailCopyId); - if (mailCopy == null) return null; + mailCopyId).ConfigureAwait(false); - await LoadAssignedPropertiesAsync(mailCopy).ConfigureAwait(false); - - return mailCopy; + return await HydrateMailCopyAsync(mailCopy).ConfigureAwait(false); } public async Task GetSingleMailItemAsync(string mailCopyId, string remoteFolderId) { var mailItem = await Connection.FindWithQueryAsync( "SELECT MailCopy.* FROM MailCopy INNER JOIN MailItemFolder ON MailCopy.FolderId = MailItemFolder.Id WHERE MailCopy.Id = ? AND MailItemFolder.RemoteFolderId = ?", - mailCopyId, remoteFolderId); + mailCopyId, remoteFolderId).ConfigureAwait(false); - if (mailItem == null) return null; - - await LoadAssignedPropertiesAsync(mailItem).ConfigureAwait(false); - - return mailItem; + return await HydrateMailCopyAsync(mailItem).ConfigureAwait(false); } public async Task GetSingleMailItemAsync(Guid uniqueMailId) { - var mailItem = await Connection.FindAsync(uniqueMailId); + var mailItem = await Connection.FindAsync(uniqueMailId).ConfigureAwait(false); - if (mailItem == null) return null; - - await LoadAssignedPropertiesAsync(mailItem).ConfigureAwait(false); - - return mailItem; + return await HydrateMailCopyAsync(mailItem).ConfigureAwait(false); } // v2 public async Task DeleteMailAsync(Guid accountId, string mailCopyId) { - var allMails = await GetMailItemsAsync(mailCopyId).ConfigureAwait(false); + var allMails = await GetMailCopiesByIdAsync([mailCopyId]).ConfigureAwait(false); foreach (var mailItem in allMails) { @@ -951,8 +908,6 @@ public class MailService : BaseDatabaseService, IMailService return; } - await PopulateAssignedPropertiesAsync(mailCopies).ConfigureAwait(false); - var pendingUpdates = new List<(MailCopy MailCopy, MailCopyChangeFlags ChangedProperties)>(); foreach (var mailCopy in mailCopies) @@ -1168,7 +1123,7 @@ public class MailService : BaseDatabaseService, IMailService if (account.ProviderType != MailProviderType.Gmail) { // Make sure there is only 1 instance left of this mail copy id. - var allMails = await GetMailItemsAsync(mailCopy.Id).ConfigureAwait(false); + var allMails = await GetMailCopiesByIdAsync([mailCopy.Id]).ConfigureAwait(false); await DeleteMailAsync(accountId, mailCopy.Id).ConfigureAwait(false); } @@ -1547,7 +1502,7 @@ public class MailService : BaseDatabaseService, IMailService var oldLocalDraftId = localDraftCopy.Id; - await LoadAssignedPropertiesAsync(localDraftCopy).ConfigureAwait(false); + localDraftCopy = await HydrateMailCopyAsync(localDraftCopy).ConfigureAwait(false); bool isIdChanging = localDraftCopy.Id != newMailCopyId; @@ -1598,7 +1553,7 @@ public class MailService : BaseDatabaseService, IMailService }); } - public Task> GetDownloadedUnreadMailsAsync(Guid accountId, IEnumerable downloadedMailCopyIds) + public async Task> GetDownloadedUnreadMailsAsync(Guid accountId, IEnumerable downloadedMailCopyIds) { var placeholders = string.Join(",", downloadedMailCopyIds.Select(_ => "?")); var sql = $"SELECT MailCopy.* FROM MailCopy INNER JOIN MailItemFolder ON MailCopy.FolderId = MailItemFolder.Id WHERE MailCopy.Id IN ({placeholders}) AND MailCopy.IsRead = ? AND MailItemFolder.MailAccountId = ? AND MailItemFolder.SpecialFolderType = ?"; @@ -1608,7 +1563,8 @@ public class MailService : BaseDatabaseService, IMailService parameters.Add(accountId); parameters.Add((int)SpecialFolderType.Inbox); - return Connection.QueryAsync(sql, parameters.ToArray()); + var mailCopies = await Connection.QueryAsync(sql, parameters.ToArray()).ConfigureAwait(false); + return await HydrateMailCopiesAsync(mailCopies).ConfigureAwait(false); } public Task GetMailAccountByUniqueIdAsync(Guid uniqueMailId) @@ -1628,7 +1584,8 @@ public class MailService : BaseDatabaseService, IMailService var placeholders = string.Join(",", localMailIds.Select(_ => "?")); var sql = $"SELECT * FROM MailCopy WHERE Id IN ({placeholders})"; - return await Connection.QueryAsync(sql, localMailIds.Cast().ToArray()); + var mailCopies = await Connection.QueryAsync(sql, localMailIds.Cast().ToArray()).ConfigureAwait(false); + return await HydrateMailCopiesAsync(mailCopies).ConfigureAwait(false); } public Task IsMailExistsAsync(string mailCopyId, Guid folderId) @@ -1744,21 +1701,7 @@ public class MailService : BaseDatabaseService, IMailService var mailCopies = await Connection.QueryAsync(sql, mailCopyIds.Cast().ToArray()); if (mailCopies?.Count == 0) return []; - var folderIds = mailCopies.Select(m => m.FolderId).Distinct().ToList(); - var folderTasks = folderIds.Select(id => _folderService.GetFolderAsync(id)); - var folders = await Task.WhenAll(folderTasks).ConfigureAwait(false); - var folderCache = folders.Where(f => f != null).ToDictionary(f => f.Id); - - var allAccounts = await _accountService.GetAccountsAsync().ConfigureAwait(false); - var accountCache = allAccounts.ToDictionary(a => a.Id); - - var addresses = mailCopies.Where(m => !string.IsNullOrEmpty(m.FromAddress)).Select(m => m.FromAddress).Distinct().ToList(); - var contactList = await _contactService.GetContactsByAddressesAsync(addresses).ConfigureAwait(false); - var contactCache = contactList.ToDictionary(c => c.Address); - - AssignPropertiesFromCaches(mailCopies, folderCache, accountCache, contactCache); - - return mailCopies; + return await HydrateMailCopiesAsync(mailCopies).ConfigureAwait(false); } public async Task> AreMailsExistsAsync(IEnumerable mailCopyIds) @@ -1769,7 +1712,7 @@ public class MailService : BaseDatabaseService, IMailService return await Connection.QueryScalarsAsync(sql, mailCopyIds.Cast().ToArray()); } - public Task> GetMailCopiesBeforeDateAsync(Guid accountId, DateTime cutoffDateUtc) + public async Task> GetMailCopiesBeforeDateAsync(Guid accountId, DateTime cutoffDateUtc) { const string query = """ SELECT MailCopy.* @@ -1779,6 +1722,7 @@ public class MailService : BaseDatabaseService, IMailService AND MailCopy.CreationDate < ? """; - return Connection.QueryAsync(query, accountId, cutoffDateUtc); + var mailCopies = await Connection.QueryAsync(query, accountId, cutoffDateUtc).ConfigureAwait(false); + return await HydrateMailCopiesAsync(mailCopies).ConfigureAwait(false); } }