// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; using osu.Framework.Development; using Realms; #nullable enable namespace osu.Game.Database { /// /// Provides a method of working with realm objects over longer application lifetimes. /// /// The underlying object type. public class RealmLive : ILive where T : RealmObject, IHasGuidPrimaryKey { public Guid ID { get; } public bool IsManaged => data.IsManaged; /// /// The original live data used to create this instance. /// private readonly T data; private readonly RealmContextFactory realmFactory; /// /// Construct a new instance of live realm data. /// /// The realm data. /// The realm factory the data was sourced from. May be null for an unmanaged object. public RealmLive(T data, RealmContextFactory realmFactory) { this.data = data; this.realmFactory = realmFactory; ID = data.ID; } /// /// Perform a read operation on this live object. /// /// The action to perform. public void PerformRead(Action perform) { if (!IsManaged) { perform(data); return; } using (var realm = realmFactory.CreateContext()) perform(realm.Find(ID)); } /// /// Perform a read operation on this live object. /// /// The action to perform. public TReturn PerformRead(Func perform) { 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); using (var realm = realmFactory.CreateContext()) return perform(realm.Find(ID)); } /// /// Perform a write operation on this live object. /// /// The action to perform. public void PerformWrite(Action perform) { if (!IsManaged) throw new InvalidOperationException(@"Can't perform writes on a non-managed underlying value"); PerformRead(t => { var transaction = t.Realm.BeginWrite(); perform(t); transaction.Commit(); }); } public T Value { get { if (!IsManaged) return data; if (!ThreadSafety.IsUpdateThread) throw new InvalidOperationException($"Can't use {nameof(Value)} on managed objects from non-update threads"); return realmFactory.Context.Find(ID); } } public bool Equals(ILive? other) => ID == other?.ID; public override string ToString() => PerformRead(i => i.ToString()); } }