mirror of https://github.com/ppy/osu
`BeatmapSetInfo` detach support
This commit is contained in:
parent
de076678fe
commit
8461eaab46
|
@ -35,6 +35,51 @@ namespace osu.Game.Tests.Database
|
|||
[TestFixture]
|
||||
public class BeatmapImporterTests : RealmTest
|
||||
{
|
||||
[Test]
|
||||
public void TestDetach()
|
||||
{
|
||||
RunTestWithRealmAsync(async (realmFactory, storage) =>
|
||||
{
|
||||
using (var importer = new BeatmapModelManager(realmFactory, storage))
|
||||
using (new RulesetStore(realmFactory, storage))
|
||||
{
|
||||
ILive<BeatmapSetInfo>? imported;
|
||||
|
||||
using (var reader = new ZipArchiveReader(TestResources.GetTestBeatmapStream()))
|
||||
imported = await importer.Import(reader);
|
||||
|
||||
Assert.NotNull(imported);
|
||||
Debug.Assert(imported != null);
|
||||
|
||||
BeatmapSetInfo? detached = null;
|
||||
|
||||
imported.PerformRead(live =>
|
||||
{
|
||||
var timer = new Stopwatch();
|
||||
timer.Start();
|
||||
detached = live.Detach();
|
||||
Logger.Log($"Detach took {timer.ElapsedMilliseconds} ms");
|
||||
|
||||
Logger.Log($"NamedFiles: {live.Files.Count} {detached.Files.Count}");
|
||||
Logger.Log($"Files: {live.Files.Select(f => f.File).Count()} {detached.Files.Select(f => f.File).Count()}");
|
||||
Logger.Log($"Difficulties: {live.Beatmaps.Count} {detached.Beatmaps.Count}");
|
||||
Logger.Log($"BeatmapDifficulties: {live.Beatmaps.Select(f => f.Difficulty).Count()} {detached.Beatmaps.Select(f => f.Difficulty).Count()}");
|
||||
Logger.Log($"Metadata: {live.Metadata} {detached.Metadata}");
|
||||
});
|
||||
|
||||
Logger.Log("Testing detached-ness");
|
||||
|
||||
Debug.Assert(detached != null);
|
||||
|
||||
Logger.Log($"NamedFiles: {detached.Files.Count}");
|
||||
Logger.Log($"Files: {detached.Files.Select(f => f.File).Count()}");
|
||||
Logger.Log($"Difficulties: {detached.Beatmaps.Count}");
|
||||
Logger.Log($"BeatmapDifficulties: {detached.Beatmaps.Select(f => f.Difficulty).Count()}");
|
||||
Logger.Log($"Metadata: {detached.Metadata}");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestImportBeatmapThenCleanup()
|
||||
{
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using AutoMapper;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Framework.Testing;
|
||||
|
@ -143,6 +144,7 @@ public bool BackgroundEquals(BeatmapInfo? other) => other != null
|
|||
private int rulesetID;
|
||||
|
||||
[Ignored]
|
||||
[IgnoreMap]
|
||||
public int RulesetID
|
||||
{
|
||||
// ReSharper disable once ConstantConditionalAccessQualifier
|
||||
|
@ -182,6 +184,8 @@ public BeatmapDifficulty BaseDifficulty
|
|||
|
||||
public BeatmapInfo Clone() => this.Detach();
|
||||
|
||||
public override string ToString() => Metadata?.ToString() ?? base.ToString();
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -151,7 +151,7 @@ public void Restore(BeatmapInfo beatmapInfo)
|
|||
public List<BeatmapSetInfo> GetAllUsableBeatmapSets()
|
||||
{
|
||||
using (var context = contextFactory.CreateContext())
|
||||
return context.All<BeatmapSetInfo>().Where(b => !b.DeletePending).ToList();
|
||||
return context.All<BeatmapSetInfo>().Where(b => !b.DeletePending).Detach();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -199,7 +199,7 @@ public IQueryable<BeatmapInfo> QueryBeatmaps(Expression<Func<BeatmapInfo, bool>>
|
|||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <returns>The first result for the provided query, or null if no results were found.</returns>
|
||||
public BeatmapInfo? QueryBeatmap(Expression<Func<BeatmapInfo, bool>> query) => beatmapModelManager.QueryBeatmap(query);
|
||||
public BeatmapInfo? QueryBeatmap(Expression<Func<BeatmapInfo, bool>> query) => beatmapModelManager.QueryBeatmap(query)?.Detach();
|
||||
|
||||
/// <summary>
|
||||
/// Saves an <see cref="IBeatmap"/> file against a given <see cref="BeatmapInfo"/>.
|
||||
|
|
|
@ -107,7 +107,7 @@ public virtual void Save(BeatmapInfo beatmapInfo, IBeatmap beatmapContent, ISkin
|
|||
public BeatmapInfo? QueryBeatmap(Expression<Func<BeatmapInfo, bool>> query)
|
||||
{
|
||||
using (var context = ContextFactory.CreateContext())
|
||||
return context.All<BeatmapInfo>().FirstOrDefault(query); // TODO: ?.ToLive();
|
||||
return context.All<BeatmapInfo>().FirstOrDefault(query)?.Detach();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AutoMapper;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Extensions;
|
||||
|
@ -75,7 +76,10 @@ public bool Equals(BeatmapSetInfo? other)
|
|||
|
||||
public bool Equals(IBeatmapSetInfo? other) => other is BeatmapSetInfo b && Equals(b);
|
||||
|
||||
[IgnoreMap]
|
||||
IEnumerable<IBeatmapInfo> IBeatmapSetInfo.Beatmaps => Beatmaps;
|
||||
|
||||
[IgnoreMap]
|
||||
IEnumerable<INamedFileUsage> IHasNamedFiles.Files => Files;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,6 +82,10 @@ public virtual WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo)
|
|||
beatmapInfo = BeatmapManager.QueryBeatmap(b => b.ID == lookupId);
|
||||
}
|
||||
|
||||
// TODO: FUCK THE WORLD :D
|
||||
if (beatmapInfo?.IsManaged == true)
|
||||
beatmapInfo = beatmapInfo.Detach();
|
||||
|
||||
if (beatmapInfo?.BeatmapSet == null)
|
||||
return DefaultBeatmap;
|
||||
|
||||
|
|
|
@ -209,7 +209,7 @@ private List<BeatmapCollection> readCollections(Stream stream, ProgressNotificat
|
|||
|
||||
string checksum = sr.ReadString();
|
||||
|
||||
var beatmap = beatmaps.QueryBeatmap(b => b.MD5Hash == checksum);
|
||||
var beatmap = beatmaps.QueryBeatmap(b => b.MD5Hash == checksum)?.Detach();
|
||||
if (beatmap != null)
|
||||
collection.Beatmaps.Add(beatmap);
|
||||
}
|
||||
|
|
|
@ -61,8 +61,9 @@ public void PerformRead(Action<T> perform)
|
|||
/// <param name="perform">The action to perform.</param>
|
||||
public TReturn PerformRead<TReturn>(Func<T, TReturn> perform)
|
||||
{
|
||||
if (typeof(RealmObjectBase).IsAssignableFrom(typeof(TReturn)))
|
||||
throw new InvalidOperationException(@$"Realm live objects should not exit the scope of {nameof(PerformRead)}.");
|
||||
// TODO: this is weird and kinda wrong... unmanaged objects should be allowed?
|
||||
// if (typeof(RealmObjectBase).IsAssignableFrom(typeof(TReturn)))
|
||||
// throw new InvalidOperationException(@$"Realm live objects should not exit the scope of {nameof(PerformRead)}.");
|
||||
|
||||
if (!IsManaged)
|
||||
return perform(data);
|
||||
|
|
|
@ -6,7 +6,10 @@
|
|||
using System.Linq;
|
||||
using AutoMapper;
|
||||
using osu.Framework.Development;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Input.Bindings;
|
||||
using osu.Game.Models;
|
||||
using osu.Game.Rulesets;
|
||||
using Realms;
|
||||
|
||||
#nullable enable
|
||||
|
@ -18,9 +21,23 @@ public static class RealmObjectExtensions
|
|||
private static readonly IMapper mapper = new MapperConfiguration(c =>
|
||||
{
|
||||
c.ShouldMapField = fi => false;
|
||||
c.ShouldMapProperty = pi => pi.SetMethod != null && pi.SetMethod.IsPublic;
|
||||
c.ShouldMapProperty = pi => true;
|
||||
|
||||
c.CreateMap<RealmKeyBinding, RealmKeyBinding>();
|
||||
c.CreateMap<BeatmapMetadata, BeatmapMetadata>();
|
||||
c.CreateMap<BeatmapDifficulty, BeatmapDifficulty>();
|
||||
c.CreateMap<RulesetInfo, RulesetInfo>();
|
||||
c.CreateMap<RealmUser, RealmUser>();
|
||||
c.CreateMap<RealmFile, RealmFile>();
|
||||
c.CreateMap<RealmNamedFileUsage, RealmNamedFileUsage>();
|
||||
c.CreateMap<BeatmapInfo, BeatmapInfo>();
|
||||
c.CreateMap<BeatmapSetInfo, BeatmapSetInfo>();
|
||||
|
||||
c.ForAllMaps((a, b) =>
|
||||
{
|
||||
b.PreserveReferences();
|
||||
b.MaxDepth(2);
|
||||
});
|
||||
}).CreateMapper();
|
||||
|
||||
/// <summary>
|
||||
|
@ -32,7 +49,7 @@ public static class RealmObjectExtensions
|
|||
/// <param name="items">A list of managed <see cref="RealmObject"/>s to detach.</param>
|
||||
/// <typeparam name="T">The type of object.</typeparam>
|
||||
/// <returns>A list containing non-managed copies of provided items.</returns>
|
||||
public static List<T> Detach<T>(this IEnumerable<T> items) where T : RealmObject
|
||||
public static List<T> Detach<T>(this IEnumerable<T> items) where T : RealmObjectBase
|
||||
{
|
||||
var list = new List<T>();
|
||||
|
||||
|
@ -51,7 +68,7 @@ public static List<T> Detach<T>(this IEnumerable<T> items) where T : RealmObject
|
|||
/// <param name="item">The managed <see cref="RealmObject"/> to detach.</param>
|
||||
/// <typeparam name="T">The type of object.</typeparam>
|
||||
/// <returns>A non-managed copy of provided item. Will return the provided item if already detached.</returns>
|
||||
public static T Detach<T>(this T item) where T : RealmObject
|
||||
public static T Detach<T>(this T item) where T : RealmObjectBase
|
||||
{
|
||||
if (!item.IsManaged)
|
||||
return item;
|
||||
|
@ -65,7 +82,8 @@ public static List<ILive<T>> ToLiveUnmanaged<T>(this IEnumerable<T> realmList)
|
|||
return realmList.Select(l => new RealmLiveUnmanaged<T>(l)).Cast<ILive<T>>().ToList();
|
||||
}
|
||||
|
||||
public static ILive<T> ToLiveUnmanaged<T>(this T realmObject)
|
||||
public static ILive<T> ToLiveUnmanaged<T>(this T realmObject
|
||||
)
|
||||
where T : RealmObject, IHasGuidPrimaryKey
|
||||
{
|
||||
return new RealmLiveUnmanaged<T>(realmObject);
|
||||
|
|
|
@ -662,6 +662,10 @@ private CarouselBeatmapSet createCarouselSet(BeatmapSetInfo beatmapSet)
|
|||
if (beatmapSet.Beatmaps.All(b => b.Hidden))
|
||||
return null;
|
||||
|
||||
// TODO: FUCK THE WORLD :D
|
||||
if (beatmapSet?.IsManaged == true)
|
||||
beatmapSet = beatmapSet.Detach();
|
||||
|
||||
// todo: probably not required any more.
|
||||
// foreach (var b in beatmapSet.Beatmaps)
|
||||
// b.Metadata ??= beatmapSet.Metadata;
|
||||
|
|
Loading…
Reference in New Issue