When book is unavailable, check other accounts (#535)
This commit is contained in:
parent
36076242a7
commit
fd16e97632
@ -25,6 +25,8 @@ namespace DataLayer
|
|||||||
Account = account;
|
Account = account;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() => $"{DateAdded:d} {Book}";
|
public void SetAccount(string account) => Account = account;
|
||||||
|
|
||||||
|
public override string ToString() => $"{DateAdded:d} {Book}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,32 +41,41 @@ namespace DtoImporterService
|
|||||||
//
|
//
|
||||||
// CURRENT SOLUTION: don't re-insert
|
// CURRENT SOLUTION: don't re-insert
|
||||||
|
|
||||||
var newItems = importItems
|
var existingEntries = DbContext.LibraryBooks.AsEnumerable().Where(l => l.Book is not null).ToDictionary(l => l.Book.AudibleProductId);
|
||||||
.ExceptBy(DbContext.LibraryBooks.Select(lb => lb.Book.AudibleProductId), imp => imp.DtoItem.ProductId)
|
var hash = ToDictionarySafe(importItems, dto => dto.DtoItem.ProductId, tieBreak);
|
||||||
.ToList();
|
int qtyNew = 0;
|
||||||
|
|
||||||
// if 2 accounts try to import the same book in the same transaction: error since we're only tracking and pulling by asin.
|
foreach (var item in hash.Values)
|
||||||
// just use the first
|
|
||||||
var hash = newItems.ToDictionarySafe(dto => dto.DtoItem.ProductId);
|
|
||||||
foreach (var kvp in hash)
|
|
||||||
{
|
{
|
||||||
var newItem = kvp.Value;
|
if (existingEntries.TryGetValue(item.DtoItem.ProductId, out LibraryBook existing))
|
||||||
|
|
||||||
var libraryBook = new LibraryBook(
|
|
||||||
bookImporter.Cache[newItem.DtoItem.ProductId],
|
|
||||||
newItem.DtoItem.DateAdded,
|
|
||||||
newItem.AccountId)
|
|
||||||
{
|
{
|
||||||
AbsentFromLastScan = isPlusTitleUnavailable(newItem)
|
if (existing.Account != item.AccountId)
|
||||||
};
|
{
|
||||||
|
//Book is absent from the existing LibraryBook's account. Use the alternate account.
|
||||||
|
existing.SetAccount(item.AccountId);
|
||||||
|
}
|
||||||
|
|
||||||
try
|
existing.AbsentFromLastScan = isPlusTitleUnavailable(item);
|
||||||
{
|
|
||||||
DbContext.LibraryBooks.Add(libraryBook);
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
else
|
||||||
{
|
{
|
||||||
Serilog.Log.Logger.Error(ex, "Error adding library book. {@DebugInfo}", new { libraryBook.Book, libraryBook.Account });
|
var libraryBook = new LibraryBook(
|
||||||
|
bookImporter.Cache[item.DtoItem.ProductId],
|
||||||
|
item.DtoItem.DateAdded,
|
||||||
|
item.AccountId)
|
||||||
|
{
|
||||||
|
AbsentFromLastScan = isPlusTitleUnavailable(item)
|
||||||
|
};
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DbContext.LibraryBooks.Add(libraryBook);
|
||||||
|
qtyNew++;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Serilog.Log.Logger.Error(ex, "Error adding library book. {@DebugInfo}", new { libraryBook.Book, libraryBook.Account });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,20 +86,28 @@ namespace DtoImporterService
|
|||||||
foreach (var nullBook in DbContext.LibraryBooks.AsEnumerable().Where(lb => lb.Book is null && lb.Account.In(scannedAccounts)))
|
foreach (var nullBook in DbContext.LibraryBooks.AsEnumerable().Where(lb => lb.Book is null && lb.Account.In(scannedAccounts)))
|
||||||
nullBook.AbsentFromLastScan = true;
|
nullBook.AbsentFromLastScan = true;
|
||||||
|
|
||||||
//Join importItems on LibraryBooks before iterating over LibraryBooks to avoid
|
|
||||||
//quadratic complexity caused by searching all of importItems for each LibraryBook.
|
|
||||||
//Join uses hashing, so complexity should approach O(N) instead of O(N^2).
|
|
||||||
var items_lbs
|
|
||||||
= importItems
|
|
||||||
.Join(DbContext.LibraryBooks, o => (o.AccountId, o.DtoItem.ProductId), i => (i.Account, i.Book?.AudibleProductId), (o, i) => (o, i));
|
|
||||||
|
|
||||||
foreach ((ImportItem item, LibraryBook lb) in items_lbs)
|
|
||||||
lb.AbsentFromLastScan = isPlusTitleUnavailable(item);
|
|
||||||
|
|
||||||
var qtyNew = hash.Count;
|
|
||||||
return qtyNew;
|
return qtyNew;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Dictionary<TKey, TSource> ToDictionarySafe<TKey, TSource>(IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TSource, TSource> tieBreaker)
|
||||||
|
{
|
||||||
|
var dictionary = new Dictionary<TKey, TSource>();
|
||||||
|
|
||||||
|
foreach (TSource newItem in source)
|
||||||
|
{
|
||||||
|
TKey key = keySelector(newItem);
|
||||||
|
|
||||||
|
dictionary[key]
|
||||||
|
= dictionary.TryGetValue(key, out TSource existingItem)
|
||||||
|
? tieBreaker(existingItem, newItem)
|
||||||
|
: newItem;
|
||||||
|
}
|
||||||
|
return dictionary;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ImportItem tieBreak(ImportItem item1, ImportItem item2)
|
||||||
|
=> isPlusTitleUnavailable(item1) && !isPlusTitleUnavailable(item2) ? item2 : item1;
|
||||||
|
|
||||||
private static bool isPlusTitleUnavailable(ImportItem item)
|
private static bool isPlusTitleUnavailable(ImportItem item)
|
||||||
=> item.DtoItem.IsAyce is true
|
=> item.DtoItem.IsAyce is true
|
||||||
&& item.DtoItem.Plans?.Any(p => p.IsAyce) is not true;
|
&& item.DtoItem.Plans?.Any(p => p.IsAyce) is not true;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user