Skip to content

Commit d7e4a29

Browse files
authored
Merge pull request #3998 from erri120/task/3966-3
Remove APIs taking transactions
2 parents 1e9a4b9 + d920908 commit d7e4a29

File tree

5 files changed

+46
-166
lines changed

5 files changed

+46
-166
lines changed

src/NexusMods.Abstractions.Library/ILibraryService.cs

Lines changed: 1 addition & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -82,63 +82,6 @@ public interface ILibraryService
8282
/// <param name="gcRunMode">Defines how the garbage collector should be run</param>
8383
Task RemoveLibraryItems(IEnumerable<LibraryItem.ReadOnly> libraryItems, GarbageCollectorRunMode gcRunMode = GarbageCollectorRunMode.RunAsynchronously);
8484

85-
/// <summary>
86-
/// Removes a single linked loadout item from its loadout,
87-
/// managing the transaction automatically.
88-
/// </summary>
89-
/// <param name="itemId">The ID of the linked loadout item to remove from the loadout.</param>
90-
Task RemoveLinkedItemFromLoadout(LibraryLinkedLoadoutItemId itemId);
91-
92-
/// <summary>
93-
/// Removes multiple linked loadout items from their loadout,
94-
/// managing the transaction automatically.
95-
/// </summary>
96-
/// <param name="itemIds">The IDs of the linked loadout items to remove from their loadout.</param>
97-
Task RemoveLinkedItemsFromLoadout(IEnumerable<LibraryLinkedLoadoutItemId> itemIds);
98-
99-
/// <summary>
100-
/// Removes a single linked loadout item from a loadout,
101-
/// using the provided transaction.
102-
/// </summary>
103-
/// <param name="itemId">The ID of the linked loadout item to remove from its loadout.</param>
104-
/// <param name="tx">Existing transaction to use for this operation.</param>
105-
void RemoveLinkedItemFromLoadout(LibraryLinkedLoadoutItemId itemId, ITransaction tx);
106-
107-
/// <summary>
108-
/// Removes multiple linked loadout items from their loadout,
109-
/// using the provided transaction.
110-
/// </summary>
111-
/// <param name="itemIds">The IDs of the linked loadout items to remove from their loadout.</param>
112-
/// <param name="tx">Existing transaction to use for this operation.</param>
113-
void RemoveLinkedItemsFromLoadout(IEnumerable<LibraryLinkedLoadoutItemId> itemIds, ITransaction tx);
114-
115-
/// <summary>
116-
/// Removes all linked loadout items from all loadouts,
117-
/// using the provided transaction.
118-
/// </summary>
119-
/// <param name="libraryItems">The library items whose associated linked loadout items should be removed.</param>
120-
/// <param name="tx">Existing transaction to use for this operation.</param>
121-
void RemoveLinkedItemsFromAllLoadouts(IEnumerable<LibraryItem.ReadOnly> libraryItems, ITransaction tx);
122-
123-
/// <summary>
124-
/// Removes all linked loadout items from all loadouts,
125-
/// managing the transaction automatically.
126-
/// </summary>
127-
/// <param name="libraryItems">The library items whose associated linked loadout items should be removed.</param>
128-
Task RemoveLinkedItemsFromAllLoadouts(IEnumerable<LibraryItem.ReadOnly> libraryItems);
129-
130-
/// <summary>
131-
/// Replaces linked loadout items across all loadouts with installations of a different library item.
132-
/// </summary>
133-
/// <param name="oldItem">The library item whose linked loadout items should be replaced.</param>
134-
/// <param name="newItem">The replacement library item from which to install the new linked loadout items from.</param>
135-
/// <param name="options">Options controlling how to replace the linked loadout items.</param>
136-
/// <param name="tx">The transaction to use for this operation.</param>
137-
/// <returns>
138-
/// A result indicating success or failure of the replacement operation.
139-
/// </returns>
140-
ValueTask<LibraryItemReplacementResult> ReplaceLinkedItemsInAllLoadouts(LibraryItem.ReadOnly oldItem, LibraryItem.ReadOnly newItem, ReplaceLibraryItemOptions options, ITransaction tx);
141-
14285
/// <summary>
14386
/// Replaces linked loadout items across all loadouts with installations of a different library item.
14487
/// </summary>
@@ -149,18 +92,7 @@ public interface ILibraryService
14992
/// A result indicating success or failure of the replacement operation.
15093
/// </returns>
15194
ValueTask<LibraryItemReplacementResult> ReplaceLinkedItemsInAllLoadouts(LibraryItem.ReadOnly oldItem, LibraryItem.ReadOnly newItem, ReplaceLibraryItemOptions options);
152-
153-
/// <summary>
154-
/// Replaces multiple sets of linked loadout items across all loadouts with new versions.
155-
/// </summary>
156-
/// <param name="replacements">The pairs of library items (old and new) whose linked loadout items should be replaced.</param>
157-
/// <param name="options">Options controlling how to replace the linked loadout items.</param>
158-
/// <param name="tx">The transaction to use for this operation.</param>
159-
/// <returns>
160-
/// A result indicating success or failure of the replacement operation.
161-
/// </returns>
162-
ValueTask<LibraryItemReplacementResult> ReplaceLinkedItemsInAllLoadouts(IEnumerable<(LibraryItem.ReadOnly oldItem, LibraryItem.ReadOnly newItem)> replacements, ReplaceLibraryItemsOptions options, ITransaction tx);
163-
95+
16496
/// <summary>
16597
/// Replaces multiple sets of linked loadout items across all loadouts with new versions,
16698
/// managing the transaction automatically.

src/NexusMods.Abstractions.Loadouts.Synchronizers/ILoadoutManager.cs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
using NexusMods.Abstractions.GC;
55
using NexusMods.Abstractions.Library.Installers;
66
using NexusMods.Abstractions.Library.Models;
7-
using NexusMods.MnemonicDB.Abstractions;
87
using NexusMods.Sdk.Jobs;
98

109
namespace NexusMods.Abstractions.Loadouts.Synchronizers;
@@ -56,7 +55,6 @@ public interface ILoadoutManager
5655
/// <param name="parent">If specified the installed item will be placed in this group, otherwise it will default to the user's local collection</param>
5756
/// <param name="installer">The Library will use this installer to install the item</param>
5857
/// <param name="fallbackInstaller">The installer to use if the default installer fails</param>
59-
/// <param name="transaction">The transaction to attach the installation to. Install is only completed when transaction is completed.</param>
6058
/// <remarks>
6159
/// Job returns a result with null <see cref="LoadoutItemGroup.ReadOnly"/> after
6260
/// if supplied an external transaction via <paramref name="transaction"/>,
@@ -67,13 +65,7 @@ IJobTask<IInstallLoadoutItemJob, InstallLoadoutItemJobResult> InstallItem(
6765
LoadoutId targetLoadout,
6866
Optional<LoadoutItemGroupId> parent = default,
6967
ILibraryItemInstaller? installer = null,
70-
ILibraryItemInstaller? fallbackInstaller = null,
71-
ITransaction? transaction = null);
72-
73-
/// <summary>
74-
/// Removes the items from their Loadouts.
75-
/// </summary>
76-
void RemoveItems(ITransaction tx, LoadoutItemGroupId[] groupIds);
68+
ILibraryItemInstaller? fallbackInstaller = null);
7769

7870
/// <summary>
7971
/// Removes the items from their Loadouts.
@@ -84,4 +76,6 @@ IJobTask<IInstallLoadoutItemJob, InstallLoadoutItemJobResult> InstallItem(
8476
/// Removes a collection.
8577
/// </summary>
8678
ValueTask RemoveCollection(LoadoutId loadoutId, CollectionGroupId collection);
79+
80+
ValueTask ReplaceItems(LoadoutId loadoutId, LoadoutItemGroupId[] groupsToRemove, LibraryItem.ReadOnly libraryItemToInstall);
8781
}

src/NexusMods.DataModel/LoadoutManager.TxFuncs.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,10 @@ public AddPriorityTxFunc(LoadoutId loadoutId, LoadoutItemGroupId targetId)
6060
public bool Equals(ITxFunction? obj)
6161
{
6262
if (obj is not AddPriorityTxFunc other) return false;
63-
return other._loadoutId.Equals(_loadoutId) && other._targetId == _targetId;
63+
return other._loadoutId.Equals(_loadoutId);
6464
}
6565

66-
public override int GetHashCode() => HashCode.Combine(_loadoutId, _targetId);
66+
public override int GetHashCode() => _loadoutId.GetHashCode();
6767

6868
public void Apply(ITransaction tx, IDb basis)
6969
{

src/NexusMods.DataModel/LoadoutManager.cs

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Diagnostics;
2+
using System.Xml;
23
using DynamicData.Kernel;
34
using Microsoft.Extensions.DependencyInjection;
45
using Microsoft.Extensions.Logging;
@@ -339,22 +340,21 @@ public IJobTask<IInstallLoadoutItemJob, InstallLoadoutItemJobResult> InstallItem
339340
LoadoutId targetLoadout,
340341
Optional<LoadoutItemGroupId> parent = default,
341342
ILibraryItemInstaller? installer = null,
342-
ILibraryItemInstaller? fallbackInstaller = null,
343-
ITransaction? transaction = null)
343+
ILibraryItemInstaller? fallbackInstaller = null)
344344
{
345-
IMainTransaction? mainTransaction;
346-
ITransaction tx;
345+
return InstallItem(libraryItem, targetLoadout, inputTx: null, parent: parent, installer: installer, fallbackInstaller: fallbackInstaller);
346+
}
347347

348-
if (transaction is null)
349-
{
350-
mainTransaction = _connection.BeginTransaction();
351-
tx = mainTransaction;
352-
}
353-
else
354-
{
355-
mainTransaction = null;
356-
tx = transaction;
357-
}
348+
private IJobTask<IInstallLoadoutItemJob, InstallLoadoutItemJobResult> InstallItem(
349+
LibraryItem.ReadOnly libraryItem,
350+
LoadoutId targetLoadout,
351+
ITransaction? inputTx,
352+
Optional<LoadoutItemGroupId> parent = default,
353+
ILibraryItemInstaller? installer = null,
354+
ILibraryItemInstaller? fallbackInstaller = null)
355+
{
356+
var mainTransaction = inputTx is null ? _connection.BeginTransaction() : null;
357+
var tx = inputTx ?? mainTransaction!;
358358

359359
var job = InstallLoadoutItemJob.Create(_serviceProvider, libraryItem, targetLoadout, tx, groupId: parent, installer: installer, fallbackInstaller: fallbackInstaller);
360360
return _jobMonitor.Begin(job, async context =>
@@ -363,7 +363,7 @@ public IJobTask<IInstallLoadoutItemJob, InstallLoadoutItemJobResult> InstallItem
363363
var targetId = result.GroupTxId;
364364
tx.Add(new AddPriorityTxFunc(targetLoadout, targetId));
365365

366-
if (mainTransaction is null) return result;
366+
if (mainTransaction is null) return new InstallLoadoutItemJobResult(null, targetId);
367367

368368
var commitResult = await mainTransaction.Commit();
369369
var remapped = commitResult[targetId];
@@ -380,7 +380,7 @@ public async ValueTask RemoveItems(LoadoutItemGroupId[] groupIds)
380380
await tx.Commit();
381381
}
382382

383-
public void RemoveItems(ITransaction tx, LoadoutItemGroupId[] groupIds)
383+
private void RemoveItems(ITransaction tx, LoadoutItemGroupId[] groupIds)
384384
{
385385
var db = _connection.Db;
386386
var loadouts = new Dictionary<LoadoutId, List<LoadoutItemGroupId>>();
@@ -425,4 +425,12 @@ public async ValueTask RemoveCollection(LoadoutId loadoutId, CollectionGroupId c
425425

426426
await tx.Commit();
427427
}
428+
429+
public async ValueTask ReplaceItems(LoadoutId loadoutId, LoadoutItemGroupId[] groupsToRemove, LibraryItem.ReadOnly libraryItemToInstall)
430+
{
431+
using var tx = _connection.BeginTransaction();
432+
RemoveItems(tx, groupsToRemove);
433+
await InstallItem(libraryItemToInstall, loadoutId, inputTx: tx);
434+
await tx.Commit();
435+
}
428436
}

src/NexusMods.Library/LibraryService.cs

Lines changed: 16 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,11 @@ public LibraryService(IServiceProvider serviceProvider)
161161

162162
public async Task RemoveLibraryItems(IEnumerable<LibraryItem.ReadOnly> libraryItems, GarbageCollectorRunMode gcRunMode = GarbageCollectorRunMode.RunAsynchronously)
163163
{
164-
using var tx = _connection.BeginTransaction();
165164
var items = libraryItems.ToArray();
166-
RemoveLinkedItemsFromAllLoadouts(items, tx);
165+
var groupIds = items.SelectMany(LoadoutsWithLibraryItem).Select(tuple => tuple.linkedItem.AsLoadoutItemGroup().LoadoutItemGroupId).ToArray();
166+
await _loadoutManager.RemoveItems(groupIds);
167+
168+
using var tx = _connection.BeginTransaction();
167169

168170
foreach (var item in items)
169171
tx.Delete(item.Id, recursive: true);
@@ -172,58 +174,12 @@ public async Task RemoveLibraryItems(IEnumerable<LibraryItem.ReadOnly> libraryIt
172174
await _gcRunner.RunWithMode(gcRunMode);
173175
}
174176

175-
public async Task RemoveLinkedItemFromLoadout(LibraryLinkedLoadoutItemId itemId)
176-
{
177-
using var tx = _connection.BeginTransaction();
178-
RemoveLinkedItemFromLoadout(itemId, tx);
179-
await tx.Commit();
180-
}
181-
182-
public async Task RemoveLinkedItemsFromLoadout(IEnumerable<LibraryLinkedLoadoutItemId> itemIds)
183-
{
184-
using var tx = _connection.BeginTransaction();
185-
RemoveLinkedItemsFromLoadout(itemIds, tx);
186-
await tx.Commit();
187-
}
188-
189-
public void RemoveLinkedItemFromLoadout(LibraryLinkedLoadoutItemId itemId, ITransaction tx)
190-
{
191-
_loadoutManager.RemoveItems(tx, [itemId.Value]);
192-
}
193-
194-
public void RemoveLinkedItemsFromLoadout(IEnumerable<LibraryLinkedLoadoutItemId> itemIds, ITransaction tx)
195-
{
196-
_loadoutManager.RemoveItems(tx, itemIds.Select(LoadoutItemGroupId (x) => x.Value).ToArray());
197-
}
198-
199-
public void RemoveLinkedItemsFromAllLoadouts(IEnumerable<LibraryItem.ReadOnly> libraryItems, ITransaction tx)
200-
{
201-
var groupIds = libraryItems.SelectMany(LoadoutsWithLibraryItem).Select(tuple => tuple.linkedItem.AsLoadoutItemGroup().LoadoutItemGroupId).ToArray();
202-
_loadoutManager.RemoveItems(tx, groupIds);
203-
}
204-
205-
public async Task RemoveLinkedItemsFromAllLoadouts(IEnumerable<LibraryItem.ReadOnly> libraryItems)
206-
{
207-
using var tx = _connection.BeginTransaction();
208-
RemoveLinkedItemsFromAllLoadouts(libraryItems, tx);
209-
await tx.Commit();
210-
}
211-
212-
public async ValueTask<LibraryItemReplacementResult> ReplaceLinkedItemsInAllLoadouts(
213-
LibraryItem.ReadOnly oldItem, LibraryItem.ReadOnly newItem, ReplaceLibraryItemOptions options)
214-
{
215-
using var tx = _connection.BeginTransaction();
216-
var result = await ReplaceLinkedItemsInAllLoadouts(oldItem, newItem, options, tx);
217-
await tx.Commit();
218-
return result;
219-
}
220-
221-
public async ValueTask<LibraryItemReplacementResult> ReplaceLinkedItemsInAllLoadouts(LibraryItem.ReadOnly oldItem, LibraryItem.ReadOnly newItem, ReplaceLibraryItemOptions options, ITransaction tx)
177+
public async ValueTask<LibraryItemReplacementResult> ReplaceLinkedItemsInAllLoadouts(LibraryItem.ReadOnly oldItem, LibraryItem.ReadOnly newItem, ReplaceLibraryItemOptions options)
222178
{
223179
try
224180
{
225181
// 1. Find affected loadouts using existing method
226-
var items = LoadoutsWithLibraryItem(oldItem)
182+
var itemsPerLoadout = LoadoutsWithLibraryItem(oldItem)
227183
.Where(tuple =>
228184
{
229185
if (options.IgnoreReadOnlyCollections)
@@ -235,15 +191,15 @@ public async ValueTask<LibraryItemReplacementResult> ReplaceLinkedItemsInAllLoad
235191

236192
return true;
237193
})
238-
.ToArray();
194+
.GroupBy(tuple => tuple.loadout.LoadoutId)
195+
.ToDictionary(grouping => grouping.Key, grouping => grouping.ToArray());
239196

240-
// 2. Unlink old mod using bulk removal
241-
foreach (var (_, libraryLinkedItem) in items)
242-
RemoveLinkedItemFromLoadout(libraryLinkedItem.Id, tx);
243-
244-
// 3. Reinstall new mod in original loadouts
245-
foreach (var (loadout, _) in items)
246-
await _loadoutManager.InstallItem(libraryItem: newItem, targetLoadout: loadout.Id, transaction: tx);
197+
foreach (var kv in itemsPerLoadout)
198+
{
199+
var (loadoutId, items) = kv;
200+
var groupIds = items.Select(x => x.linkedItem.AsLoadoutItemGroup().LoadoutItemGroupId).ToArray();
201+
await _loadoutManager.ReplaceItems(loadoutId, groupIds, newItem);
202+
}
247203
}
248204
catch
249205
{
@@ -253,14 +209,14 @@ public async ValueTask<LibraryItemReplacementResult> ReplaceLinkedItemsInAllLoad
253209
return LibraryItemReplacementResult.Success;
254210
}
255211

256-
public async ValueTask<LibraryItemReplacementResult> ReplaceLinkedItemsInAllLoadouts(IEnumerable<(LibraryItem.ReadOnly oldItem, LibraryItem.ReadOnly newItem)> replacements, ReplaceLibraryItemsOptions options, ITransaction tx)
212+
public async ValueTask<LibraryItemReplacementResult> ReplaceLinkedItemsInAllLoadouts(IEnumerable<(LibraryItem.ReadOnly oldItem, LibraryItem.ReadOnly newItem)> replacements, ReplaceLibraryItemsOptions options)
257213
{
258214
var replacementsArr = replacements.ToArray();
259215
try
260216
{
261217
foreach (var (oldItem, newItem) in replacementsArr)
262218
{
263-
var result = await ReplaceLinkedItemsInAllLoadouts(oldItem, newItem, options.ToReplaceLibraryItemOptions(), tx);
219+
var result = await ReplaceLinkedItemsInAllLoadouts(oldItem, newItem, options.ToReplaceLibraryItemOptions());
264220
if (result != LibraryItemReplacementResult.Success)
265221
return result; // failed due to some reason.
266222
}
@@ -272,14 +228,4 @@ public async ValueTask<LibraryItemReplacementResult> ReplaceLinkedItemsInAllLoad
272228

273229
return LibraryItemReplacementResult.Success;
274230
}
275-
276-
public async ValueTask<LibraryItemReplacementResult> ReplaceLinkedItemsInAllLoadouts(IEnumerable<(LibraryItem.ReadOnly oldItem, LibraryItem.ReadOnly newItem)> replacements, ReplaceLibraryItemsOptions options)
277-
{
278-
using var tx = _connection.BeginTransaction();
279-
var result = await ReplaceLinkedItemsInAllLoadouts(replacements, options, tx);
280-
if (result == LibraryItemReplacementResult.Success)
281-
await tx.Commit();
282-
283-
return result;
284-
}
285231
}

0 commit comments

Comments
 (0)