Remove ILive<> interface (and use abstract Live<> instead)

This commit is contained in:
Dean Herbert
2022-01-26 13:37:33 +09:00
parent d37c3c463e
commit cd71ec0edd
20 changed files with 108 additions and 108 deletions

View File

@ -16,9 +16,9 @@ namespace osu.Game.Database
/// </summary>
/// <typeparam name="TModel">The model type.</typeparam>
public interface IModelImporter<TModel> : IPostNotifications, IPostImports<TModel>, ICanAcceptFiles
where TModel : class
where TModel : class, IHasGuidPrimaryKey
{
Task<IEnumerable<ILive<TModel>>> Import(ProgressNotification notification, params ImportTask[] tasks);
Task<IEnumerable<Live<TModel>>> Import(ProgressNotification notification, params ImportTask[] tasks);
/// <summary>
/// Import one <typeparamref name="TModel"/> from the filesystem and delete the file on success.
@ -28,7 +28,7 @@ namespace osu.Game.Database
/// <param name="lowPriority">Whether this is a low priority import.</param>
/// <param name="cancellationToken">An optional cancellation token.</param>
/// <returns>The imported model, if successful.</returns>
Task<ILive<TModel>?> Import(ImportTask task, bool lowPriority = false, CancellationToken cancellationToken = default);
Task<Live<TModel>?> Import(ImportTask task, bool lowPriority = false, CancellationToken cancellationToken = default);
/// <summary>
/// Silently import an item from an <see cref="ArchiveReader"/>.
@ -36,7 +36,7 @@ namespace osu.Game.Database
/// <param name="archive">The archive to be imported.</param>
/// <param name="lowPriority">Whether this is a low priority import.</param>
/// <param name="cancellationToken">An optional cancellation token.</param>
Task<ILive<TModel>?> Import(ArchiveReader archive, bool lowPriority = false, CancellationToken cancellationToken = default);
Task<Live<TModel>?> Import(ArchiveReader archive, bool lowPriority = false, CancellationToken cancellationToken = default);
/// <summary>
/// Silently import an item from a <typeparamref name="TModel"/>.
@ -45,7 +45,7 @@ namespace osu.Game.Database
/// <param name="archive">An optional archive to use for model population.</param>
/// <param name="lowPriority">Whether this is a low priority import.</param>
/// <param name="cancellationToken">An optional cancellation token.</param>
ILive<TModel>? Import(TModel item, ArchiveReader? archive = null, bool lowPriority = false, CancellationToken cancellationToken = default);
Live<TModel>? Import(TModel item, ArchiveReader? archive = null, bool lowPriority = false, CancellationToken cancellationToken = default);
/// <summary>
/// A user displayable name for the model type associated with this manager.

View File

@ -9,11 +9,11 @@ using System.Collections.Generic;
namespace osu.Game.Database
{
public interface IPostImports<TModel>
where TModel : class
where TModel : class, IHasGuidPrimaryKey
{
/// <summary>
/// Fired when the user requests to view the resulting import.
/// </summary>
public Action<IEnumerable<ILive<TModel>>>? PostImport { set; }
public Action<IEnumerable<Live<TModel>>>? PostImport { set; }
}
}

View File

@ -14,7 +14,7 @@ namespace osu.Game.Database
/// A class which handles importing legacy user data of a single type from osu-stable.
/// </summary>
public abstract class LegacyModelImporter<TModel>
where TModel : class
where TModel : class, IHasGuidPrimaryKey
{
/// <summary>
/// The relative path from osu-stable's data directory to import items from.

View File

@ -3,39 +3,41 @@
using System;
#nullable enable
namespace osu.Game.Database
{
/// <summary>
/// A wrapper to provide access to database backed classes in a thread-safe manner.
/// </summary>
/// <typeparam name="T">The databased type.</typeparam>
public interface ILive<T> : IEquatable<ILive<T>>
where T : class // TODO: Add IHasGuidPrimaryKey once we don't need EF support any more.
public abstract class Live<T> : IEquatable<Live<T>>
where T : class, IHasGuidPrimaryKey
{
Guid ID { get; }
public Guid ID { get; }
/// <summary>
/// Perform a read operation on this live object.
/// </summary>
/// <param name="perform">The action to perform.</param>
void PerformRead(Action<T> perform);
public abstract void PerformRead(Action<T> perform);
/// <summary>
/// Perform a read operation on this live object.
/// </summary>
/// <param name="perform">The action to perform.</param>
TReturn PerformRead<TReturn>(Func<T, TReturn> perform);
public abstract TReturn PerformRead<TReturn>(Func<T, TReturn> perform);
/// <summary>
/// Perform a write operation on this live object.
/// </summary>
/// <param name="perform">The action to perform.</param>
void PerformWrite(Action<T> perform);
public abstract void PerformWrite(Action<T> perform);
/// <summary>
/// Whether this instance is tracking data which is managed by the database backing.
/// </summary>
bool IsManaged { get; }
public abstract bool IsManaged { get; }
/// <summary>
/// Resolve the value of this instance on the update thread.
@ -43,6 +45,15 @@ namespace osu.Game.Database
/// <remarks>
/// After resolving, the data should not be passed between threads.
/// </remarks>
T Value { get; }
public abstract T Value { get; }
protected Live(Guid id)
{
ID = id;
}
public bool Equals(Live<T>? other) => ID == other?.ID;
public override string ToString() => PerformRead(i => i.ToString());
}
}

View File

@ -15,11 +15,9 @@ namespace osu.Game.Database
/// Provides a method of working with realm objects over longer application lifetimes.
/// </summary>
/// <typeparam name="T">The underlying object type.</typeparam>
public class RealmLive<T> : ILive<T> where T : RealmObject, IHasGuidPrimaryKey
public class RealmLive<T> : Live<T> where T : RealmObject, IHasGuidPrimaryKey
{
public Guid ID { get; }
public bool IsManaged => data.IsManaged;
public override bool IsManaged => data.IsManaged;
/// <summary>
/// The original live data used to create this instance.
@ -36,11 +34,11 @@ namespace osu.Game.Database
/// <param name="data">The realm data.</param>
/// <param name="realm">The realm factory the data was sourced from. May be null for an unmanaged object.</param>
public RealmLive(T data, RealmAccess realm)
: base(data.ID)
{
this.data = data;
this.realm = realm;
ID = data.ID;
dataIsFromUpdateThread = ThreadSafety.IsUpdateThread;
}
@ -48,7 +46,7 @@ namespace osu.Game.Database
/// Perform a read operation on this live object.
/// </summary>
/// <param name="perform">The action to perform.</param>
public void PerformRead(Action<T> perform)
public override void PerformRead(Action<T> perform)
{
if (!IsManaged)
{
@ -74,7 +72,7 @@ namespace osu.Game.Database
/// Perform a read operation on this live object.
/// </summary>
/// <param name="perform">The action to perform.</param>
public TReturn PerformRead<TReturn>(Func<T, TReturn> perform)
public override TReturn PerformRead<TReturn>(Func<T, TReturn> perform)
{
if (!IsManaged)
return perform(data);
@ -101,7 +99,7 @@ namespace osu.Game.Database
/// Perform a write operation on this live object.
/// </summary>
/// <param name="perform">The action to perform.</param>
public void PerformWrite(Action<T> perform)
public override void PerformWrite(Action<T> perform)
{
if (!IsManaged)
throw new InvalidOperationException(@"Can't perform writes on a non-managed underlying value");
@ -115,7 +113,7 @@ namespace osu.Game.Database
});
}
public T Value
public override T Value
{
get
{
@ -160,10 +158,6 @@ namespace osu.Game.Database
return found;
}
public bool Equals(ILive<T>? other) => ID == other?.ID;
public override string ToString() => PerformRead(i => i.ToString());
}
internal static class RealmLiveStatistics

View File

@ -13,13 +13,19 @@ namespace osu.Game.Database
/// Usually used for testing purposes where the instance is never required to be managed.
/// </summary>
/// <typeparam name="T">The underlying object type.</typeparam>
public class RealmLiveUnmanaged<T> : ILive<T> where T : RealmObjectBase, IHasGuidPrimaryKey
public class RealmLiveUnmanaged<T> : Live<T> where T : RealmObjectBase, IHasGuidPrimaryKey
{
/// <summary>
/// The original live data used to create this instance.
/// </summary>
public override T Value { get; }
/// <summary>
/// Construct a new instance of live realm data.
/// </summary>
/// <param name="data">The realm data.</param>
public RealmLiveUnmanaged(T data)
: base(data.ID)
{
if (data.IsManaged)
throw new InvalidOperationException($"Cannot use {nameof(RealmLiveUnmanaged<T>)} with managed instances");
@ -27,23 +33,12 @@ namespace osu.Game.Database
Value = data;
}
public bool Equals(ILive<T>? other) => ID == other?.ID;
public override void PerformRead(Action<T> perform) => perform(Value);
public override string ToString() => Value.ToString();
public override TReturn PerformRead<TReturn>(Func<T, TReturn> perform) => perform(Value);
public Guid ID => Value.ID;
public override void PerformWrite(Action<T> perform) => throw new InvalidOperationException(@"Can't perform writes on a non-managed underlying value");
public void PerformRead(Action<T> perform) => perform(Value);
public TReturn PerformRead<TReturn>(Func<T, TReturn> perform) => perform(Value);
public void PerformWrite(Action<T> perform) => throw new InvalidOperationException(@"Can't perform writes on a non-managed underlying value");
public bool IsManaged => false;
/// <summary>
/// The original live data used to create this instance.
/// </summary>
public T Value { get; }
public override bool IsManaged => false;
}
}

View File

@ -204,25 +204,25 @@ namespace osu.Game.Database
private static void copyChangesToRealm<T>(T source, T destination) where T : RealmObjectBase
=> write_mapper.Map(source, destination);
public static List<ILive<T>> ToLiveUnmanaged<T>(this IEnumerable<T> realmList)
public static List<Live<T>> ToLiveUnmanaged<T>(this IEnumerable<T> realmList)
where T : RealmObject, IHasGuidPrimaryKey
{
return realmList.Select(l => new RealmLiveUnmanaged<T>(l)).Cast<ILive<T>>().ToList();
return realmList.Select(l => new RealmLiveUnmanaged<T>(l)).Cast<Live<T>>().ToList();
}
public static ILive<T> ToLiveUnmanaged<T>(this T realmObject)
public static Live<T> ToLiveUnmanaged<T>(this T realmObject)
where T : RealmObject, IHasGuidPrimaryKey
{
return new RealmLiveUnmanaged<T>(realmObject);
}
public static List<ILive<T>> ToLive<T>(this IEnumerable<T> realmList, RealmAccess realm)
public static List<Live<T>> ToLive<T>(this IEnumerable<T> realmList, RealmAccess realm)
where T : RealmObject, IHasGuidPrimaryKey
{
return realmList.Select(l => new RealmLive<T>(l, realm)).Cast<ILive<T>>().ToList();
return realmList.Select(l => new RealmLive<T>(l, realm)).Cast<Live<T>>().ToList();
}
public static ILive<T> ToLive<T>(this T realmObject, RealmAccess realm)
public static Live<T> ToLive<T>(this T realmObject, RealmAccess realm)
where T : RealmObject, IHasGuidPrimaryKey
{
return new RealmLive<T>(realmObject, realm);