Skip to content

Commit

Permalink
Implement .As<T>, add some notification tests
Browse files Browse the repository at this point in the history
  • Loading branch information
nirinchev committed Jul 1, 2024
1 parent 6c02a12 commit 7b5d834
Show file tree
Hide file tree
Showing 3 changed files with 225 additions and 11 deletions.
21 changes: 15 additions & 6 deletions Realm/Realm/DatabaseTypes/RealmValue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -789,13 +789,17 @@ public T AsRealmObject<T>()
where T : class, IRealmObjectBase
=> Type == RealmValueType.Null ? null : AsRealmObject<T>();

// TODO (ni): add docs

Check warning on line 792 in Realm/Realm/DatabaseTypes/RealmValue.cs

View workflow job for this annotation

GitHub Actions / Verify TODOs

Realm/Realm/DatabaseTypes/RealmValue.cs#L792

TODO entry doesn't have a link to Github issue or Jira ticket ni): add docs
public T AsMappedObject<T>()

Check warning on line 793 in Realm/Realm/DatabaseTypes/RealmValue.cs

View workflow job for this annotation

GitHub Actions / Test Weaver (ubuntu-latest, linux-x64)

Check warning on line 793 in Realm/Realm/DatabaseTypes/RealmValue.cs

View workflow job for this annotation

GitHub Actions / Test Weaver (ubuntu-latest, linux-x64)

Check warning on line 793 in Realm/Realm/DatabaseTypes/RealmValue.cs

View workflow job for this annotation

GitHub Actions / Test Weaver (macos-14, osx-arm64)

Check warning on line 793 in Realm/Realm/DatabaseTypes/RealmValue.cs

View workflow job for this annotation

GitHub Actions / Test Weaver (macos-14, osx-arm64)

Check warning on line 793 in Realm/Realm/DatabaseTypes/RealmValue.cs

View workflow job for this annotation

GitHub Actions / Test Source Generation

Check warning on line 793 in Realm/Realm/DatabaseTypes/RealmValue.cs

View workflow job for this annotation

GitHub Actions / Package NuGet

Check warning on line 793 in Realm/Realm/DatabaseTypes/RealmValue.cs

View workflow job for this annotation

GitHub Actions / Package NuGet

Check warning on line 793 in Realm/Realm/DatabaseTypes/RealmValue.cs

View workflow job for this annotation

GitHub Actions / Package NuGet

Check warning on line 793 in Realm/Realm/DatabaseTypes/RealmValue.cs

View workflow job for this annotation

GitHub Actions / Test Weaver (windows-latest, win-x64)

Check warning on line 793 in Realm/Realm/DatabaseTypes/RealmValue.cs

View workflow job for this annotation

GitHub Actions / Test Weaver (windows-latest, win-x64)

Check warning on line 793 in Realm/Realm/DatabaseTypes/RealmValue.cs

View workflow job for this annotation

GitHub Actions / Test Weaver (windows-latest, win-x64)

Check warning on line 793 in Realm/Realm/DatabaseTypes/RealmValue.cs

View workflow job for this annotation

GitHub Actions / Analyze C#

Check warning on line 793 in Realm/Realm/DatabaseTypes/RealmValue.cs

View workflow job for this annotation

GitHub Actions / Analyze C#

Check warning on line 793 in Realm/Realm/DatabaseTypes/RealmValue.cs

View workflow job for this annotation

GitHub Actions / Analyze C#

Check warning on line 793 in Realm/Realm/DatabaseTypes/RealmValue.cs

View workflow job for this annotation

GitHub Actions / Test Code Coverage

Elements should be documented (https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1600.md) [/home/runner/work/realm-dotnet/realm-dotnet/Realm/Realm/Realm.csproj::TargetFramework=net8.0]
where T : class, IMappedObject
{
EnsureType("dictionary", RealmValueType.Dictionary);
throw new NotImplementedException();
var result = Activator.CreateInstance<T>();
result.SetBackingStorage(_dictionaryValue!);
return result;
}

// TODO (ni): add docs

Check warning on line 802 in Realm/Realm/DatabaseTypes/RealmValue.cs

View workflow job for this annotation

GitHub Actions / Verify TODOs

Realm/Realm/DatabaseTypes/RealmValue.cs#L802

TODO entry doesn't have a link to Github issue or Jira ticket ni): add docs
public T? AsNullableMappedObject<T>()

Check warning on line 803 in Realm/Realm/DatabaseTypes/RealmValue.cs

View workflow job for this annotation

GitHub Actions / Test Weaver (ubuntu-latest, linux-x64)

Check warning on line 803 in Realm/Realm/DatabaseTypes/RealmValue.cs

View workflow job for this annotation

GitHub Actions / Test Weaver (ubuntu-latest, linux-x64)

Check warning on line 803 in Realm/Realm/DatabaseTypes/RealmValue.cs

View workflow job for this annotation

GitHub Actions / Test Weaver (macos-14, osx-arm64)

Check warning on line 803 in Realm/Realm/DatabaseTypes/RealmValue.cs

View workflow job for this annotation

GitHub Actions / Test Weaver (macos-14, osx-arm64)

Check warning on line 803 in Realm/Realm/DatabaseTypes/RealmValue.cs

View workflow job for this annotation

GitHub Actions / Test Source Generation

Check warning on line 803 in Realm/Realm/DatabaseTypes/RealmValue.cs

View workflow job for this annotation

GitHub Actions / Package NuGet

Check warning on line 803 in Realm/Realm/DatabaseTypes/RealmValue.cs

View workflow job for this annotation

GitHub Actions / Package NuGet

Check warning on line 803 in Realm/Realm/DatabaseTypes/RealmValue.cs

View workflow job for this annotation

GitHub Actions / Test Weaver (windows-latest, win-x64)

Check warning on line 803 in Realm/Realm/DatabaseTypes/RealmValue.cs

View workflow job for this annotation

GitHub Actions / Test Weaver (windows-latest, win-x64)

Check warning on line 803 in Realm/Realm/DatabaseTypes/RealmValue.cs

View workflow job for this annotation

GitHub Actions / Analyze C#

Check warning on line 803 in Realm/Realm/DatabaseTypes/RealmValue.cs

View workflow job for this annotation

GitHub Actions / Analyze C#

Check warning on line 803 in Realm/Realm/DatabaseTypes/RealmValue.cs

View workflow job for this annotation

GitHub Actions / Test Code Coverage

Elements should be documented (https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1600.md) [/home/runner/work/realm-dotnet/realm-dotnet/Realm/Realm/Realm.csproj::TargetFramework=net8.0]
where T : class, IMappedObject
=> Type == RealmValueType.Null ? null : AsMappedObject<T>();
Expand All @@ -815,12 +819,17 @@ public T As<T>()

if (typeof(IMappedObject).IsAssignableFrom(typeof(T)))
{
return Type switch
switch (Type)
{
RealmValueType.Null => Operator.Convert<T>(null)!,
RealmValueType.Dictionary => throw new NotImplementedException(),
_ => throw new NotSupportedException($"Can't convert from {Type} to dictionary, which is the backing storage type for {typeof(T)}"),
};
case RealmValueType.Null:
return Operator.Convert<T>(null)!;
case RealmValueType.Dictionary:
var result = Activator.CreateInstance<T>()!;
((IMappedObject)result).SetBackingStorage(_dictionaryValue!);
return result;
default:
throw new InvalidCastException($"Can't convert from {Type} to dictionary, which is the backing storage type for {typeof(T)}");
}
}

// This largely copies AsAny to avoid boxing the underlying value in an object
Expand Down
9 changes: 9 additions & 0 deletions Realm/Realm/Extensions/CollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,15 @@ public static async Task<IQueryable<T>> SubscribeAsync<T>(this IQueryable<T> que
return query;
}

// TODO (ni): add docs

Check warning on line 560 in Realm/Realm/Extensions/CollectionExtensions.cs

View workflow job for this annotation

GitHub Actions / Verify TODOs

Realm/Realm/Extensions/CollectionExtensions.cs#L560

TODO entry doesn't have a link to Github issue or Jira ticket ni): add docs
public static T As<T>(this IDictionary<string, RealmValue> dict)

Check warning on line 561 in Realm/Realm/Extensions/CollectionExtensions.cs

View workflow job for this annotation

GitHub Actions / Test Weaver (ubuntu-latest, linux-x64)

Check warning on line 561 in Realm/Realm/Extensions/CollectionExtensions.cs

View workflow job for this annotation

GitHub Actions / Test Weaver (ubuntu-latest, linux-x64)

Check warning on line 561 in Realm/Realm/Extensions/CollectionExtensions.cs

View workflow job for this annotation

GitHub Actions / Test Weaver (ubuntu-latest, linux-x64)

Check warning on line 561 in Realm/Realm/Extensions/CollectionExtensions.cs

View workflow job for this annotation

GitHub Actions / Test Weaver (macos-14, osx-arm64)

Check warning on line 561 in Realm/Realm/Extensions/CollectionExtensions.cs

View workflow job for this annotation

GitHub Actions / Test Weaver (macos-14, osx-arm64)

Check warning on line 561 in Realm/Realm/Extensions/CollectionExtensions.cs

View workflow job for this annotation

GitHub Actions / Test Weaver (macos-14, osx-arm64)

Check warning on line 561 in Realm/Realm/Extensions/CollectionExtensions.cs

View workflow job for this annotation

GitHub Actions / Test Source Generation

Check warning on line 561 in Realm/Realm/Extensions/CollectionExtensions.cs

View workflow job for this annotation

GitHub Actions / Package NuGet

Check warning on line 561 in Realm/Realm/Extensions/CollectionExtensions.cs

View workflow job for this annotation

GitHub Actions / Package NuGet

Check warning on line 561 in Realm/Realm/Extensions/CollectionExtensions.cs

View workflow job for this annotation

GitHub Actions / Test Weaver (windows-latest, win-x64)

Check warning on line 561 in Realm/Realm/Extensions/CollectionExtensions.cs

View workflow job for this annotation

GitHub Actions / Test Weaver (windows-latest, win-x64)

Check warning on line 561 in Realm/Realm/Extensions/CollectionExtensions.cs

View workflow job for this annotation

GitHub Actions / Test Weaver (windows-latest, win-x64)

Check warning on line 561 in Realm/Realm/Extensions/CollectionExtensions.cs

View workflow job for this annotation

GitHub Actions / Analyze C#

Check warning on line 561 in Realm/Realm/Extensions/CollectionExtensions.cs

View workflow job for this annotation

GitHub Actions / Analyze C#

Check warning on line 561 in Realm/Realm/Extensions/CollectionExtensions.cs

View workflow job for this annotation

GitHub Actions / Test Code Coverage

Elements should be documented (https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1600.md) [/home/runner/work/realm-dotnet/realm-dotnet/Realm/Realm/Realm.csproj::TargetFramework=net8.0]
where T : IMappedObject
{
var result = Activator.CreateInstance<T>();
result.SetBackingStorage(dict);
return result;
}

[EditorBrowsable(EditorBrowsableState.Never)]
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented",
Justification = "This is only used by the weaver/source generated classes and should not be exposed to users.")]
Expand Down
206 changes: 201 additions & 5 deletions Tests/Realm.Tests/Database/FlexibleSchemaPocTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@
//
////////////////////////////////////////////////////////////////////////////

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using NUnit.Framework;

namespace Realms.Tests.Database;
Expand All @@ -26,15 +29,45 @@ namespace Realms.Tests.Database;
public partial class FlexibleSchemaPocTests : RealmInstanceTest
{
[Test]
public void ConvertDictionary_ToMappedType()
public void RealmValue_AsMappedType_ReturnsCorrectObject()
{
// TODO: NI to get this to work
AddData();

var dogContainer = _realm.All<FlexibleSchemaPocContainer>().First(c => c.ContainedObjectType == nameof(Dog));

var dog = dogContainer.MixedProperty.As<Dog>();
// var dogFromDict = dogContainer.MixedDict.As<Dog>();

// TODO: add assertions for the values

Check warning on line 40 in Tests/Realm.Tests/Database/FlexibleSchemaPocTests.cs

View workflow job for this annotation

GitHub Actions / Verify TODOs

Tests/Realm.Tests/Database/FlexibleSchemaPocTests.cs#L40

TODO entry doesn't have a link to Github issue or Jira ticket add assertions for the values
Assert.That(dog, Is.TypeOf<Dog>());

var dog2 = dogContainer.MixedProperty.AsMappedObject<Dog>();

// TODO: add assertions for the values

Check warning on line 45 in Tests/Realm.Tests/Database/FlexibleSchemaPocTests.cs

View workflow job for this annotation

GitHub Actions / Verify TODOs

Tests/Realm.Tests/Database/FlexibleSchemaPocTests.cs#L45

TODO entry doesn't have a link to Github issue or Jira ticket add assertions for the values
Assert.That(dog2, Is.TypeOf<Dog>());

var nullContainer = _realm.Write(() => _realm.Add(new FlexibleSchemaPocContainer("null")
{
MixedProperty = RealmValue.Null
}));

var nullDog = nullContainer.MixedProperty.As<Dog?>();
Assert.That(nullDog, Is.Null);

var nullDog2 = nullContainer.MixedProperty.AsNullableMappedObject<Dog>();
Assert.That(nullDog2, Is.Null);
}

[Test]
public void RealmValue_AsMappedType_WhenTypeIsIncorrect_Throws()
{
var intContainer = _realm.Write(() => _realm.Add(new FlexibleSchemaPocContainer("int")
{
MixedProperty = 5
}));

Assert.Throws<InvalidCastException>(() => intContainer.MixedProperty.As<Dog>());
Assert.Throws<InvalidCastException>(() => intContainer.MixedProperty.AsMappedObject<Dog>());
Assert.Throws<InvalidCastException>(() => intContainer.MixedProperty.AsNullableMappedObject<Dog>());
}

[Test]
Expand All @@ -59,6 +92,43 @@ public void AccessMappedTypeProperties_ReadsValuesFromBackingStorage()
Assert.That(bird.CanFly, Is.True);
}

[Test]
public void NotifyPropertyChanged_NotifiesForModifications()
{
AddData();

var dogContainer = _realm.All<FlexibleSchemaPocContainer>().First(c => c.ContainedObjectType == nameof(Dog));

var dog = dogContainer.MixedProperty.As<Dog>();
var changes = new List<PropertyChangedEventArgs>();
dog.PropertyChanged += (s, e) =>
{
Assert.That(s, Is.EqualTo(dog));
changes.Add(e);
};

_realm.Write(() =>
{
dogContainer.MixedProperty.AsDictionary()[nameof(Dog.BarkCount)] = 10;
});

_realm.Refresh();

Assert.That(changes.Count, Is.EqualTo(1));
Assert.That(changes[0].PropertyName, Is.EqualTo(nameof(Dog.BarkCount)));

_realm.Write(() =>
{
dogContainer.MixedProperty.AsDictionary()[nameof(Dog.BarkCount)] = 15;
dogContainer.MixedProperty.AsDictionary()[nameof(Dog.Name)] = "Fido III";
});
_realm.Refresh();

Assert.That(changes.Count, Is.EqualTo(3));
Assert.That(changes[1].PropertyName, Is.EqualTo(nameof(Dog.BarkCount)));
Assert.That(changes[2].PropertyName, Is.EqualTo(nameof(Dog.Name)));
}

private void AddData()
{
_realm.Write(() =>
Expand Down Expand Up @@ -115,14 +185,77 @@ public partial class Dog : IMappedObject
}

// Generated
public partial class Dog
public partial class Dog : INotifyPropertyChanged
{
private IDictionary<string, RealmValue> _backingStorage = null!;

public void SetBackingStorage(IDictionary<string, RealmValue> dictionary)
{
_backingStorage = dictionary;
}

#region INotifyPropertyChanged

private IDisposable? _notificationToken;

private event PropertyChangedEventHandler? _propertyChanged;

/// <inheritdoc />
public event PropertyChangedEventHandler? PropertyChanged
{
add
{
if (_propertyChanged == null)
{
SubscribeForNotifications();
}

_propertyChanged += value;
}

remove
{
_propertyChanged -= value;

if (_propertyChanged == null)
{
UnsubscribeFromNotifications();
}
}
}

partial void OnPropertyChanged(string? propertyName);

private void RaisePropertyChanged([CallerMemberName] string propertyName = "")
{
_propertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
OnPropertyChanged(propertyName);
}

private void SubscribeForNotifications()
{
_notificationToken = _backingStorage.SubscribeForKeyNotifications((sender, changes) =>
{
if (changes == null)
{
return;
}
foreach (var key in changes.ModifiedKeys)
{
RaisePropertyChanged(key);
}
// TODO: what do we do with deleted/inserted keys

Check warning on line 249 in Tests/Realm.Tests/Database/FlexibleSchemaPocTests.cs

View workflow job for this annotation

GitHub Actions / Verify TODOs

Tests/Realm.Tests/Database/FlexibleSchemaPocTests.cs#L249

TODO entry doesn't have a link to Github issue or Jira ticket what do we do with deleted/inserted keys
});
}

private void UnsubscribeFromNotifications()
{
_notificationToken?.Dispose();
}

#endregion
}

// User-defined
Expand All @@ -134,13 +267,76 @@ public partial class Bird : IMappedObject
}

// Generated
public partial class Bird
public partial class Bird : INotifyPropertyChanged
{
private IDictionary<string, RealmValue> _backingStorage = null!;

public void SetBackingStorage(IDictionary<string, RealmValue> dictionary)
{
_backingStorage = dictionary;
}

#region INotifyPropertyChanged

private IDisposable? _notificationToken;

private event PropertyChangedEventHandler? _propertyChanged;

/// <inheritdoc />
public event PropertyChangedEventHandler? PropertyChanged
{
add
{
if (_propertyChanged == null)
{
SubscribeForNotifications();
}

_propertyChanged += value;
}

remove
{
_propertyChanged -= value;

if (_propertyChanged == null)
{
UnsubscribeFromNotifications();
}
}
}

partial void OnPropertyChanged(string? propertyName);

private void RaisePropertyChanged([CallerMemberName] string propertyName = "")
{
_propertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
OnPropertyChanged(propertyName);
}

private void SubscribeForNotifications()
{
_notificationToken = _backingStorage.SubscribeForKeyNotifications((sender, changes) =>
{
if (changes == null)
{
return;
}
foreach (var key in changes.ModifiedKeys)
{
RaisePropertyChanged(key);
}
// TODO: what do we do with deleted/inserted keys

Check warning on line 331 in Tests/Realm.Tests/Database/FlexibleSchemaPocTests.cs

View workflow job for this annotation

GitHub Actions / Verify TODOs

Tests/Realm.Tests/Database/FlexibleSchemaPocTests.cs#L331

TODO entry doesn't have a link to Github issue or Jira ticket what do we do with deleted/inserted keys
});
}

private void UnsubscribeFromNotifications()
{
_notificationToken?.Dispose();
}

#endregion
}
}

0 comments on commit 7b5d834

Please sign in to comment.