<commit_before>// Copyright (c) ppy Pty Ltd <<EMAIL>>. 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
{
    /// <summary>
    /// 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 Guid ID { get; }

        public bool IsManaged => data.IsManaged;

        /// <summary>
        /// The original live data used to create this instance.
        /// </summary>
        private readonly T data;

        private readonly RealmContextFactory realmFactory;

        /// <summary>
        /// Construct a new instance of live realm data.
        /// </summary>
        /// <param name="data">The realm data.</param>
        /// <param name="realmFactory">The realm factory the data was sourced from. May be null for an unmanaged object.</param>
        public RealmLive(T data, RealmContextFactory realmFactory)
        {
            this.data = data;
            this.realmFactory = realmFactory;

            ID = data.ID;
        }

        /// <summary>
        /// Perform a read operation on this live object.
        /// </summary>
        /// <param name="perform">The action to perform.</param>
        public void PerformRead(Action<T> perform)
        {
            if (!IsManaged)
            {
                perform(data);
                return;
            }

            using (var realm = realmFactory.CreateContext())
                perform(realm.Find<T>(ID));
        }

        /// <summary>
        /// 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)
        {
            // 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);

            using (var realm = realmFactory.CreateContext())
                return perform(realm.Find<T>(ID));
        }

        /// <summary>
        /// Perform a write operation on this live object.
        /// </summary>
        /// <param name="perform">The action to perform.</param>
        public void PerformWrite(Action<T> 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
            {<commit_msg>Add back `PerformRead` return safety by checking `IsManaged` status of returned data<commit_after>// Copyright (c) ppy Pty Ltd <<EMAIL>>. 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
{
    /// <summary>
    /// 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 Guid ID { get; }

        public bool IsManaged => data.IsManaged;

        /// <summary>
        /// The original live data used to create this instance.
        /// </summary>
        private readonly T data;

        private readonly RealmContextFactory realmFactory;

        /// <summary>
        /// Construct a new instance of live realm data.
        /// </summary>
        /// <param name="data">The realm data.</param>
        /// <param name="realmFactory">The realm factory the data was sourced from. May be null for an unmanaged object.</param>
        public RealmLive(T data, RealmContextFactory realmFactory)
        {
            this.data = data;
            this.realmFactory = realmFactory;

            ID = data.ID;
        }

        /// <summary>
        /// Perform a read operation on this live object.
        /// </summary>
        /// <param name="perform">The action to perform.</param>
        public void PerformRead(Action<T> perform)
        {
            if (!IsManaged)
            {
                perform(data);
                return;
            }

            using (var realm = realmFactory.CreateContext())
                perform(realm.Find<T>(ID));
        }

        /// <summary>
        /// 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)
        {
            if (!IsManaged)
                return perform(data);

            using (var realm = realmFactory.CreateContext())
            {
                var returnData = perform(realm.Find<T>(ID));

                if (returnData is RealmObjectBase realmObject && realmObject.IsManaged)
                    throw new InvalidOperationException(@$"Managed realm objects should not exit the scope of {nameof(PerformRead)}.");

                return returnData;
            }
        }

        /// <summary>
        /// Perform a write operation on this live object.
        /// </summary>
        /// <param name="perform">The action to perform.</param>
        public void PerformWrite(Action<T> 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
            {
{'fraction_non_alphanumeric': 0.1081293157564344, 'fraction_numerical': 0.0, 'mean_word_length': 1.7328473413379073, 'pattern_counts': {'":': 0, '<': 71, '<?xml version=': 0, '>': 75, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6790590', 'n_tokens_mistral': 1630, 'n_tokens_neox': 1574, 'n_words': 514}