From 49e020056e6024ab407967cfec43776a24258e7d Mon Sep 17 00:00:00 2001
From: Ferdinando Papale <4850119+papafe@users.noreply.github.com>
Date: Tue, 5 Sep 2023 14:00:39 +0200
Subject: [PATCH 01/88] Added stub
---
Realm/Realm/DatabaseTypes/RealmValue.cs | 6 ++++++
Realm/Realm/DatabaseTypes/RealmValueType.cs | 15 +++++++++++++++
Realm/Realm/Extensions/CollectionExtensions.cs | 8 +++++---
.../Benchmarks.Android/Benchmarks.Android.csproj | 2 +-
4 files changed, 27 insertions(+), 4 deletions(-)
diff --git a/Realm/Realm/DatabaseTypes/RealmValue.cs b/Realm/Realm/DatabaseTypes/RealmValue.cs
index 5f37c939b7..85bc00ec86 100644
--- a/Realm/Realm/DatabaseTypes/RealmValue.cs
+++ b/Realm/Realm/DatabaseTypes/RealmValue.cs
@@ -18,6 +18,7 @@
using System;
using System.Buffers;
+using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
@@ -813,6 +814,11 @@ public override int GetHashCode()
}
}
+ public static RealmValue List(IList list)
+ {
+
+ }
+
///
/// Converts a to . Equivalent to .
///
diff --git a/Realm/Realm/DatabaseTypes/RealmValueType.cs b/Realm/Realm/DatabaseTypes/RealmValueType.cs
index c416932927..d1069d6b48 100644
--- a/Realm/Realm/DatabaseTypes/RealmValueType.cs
+++ b/Realm/Realm/DatabaseTypes/RealmValueType.cs
@@ -93,5 +93,20 @@ public enum RealmValueType : byte
/// The value represents a .
///
Guid,
+
+ ///
+ /// The value represents a .
+ ///
+ List,
+
+ ///
+ /// The value represents a .
+ ///
+ Set,
+
+ ///
+ /// The value represents a .
+ ///
+ Dictionary,
}
}
diff --git a/Realm/Realm/Extensions/CollectionExtensions.cs b/Realm/Realm/Extensions/CollectionExtensions.cs
index af2770d543..c68821554b 100644
--- a/Realm/Realm/Extensions/CollectionExtensions.cs
+++ b/Realm/Realm/Extensions/CollectionExtensions.cs
@@ -551,12 +551,14 @@ public static async Task> SubscribeAsync(this IQueryable que
}
[EditorBrowsable(EditorBrowsableState.Never)]
- [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "This is only used by the weaver and should not be exposed to users.")]
+ [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.")]
public static void PopulateCollection(ICollection source, ICollection target, bool update, bool skipDefaults)
=> PopulateCollectionCore(source, target, update, skipDefaults, value => value);
[EditorBrowsable(EditorBrowsableState.Never)]
- [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "This is only used by the weaver and should not be exposed to users.")]
+ [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.")]
public static void PopulateCollection(IDictionary source, IDictionary target, bool update, bool skipDefaults)
=> PopulateCollectionCore(source, target, update, skipDefaults, kvp => kvp.Value);
@@ -583,7 +585,7 @@ private static void PopulateCollectionCore(ICollection? source, ICollectio
{
Argument.NotNull(target, nameof(target));
- if (!skipDefaults || source != null)
+ if (!skipDefaults || source != null) //TODO Need to check what skipDefaults does
{
target.Clear();
}
diff --git a/Tests/Benchmarks/Benchmarks.Android/Benchmarks.Android.csproj b/Tests/Benchmarks/Benchmarks.Android/Benchmarks.Android.csproj
index 19567ca866..dc7c2eca95 100644
--- a/Tests/Benchmarks/Benchmarks.Android/Benchmarks.Android.csproj
+++ b/Tests/Benchmarks/Benchmarks.Android/Benchmarks.Android.csproj
@@ -79,7 +79,7 @@
- {BA9ED757-BBE5-486F-BE4A-8D5542504030}
+ {BECF4F60-9741-49A6-BD79-D59664C2682E}
Benchmarks
From 572704f7f561ceaeb4754ab88f5e766352fc2336 Mon Sep 17 00:00:00 2001
From: Ferdinando Papale <4850119+papafe@users.noreply.github.com>
Date: Tue, 5 Sep 2023 15:37:30 +0200
Subject: [PATCH 02/88] Stubs with comments
---
Realm/Realm/DatabaseTypes/RealmValue.cs | 14 +++++++++-----
Realm/Realm/Native/PrimitiveValue.cs | 5 +++++
2 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/Realm/Realm/DatabaseTypes/RealmValue.cs b/Realm/Realm/DatabaseTypes/RealmValue.cs
index 85bc00ec86..f36527410c 100644
--- a/Realm/Realm/DatabaseTypes/RealmValue.cs
+++ b/Realm/Realm/DatabaseTypes/RealmValue.cs
@@ -62,6 +62,7 @@ namespace Realms
private readonly string? _stringValue;
private readonly byte[]? _dataValue;
private readonly IRealmObjectBase? _objectValue;
+ private readonly IList? _listValue;
private readonly ObjectHandle? _objectHandle;
private readonly IntPtr _propertyIndex;
@@ -121,6 +122,12 @@ private RealmValue(IRealmObjectBase obj) : this()
_objectValue = obj;
}
+ private RealmValue(IList list) : this()
+ {
+ Type = RealmValueType.List;
+ _listValue = list;
+ }
+
///
/// Gets a RealmValue representing null.
///
@@ -150,6 +157,8 @@ private RealmValue(IRealmObjectBase obj) : this()
[EditorBrowsable(EditorBrowsableState.Never)]
public static RealmValue Object(IRealmObjectBase value) => new(value);
+ public static RealmValue List(IList value) => new(value);
+
internal static RealmValue Create(T value, RealmValueType type)
{
if (value is null)
@@ -814,11 +823,6 @@ public override int GetHashCode()
}
}
- public static RealmValue List(IList list)
- {
-
- }
-
///
/// Converts a to . Equivalent to .
///
diff --git a/Realm/Realm/Native/PrimitiveValue.cs b/Realm/Realm/Native/PrimitiveValue.cs
index 8aabc17344..bf1f43c0a6 100644
--- a/Realm/Realm/Native/PrimitiveValue.cs
+++ b/Realm/Realm/Native/PrimitiveValue.cs
@@ -67,6 +67,11 @@ internal unsafe struct PrimitiveValue
[FieldOffset(0)]
private LinkValue link_value;
+ /**
+ * We need to create something similar to LinkValue (maybe ListValue)
+ * that will contain a IntPtr to the list, because it seems this is the only thing we need to create the list handle
+ */
+
[FieldOffset(16)]
[MarshalAs(UnmanagedType.U1)]
public RealmValueType Type;
From 3f0ed7f0e88c81b8ac65cd1dc40032a314005b28 Mon Sep 17 00:00:00 2001
From: Ferdinando Papale <4850119+papafe@users.noreply.github.com>
Date: Thu, 14 Sep 2023 10:25:27 +0200
Subject: [PATCH 03/88] Notes
---
Realm/Realm/DatabaseTypes/RealmValue.cs | 8 ++++++++
Realm/Realm/Native/PrimitiveValue.cs | 12 ++++++++----
2 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/Realm/Realm/DatabaseTypes/RealmValue.cs b/Realm/Realm/DatabaseTypes/RealmValue.cs
index f36527410c..82272b523d 100644
--- a/Realm/Realm/DatabaseTypes/RealmValue.cs
+++ b/Realm/Realm/DatabaseTypes/RealmValue.cs
@@ -122,6 +122,14 @@ private RealmValue(IRealmObjectBase obj) : this()
_objectValue = obj;
}
+ /*
+ * This is enough for when needing to call SetValue(RealmValue val,...)
+ * We get this value and we do what we need to do (maybe modify PopulateCollection..., probably yes)
+ *
+ * For the opposite, we need to find a way to save this inside primitive value, maybe
+ * we just need something to keep a link to the realmList
+ *
+ */
private RealmValue(IList list) : this()
{
Type = RealmValueType.List;
diff --git a/Realm/Realm/Native/PrimitiveValue.cs b/Realm/Realm/Native/PrimitiveValue.cs
index bf1f43c0a6..c96cf3937d 100644
--- a/Realm/Realm/Native/PrimitiveValue.cs
+++ b/Realm/Realm/Native/PrimitiveValue.cs
@@ -67,10 +67,8 @@ internal unsafe struct PrimitiveValue
[FieldOffset(0)]
private LinkValue link_value;
- /**
- * We need to create something similar to LinkValue (maybe ListValue)
- * that will contain a IntPtr to the list, because it seems this is the only thing we need to create the list handle
- */
+ [FieldOffset(0)]
+ private ListValue list_value;
[FieldOffset(16)]
[MarshalAs(UnmanagedType.U1)]
@@ -289,6 +287,12 @@ private struct LinkValue
public readonly TableKey table_key;
}
+ [StructLayout(LayoutKind.Sequential)]
+ private struct ListValue
+ {
+ public IntPtr list_ptr;
+ }
+
[StructLayout(LayoutKind.Sequential)]
private readonly struct TimestampValue
{
From 197aee1f91a87857381601ffdd7cb7ffaf301a6f Mon Sep 17 00:00:00 2001
From: Ferdinando Papale <4850119+papafe@users.noreply.github.com>
Date: Thu, 14 Sep 2023 12:47:20 +0200
Subject: [PATCH 04/88] Various fixes
---
Realm/Realm/DatabaseTypes/RealmValue.cs | 20 +++++++++--
.../Realm/Extensions/CollectionExtensions.cs | 4 ++-
Realm/Realm/Handles/ObjectHandle.cs | 33 +++++++++++++++++++
Realm/Realm/Native/PrimitiveValue.cs | 19 +++++++++++
wrappers/src/marshalling.hpp | 6 ++++
wrappers/src/object_cs.cpp | 9 +++++
6 files changed, 87 insertions(+), 4 deletions(-)
diff --git a/Realm/Realm/DatabaseTypes/RealmValue.cs b/Realm/Realm/DatabaseTypes/RealmValue.cs
index 82272b523d..04e0c4ca3a 100644
--- a/Realm/Realm/DatabaseTypes/RealmValue.cs
+++ b/Realm/Realm/DatabaseTypes/RealmValue.cs
@@ -19,6 +19,7 @@
using System;
using System.Buffers;
using System.Collections;
+using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
@@ -62,7 +63,7 @@ namespace Realms
private readonly string? _stringValue;
private readonly byte[]? _dataValue;
private readonly IRealmObjectBase? _objectValue;
- private readonly IList? _listValue;
+ private readonly IList? _listValue;
private readonly ObjectHandle? _objectHandle;
private readonly IntPtr _propertyIndex;
@@ -98,6 +99,10 @@ internal RealmValue(PrimitiveValue primitive, Realm? realm = null, ObjectHandle?
Argument.NotNull(realm, nameof(realm));
_objectValue = primitive.AsObject(realm!);
break;
+ case RealmValueType.List:
+ Argument.NotNull(realm, nameof(realm));
+ _listValue = primitive.AsList(realm!);
+ break;
default:
_primitiveValue = primitive;
break;
@@ -130,7 +135,7 @@ private RealmValue(IRealmObjectBase obj) : this()
* we just need something to keep a link to the realmList
*
*/
- private RealmValue(IList list) : this()
+ private RealmValue(IList list) : this()
{
Type = RealmValueType.List;
_listValue = list;
@@ -165,7 +170,7 @@ private RealmValue(IList list) : this()
[EditorBrowsable(EditorBrowsableState.Never)]
public static RealmValue Object(IRealmObjectBase value) => new(value);
- public static RealmValue List(IList value) => new(value);
+ public static RealmValue List(IList value) => new(value);
internal static RealmValue Create(T value, RealmValueType type)
{
@@ -221,6 +226,9 @@ internal static RealmValue Create(T value, RealmValueType type)
}
return (PrimitiveValue.Object(obj.GetObjectHandle()!), null);
+ case RealmValueType.List:
+ var realmList = _listValue as RealmList;
+ return (PrimitiveValue.List(realmList.Handle.Value as ListHandle), null);
default:
return (_primitiveValue, null);
}
@@ -442,6 +450,12 @@ public string AsString()
return _stringValue!;
}
+ public IList AsList()
+ {
+ EnsureType("List", RealmValueType.List);
+ return _listValue!;
+ }
+
///
/// Returns the stored value as a .
///
diff --git a/Realm/Realm/Extensions/CollectionExtensions.cs b/Realm/Realm/Extensions/CollectionExtensions.cs
index c68821554b..2f88a340d9 100644
--- a/Realm/Realm/Extensions/CollectionExtensions.cs
+++ b/Realm/Realm/Extensions/CollectionExtensions.cs
@@ -609,9 +609,11 @@ private static void PopulateCollectionCore(ICollection? source, ICollectio
realm.Add(robj, update);
}
}
+ //TODO I think here we could need a new case for Collections of Mixed
target.Add(item);
}
+
}
}
-}
\ No newline at end of file
+}
diff --git a/Realm/Realm/Handles/ObjectHandle.cs b/Realm/Realm/Handles/ObjectHandle.cs
index b588838b43..d02acc33f1 100644
--- a/Realm/Realm/Handles/ObjectHandle.cs
+++ b/Realm/Realm/Handles/ObjectHandle.cs
@@ -45,6 +45,9 @@ private static class NativeMethods
[DllImport(InteropConfig.DLL_NAME, EntryPoint = "object_set_value", CallingConvention = CallingConvention.Cdecl)]
public static extern void set_value(ObjectHandle handle, IntPtr propertyIndex, PrimitiveValue value, out NativeException ex);
+ [DllImport(InteropConfig.DLL_NAME, EntryPoint = "object_set_list_value", CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr set_list_value(ObjectHandle handle, IntPtr propertyIndex, out NativeException ex);
+
[DllImport(InteropConfig.DLL_NAME, EntryPoint = "object_create_embedded", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr create_embedded_link(ObjectHandle handle, IntPtr propertyIndex, out NativeException ex);
@@ -219,6 +222,36 @@ public void SetValue(string propertyName, Metadata metadata, in RealmValue value
throw new NotSupportedException($"Asymmetric objects cannot be linked to and cannot be contained in a RealmValue. Attempted to set {value} to {metadata.Schema.Name}.{propertyName}");
}
}
+ else if (value.Type == RealmValueType.List)
+ {
+ var listPtr = NativeMethods.set_list_value(this, propertyIndex, out var listNativeException);
+
+ var listHandle = new ListHandle(Root!, listPtr);
+ var realmList = new RealmList(realm, listHandle, null);
+
+ foreach (var item in value.AsList())
+ {
+ if (item is RealmValue { Type: RealmValueType.Object } val)
+ {
+ var wrappedObj = val.AsIRealmObject();
+ if (wrappedObj is IRealmObject robj)
+ {
+ realm.Add(robj, false); //TODO Update?
+ }
+ }
+ //TODO I think here we could need a new case for Collections of Mixed
+
+ realmList.Add(item);
+ }
+
+ var newRealmVal = RealmValue.List(realmList);
+
+ var (prim, handl) = newRealmVal.ToNative();
+ NativeMethods.set_value(this, propertyIndex, prim, out var setValueNativeException);
+ handl?.Dispose();
+ setValueNativeException.ThrowIfNecessary();
+ return;
+ }
var (primitive, handles) = value.ToNative();
NativeMethods.set_value(this, propertyIndex, primitive, out var nativeException);
diff --git a/Realm/Realm/Native/PrimitiveValue.cs b/Realm/Realm/Native/PrimitiveValue.cs
index c96cf3937d..07baab9dbf 100644
--- a/Realm/Realm/Native/PrimitiveValue.cs
+++ b/Realm/Realm/Native/PrimitiveValue.cs
@@ -18,6 +18,7 @@
using System;
using System.Buffers;
+using System.Collections;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
@@ -210,6 +211,18 @@ public static PrimitiveValue Object(ObjectHandle handle)
};
}
+ public static PrimitiveValue List(ListHandle handle)
+ {
+ return new PrimitiveValue
+ {
+ Type = RealmValueType.List,
+ list_value = new ListValue
+ {
+ list_ptr = handle.DangerousGetHandle()
+ }
+ };
+ }
+
public readonly bool AsBool() => int_value == 1;
public readonly long AsInt() => int_value;
@@ -266,6 +279,12 @@ public readonly IRealmObjectBase AsObject(Realm realm)
return realm.MakeObject(objectMetadata, handle);
}
+ public readonly RealmList AsList(Realm realm)
+ {
+ var handle = new ListHandle(realm.SharedRealmHandle, list_value.list_ptr);
+ return new RealmList(realm, handle, null);
+ }
+
public readonly bool TryGetObjectHandle(Realm realm, [NotNullWhen(true)] out ObjectHandle? handle)
{
if (Type == RealmValueType.Object)
diff --git a/wrappers/src/marshalling.hpp b/wrappers/src/marshalling.hpp
index 4470f76331..925d8e748b 100644
--- a/wrappers/src/marshalling.hpp
+++ b/wrappers/src/marshalling.hpp
@@ -101,6 +101,7 @@ enum class realm_value_type : uint8_t {
RLM_TYPE_OBJECT_ID,
RLM_TYPE_LINK,
RLM_TYPE_UUID,
+ RLM_TYPE_LIST
};
enum class query_argument_type : uint8_t {
@@ -134,6 +135,10 @@ typedef struct realm_link {
TableKey table_key;
} realm_link_t;
+typedef struct realm_list {
+ List* list;
+} realm_list_t;
+
typedef struct realm_object_id {
uint8_t bytes[12];
} realm_object_id_t;
@@ -156,6 +161,7 @@ typedef struct realm_value {
realm_uuid_t uuid;
realm_link_t link;
+ realm_list_t list;
char data[16];
};
diff --git a/wrappers/src/object_cs.cpp b/wrappers/src/object_cs.cpp
index d9259f5334..72031578ce 100644
--- a/wrappers/src/object_cs.cpp
+++ b/wrappers/src/object_cs.cpp
@@ -159,6 +159,15 @@ extern "C" {
});
}
+ REALM_EXPORT void object_set_list_value(Object& object, size_t property_ndx, NativeException::Marshallable& ex)
+ {
+ handle_errors(ex, [&]() {
+ verify_can_set(object);
+
+ auto prop = get_property(object, property_ndx);
+ });
+ }
+
REALM_EXPORT Results* object_get_backlinks(Object& object, size_t property_ndx, NativeException::Marshallable& ex)
{
return handle_errors(ex, [&] {
From 3f46db7cf8c931b2e7f82204a52dcc0f9d0538e7 Mon Sep 17 00:00:00 2001
From: Ferdinando Papale <4850119+papafe@users.noreply.github.com>
Date: Thu, 14 Sep 2023 13:47:08 +0200
Subject: [PATCH 05/88] Updated core
---
wrappers/realm-core | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/wrappers/realm-core b/wrappers/realm-core
index 03ba58ace5..0da737b699 160000
--- a/wrappers/realm-core
+++ b/wrappers/realm-core
@@ -1 +1 @@
-Subproject commit 03ba58ace5d29685154a9287d1f914aabd9b4928
+Subproject commit 0da737b699bf4bcfc1a3772385cd49cd9eb9cad9
From d4601c062d9dc354e212cda85e38d51039361141 Mon Sep 17 00:00:00 2001
From: Ferdinando Papale <4850119+papafe@users.noreply.github.com>
Date: Thu, 14 Sep 2023 14:58:33 +0200
Subject: [PATCH 06/88] Finished stub
---
Realm/Realm/Handles/ObjectHandle.cs | 17 +-----------
Tests/Realm.Tests/Database/RealmValueTests.cs | 26 +++++++++++++++++++
wrappers/realm-core | 2 +-
wrappers/src/marshalling.hpp | 8 ++++++
wrappers/src/object_cs.cpp | 12 +++++++--
5 files changed, 46 insertions(+), 19 deletions(-)
diff --git a/Realm/Realm/Handles/ObjectHandle.cs b/Realm/Realm/Handles/ObjectHandle.cs
index d02acc33f1..d1008546b3 100644
--- a/Realm/Realm/Handles/ObjectHandle.cs
+++ b/Realm/Realm/Handles/ObjectHandle.cs
@@ -231,25 +231,10 @@ public void SetValue(string propertyName, Metadata metadata, in RealmValue value
foreach (var item in value.AsList())
{
- if (item is RealmValue { Type: RealmValueType.Object } val)
- {
- var wrappedObj = val.AsIRealmObject();
- if (wrappedObj is IRealmObject robj)
- {
- realm.Add(robj, false); //TODO Update?
- }
- }
- //TODO I think here we could need a new case for Collections of Mixed
-
+ // TODO Need to add special cases for objects and other collections
realmList.Add(item);
}
- var newRealmVal = RealmValue.List(realmList);
-
- var (prim, handl) = newRealmVal.ToNative();
- NativeMethods.set_value(this, propertyIndex, prim, out var setValueNativeException);
- handl?.Dispose();
- setValueNativeException.ThrowIfNecessary();
return;
}
diff --git a/Tests/Realm.Tests/Database/RealmValueTests.cs b/Tests/Realm.Tests/Database/RealmValueTests.cs
index d8fc5c1b44..5ca7846ff9 100644
--- a/Tests/Realm.Tests/Database/RealmValueTests.cs
+++ b/Tests/Realm.Tests/Database/RealmValueTests.cs
@@ -674,6 +674,32 @@ public void RealmValue_Reference_IsChangedCorrectly()
Assert.That(savedValue == 10);
}
+ [Test]
+ public void AAAARealmValueList()
+ {
+ var rvo = new RealmValueObject();
+
+ rvo.RealmValueProperty = RealmValue.List(new List { 1, "two", 3 });
+
+ _realm.Write(() =>
+ {
+ _realm.Add(rvo);
+ });
+
+ var savedValue = rvo.RealmValueProperty;
+ var list = savedValue.AsList();
+
+ Assert.That(list.Count(), Is.EqualTo(3));
+
+ var firstVal = list[0].AsInt16();
+ var secondVal = list[1].AsString();
+ var thirdVal = list[2].AsInt16();
+
+ Assert.That(firstVal, Is.EqualTo(1));
+ Assert.That(secondVal, Is.EqualTo("two"));
+ Assert.That(thirdVal, Is.EqualTo(3));
+ }
+
[Test]
public void RealmValue_WhenManaged_CanChangeType()
{
diff --git a/wrappers/realm-core b/wrappers/realm-core
index 0da737b699..cc3c496740 160000
--- a/wrappers/realm-core
+++ b/wrappers/realm-core
@@ -1 +1 @@
-Subproject commit 0da737b699bf4bcfc1a3772385cd49cd9eb9cad9
+Subproject commit cc3c4967407afdce1681cdd02a76552938f4ccb7
diff --git a/wrappers/src/marshalling.hpp b/wrappers/src/marshalling.hpp
index 925d8e748b..2be6c4e6f7 100644
--- a/wrappers/src/marshalling.hpp
+++ b/wrappers/src/marshalling.hpp
@@ -507,6 +507,14 @@ static inline realm_value_t to_capi(ObjLink obj_link, SharedRealm realm)
return to_capi(realm->read_group().get_object(obj_link), realm);
}
+static inline realm_value_t to_capi(List* list)
+{
+ realm_value_t val{};
+ val.type = realm_value_type::RLM_TYPE_LIST;
+ val.list.list = list;
+ return val;
+}
+
static inline realm_value_t to_capi(const Mixed& value)
{
realm_value_t val{};
diff --git a/wrappers/src/object_cs.cpp b/wrappers/src/object_cs.cpp
index 72031578ce..e6bc37275b 100644
--- a/wrappers/src/object_cs.cpp
+++ b/wrappers/src/object_cs.cpp
@@ -106,6 +106,11 @@ extern "C" {
if (!val.is_null() && val.get_type() == type_TypedLink) {
*value = to_capi(val.get(), object.realm());
}
+ if (val.get_type() == type_List)
+ {
+ auto list = new List(object.realm(), object.get_obj(), prop.column_key);
+ *value = to_capi(list);
+ }
else {
*value = to_capi(std::move(val));
}
@@ -159,12 +164,15 @@ extern "C" {
});
}
- REALM_EXPORT void object_set_list_value(Object& object, size_t property_ndx, NativeException::Marshallable& ex)
+ REALM_EXPORT List* object_set_list_value(Object& object, size_t property_ndx, NativeException::Marshallable& ex)
{
- handle_errors(ex, [&]() {
+ return handle_errors(ex, [&]() {
verify_can_set(object);
auto prop = get_property(object, property_ndx);
+ object.get_obj().set_collection(prop.column_key, CollectionType::List);
+
+ return new List(object.realm(), object.get_obj(), prop.column_key);
});
}
From c0f01c893199a870f3295fe8b14c5b5948099a24 Mon Sep 17 00:00:00 2001
From: Ferdinando Papale <4850119+papafe@users.noreply.github.com>
Date: Thu, 14 Sep 2023 15:08:46 +0200
Subject: [PATCH 07/88] Removed comment [skip-ci]
---
Realm/Realm/DatabaseTypes/RealmValue.cs | 8 --------
1 file changed, 8 deletions(-)
diff --git a/Realm/Realm/DatabaseTypes/RealmValue.cs b/Realm/Realm/DatabaseTypes/RealmValue.cs
index 04e0c4ca3a..fda3051c4f 100644
--- a/Realm/Realm/DatabaseTypes/RealmValue.cs
+++ b/Realm/Realm/DatabaseTypes/RealmValue.cs
@@ -127,14 +127,6 @@ private RealmValue(IRealmObjectBase obj) : this()
_objectValue = obj;
}
- /*
- * This is enough for when needing to call SetValue(RealmValue val,...)
- * We get this value and we do what we need to do (maybe modify PopulateCollection..., probably yes)
- *
- * For the opposite, we need to find a way to save this inside primitive value, maybe
- * we just need something to keep a link to the realmList
- *
- */
private RealmValue(IList list) : this()
{
Type = RealmValueType.List;
From 877190e6ac460e9ee45f9726f9bf3d8bfa0e3a20 Mon Sep 17 00:00:00 2001
From: Ferdinando Papale <4850119+papafe@users.noreply.github.com>
Date: Fri, 15 Sep 2023 09:49:34 +0200
Subject: [PATCH 08/88] Removed unused
---
Realm/Realm/DatabaseTypes/RealmValue.cs | 3 ---
Realm/Realm/Native/PrimitiveValue.cs | 12 ------------
2 files changed, 15 deletions(-)
diff --git a/Realm/Realm/DatabaseTypes/RealmValue.cs b/Realm/Realm/DatabaseTypes/RealmValue.cs
index fda3051c4f..b8f971fb90 100644
--- a/Realm/Realm/DatabaseTypes/RealmValue.cs
+++ b/Realm/Realm/DatabaseTypes/RealmValue.cs
@@ -218,9 +218,6 @@ internal static RealmValue Create(T value, RealmValueType type)
}
return (PrimitiveValue.Object(obj.GetObjectHandle()!), null);
- case RealmValueType.List:
- var realmList = _listValue as RealmList;
- return (PrimitiveValue.List(realmList.Handle.Value as ListHandle), null);
default:
return (_primitiveValue, null);
}
diff --git a/Realm/Realm/Native/PrimitiveValue.cs b/Realm/Realm/Native/PrimitiveValue.cs
index 07baab9dbf..b5de932013 100644
--- a/Realm/Realm/Native/PrimitiveValue.cs
+++ b/Realm/Realm/Native/PrimitiveValue.cs
@@ -211,18 +211,6 @@ public static PrimitiveValue Object(ObjectHandle handle)
};
}
- public static PrimitiveValue List(ListHandle handle)
- {
- return new PrimitiveValue
- {
- Type = RealmValueType.List,
- list_value = new ListValue
- {
- list_ptr = handle.DangerousGetHandle()
- }
- };
- }
-
public readonly bool AsBool() => int_value == 1;
public readonly long AsInt() => int_value;
From 686d5fe332e75f4186ea1753c25504db4ad90de9 Mon Sep 17 00:00:00 2001
From: Ferdinando Papale <4850119+papafe@users.noreply.github.com>
Date: Wed, 20 Sep 2023 16:07:10 +0200
Subject: [PATCH 09/88] Added stub for lists in lists
---
Realm/Realm/DatabaseTypes/RealmList.cs | 13 +++
Realm/Realm/Handles/ListHandle.cs | 12 +++
Realm/Realm/Handles/ObjectHandle.cs | 2 +-
Tests/Realm.Tests/Database/RealmValueTests.cs | 26 ------
.../Database/RealmValueWithCollections.cs | 80 +++++++++++++++++++
wrappers/src/list_cs.cpp | 23 ++++++
6 files changed, 129 insertions(+), 27 deletions(-)
create mode 100644 Tests/Realm.Tests/Database/RealmValueWithCollections.cs
diff --git a/Realm/Realm/DatabaseTypes/RealmList.cs b/Realm/Realm/DatabaseTypes/RealmList.cs
index de67a582b5..2ae270eb36 100644
--- a/Realm/Realm/DatabaseTypes/RealmList.cs
+++ b/Realm/Realm/DatabaseTypes/RealmList.cs
@@ -88,6 +88,19 @@ public void Add(T value)
{
var realmValue = ValidateValueToInsert(value);
+ if (realmValue.Type == RealmValueType.List)
+ {
+ var newListHandle = _listHandle.AddList();
+ var newList = new RealmList(Realm, newListHandle, null);
+
+ foreach (var item in realmValue.AsList())
+ {
+ newList.Add(item);
+ }
+
+ return;
+ }
+
if (_isEmbedded)
{
if (IsDynamic)
diff --git a/Realm/Realm/Handles/ListHandle.cs b/Realm/Realm/Handles/ListHandle.cs
index bfcdcf1d54..27f3cc5045 100644
--- a/Realm/Realm/Handles/ListHandle.cs
+++ b/Realm/Realm/Handles/ListHandle.cs
@@ -32,6 +32,9 @@ private static class NativeMethods
[DllImport(InteropConfig.DLL_NAME, EntryPoint = "list_add_embedded", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr add_embedded(ListHandle listHandle, out NativeException ex);
+ [DllImport(InteropConfig.DLL_NAME, EntryPoint = "list_add_list_value", CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr add_list_value(ListHandle listHandle, out NativeException ex);
+
[DllImport(InteropConfig.DLL_NAME, EntryPoint = "list_set_value", CallingConvention = CallingConvention.Cdecl)]
public static extern void set_value(ListHandle listHandle, IntPtr targetIndex, PrimitiveValue value, out NativeException ex);
@@ -140,6 +143,15 @@ public ObjectHandle AddEmbedded()
return new ObjectHandle(Root!, result);
}
+ public ListHandle AddList()
+ {
+ EnsureIsOpen();
+
+ var listPtr = NativeMethods.add_list_value(this, out var nativeException);
+ nativeException.ThrowIfNecessary();
+ return new ListHandle(Root!, listPtr);
+ }
+
public void Set(int targetIndex, in RealmValue value)
{
EnsureIsOpen();
diff --git a/Realm/Realm/Handles/ObjectHandle.cs b/Realm/Realm/Handles/ObjectHandle.cs
index d1008546b3..2e818f47af 100644
--- a/Realm/Realm/Handles/ObjectHandle.cs
+++ b/Realm/Realm/Handles/ObjectHandle.cs
@@ -225,13 +225,13 @@ public void SetValue(string propertyName, Metadata metadata, in RealmValue value
else if (value.Type == RealmValueType.List)
{
var listPtr = NativeMethods.set_list_value(this, propertyIndex, out var listNativeException);
+ //TODO Need to do something with the exception
var listHandle = new ListHandle(Root!, listPtr);
var realmList = new RealmList(realm, listHandle, null);
foreach (var item in value.AsList())
{
- // TODO Need to add special cases for objects and other collections
realmList.Add(item);
}
diff --git a/Tests/Realm.Tests/Database/RealmValueTests.cs b/Tests/Realm.Tests/Database/RealmValueTests.cs
index 5ca7846ff9..d8fc5c1b44 100644
--- a/Tests/Realm.Tests/Database/RealmValueTests.cs
+++ b/Tests/Realm.Tests/Database/RealmValueTests.cs
@@ -674,32 +674,6 @@ public void RealmValue_Reference_IsChangedCorrectly()
Assert.That(savedValue == 10);
}
- [Test]
- public void AAAARealmValueList()
- {
- var rvo = new RealmValueObject();
-
- rvo.RealmValueProperty = RealmValue.List(new List { 1, "two", 3 });
-
- _realm.Write(() =>
- {
- _realm.Add(rvo);
- });
-
- var savedValue = rvo.RealmValueProperty;
- var list = savedValue.AsList();
-
- Assert.That(list.Count(), Is.EqualTo(3));
-
- var firstVal = list[0].AsInt16();
- var secondVal = list[1].AsString();
- var thirdVal = list[2].AsInt16();
-
- Assert.That(firstVal, Is.EqualTo(1));
- Assert.That(secondVal, Is.EqualTo("two"));
- Assert.That(thirdVal, Is.EqualTo(3));
- }
-
[Test]
public void RealmValue_WhenManaged_CanChangeType()
{
diff --git a/Tests/Realm.Tests/Database/RealmValueWithCollections.cs b/Tests/Realm.Tests/Database/RealmValueWithCollections.cs
new file mode 100644
index 0000000000..334a0f38e3
--- /dev/null
+++ b/Tests/Realm.Tests/Database/RealmValueWithCollections.cs
@@ -0,0 +1,80 @@
+////////////////////////////////////////////////////////////////////////////
+//
+// Copyright 2023 Realm Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License")
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////
+
+using System.Collections.Generic;
+using System.Linq;
+using NUnit.Framework;
+
+namespace Realms.Tests.Database
+{
+ [TestFixture, Preserve(AllMembers = true)]
+ internal class RealmValueWithCollections : RealmInstanceTest
+ {
+ [Test]
+ public void Test1()
+ {
+ var rvo = new RealmValueObject();
+
+ rvo.RealmValueProperty = RealmValue.List(new List { 1, "two", 3 });
+
+ _realm.Write(() =>
+ {
+ _realm.Add(rvo);
+ });
+
+ var savedValue = rvo.RealmValueProperty;
+ var list = savedValue.AsList();
+
+ Assert.That(list.Count(), Is.EqualTo(3));
+
+ var firstVal = list[0].AsInt16();
+ var secondVal = list[1].AsString();
+ var thirdVal = list[2].AsInt16();
+
+ Assert.That(firstVal, Is.EqualTo(1));
+ Assert.That(secondVal, Is.EqualTo("two"));
+ Assert.That(thirdVal, Is.EqualTo(3));
+ }
+
+ [Test]
+ public void Test2()
+ {
+ var rvo = new RealmValueObject();
+
+ rvo.RealmValueProperty = RealmValue.List(new List { 1, "two", RealmValue.List(new List { 0, 15 }) });
+
+ _realm.Write(() =>
+ {
+ _realm.Add(rvo);
+ });
+
+ var savedValue = rvo.RealmValueProperty;
+ var list = savedValue.AsList();
+
+ Assert.That(list.Count(), Is.EqualTo(3));
+
+ var thirdVal = list[2].AsList();
+
+ var firstEl = thirdVal[0].AsInt16();
+ var secondEl = thirdVal[1].AsInt16();
+
+ Assert.That(firstEl, Is.EqualTo(0));
+ Assert.That(secondEl, Is.EqualTo(15));
+ }
+ }
+}
diff --git a/wrappers/src/list_cs.cpp b/wrappers/src/list_cs.cpp
index 1fef7762c3..f109c05d4d 100644
--- a/wrappers/src/list_cs.cpp
+++ b/wrappers/src/list_cs.cpp
@@ -119,6 +119,24 @@ REALM_EXPORT void list_add_value(List& list, realm_value_t value, NativeExceptio
list_insert_value(list, list.size(), value, ex);
}
+REALM_EXPORT List* list_insert_list_value(List& list, size_t list_ndx, NativeException::Marshallable& ex)
+{
+ return handle_errors(ex, [&]() {
+
+ if (list_ndx > list.size()) {
+ throw IndexOutOfRangeException("Insert into RealmList", list_ndx, list.size());
+ }
+
+ list.insert_collection(list_ndx, CollectionType::List);
+ return new List(list.get_list(list_ndx));
+ });
+}
+
+REALM_EXPORT List* list_add_list_value(List& list, NativeException::Marshallable& ex)
+{
+ return list_insert_list_value(list, list.size(), ex);
+}
+
REALM_EXPORT Object* list_insert_embedded(List& list, size_t list_ndx, NativeException::Marshallable& ex)
{
return handle_errors(ex, [&]() {
@@ -146,6 +164,11 @@ REALM_EXPORT void list_get_value(List& list, size_t ndx, realm_value_t* value, N
if (!val.is_null() && val.get_type() == type_TypedLink) {
*value = to_capi(val.get(), list.get_realm());
}
+ else if (val.get_type() == type_List)
+ {
+ auto internalList = new List(list.get_list(ndx));
+ *value = to_capi(internalList);
+ }
else {
*value = to_capi(std::move(val));
}
From b9c5a8fb36c1221e5ba2112735a1ad2934d809a7 Mon Sep 17 00:00:00 2001
From: Ferdinando Papale <4850119+papafe@users.noreply.github.com>
Date: Thu, 21 Sep 2023 11:55:17 +0200
Subject: [PATCH 10/88] Fixed error with null and added basic test with all
types
---
Realm/Realm/DatabaseTypes/RealmValue.cs | 3 +
.../Database/RealmValueWithCollections.cs | 69 ++++++++++++++++++-
wrappers/src/list_cs.cpp | 16 +++--
3 files changed, 80 insertions(+), 8 deletions(-)
diff --git a/Realm/Realm/DatabaseTypes/RealmValue.cs b/Realm/Realm/DatabaseTypes/RealmValue.cs
index b8f971fb90..9f3570c98c 100644
--- a/Realm/Realm/DatabaseTypes/RealmValue.cs
+++ b/Realm/Realm/DatabaseTypes/RealmValue.cs
@@ -1360,6 +1360,9 @@ public override int GetHashCode()
/// A containing the supplied .
public static implicit operator RealmValue(RealmObjectBase? val) => val == null ? Null : Object(val);
+ //TODO Add docs
+ public static implicit operator RealmValue(List? val) => val == null ? Null : List(val);
+
private void EnsureType(string target, RealmValueType type)
{
if (Type != type)
diff --git a/Tests/Realm.Tests/Database/RealmValueWithCollections.cs b/Tests/Realm.Tests/Database/RealmValueWithCollections.cs
index 334a0f38e3..25593e0f96 100644
--- a/Tests/Realm.Tests/Database/RealmValueWithCollections.cs
+++ b/Tests/Realm.Tests/Database/RealmValueWithCollections.cs
@@ -16,8 +16,10 @@
//
////////////////////////////////////////////////////////////////////////////
+using System;
using System.Collections.Generic;
using System.Linq;
+using MongoDB.Bson;
using NUnit.Framework;
namespace Realms.Tests.Database
@@ -25,12 +27,75 @@ namespace Realms.Tests.Database
[TestFixture, Preserve(AllMembers = true)]
internal class RealmValueWithCollections : RealmInstanceTest
{
+ private RealmValueObject PersistAndFind(RealmValue rv)
+ {
+ _realm.Write(() =>
+ {
+ _realm.Add(new RealmValueObject { RealmValueProperty = rv });
+ });
+
+ return _realm.All().First();
+ }
+
+ [Test]
+ public void TestA([Values(true, false)] bool isManaged)
+ {
+ var originalList = new List
+ {
+ RealmValue.Null,
+ 1,
+ true,
+ "string",
+ new byte[] { 0, 1, 2 },
+ new DateTimeOffset(1234, 5, 6, 7, 8, 9, TimeSpan.Zero),
+ 1f,
+ 2d,
+ 3m,
+ new ObjectId("5f63e882536de46d71877979"),
+ Guid.Parse("3809d6d9-7618-4b3d-8044-2aa35fd02f31"),
+ new InternalObject { IntProperty = 10, StringProperty = "brown" },
+ };
+
+ RealmValue rv = originalList;
+
+ if (isManaged)
+ {
+ rv = PersistAndFind(rv).RealmValueProperty;
+ }
+
+ Assert.That(rv.Type, Is.EqualTo(RealmValueType.List));
+ Assert.That(rv != RealmValue.Null);
+
+ var retrievedList = rv.AsList();
+
+ Assert.That(retrievedList, Is.EquivalentTo(originalList));
+ }
+
+ /* To test:
+ * - everything works both managed and unmanaged
+ * - explicit/implicit conversion work
+ * - works with objects
+ * - works with lists inside lists
+ * - Can change type
+ * - Can add/replace at index
+ * - Can delete elements
+ *
+ *
+ * DONE:
+ * -
+ *
+ * - Doesn't cause issues with queries
+ * - Dynamic ?
+ * - sets can't contain other collections
+ *
+ */
+
[Test]
public void Test1()
{
var rvo = new RealmValueObject();
- rvo.RealmValueProperty = RealmValue.List(new List { 1, "two", 3 });
+ rvo.RealmValueProperty = new List { 1, "two", 3 };
_realm.Write(() =>
{
@@ -56,7 +121,7 @@ public void Test2()
{
var rvo = new RealmValueObject();
- rvo.RealmValueProperty = RealmValue.List(new List { 1, "two", RealmValue.List(new List { 0, 15 }) });
+ rvo.RealmValueProperty = new List { 1, "two", new List { 0, 15 } };
_realm.Write(() =>
{
diff --git a/wrappers/src/list_cs.cpp b/wrappers/src/list_cs.cpp
index f109c05d4d..13badad320 100644
--- a/wrappers/src/list_cs.cpp
+++ b/wrappers/src/list_cs.cpp
@@ -161,13 +161,17 @@ REALM_EXPORT void list_get_value(List& list, size_t ndx, realm_value_t* value, N
}
else {
auto val = list.get_any(ndx);
- if (!val.is_null() && val.get_type() == type_TypedLink) {
- *value = to_capi(val.get(), list.get_realm());
- }
- else if (val.get_type() == type_List)
+ if (!val.is_null())
{
- auto internalList = new List(list.get_list(ndx));
- *value = to_capi(internalList);
+ auto type = val.get_type();
+ if (type == type_TypedLink) {
+ *value = to_capi(val.get(), list.get_realm());
+ }
+ else if (type == type_List)
+ {
+ auto internalList = new List(list.get_list(ndx));
+ *value = to_capi(internalList);
+ }
}
else {
*value = to_capi(std::move(val));
From dfd769740672d365dc70b7b069d12e163d94ef5f Mon Sep 17 00:00:00 2001
From: Ferdinando Papale <4850119+papafe@users.noreply.github.com>
Date: Fri, 22 Sep 2023 14:05:46 +0200
Subject: [PATCH 11/88] Improved base testing for list, added support for
add/insert/set and equality checking
---
Realm/Realm/DatabaseTypes/RealmList.cs | 28 +++
Realm/Realm/DatabaseTypes/RealmValue.cs | 2 +
Realm/Realm/Handles/ListHandle.cs | 30 ++-
.../Database/RealmValueWithCollections.cs | 178 +++++++++++++-----
wrappers/src/list_cs.cpp | 68 ++++---
5 files changed, 228 insertions(+), 78 deletions(-)
diff --git a/Realm/Realm/DatabaseTypes/RealmList.cs b/Realm/Realm/DatabaseTypes/RealmList.cs
index 2ae270eb36..2318670b95 100644
--- a/Realm/Realm/DatabaseTypes/RealmList.cs
+++ b/Realm/Realm/DatabaseTypes/RealmList.cs
@@ -66,6 +66,20 @@ internal RealmList(Realm realm, ListHandle adoptedList, Metadata? metadata) : ba
ValidateIndex(index);
var realmValue = ValidateValueToInsert(value);
+ if (realmValue.Type == RealmValueType.List)
+ {
+ var newListHandle = _listHandle.SetList(index);
+ var newList = new RealmList(Realm, newListHandle, null);
+
+ foreach (var item in realmValue.AsList())
+ {
+ newList.Add(item);
+ }
+
+ return;
+ }
+
+
if (_isEmbedded)
{
if (IsDynamic)
@@ -133,6 +147,20 @@ public void Insert(int index, T value)
ValidateIndex(index);
var realmValue = ValidateValueToInsert(value);
+ //TODO Can we do something better than this, so at least we can take out the common?
+ if (realmValue.Type == RealmValueType.List)
+ {
+ var newListHandle = _listHandle.InsertList(index);
+ var newList = new RealmList(Realm, newListHandle, null);
+
+ foreach (var item in realmValue.AsList())
+ {
+ newList.Add(item);
+ }
+
+ return;
+ }
+
if (_isEmbedded)
{
if (IsDynamic)
diff --git a/Realm/Realm/DatabaseTypes/RealmValue.cs b/Realm/Realm/DatabaseTypes/RealmValue.cs
index 9f3570c98c..2843d94fc4 100644
--- a/Realm/Realm/DatabaseTypes/RealmValue.cs
+++ b/Realm/Realm/DatabaseTypes/RealmValue.cs
@@ -759,6 +759,7 @@ public T As()
RealmValueType.ObjectId => AsObjectId(),
RealmValueType.Guid => AsGuid(),
RealmValueType.Object => AsIRealmObject(),
+ RealmValueType.List => AsList(),
_ => throw new NotSupportedException($"RealmValue of type {Type} is not supported."),
};
}
@@ -1427,6 +1428,7 @@ public bool Equals(RealmValue other)
RealmValueType.ObjectId => AsObjectId() == other.AsObjectId(),
RealmValueType.Guid => AsGuid() == other.AsGuid(),
RealmValueType.Object => AsIRealmObject().Equals(other.AsIRealmObject()),
+ RealmValueType.List => AsList().SequenceEqual(other.AsList()),
RealmValueType.Null => true,
_ => false,
};
diff --git a/Realm/Realm/Handles/ListHandle.cs b/Realm/Realm/Handles/ListHandle.cs
index 27f3cc5045..859863564e 100644
--- a/Realm/Realm/Handles/ListHandle.cs
+++ b/Realm/Realm/Handles/ListHandle.cs
@@ -32,8 +32,8 @@ private static class NativeMethods
[DllImport(InteropConfig.DLL_NAME, EntryPoint = "list_add_embedded", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr add_embedded(ListHandle listHandle, out NativeException ex);
- [DllImport(InteropConfig.DLL_NAME, EntryPoint = "list_add_list_value", CallingConvention = CallingConvention.Cdecl)]
- public static extern IntPtr add_list_value(ListHandle listHandle, out NativeException ex);
+ [DllImport(InteropConfig.DLL_NAME, EntryPoint = "list_add_list", CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr add_list(ListHandle listHandle, out NativeException ex);
[DllImport(InteropConfig.DLL_NAME, EntryPoint = "list_set_value", CallingConvention = CallingConvention.Cdecl)]
public static extern void set_value(ListHandle listHandle, IntPtr targetIndex, PrimitiveValue value, out NativeException ex);
@@ -41,12 +41,18 @@ private static class NativeMethods
[DllImport(InteropConfig.DLL_NAME, EntryPoint = "list_set_embedded", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr set_embedded(ListHandle listHandle, IntPtr targetIndex, out NativeException ex);
+ [DllImport(InteropConfig.DLL_NAME, EntryPoint = "list_set_list", CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr set_list(ListHandle listHandle, IntPtr targetIndex, out NativeException ex);
+
[DllImport(InteropConfig.DLL_NAME, EntryPoint = "list_insert_value", CallingConvention = CallingConvention.Cdecl)]
public static extern void insert_value(ListHandle listHandle, IntPtr targetIndex, PrimitiveValue value, out NativeException ex);
[DllImport(InteropConfig.DLL_NAME, EntryPoint = "list_insert_embedded", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr insert_embedded(ListHandle listHandle, IntPtr targetIndex, out NativeException ex);
+ [DllImport(InteropConfig.DLL_NAME, EntryPoint = "list_insert_list", CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr insert_list(ListHandle listHandle, IntPtr targetIndex, out NativeException ex);
+
[DllImport(InteropConfig.DLL_NAME, EntryPoint = "list_get_value", CallingConvention = CallingConvention.Cdecl)]
public static extern void get_value(ListHandle listHandle, IntPtr link_ndx, out PrimitiveValue value, out NativeException ex);
@@ -147,7 +153,7 @@ public ListHandle AddList()
{
EnsureIsOpen();
- var listPtr = NativeMethods.add_list_value(this, out var nativeException);
+ var listPtr = NativeMethods.add_list(this, out var nativeException);
nativeException.ThrowIfNecessary();
return new ListHandle(Root!, listPtr);
}
@@ -171,6 +177,15 @@ public ObjectHandle SetEmbedded(int targetIndex)
return new ObjectHandle(Root!, result);
}
+ public ListHandle SetList(int targetIndex)
+ {
+ EnsureIsOpen();
+
+ var listPtr = NativeMethods.set_list(this, (IntPtr)targetIndex, out var nativeException);
+ nativeException.ThrowIfNecessary();
+ return new ListHandle(Root!, listPtr);
+ }
+
public void Insert(int targetIndex, in RealmValue value)
{
EnsureIsOpen();
@@ -190,6 +205,15 @@ public ObjectHandle InsertEmbedded(int targetIndex)
return new ObjectHandle(Root!, result);
}
+ public ListHandle InsertList(int targetIndex)
+ {
+ EnsureIsOpen();
+
+ var listPtr = NativeMethods.insert_list(this, (IntPtr)targetIndex, out var nativeException);
+ nativeException.ThrowIfNecessary();
+ return new ListHandle(Root!, listPtr);
+ }
+
public int Find(in RealmValue value)
{
EnsureIsOpen();
diff --git a/Tests/Realm.Tests/Database/RealmValueWithCollections.cs b/Tests/Realm.Tests/Database/RealmValueWithCollections.cs
index 25593e0f96..69c32c4bfa 100644
--- a/Tests/Realm.Tests/Database/RealmValueWithCollections.cs
+++ b/Tests/Realm.Tests/Database/RealmValueWithCollections.cs
@@ -38,8 +38,11 @@ private RealmValueObject PersistAndFind(RealmValue rv)
}
[Test]
- public void TestA([Values(true, false)] bool isManaged)
+ public void List_WhenRetrieved_WorksWithAllTypes([Values(true, false)] bool isManaged)
{
+ var innerList1 = new List { "inner1" };
+ var innerList2 = new List { "inner2", innerList1 };
+
var originalList = new List
{
RealmValue.Null,
@@ -54,6 +57,7 @@ public void TestA([Values(true, false)] bool isManaged)
new ObjectId("5f63e882536de46d71877979"),
Guid.Parse("3809d6d9-7618-4b3d-8044-2aa35fd02f31"),
new InternalObject { IntProperty = 10, StringProperty = "brown" },
+ innerList2,
};
RealmValue rv = originalList;
@@ -66,80 +70,164 @@ public void TestA([Values(true, false)] bool isManaged)
Assert.That(rv.Type, Is.EqualTo(RealmValueType.List));
Assert.That(rv != RealmValue.Null);
+ Assert.That(rv.AsList(), Is.EqualTo(originalList));
+ Assert.That(rv == originalList);
+ Assert.That(rv.Equals(originalList));
+ }
+
+ [Test]
+ public void List_WithConstructorMethodOrOperator_WorksTheSame([Values(true, false)] bool isManaged)
+ {
+ var originalList = new List { 1, "string", true };
+
+ RealmValue rvOperator = originalList;
+ RealmValue rvConstructor = RealmValue.List(originalList);
+
+ if (isManaged)
+ {
+ rvOperator = PersistAndFind(rvOperator).RealmValueProperty;
+ rvConstructor = PersistAndFind(rvConstructor).RealmValueProperty;
+ }
+
+ Assert.That(rvOperator.AsList(), Is.EqualTo(originalList));
+ Assert.That(rvConstructor.AsList(), Is.EqualTo(originalList));
+ }
+
+ [Test]
+ public void List_WhenManaged_IsNotSameReferenceAsOriginalList()
+ {
+ var originalList = new List { 1, "string", true };
+
+ RealmValue rv = originalList;
+ rv = PersistAndFind(rv).RealmValueProperty;
var retrievedList = rv.AsList();
- Assert.That(retrievedList, Is.EquivalentTo(originalList));
+ originalList.RemoveAt(1);
+ Assert.That(ReferenceEquals(originalList, retrievedList), Is.False);
}
- /* To test:
- * - everything works both managed and unmanaged
- * - explicit/implicit conversion work
- * - works with objects
- * - works with lists inside lists
- * - Can change type
- * - Can add/replace at index
- * - Can delete elements
- *
- *
- * DONE:
- * -
- *
- * - Doesn't cause issues with queries
- * - Dynamic ?
- * - sets can't contain other collections
- *
- */
+ [Test]
+ public void ListInsideMixed_WhenUnmanaged_IsSameReferenceAsOriginalList()
+ {
+ var originalList = new List { 1, "string", true };
+
+ RealmValue rv = originalList;
+ var retrievedList = rv.AsList();
+
+ originalList.RemoveAt(1);
+ Assert.That(ReferenceEquals(originalList, retrievedList), Is.True);
+ }
[Test]
- public void Test1()
+ public void List_AfterCreation_CanBeAssigned([Values(true, false)] bool isManaged)
{
- var rvo = new RealmValueObject();
+ var stringVal = "Mario";
+ var rvo = new RealmValueObject { RealmValueProperty = stringVal };
- rvo.RealmValueProperty = new List { 1, "two", 3 };
+ if (isManaged)
+ {
+ _realm.Write(() =>
+ {
+ _realm.Add(rvo);
+ });
+ }
+
+ Assert.That(rvo.RealmValueProperty == stringVal);
+
+ var listVal = new List { 1, "string", true };
_realm.Write(() =>
{
- _realm.Add(rvo);
+ rvo.RealmValueProperty = listVal;
});
- var savedValue = rvo.RealmValueProperty;
- var list = savedValue.AsList();
+ Assert.That(rvo.RealmValueProperty.AsList(), Is.EqualTo(listVal));
- Assert.That(list.Count(), Is.EqualTo(3));
+ var newStringVal = "Luigi";
- var firstVal = list[0].AsInt16();
- var secondVal = list[1].AsString();
- var thirdVal = list[2].AsInt16();
+ _realm.Write(() =>
+ {
+ rvo.RealmValueProperty = newStringVal;
+ });
- Assert.That(firstVal, Is.EqualTo(1));
- Assert.That(secondVal, Is.EqualTo("two"));
- Assert.That(thirdVal, Is.EqualTo(3));
+ Assert.That(rvo.RealmValueProperty == newStringVal);
}
[Test]
- public void Test2()
+ public void List_WhenManaged_CanBeModified()
{
- var rvo = new RealmValueObject();
+ var listVal = new List { 1, "string", true };
+
+ var rvo = _realm.Write(() =>
+ {
+ return _realm.Add(new RealmValueObject { RealmValueProperty = listVal });
+ });
+
+ _realm.Write(() =>
+ {
+ rvo.RealmValueProperty.AsList()[1] = "Mario";
+ listVal[1] = "Mario"; // To keep both list updated
+ });
+
+ Assert.That(rvo.RealmValueProperty.AsList(), Is.EqualTo(listVal));
+
+ _realm.Write(() =>
+ {
+ rvo.RealmValueProperty.AsList().RemoveAt(2);
+ listVal.RemoveAt(2);
+ });
- rvo.RealmValueProperty = new List { 1, "two", new List { 0, 15 } };
+ Assert.That(rvo.RealmValueProperty.AsList(), Is.EqualTo(listVal));
_realm.Write(() =>
{
- _realm.Add(rvo);
+ rvo.RealmValueProperty.AsList().Add("newVal");
+ listVal.Add("newVal");
});
- var savedValue = rvo.RealmValueProperty;
- var list = savedValue.AsList();
+ Assert.That(rvo.RealmValueProperty.AsList(), Is.EqualTo(listVal));
- Assert.That(list.Count(), Is.EqualTo(3));
+ //TODO Maybe the set/insert/add lists and other collections can be made in another test
+ var innerList1 = new List { "inner", 23, false };
- var thirdVal = list[2].AsList();
+ _realm.Write(() =>
+ {
+ rvo.RealmValueProperty.AsList()[1] = innerList1;
+ listVal[1] = innerList1;
+ });
- var firstEl = thirdVal[0].AsInt16();
- var secondEl = thirdVal[1].AsInt16();
+ Assert.That(rvo.RealmValueProperty.AsList(), Is.EqualTo(listVal));
- Assert.That(firstEl, Is.EqualTo(0));
- Assert.That(secondEl, Is.EqualTo(15));
+ var innerList2 = new List { "inner2", 23, false };
+
+ _realm.Write(() =>
+ {
+ rvo.RealmValueProperty.AsList().Insert(1, innerList2);
+ listVal.Insert(1, innerList2);
+ });
+
+ Assert.That(rvo.RealmValueProperty.AsList(), Is.EqualTo(listVal));
}
+
+ /* To test:
+ * - everything works both managed and unmanaged
+ * - Can add/replace at index
+ * - Can delete elements
+ *
+ *
+ * DONE:
+ * - Works with objects
+ * - Works with lists inside lists
+ * - Explicit/implicit conversion works
+ * - Can changeType
+ * - Different equality comparer
+ * - Can add/replace/modify elements
+ *
+ * - Doesn't cause issues with queries
+ * - Dynamic ?
+ * - sets can't contain other collections
+ * - Notifications?
+ *
+ */
}
}
diff --git a/wrappers/src/list_cs.cpp b/wrappers/src/list_cs.cpp
index 13badad320..a25b20ff54 100644
--- a/wrappers/src/list_cs.cpp
+++ b/wrappers/src/list_cs.cpp
@@ -46,13 +46,6 @@ namespace {
extern "C" {
-REALM_EXPORT Object* list_add_embedded(List& list, NativeException::Marshallable& ex)
-{
- return handle_errors(ex, [&]() {
- return new Object(list.get_realm(), list.get_object_schema(), list.add_embedded());
- });
-}
-
REALM_EXPORT void list_set_value(List& list, size_t list_ndx, realm_value_t value, NativeException::Marshallable& ex)
{
handle_errors(ex, [&]() {
@@ -90,6 +83,19 @@ REALM_EXPORT Object* list_set_embedded(List& list, size_t list_ndx, NativeExcept
});
}
+REALM_EXPORT List* list_set_list(List& list, size_t list_ndx, NativeException::Marshallable& ex)
+{
+ return handle_errors(ex, [&]() {
+
+ if (list_ndx > list.size()) {
+ throw IndexOutOfRangeException("Insert into RealmList", list_ndx, list.size());
+ }
+
+ list.set_collection(list_ndx, CollectionType::List);
+ return new List(list.get_list(list_ndx));
+ });
+}
+
REALM_EXPORT void list_insert_value(List& list, size_t list_ndx, realm_value_t value, NativeException::Marshallable& ex)
{
handle_errors(ex, [&]() {
@@ -114,12 +120,19 @@ REALM_EXPORT void list_insert_value(List& list, size_t list_ndx, realm_value_t v
});
}
-REALM_EXPORT void list_add_value(List& list, realm_value_t value, NativeException::Marshallable& ex)
+REALM_EXPORT Object* list_insert_embedded(List& list, size_t list_ndx, NativeException::Marshallable& ex)
{
- list_insert_value(list, list.size(), value, ex);
+ return handle_errors(ex, [&]() {
+ const size_t count = list.size();
+ if (list_ndx > count) {
+ throw IndexOutOfRangeException("Insert into RealmList", list_ndx, count);
+ }
+
+ return new Object(list.get_realm(), list.get_object_schema(), list.insert_embedded(list_ndx));
+ });
}
-REALM_EXPORT List* list_insert_list_value(List& list, size_t list_ndx, NativeException::Marshallable& ex)
+REALM_EXPORT List* list_insert_list(List& list, size_t list_ndx, NativeException::Marshallable& ex)
{
return handle_errors(ex, [&]() {
@@ -132,23 +145,23 @@ REALM_EXPORT List* list_insert_list_value(List& list, size_t list_ndx, NativeExc
});
}
-REALM_EXPORT List* list_add_list_value(List& list, NativeException::Marshallable& ex)
+REALM_EXPORT void list_add_value(List& list, realm_value_t value, NativeException::Marshallable& ex)
{
- return list_insert_list_value(list, list.size(), ex);
+ list_insert_value(list, list.size(), value, ex);
}
-REALM_EXPORT Object* list_insert_embedded(List& list, size_t list_ndx, NativeException::Marshallable& ex)
+REALM_EXPORT Object* list_add_embedded(List& list, NativeException::Marshallable& ex)
{
return handle_errors(ex, [&]() {
- const size_t count = list.size();
- if (list_ndx > count) {
- throw IndexOutOfRangeException("Insert into RealmList", list_ndx, count);
- }
-
- return new Object(list.get_realm(), list.get_object_schema(), list.insert_embedded(list_ndx));
+ return new Object(list.get_realm(), list.get_object_schema(), list.add_embedded());
});
}
+REALM_EXPORT List* list_add_list(List& list, NativeException::Marshallable& ex)
+{
+ return list_insert_list(list, list.size(), ex);
+}
+
REALM_EXPORT void list_get_value(List& list, size_t ndx, realm_value_t* value, NativeException::Marshallable& ex)
{
handle_errors(ex, [&]() {
@@ -161,17 +174,12 @@ REALM_EXPORT void list_get_value(List& list, size_t ndx, realm_value_t* value, N
}
else {
auto val = list.get_any(ndx);
- if (!val.is_null())
- {
- auto type = val.get_type();
- if (type == type_TypedLink) {
- *value = to_capi(val.get(), list.get_realm());
- }
- else if (type == type_List)
- {
- auto internalList = new List(list.get_list(ndx));
- *value = to_capi(internalList);
- }
+ if (!val.is_null() && val.get_type() == type_TypedLink) {
+ *value = to_capi(val.get(), list.get_realm());
+ }
+ else if (!val.is_null() && val.get_type() == type_List) {
+ auto internalList = new List(list.get_list(ndx));
+ *value = to_capi(internalList);
}
else {
*value = to_capi(std::move(val));
From cda7a87bb13fb87dbe8144db2a8583834d863bac Mon Sep 17 00:00:00 2001
From: Ferdinando Papale <4850119+papafe@users.noreply.github.com>
Date: Fri, 22 Sep 2023 14:31:51 +0200
Subject: [PATCH 12/88] Improved test and removed useless content
---
Realm/Realm/DatabaseTypes/RealmList.cs | 1 -
.../Realm/Extensions/CollectionExtensions.cs | 4 +-
.../Database/RealmValueWithCollections.cs | 49 +++++++++++++++++--
3 files changed, 45 insertions(+), 9 deletions(-)
diff --git a/Realm/Realm/DatabaseTypes/RealmList.cs b/Realm/Realm/DatabaseTypes/RealmList.cs
index 2318670b95..41a61b4bc3 100644
--- a/Realm/Realm/DatabaseTypes/RealmList.cs
+++ b/Realm/Realm/DatabaseTypes/RealmList.cs
@@ -79,7 +79,6 @@ internal RealmList(Realm realm, ListHandle adoptedList, Metadata? metadata) : ba
return;
}
-
if (_isEmbedded)
{
if (IsDynamic)
diff --git a/Realm/Realm/Extensions/CollectionExtensions.cs b/Realm/Realm/Extensions/CollectionExtensions.cs
index 2f88a340d9..5f78c3d5cc 100644
--- a/Realm/Realm/Extensions/CollectionExtensions.cs
+++ b/Realm/Realm/Extensions/CollectionExtensions.cs
@@ -585,7 +585,7 @@ private static void PopulateCollectionCore(ICollection? source, ICollectio
{
Argument.NotNull(target, nameof(target));
- if (!skipDefaults || source != null) //TODO Need to check what skipDefaults does
+ if (!skipDefaults || source != null)
{
target.Clear();
}
@@ -609,11 +609,9 @@ private static void PopulateCollectionCore(ICollection? source, ICollectio
realm.Add(robj, update);
}
}
- //TODO I think here we could need a new case for Collections of Mixed
target.Add(item);
}
-
}
}
}
diff --git a/Tests/Realm.Tests/Database/RealmValueWithCollections.cs b/Tests/Realm.Tests/Database/RealmValueWithCollections.cs
index 69c32c4bfa..5d640d0604 100644
--- a/Tests/Realm.Tests/Database/RealmValueWithCollections.cs
+++ b/Tests/Realm.Tests/Database/RealmValueWithCollections.cs
@@ -75,6 +75,28 @@ public void List_WhenRetrieved_WorksWithAllTypes([Values(true, false)] bool isMa
Assert.That(rv.Equals(originalList));
}
+ [Test]
+ public void List_WhenSetBeforeBeingManaged_WorksAsIntended()
+ {
+ var originalList = new List { 1, "string", true };
+
+ RealmValue rv = originalList;
+
+ var rvo = new RealmValueObject { RealmValueProperty = rv };
+
+ _realm.Write(() =>
+ {
+ _realm.Add(rvo);
+ });
+
+ rv = rvo.RealmValueProperty;
+
+ Assert.That(rv.Type, Is.EqualTo(RealmValueType.List));
+ Assert.That(rv != RealmValue.Null);
+
+ Assert.That(rv.AsList(), Is.EqualTo(originalList));
+ }
+
[Test]
public void List_WithConstructorMethodOrOperator_WorksTheSame([Values(true, false)] bool isManaged)
{
@@ -186,8 +208,18 @@ public void List_WhenManaged_CanBeModified()
});
Assert.That(rvo.RealmValueProperty.AsList(), Is.EqualTo(listVal));
+ }
+
+ [Test]
+ public void List_AddSetInsertList_WorksAsIntended()
+ {
+ var listVal = new List { 1, "string", true };
+
+ var rvo = _realm.Write(() =>
+ {
+ return _realm.Add(new RealmValueObject { RealmValueProperty = listVal });
+ });
- //TODO Maybe the set/insert/add lists and other collections can be made in another test
var innerList1 = new List { "inner", 23, false };
_realm.Write(() =>
@@ -207,15 +239,22 @@ public void List_WhenManaged_CanBeModified()
});
Assert.That(rvo.RealmValueProperty.AsList(), Is.EqualTo(listVal));
- }
+ var innerList3 = new List { "inner3", 23, false };
+
+ _realm.Write(() =>
+ {
+ rvo.RealmValueProperty.AsList().Add(innerList3);
+ listVal.Add(innerList3);
+ });
+
+ Assert.That(rvo.RealmValueProperty.AsList(), Is.EqualTo(listVal));
+ }
/* To test:
- * - everything works both managed and unmanaged
- * - Can add/replace at index
- * - Can delete elements
*
*
* DONE:
+ * - everything works both managed and unmanaged
* - Works with objects
* - Works with lists inside lists
* - Explicit/implicit conversion works
From 7727f37a8d46f1c73a2b9befa27711b54310202b Mon Sep 17 00:00:00 2001
From: Ferdinando Papale <4850119+papafe@users.noreply.github.com>
Date: Mon, 25 Sep 2023 10:33:32 +0200
Subject: [PATCH 13/88] Added tests
---
.../Database/RealmValueWithCollections.cs | 67 ++++++++++++++-----
1 file changed, 49 insertions(+), 18 deletions(-)
diff --git a/Tests/Realm.Tests/Database/RealmValueWithCollections.cs b/Tests/Realm.Tests/Database/RealmValueWithCollections.cs
index 5d640d0604..3a2f57098d 100644
--- a/Tests/Realm.Tests/Database/RealmValueWithCollections.cs
+++ b/Tests/Realm.Tests/Database/RealmValueWithCollections.cs
@@ -250,23 +250,54 @@ public void List_AddSetInsertList_WorksAsIntended()
Assert.That(rvo.RealmValueProperty.AsList(), Is.EqualTo(listVal));
}
- /* To test:
- *
- *
- * DONE:
- * - everything works both managed and unmanaged
- * - Works with objects
- * - Works with lists inside lists
- * - Explicit/implicit conversion works
- * - Can changeType
- * - Different equality comparer
- * - Can add/replace/modify elements
- *
- * - Doesn't cause issues with queries
- * - Dynamic ?
- * - sets can't contain other collections
- * - Notifications?
- *
- */
+
+ [Test]
+ public void List_WhenManaged_WorksWithDynamic()
+ {
+ var originalList = new List { 1, "string", true };
+
+ var rvo = _realm.Write(() =>
+ {
+ return _realm.Add(new RealmValueObject());
+ });
+
+ _realm.Write(() =>
+ {
+ rvo.DynamicApi.Set(nameof(RealmValueObject.RealmValueProperty), originalList);
+ });
+
+ var rvp = rvo.DynamicApi.Get(nameof(RealmValueObject.RealmValueProperty));
+
+ Assert.That(rvp.AsList(), Is.EqualTo(originalList));
+ }
+
+ [Test]
+ public void List_WhenManaged_WorksWithNotifications()
+ {
+ var originalList = new List { 1, "string", true };
+
+ var rvo = _realm.Write(() =>
+ {
+ return _realm.Add(new RealmValueObject { RealmValueProperty = originalList });
+ });
+
+ var callbacks = new List();
+ using var token = rvo.RealmValueProperty.AsList().SubscribeForNotifications((collection, changes) =>
+ {
+ if (changes != null)
+ {
+ callbacks.Add(changes);
+ }
+ });
+
+ _realm.Write(() =>
+ {
+ rvo.RealmValueProperty.AsList()[2] = "mario";
+ });
+
+ _realm.Refresh();
+
+ Assert.That(callbacks.Count, Is.EqualTo(1));
+ }
}
}
From 2fdefc77a0198a690f19cb4186c7c78d94c2bf77 Mon Sep 17 00:00:00 2001
From: Ferdinando Papale <4850119+papafe@users.noreply.github.com>
Date: Mon, 25 Sep 2023 11:29:46 +0200
Subject: [PATCH 14/88] Small fixes
---
Realm/Realm/DatabaseTypes/RealmList.cs | 8 ++++++--
Realm/Realm/Handles/ListHandle.cs | 4 ++--
2 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/Realm/Realm/DatabaseTypes/RealmList.cs b/Realm/Realm/DatabaseTypes/RealmList.cs
index 41a61b4bc3..ea6699742b 100644
--- a/Realm/Realm/DatabaseTypes/RealmList.cs
+++ b/Realm/Realm/DatabaseTypes/RealmList.cs
@@ -138,6 +138,11 @@ public override int IndexOf([AllowNull] T value)
return -1;
}
+ if (realmValue.Type == RealmValueType.List)
+ {
+ return -1;
+ }
+
return _listHandle.Find(realmValue);
}
@@ -146,7 +151,6 @@ public void Insert(int index, T value)
ValidateIndex(index);
var realmValue = ValidateValueToInsert(value);
- //TODO Can we do something better than this, so at least we can take out the common?
if (realmValue.Type == RealmValueType.List)
{
var newListHandle = _listHandle.InsertList(index);
@@ -191,7 +195,7 @@ public override void RemoveAt(int index)
{
ValidateIndex(index);
- _listHandle.Erase((IntPtr)index);
+ _listHandle.Erase(index);
}
#endregion
diff --git a/Realm/Realm/Handles/ListHandle.cs b/Realm/Realm/Handles/ListHandle.cs
index 859863564e..25aa3886e6 100644
--- a/Realm/Realm/Handles/ListHandle.cs
+++ b/Realm/Realm/Handles/ListHandle.cs
@@ -225,11 +225,11 @@ public int Find(in RealmValue value)
return (int)result;
}
- public void Erase(IntPtr rowIndex)
+ public void Erase(int targetIndex)
{
EnsureIsOpen();
- NativeMethods.erase(this, rowIndex, out var nativeException);
+ NativeMethods.erase(this, (IntPtr)targetIndex, out var nativeException);
nativeException.ThrowIfNecessary();
}
From cdeaa4cbaee69b6c7f15e19a32f2702911eb1df2 Mon Sep 17 00:00:00 2001
From: Ferdinando Papale <4850119+papafe@users.noreply.github.com>
Date: Mon, 25 Sep 2023 11:33:53 +0200
Subject: [PATCH 15/88] Small fixes
---
.../Database/RealmValueWithCollections.cs | 39 ++++++++++++++++++-
1 file changed, 38 insertions(+), 1 deletion(-)
diff --git a/Tests/Realm.Tests/Database/RealmValueWithCollections.cs b/Tests/Realm.Tests/Database/RealmValueWithCollections.cs
index 3a2f57098d..e4ea636ed1 100644
--- a/Tests/Realm.Tests/Database/RealmValueWithCollections.cs
+++ b/Tests/Realm.Tests/Database/RealmValueWithCollections.cs
@@ -211,7 +211,7 @@ public void List_WhenManaged_CanBeModified()
}
[Test]
- public void List_AddSetInsertList_WorksAsIntended()
+ public void List_AddSetInsertMoveRemoveList_WorksAsIntended()
{
var listVal = new List { 1, "string", true };
@@ -222,6 +222,7 @@ public void List_AddSetInsertList_WorksAsIntended()
var innerList1 = new List { "inner", 23, false };
+ // Indexer
_realm.Write(() =>
{
rvo.RealmValueProperty.AsList()[1] = innerList1;
@@ -230,6 +231,7 @@ public void List_AddSetInsertList_WorksAsIntended()
Assert.That(rvo.RealmValueProperty.AsList(), Is.EqualTo(listVal));
+ // Insert
var innerList2 = new List { "inner2", 23, false };
_realm.Write(() =>
@@ -240,6 +242,7 @@ public void List_AddSetInsertList_WorksAsIntended()
Assert.That(rvo.RealmValueProperty.AsList(), Is.EqualTo(listVal));
+ // Add
var innerList3 = new List { "inner3", 23, false };
_realm.Write(() =>
@@ -249,6 +252,40 @@ public void List_AddSetInsertList_WorksAsIntended()
});
Assert.That(rvo.RealmValueProperty.AsList(), Is.EqualTo(listVal));
+
+ // Move
+ _realm.Write(() =>
+ {
+ rvo.RealmValueProperty.AsList().Move(0, 1);
+ listVal.Move(0, 1);
+ });
+
+ Assert.That(rvo.RealmValueProperty.AsList(), Is.EqualTo(listVal));
+
+ // Remove
+ _realm.Write(() =>
+ {
+ rvo.RealmValueProperty.AsList().RemoveAt(2);
+ listVal.RemoveAt(2);
+ });
+
+ Assert.That(rvo.RealmValueProperty.AsList(), Is.EqualTo(listVal));
+ }
+
+ public void List_RemoveWithListArgument_ReturnsFalse()
+ {
+ var innerListVal = new List { 1, "string", true };
+ var listVal = new List { innerListVal, 23 };
+
+ var rvo = _realm.Write(() =>
+ {
+ return _realm.Add(new RealmValueObject { RealmValueProperty = listVal });
+ });
+
+ _realm.Write(() =>
+ {
+ Assert.That(rvo.RealmValueProperty.AsList().Remove(innerListVal), Is.False);
+ });
}
[Test]
From 0c888ce0a7c322aa60514dc406ba67962a9372f4 Mon Sep 17 00:00:00 2001
From: Ferdinando Papale <4850119+papafe@users.noreply.github.com>
Date: Wed, 27 Sep 2023 14:47:30 +0200
Subject: [PATCH 16/88] Added common method for creating a list and adding
elements
---
Realm/Realm/DatabaseTypes/RealmList.cs | 33 ++++++++++-----------
Realm/Realm/DatabaseTypes/RealmValueType.cs | 6 ++--
Realm/Realm/Handles/ObjectHandle.cs | 9 ++----
3 files changed, 20 insertions(+), 28 deletions(-)
diff --git a/Realm/Realm/DatabaseTypes/RealmList.cs b/Realm/Realm/DatabaseTypes/RealmList.cs
index ea6699742b..bb0b79288d 100644
--- a/Realm/Realm/DatabaseTypes/RealmList.cs
+++ b/Realm/Realm/DatabaseTypes/RealmList.cs
@@ -69,12 +69,7 @@ internal RealmList(Realm realm, ListHandle adoptedList, Metadata? metadata) : ba
if (realmValue.Type == RealmValueType.List)
{
var newListHandle = _listHandle.SetList(index);
- var newList = new RealmList(Realm, newListHandle, null);
-
- foreach (var item in realmValue.AsList())
- {
- newList.Add(item);
- }
+ CreateAndAdd(Realm, newListHandle, realmValue);
return;
}
@@ -95,6 +90,18 @@ internal RealmList(Realm realm, ListHandle adoptedList, Metadata? metadata) : ba
}
}
+ internal static RealmList CreateAndAdd(Realm realm, ListHandle handle, RealmValue content)
+ {
+ var newList = new RealmList(realm, handle, null);
+
+ foreach (var item in content.AsList())
+ {
+ newList.Add(item);
+ }
+
+ return newList;
+ }
+
#region implementing IList members
public void Add(T value)
@@ -104,12 +111,7 @@ public void Add(T value)
if (realmValue.Type == RealmValueType.List)
{
var newListHandle = _listHandle.AddList();
- var newList = new RealmList(Realm, newListHandle, null);
-
- foreach (var item in realmValue.AsList())
- {
- newList.Add(item);
- }
+ CreateAndAdd(Realm, newListHandle, realmValue);
return;
}
@@ -154,12 +156,7 @@ public void Insert(int index, T value)
if (realmValue.Type == RealmValueType.List)
{
var newListHandle = _listHandle.InsertList(index);
- var newList = new RealmList(Realm, newListHandle, null);
-
- foreach (var item in realmValue.AsList())
- {
- newList.Add(item);
- }
+ CreateAndAdd(Realm, newListHandle, realmValue);
return;
}
diff --git a/Realm/Realm/DatabaseTypes/RealmValueType.cs b/Realm/Realm/DatabaseTypes/RealmValueType.cs
index d1069d6b48..1c409d6483 100644
--- a/Realm/Realm/DatabaseTypes/RealmValueType.cs
+++ b/Realm/Realm/DatabaseTypes/RealmValueType.cs
@@ -95,17 +95,17 @@ public enum RealmValueType : byte
Guid,
///
- /// The value represents a .
+ /// The value represents a .
///
List,
///
- /// The value represents a .
+ /// The value represents a .
///
Set,
///
- /// The value represents a .
+ /// The value represents a .
///
Dictionary,
}
diff --git a/Realm/Realm/Handles/ObjectHandle.cs b/Realm/Realm/Handles/ObjectHandle.cs
index 2e818f47af..2f9b9da535 100644
--- a/Realm/Realm/Handles/ObjectHandle.cs
+++ b/Realm/Realm/Handles/ObjectHandle.cs
@@ -225,15 +225,10 @@ public void SetValue(string propertyName, Metadata metadata, in RealmValue value
else if (value.Type == RealmValueType.List)
{
var listPtr = NativeMethods.set_list_value(this, propertyIndex, out var listNativeException);
- //TODO Need to do something with the exception
+ listNativeException.ThrowIfNecessary();
var listHandle = new ListHandle(Root!, listPtr);
- var realmList = new RealmList(realm, listHandle, null);
-
- foreach (var item in value.AsList())
- {
- realmList.Add(item);
- }
+ RealmList.CreateAndAdd(realm, listHandle, value);
return;
}
From 19f2167286869f4c891931bfd6e7daee142078c0 Mon Sep 17 00:00:00 2001
From: Ferdinando Papale <4850119+papafe@users.noreply.github.com>
Date: Wed, 27 Sep 2023 15:22:33 +0200
Subject: [PATCH 17/88] Fixed error [skip-ci]
---
wrappers/src/object_cs.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/wrappers/src/object_cs.cpp b/wrappers/src/object_cs.cpp
index e6bc37275b..9b30dfe73b 100644
--- a/wrappers/src/object_cs.cpp
+++ b/wrappers/src/object_cs.cpp
@@ -106,7 +106,7 @@ extern "C" {
if (!val.is_null() && val.get_type() == type_TypedLink) {
*value = to_capi(val.get(), object.realm());
}
- if (val.get_type() == type_List)
+ if (!val.is_null() && val.get_type() == type_List)
{
auto list = new List(object.realm(), object.get_obj(), prop.column_key);
*value = to_capi(list);
From 064a559deaabf7c8066b85eb2e7b645c8d67b765 Mon Sep 17 00:00:00 2001
From: Ferdinando Papale <4850119+papafe@users.noreply.github.com>
Date: Wed, 27 Sep 2023 15:40:18 +0200
Subject: [PATCH 18/88] Added set and dictionary to primitive value
---
Realm/Realm/Native/PrimitiveValue.cs | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/Realm/Realm/Native/PrimitiveValue.cs b/Realm/Realm/Native/PrimitiveValue.cs
index b5de932013..ddda090d21 100644
--- a/Realm/Realm/Native/PrimitiveValue.cs
+++ b/Realm/Realm/Native/PrimitiveValue.cs
@@ -71,6 +71,12 @@ internal unsafe struct PrimitiveValue
[FieldOffset(0)]
private ListValue list_value;
+ [FieldOffset(0)]
+ private SetValue set_value;
+
+ [FieldOffset(0)]
+ private DictionaryValue dictionary_value;
+
[FieldOffset(16)]
[MarshalAs(UnmanagedType.U1)]
public RealmValueType Type;
@@ -300,6 +306,18 @@ private struct ListValue
public IntPtr list_ptr;
}
+ [StructLayout(LayoutKind.Sequential)]
+ private struct SetValue
+ {
+ public IntPtr set_ptr;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct DictionaryValue
+ {
+ public IntPtr dict_ptr;
+ }
+
[StructLayout(LayoutKind.Sequential)]
private readonly struct TimestampValue
{
From 9b752904cc9f9696055897450043631feb6726f8 Mon Sep 17 00:00:00 2001
From: Ferdinando Papale <4850119+papafe@users.noreply.github.com>
Date: Thu, 28 Sep 2023 11:30:22 +0200
Subject: [PATCH 19/88] Various improvements
---
Realm/Realm/DatabaseTypes/RealmValue.cs | 105 +++++++++++++++++-
Realm/Realm/Native/PrimitiveValue.cs | 12 ++
.../Database/RealmValueWithCollections.cs | 3 +
3 files changed, 118 insertions(+), 2 deletions(-)
diff --git a/Realm/Realm/DatabaseTypes/RealmValue.cs b/Realm/Realm/DatabaseTypes/RealmValue.cs
index 2843d94fc4..080fc477ce 100644
--- a/Realm/Realm/DatabaseTypes/RealmValue.cs
+++ b/Realm/Realm/DatabaseTypes/RealmValue.cs
@@ -63,7 +63,10 @@ namespace Realms
private readonly string? _stringValue;
private readonly byte[]? _dataValue;
private readonly IRealmObjectBase? _objectValue;
+
private readonly IList? _listValue;
+ private readonly ISet? _setValue;
+ private readonly IDictionary? _dictionaryValue;
private readonly ObjectHandle? _objectHandle;
private readonly IntPtr _propertyIndex;
@@ -103,6 +106,14 @@ internal RealmValue(PrimitiveValue primitive, Realm? realm = null, ObjectHandle?
Argument.NotNull(realm, nameof(realm));
_listValue = primitive.AsList(realm!);
break;
+ case RealmValueType.Set:
+ Argument.NotNull(realm, nameof(realm));
+ _setValue = primitive.AsSet(realm!);
+ break;
+ case RealmValueType.Dictionary:
+ Argument.NotNull(realm, nameof(realm));
+ _dictionaryValue = primitive.AsDictionary(realm!);
+ break;
default:
_primitiveValue = primitive;
break;
@@ -133,6 +144,18 @@ private RealmValue(IList list) : this()
_listValue = list;
}
+ private RealmValue(ISet set) : this()
+ {
+ Type = RealmValueType.Set;
+ _setValue = set;
+ }
+
+ private RealmValue(IDictionary dict) : this()
+ {
+ Type = RealmValueType.Dictionary;
+ _dictionaryValue = dict;
+ }
+
///
/// Gets a RealmValue representing null.
///
@@ -162,8 +185,33 @@ private RealmValue(IList list) : this()
[EditorBrowsable(EditorBrowsableState.Never)]
public static RealmValue Object(IRealmObjectBase value) => new(value);
+ ///
+ /// Gets a RealmValue representing a list.
+ ///
+ /// The input list to copy.
+ /// A new RealmValue representing the input list.
+ /// Once created, this RealmValue will just wrap the input collection.
+ /// When the object containing this RealmValue gets managed, then this value will be a Realm list.
public static RealmValue List(IList value) => new(value);
+ ///
+ /// Gets a RealmValue representing a set.
+ ///
+ /// The input set to copy.
+ /// A new RealmValue representing the input set.
+ /// Once created, this RealmValue will just wrap the input collection.
+ /// When the object containing this RealmValue gets managed, then this value will be a Realm set.
+ public static RealmValue Set(ISet value) => new(value);
+
+ ///
+ /// Gets a RealmValue representing a dictionary.
+ ///
+ /// The input dictionary to copy.
+ /// A new RealmValue representing the input dictionary.
+ /// Once created, this RealmValue will just wrap the input collection.
+ /// When the object containing this RealmValue gets managed, then this value will be a Realm dictionary.
+ public static RealmValue Dictionary(IDictionary value) => new(value);
+
internal static RealmValue Create(T value, RealmValueType type)
{
if (value is null)
@@ -432,19 +480,46 @@ public byte[] AsData()
/// Returns the stored value as a string.
///
/// Thrown if the underlying value is not of type .
- /// /// A string representing the value stored in the database.
+ /// A string representing the value stored in the database.
public string AsString()
{
EnsureType("string", RealmValueType.String);
return _stringValue!;
}
+ ///
+ /// Returns the stored value as a list.
+ ///
+ /// Thrown if the underlying value is not of type .
+ /// A list representing the value stored in the database.
public IList AsList()
{
EnsureType("List", RealmValueType.List);
return _listValue!;
}
+ ///
+ /// Returns the stored value as a set.
+ ///
+ /// Thrown if the underlying value is not of type .
+ /// A set representing the value stored in the database.
+ public ISet AsSet()
+ {
+ EnsureType("Set", RealmValueType.Set);
+ return _setValue!;
+ }
+
+ ///
+ /// Returns the stored value as a dictionary.
+ ///
+ /// Thrown if the underlying value is not of type .
+ /// A dictionary representing the value stored in the database.
+ public IDictionary AsDictionary()
+ {
+ EnsureType("Dictionary", RealmValueType.Dictionary);
+ return _dictionaryValue!;
+ }
+
///
/// Returns the stored value as a .
///
@@ -735,6 +810,7 @@ public T As()
RealmValueType.ObjectId => Operator.Convert(AsObjectId()),
RealmValueType.Guid => Operator.Convert(AsGuid()),
RealmValueType.Object => Operator.Convert(AsIRealmObject()),
+ RealmValueType.List => (T)AsAny(),
_ => throw new NotSupportedException($"RealmValue of type {Type} is not supported."),
};
}
@@ -760,6 +836,8 @@ public T As()
RealmValueType.Guid => AsGuid(),
RealmValueType.Object => AsIRealmObject(),
RealmValueType.List => AsList(),
+ RealmValueType.Set => AsSet(),
+ RealmValueType.Dictionary => AsDictionary(),
_ => throw new NotSupportedException($"RealmValue of type {Type} is not supported."),
};
}
@@ -827,6 +905,9 @@ public override int GetHashCode()
RealmValueType.Decimal128 => AsDecimal128().GetHashCode(),
RealmValueType.ObjectId => AsObjectId().GetHashCode(),
RealmValueType.Object => AsIRealmObject().GetHashCode(),
+ RealmValueType.List => AsList().GetHashCode(),
+ RealmValueType.Set => AsSet().GetHashCode(),
+ RealmValueType.Dictionary => AsDictionary().GetHashCode(),
_ => 0,
};
@@ -1361,9 +1442,27 @@ public override int GetHashCode()
/// A containing the supplied .
public static implicit operator RealmValue(RealmObjectBase? val) => val == null ? Null : Object(val);
- //TODO Add docs
+ ///
+ /// Implicitly constructs a from List<RealmValue>?.
+ ///
+ /// The value to store in the .
+ /// A containing the supplied .
public static implicit operator RealmValue(List? val) => val == null ? Null : List(val);
+ ///
+ /// Implicitly constructs a from HashSet<RealmValue>.
+ ///
+ /// The value to store in the .
+ /// A containing the supplied .
+ public static implicit operator RealmValue(HashSet? val) => val == null ? Null : Set(val);
+
+ ///
+ /// Implicitly constructs a from Dictionary<string, RealmValue>.
+ ///
+ /// The value to store in the .
+ /// A containing the supplied .
+ public static implicit operator RealmValue(Dictionary? val) => val == null ? Null : Dictionary(val);
+
private void EnsureType(string target, RealmValueType type)
{
if (Type != type)
@@ -1429,6 +1528,8 @@ public bool Equals(RealmValue other)
RealmValueType.Guid => AsGuid() == other.AsGuid(),
RealmValueType.Object => AsIRealmObject().Equals(other.AsIRealmObject()),
RealmValueType.List => AsList().SequenceEqual(other.AsList()),
+ RealmValueType.Set => AsSet().SequenceEqual(other.AsSet()),
+ RealmValueType.Dictionary => AsDictionary().SequenceEqual(other.AsDictionary()),
RealmValueType.Null => true,
_ => false,
};
diff --git a/Realm/Realm/Native/PrimitiveValue.cs b/Realm/Realm/Native/PrimitiveValue.cs
index ddda090d21..439e85db07 100644
--- a/Realm/Realm/Native/PrimitiveValue.cs
+++ b/Realm/Realm/Native/PrimitiveValue.cs
@@ -279,6 +279,18 @@ public readonly RealmList AsList(Realm realm)
return new RealmList(realm, handle, null);
}
+ public readonly RealmSet AsSet(Realm realm)
+ {
+ var handle = new SetHandle(realm.SharedRealmHandle, set_value.set_ptr);
+ return new RealmSet(realm, handle, null);
+ }
+
+ public readonly RealmDictionary AsDictionary(Realm realm)
+ {
+ var handle = new DictionaryHandle(realm.SharedRealmHandle, dictionary_value.dict_ptr);
+ return new RealmDictionary(realm, handle, null);
+ }
+
public readonly bool TryGetObjectHandle(Realm realm, [NotNullWhen(true)] out ObjectHandle? handle)
{
if (Type == RealmValueType.Object)
diff --git a/Tests/Realm.Tests/Database/RealmValueWithCollections.cs b/Tests/Realm.Tests/Database/RealmValueWithCollections.cs
index e4ea636ed1..4c5b7eb666 100644
--- a/Tests/Realm.Tests/Database/RealmValueWithCollections.cs
+++ b/Tests/Realm.Tests/Database/RealmValueWithCollections.cs
@@ -71,6 +71,9 @@ public void List_WhenRetrieved_WorksWithAllTypes([Values(true, false)] bool isMa
Assert.That(rv != RealmValue.Null);
Assert.That(rv.AsList(), Is.EqualTo(originalList));
+ Assert.That(rv.AsAny(), Is.EqualTo(originalList));
+ Assert.That(rv.As>(), Is.EqualTo(originalList));
+
Assert.That(rv == originalList);
Assert.That(rv.Equals(originalList));
}
From 87b7ce35d4867b06f04ee250c0c38399c69647d0 Mon Sep 17 00:00:00 2001
From: Ferdinando Papale <4850119+papafe@users.noreply.github.com>
Date: Thu, 28 Sep 2023 12:56:59 +0200
Subject: [PATCH 20/88] Added conversion per list
---
Realm/Realm/DatabaseTypes/RealmValue.cs | 4 +++-
Realm/Realm/Helpers/Operator.cs | 14 ++++++++++++++
.../Database/RealmValueWithCollections.cs | 5 ++++-
3 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/Realm/Realm/DatabaseTypes/RealmValue.cs b/Realm/Realm/DatabaseTypes/RealmValue.cs
index 080fc477ce..fc33c80355 100644
--- a/Realm/Realm/DatabaseTypes/RealmValue.cs
+++ b/Realm/Realm/DatabaseTypes/RealmValue.cs
@@ -232,6 +232,8 @@ internal static RealmValue Create(T value, RealmValueType type)
RealmValueType.ObjectId => ObjectId(Operator.Convert(value)),
RealmValueType.Guid => Guid(Operator.Convert(value)),
RealmValueType.Object => Object(Operator.Convert(value)),
+ RealmValueType.List => List(Operator.Convert>(value)),
+ //TODO Need to add list here too?
_ => throw new NotSupportedException($"RealmValueType {type} is not supported."),
};
}
@@ -810,7 +812,7 @@ public T As()
RealmValueType.ObjectId => Operator.Convert(AsObjectId()),
RealmValueType.Guid => Operator.Convert(AsGuid()),
RealmValueType.Object => Operator.Convert(AsIRealmObject()),
- RealmValueType.List => (T)AsAny(),
+ RealmValueType.List => Operator.Convert, T>(AsList()),
_ => throw new NotSupportedException($"RealmValue of type {Type} is not supported."),
};
}
diff --git a/Realm/Realm/Helpers/Operator.cs b/Realm/Realm/Helpers/Operator.cs
index 2595d7a7eb..201de9ba9e 100644
--- a/Realm/Realm/Helpers/Operator.cs
+++ b/Realm/Realm/Helpers/Operator.cs
@@ -362,6 +362,9 @@ internal static class Operator
[(typeof(Decimal128), typeof(decimal))] = new Decimal128DecimalConverter(),
[(typeof(RealmValue), typeof(IRealmObjectBase))] = new RealmValueIRealmObjectBaseConverter(),
[(typeof(IRealmObjectBase), typeof(RealmValue))] = new IRealmObjectBaseRealmValueConverter(),
+
+ [(typeof(IList), typeof(RealmValue))] = new IListRealmValueConverter(),
+ [(typeof(RealmValue), typeof(IList))] = new RealmValueIListConverter(),
};
///
@@ -801,6 +804,17 @@ private class IRealmObjectBaseRealmValueConverter : SpecializedConverterBase value is null ? RealmValue.Null : RealmValue.Object(value);
}
+
+ private class IListRealmValueConverter : SpecializedConverterBase, RealmValue>
+ {
+ public override RealmValue Convert(IList? value) => value is null ? RealmValue.Null : RealmValue.List(value);
+ }
+
+ private class RealmValueIListConverter : SpecializedConverterBase>
+ {
+ public override IList Convert(RealmValue value) => value.AsList();
+ }
+
#endregion ToRealmValue Converters
#region FromRealmValue Converters
diff --git a/Tests/Realm.Tests/Database/RealmValueWithCollections.cs b/Tests/Realm.Tests/Database/RealmValueWithCollections.cs
index 4c5b7eb666..a377462bf8 100644
--- a/Tests/Realm.Tests/Database/RealmValueWithCollections.cs
+++ b/Tests/Realm.Tests/Database/RealmValueWithCollections.cs
@@ -101,21 +101,24 @@ public void List_WhenSetBeforeBeingManaged_WorksAsIntended()
}
[Test]
- public void List_WithConstructorMethodOrOperator_WorksTheSame([Values(true, false)] bool isManaged)
+ public void List_BuiltWithConstructorMethodOrOperatorOrCreate_WorksTheSame([Values(true, false)] bool isManaged)
{
var originalList = new List { 1, "string", true };
RealmValue rvOperator = originalList;
RealmValue rvConstructor = RealmValue.List(originalList);
+ RealmValue rvCreate = RealmValue.Create(originalList, RealmValueType.List);
if (isManaged)
{
rvOperator = PersistAndFind(rvOperator).RealmValueProperty;
rvConstructor = PersistAndFind(rvConstructor).RealmValueProperty;
+ rvCreate = PersistAndFind(rvCreate).RealmValueProperty;
}
Assert.That(rvOperator.AsList(), Is.EqualTo(originalList));
Assert.That(rvConstructor.AsList(), Is.EqualTo(originalList));
+ Assert.That(rvCreate.AsList(), Is.EqualTo(originalList));
}
[Test]
From 47119124a21aa7b3ba3731816b82a1fe63785334 Mon Sep 17 00:00:00 2001
From: Ferdinando Papale <4850119+papafe@users.noreply.github.com>
Date: Thu, 28 Sep 2023 13:11:44 +0200
Subject: [PATCH 21/88] Fixed Operator
---
Realm/Realm/Helpers/Operator.cs | 30 +++++++++++++++++++---
Realm/Realm/Helpers/Operator.tt | 45 ++++++++++++++++++++++++++++++++-
2 files changed, 70 insertions(+), 5 deletions(-)
diff --git a/Realm/Realm/Helpers/Operator.cs b/Realm/Realm/Helpers/Operator.cs
index 201de9ba9e..b0c94ddb9e 100644
--- a/Realm/Realm/Helpers/Operator.cs
+++ b/Realm/Realm/Helpers/Operator.cs
@@ -1,4 +1,4 @@
-////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////
//
// Copyright 2020 Realm Inc.
//
@@ -362,9 +362,12 @@ internal static class Operator
[(typeof(Decimal128), typeof(decimal))] = new Decimal128DecimalConverter(),
[(typeof(RealmValue), typeof(IRealmObjectBase))] = new RealmValueIRealmObjectBaseConverter(),
[(typeof(IRealmObjectBase), typeof(RealmValue))] = new IRealmObjectBaseRealmValueConverter(),
-
[(typeof(IList), typeof(RealmValue))] = new IListRealmValueConverter(),
[(typeof(RealmValue), typeof(IList))] = new RealmValueIListConverter(),
+ [(typeof(ISet), typeof(RealmValue))] = new ISetRealmValueConverter(),
+ [(typeof(RealmValue), typeof(ISet))] = new RealmValueISetConverter(),
+ [(typeof(IDictionary), typeof(RealmValue))] = new IDictionaryRealmValueConverter(),
+ [(typeof(RealmValue), typeof(IDictionary))] = new RealmValueIDictionaryConverter(),
};
///
@@ -810,11 +813,15 @@ private class IListRealmValueConverter : SpecializedConverterBase? value) => value is null ? RealmValue.Null : RealmValue.List(value);
}
- private class RealmValueIListConverter : SpecializedConverterBase>
+ private class ISetRealmValueConverter : SpecializedConverterBase, RealmValue>
{
- public override IList Convert(RealmValue value) => value.AsList();
+ public override RealmValue Convert(ISet? value) => value is null ? RealmValue.Null : RealmValue.Set(value);
}
+ private class IDictionaryRealmValueConverter : SpecializedConverterBase, RealmValue>
+ {
+ public override RealmValue Convert(IDictionary? value) => value is null ? RealmValue.Null : RealmValue.Dictionary(value);
+ }
#endregion ToRealmValue Converters
#region FromRealmValue Converters
@@ -1008,6 +1015,21 @@ private class RealmValueIRealmObjectBaseConverter : SpecializedConverterBase value.AsIRealmObject();
}
+
+ private class RealmValueIListConverter : SpecializedConverterBase>
+ {
+ public override IList Convert(RealmValue value) => value.AsList();
+ }
+
+ private class RealmValueISetConverter : SpecializedConverterBase>
+ {
+ public override ISet Convert(RealmValue value) => value.AsSet();
+ }
+
+ private class RealmValueIDictionaryConverter : SpecializedConverterBase>
+ {
+ public override IDictionary Convert(RealmValue value) => value.AsDictionary();
+ }
#endregion FromRealmValue Converters
#region Integral Converters
diff --git a/Realm/Realm/Helpers/Operator.tt b/Realm/Realm/Helpers/Operator.tt
index a4c3dec819..73de520bfa 100644
--- a/Realm/Realm/Helpers/Operator.tt
+++ b/Realm/Realm/Helpers/Operator.tt
@@ -43,7 +43,7 @@ namespace Realms.Helpers
{
<#
var realmValueContents = GetFileContents("../DatabaseTypes/RealmValue.cs");
- var implicitToRealmValueTypes = GetMatchedGroups(realmValueContents, _implicitTypeToRealmValueRegex, "fromType");
+ var implicitToRealmValueTypes = GetMatchedGroups(realmValueContents, _implicitTypeToRealmValueRegex, "fromType").Except(_implicitTypeExcludeList);
foreach (var type in implicitToRealmValueTypes)
{
#>
@@ -75,6 +75,12 @@ namespace Realms.Helpers
#>
[(typeof(RealmValue), typeof(IRealmObjectBase))] = new RealmValueIRealmObjectBaseConverter(),
[(typeof(IRealmObjectBase), typeof(RealmValue))] = new IRealmObjectBaseRealmValueConverter(),
+ [(typeof(IList), typeof(RealmValue))] = new IListRealmValueConverter(),
+ [(typeof(RealmValue), typeof(IList))] = new RealmValueIListConverter(),
+ [(typeof(ISet), typeof(RealmValue))] = new ISetRealmValueConverter(),
+ [(typeof(RealmValue), typeof(ISet))] = new RealmValueISetConverter(),
+ [(typeof(IDictionary), typeof(RealmValue))] = new IDictionaryRealmValueConverter(),
+ [(typeof(RealmValue), typeof(IDictionary))] = new RealmValueIDictionaryConverter(),
};
///
@@ -341,6 +347,21 @@ namespace Realms.Helpers
{
public override RealmValue Convert(IRealmObjectBase? value) => value is null ? RealmValue.Null : RealmValue.Object(value);
}
+
+ private class IListRealmValueConverter : SpecializedConverterBase, RealmValue>
+ {
+ public override RealmValue Convert(IList? value) => value is null ? RealmValue.Null : RealmValue.List(value);
+ }
+
+ private class ISetRealmValueConverter : SpecializedConverterBase, RealmValue>
+ {
+ public override RealmValue Convert(ISet? value) => value is null ? RealmValue.Null : RealmValue.Set(value);
+ }
+
+ private class IDictionaryRealmValueConverter : SpecializedConverterBase, RealmValue>
+ {
+ public override RealmValue Convert(IDictionary? value) => value is null ? RealmValue.Null : RealmValue.Dictionary(value);
+ }
#endregion ToRealmValue Converters
#region FromRealmValue Converters
@@ -361,6 +382,21 @@ namespace Realms.Helpers
{
public override IRealmObjectBase Convert(RealmValue value) => value.AsIRealmObject();
}
+
+ private class RealmValueIListConverter : SpecializedConverterBase>
+ {
+ public override IList Convert(RealmValue value) => value.AsList();
+ }
+
+ private class RealmValueISetConverter : SpecializedConverterBase>
+ {
+ public override ISet Convert(RealmValue value) => value.AsSet();
+ }
+
+ private class RealmValueIDictionaryConverter : SpecializedConverterBase>
+ {
+ public override IDictionary Convert(RealmValue value) => value.AsDictionary();
+ }
#endregion FromRealmValue Converters
#region Integral Converters
@@ -400,6 +436,13 @@ namespace Realms.Helpers
private static readonly Regex _implicitTypeToRealmValueRegex = new Regex(@"public static implicit operator RealmValue\((?\S*)");
private static readonly Regex _explicitRealmValueToTypeRegex = new Regex(@"public static explicit operator (?[^\(]*)\(RealmValue");
+ private static readonly List _implicitTypeExcludeList = new()
+ {
+ "List?",
+ "HashSet?",
+ "Dictionary
Date: Thu, 28 Sep 2023 13:14:07 +0200
Subject: [PATCH 22/88] Added missing conversion methods
---
Realm/Realm/DatabaseTypes/RealmValue.cs | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/Realm/Realm/DatabaseTypes/RealmValue.cs b/Realm/Realm/DatabaseTypes/RealmValue.cs
index fc33c80355..928714b897 100644
--- a/Realm/Realm/DatabaseTypes/RealmValue.cs
+++ b/Realm/Realm/DatabaseTypes/RealmValue.cs
@@ -233,7 +233,8 @@ internal static RealmValue Create(T value, RealmValueType type)
RealmValueType.Guid => Guid(Operator.Convert(value)),
RealmValueType.Object => Object(Operator.Convert(value)),
RealmValueType.List => List(Operator.Convert>(value)),
- //TODO Need to add list here too?
+ RealmValueType.Set => Set(Operator.Convert>(value)),
+ RealmValueType.Dictionary => Dictionary(Operator.Convert>(value)),
_ => throw new NotSupportedException($"RealmValueType {type} is not supported."),
};
}
@@ -813,6 +814,8 @@ public T As()
RealmValueType.Guid => Operator.Convert(AsGuid()),
RealmValueType.Object => Operator.Convert(AsIRealmObject()),
RealmValueType.List => Operator.Convert, T>(AsList()),
+ RealmValueType.Set => Operator.Convert, T>(AsSet()),
+ RealmValueType.Dictionary => Operator.Convert, T>(AsDictionary()),
_ => throw new NotSupportedException($"RealmValue of type {Type} is not supported."),
};
}
From acf2b825924dc353d26ceb274065061286fc8282 Mon Sep 17 00:00:00 2001
From: Ferdinando Papale <4850119+papafe@users.noreply.github.com>
Date: Thu, 28 Sep 2023 13:26:48 +0200
Subject: [PATCH 23/88] Corrected wrapper
---
wrappers/src/object_cs.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/wrappers/src/object_cs.cpp b/wrappers/src/object_cs.cpp
index 9b30dfe73b..d805c78fd9 100644
--- a/wrappers/src/object_cs.cpp
+++ b/wrappers/src/object_cs.cpp
@@ -106,7 +106,7 @@ extern "C" {
if (!val.is_null() && val.get_type() == type_TypedLink) {
*value = to_capi(val.get(), object.realm());
}
- if (!val.is_null() && val.get_type() == type_List)
+ else if (!val.is_null() && val.get_type() == type_List)
{
auto list = new List(object.realm(), object.get_obj(), prop.column_key);
*value = to_capi(list);
From bbc8f43d29b83d794370873f96b81d5483304d14 Mon Sep 17 00:00:00 2001
From: Ferdinando Papale <4850119+papafe@users.noreply.github.com>
Date: Thu, 28 Sep 2023 14:23:38 +0200
Subject: [PATCH 24/88] Added test helper method for realm value types and
removed unused reflextion extension method
---
Realm/Realm/DatabaseTypes/RealmValueType.cs | 6 +++---
Realm/Realm/Extensions/ReflectionExtensions.cs | 2 --
Tests/Realm.Tests/Database/ObjectSchemaTests.cs | 6 ++----
Tests/Realm.Tests/Database/RealmValueTests.cs | 2 +-
Tests/Realm.Tests/TestHelpers.cs | 6 ++++++
wrappers/src/object_cs.cpp | 3 +--
6 files changed, 13 insertions(+), 12 deletions(-)
diff --git a/Realm/Realm/DatabaseTypes/RealmValueType.cs b/Realm/Realm/DatabaseTypes/RealmValueType.cs
index 1c409d6483..ab60b1776c 100644
--- a/Realm/Realm/DatabaseTypes/RealmValueType.cs
+++ b/Realm/Realm/DatabaseTypes/RealmValueType.cs
@@ -95,17 +95,17 @@ public enum RealmValueType : byte
Guid,
///
- /// The value represents a .
+ /// The value represents a .
///
List,
///
- /// The value represents a .
+ /// The value represents a .
///
Set,
///
- /// The value represents a .
+ /// The value represents a .
///
Dictionary,
}
diff --git a/Realm/Realm/Extensions/ReflectionExtensions.cs b/Realm/Realm/Extensions/ReflectionExtensions.cs
index fafb8da79a..d0b0cce93d 100644
--- a/Realm/Realm/Extensions/ReflectionExtensions.cs
+++ b/Realm/Realm/Extensions/ReflectionExtensions.cs
@@ -67,7 +67,5 @@ public static ObjectSchema.ObjectType GetRealmSchemaType(this Type type)
return ObjectSchema.ObjectType.RealmObject;
}
-
- public static T[] GetEnumValues() => Enum.GetValues(typeof(T)).Cast().ToArray();
}
}
diff --git a/Tests/Realm.Tests/Database/ObjectSchemaTests.cs b/Tests/Realm.Tests/Database/ObjectSchemaTests.cs
index 53db7773e7..d461fc5650 100644
--- a/Tests/Realm.Tests/Database/ObjectSchemaTests.cs
+++ b/Tests/Realm.Tests/Database/ObjectSchemaTests.cs
@@ -313,11 +313,9 @@ public void Property_FromTypeGeneric_Object(
}
}
- public static readonly RealmValueType[] PrimitiveTypes = ReflectionExtensions.GetEnumValues();
-
[Test]
public void Property_Primitive_Tests(
- [ValueSource(nameof(PrimitiveTypes))] RealmValueType type,
+ [ValueSource(nameof(TestHelpers.PrimitiveRealmValueTypes))] RealmValueType type,
[ValueSource(nameof(BoolValues))] bool isPrimaryKey,
[ValueSource(nameof(IndexTypes))] IndexType indexType,
[ValueSource(nameof(BoolValues))] bool isNullable)
@@ -369,7 +367,7 @@ public void Property_Primitive_Tests(
[Test]
public void Property_PrimitiveCollection_Tests(
[ValueSource(nameof(CollectionTypes))] PropertyType collectionType,
- [ValueSource(nameof(PrimitiveTypes))] RealmValueType type,
+ [ValueSource(nameof(TestHelpers.PrimitiveRealmValueTypes))] RealmValueType type,
[ValueSource(nameof(BoolValues))] bool isNullable)
{
Property getProperty() => collectionType switch
diff --git a/Tests/Realm.Tests/Database/RealmValueTests.cs b/Tests/Realm.Tests/Database/RealmValueTests.cs
index d8fc5c1b44..8427e5f188 100644
--- a/Tests/Realm.Tests/Database/RealmValueTests.cs
+++ b/Tests/Realm.Tests/Database/RealmValueTests.cs
@@ -1010,7 +1010,7 @@ public void Query_Generic()
Assert.That(f, Is.EquivalentTo(referenceResult));
}
- foreach (var type in (RealmValueType[])Enum.GetValues(typeof(RealmValueType)))
+ foreach (var type in TestHelpers.PrimitiveRealmValueTypes)
{
// Equality on RealmValueType
var referenceResult = rvObjects.Where(r => r.RealmValueProperty.Type == type).OrderBy(r => r.Id).ToList();
diff --git a/Tests/Realm.Tests/TestHelpers.cs b/Tests/Realm.Tests/TestHelpers.cs
index 820e08842d..b06b2374cd 100644
--- a/Tests/Realm.Tests/TestHelpers.cs
+++ b/Tests/Realm.Tests/TestHelpers.cs
@@ -410,5 +410,11 @@ public class StrongBox
public static implicit operator StrongBox(T value) => new() { Value = value };
}
+
+ public static IEnumerable CollectionRealmValueTypes =
+ new[] { RealmValueType.List, RealmValueType.Set, RealmValueType.Dictionary };
+
+ public static IEnumerable PrimitiveRealmValueTypes = ((RealmValueType[])Enum.GetValues(typeof(RealmValueType)))
+ .Except(CollectionRealmValueTypes);
}
}
diff --git a/wrappers/src/object_cs.cpp b/wrappers/src/object_cs.cpp
index d805c78fd9..3569488234 100644
--- a/wrappers/src/object_cs.cpp
+++ b/wrappers/src/object_cs.cpp
@@ -108,8 +108,7 @@ extern "C" {
}
else if (!val.is_null() && val.get_type() == type_List)
{
- auto list = new List(object.realm(), object.get_obj(), prop.column_key);
- *value = to_capi(list);
+ *value = to_capi(new List(object.realm(), object.get_obj(), prop.column_key));
}
else {
*value = to_capi(std::move(val));
From 4cb30202c699f191533248bdf63ba4eac209bf4c Mon Sep 17 00:00:00 2001
From: Ferdinando Papale <4850119+papafe@users.noreply.github.com>
Date: Thu, 28 Sep 2023 14:46:14 +0200
Subject: [PATCH 25/88] Added missing types for marshaling
---
wrappers/src/marshalling.hpp | 38 +++++++++++++++++++++++++++++++++---
1 file changed, 35 insertions(+), 3 deletions(-)
diff --git a/wrappers/src/marshalling.hpp b/wrappers/src/marshalling.hpp
index 2be6c4e6f7..8c9484fbbe 100644
--- a/wrappers/src/marshalling.hpp
+++ b/wrappers/src/marshalling.hpp
@@ -101,7 +101,9 @@ enum class realm_value_type : uint8_t {
RLM_TYPE_OBJECT_ID,
RLM_TYPE_LINK,
RLM_TYPE_UUID,
- RLM_TYPE_LIST
+ RLM_TYPE_LIST,
+ RLM_TYPE_SET,
+ RLM_TYPE_DICTIONARY,
};
enum class query_argument_type : uint8_t {
@@ -136,9 +138,17 @@ typedef struct realm_link {
} realm_link_t;
typedef struct realm_list {
- List* list;
+ List* list_ptr;
} realm_list_t;
+typedef struct realm_set {
+ object_store::Set* set_ptr;
+} realm_set_t;
+
+typedef struct realm_dict {
+ Dictionary* dictionary_ptr;
+} realm_dict_t;
+
typedef struct realm_object_id {
uint8_t bytes[12];
} realm_object_id_t;
@@ -162,6 +172,8 @@ typedef struct realm_value {
realm_link_t link;
realm_list_t list;
+ realm_set_t set;
+ realm_dict_t dictionary;
char data[16];
};
@@ -511,7 +523,23 @@ static inline realm_value_t to_capi(List* list)
{
realm_value_t val{};
val.type = realm_value_type::RLM_TYPE_LIST;
- val.list.list = list;
+ val.list.list_ptr = list;
+ return val;
+}
+
+static inline realm_value_t to_capi(object_store::Set* set)
+{
+ realm_value_t val{};
+ val.type = realm_value_type::RLM_TYPE_SET;
+ val.set.set_ptr = set;
+ return val;
+}
+
+static inline realm_value_t to_capi(Dictionary* dictionary)
+{
+ realm_value_t val{};
+ val.type = realm_value_type::RLM_TYPE_DICTIONARY;
+ val.dictionary.dictionary_ptr = dictionary;
return val;
}
@@ -577,6 +605,10 @@ static inline realm_value_t to_capi(const Mixed& value)
val.uuid = to_capi(value.get());
break;
}
+ case type_List:
+ case type_Set:
+ case type_Dictionary:
+ REALM_TERMINATE("Can't use this overload of to_capi on values containing collections, use to_capi(Collection*) instead.");
default:
REALM_TERMINATE("Invalid Mixed value type");
}
From b0e4cd967e52df87468e152e87d5498173d2ca0e Mon Sep 17 00:00:00 2001
From: Ferdinando Papale <4850119+papafe@users.noreply.github.com>
Date: Thu, 28 Sep 2023 14:48:55 +0200
Subject: [PATCH 26/88] Small improvement in operator
---
Realm/Realm/Helpers/Operator.tt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Realm/Realm/Helpers/Operator.tt b/Realm/Realm/Helpers/Operator.tt
index 73de520bfa..f0c87aee01 100644
--- a/Realm/Realm/Helpers/Operator.tt
+++ b/Realm/Realm/Helpers/Operator.tt
@@ -436,7 +436,7 @@ namespace Realms.Helpers
private static readonly Regex _implicitTypeToRealmValueRegex = new Regex(@"public static implicit operator RealmValue\((?\S*)");
private static readonly Regex _explicitRealmValueToTypeRegex = new Regex(@"public static explicit operator (?[^\(]*)\(RealmValue");
- private static readonly List _implicitTypeExcludeList = new()
+ private static readonly string[] _implicitTypeExcludeList = new[]
{
"List?",
"HashSet?",
From 4785943f0a66ec4d1bc26f778b87af8cf42f1ee6 Mon Sep 17 00:00:00 2001
From: Ferdinando Papale <4850119+papafe@users.noreply.github.com>
Date: Thu, 28 Sep 2023 16:21:08 +0200
Subject: [PATCH 27/88] Small corrections
---
Realm/Realm/DatabaseTypes/RealmDictionary.cs | 12 ++++++++
Realm/Realm/DatabaseTypes/RealmList.cs | 24 +++++++--------
Realm/Realm/DatabaseTypes/RealmSet.cs | 12 ++++++++
Realm/Realm/DatabaseTypes/RealmValue.cs | 4 +--
Realm/Realm/Handles/ObjectHandle.cs | 30 +++++++++++++++++--
.../Database/RealmValueWithCollections.cs | 2 ++
wrappers/src/marshalling.hpp | 4 +--
wrappers/src/object_cs.cpp | 24 +++++++++++++++
8 files changed, 94 insertions(+), 18 deletions(-)
diff --git a/Realm/Realm/DatabaseTypes/RealmDictionary.cs b/Realm/Realm/DatabaseTypes/RealmDictionary.cs
index 230c7a91bc..1e8ba2cc8a 100644
--- a/Realm/Realm/DatabaseTypes/RealmDictionary.cs
+++ b/Realm/Realm/DatabaseTypes/RealmDictionary.cs
@@ -243,6 +243,18 @@ private static void ValidateKey(string key)
}
}
+ internal static RealmDictionary CreateAndAdd(Realm realm, DictionaryHandle handle, RealmValue content)
+ {
+ var newDictionary = new RealmDictionary(realm, handle, null);
+
+ foreach (var item in content.AsList())
+ {
+ newDictionary.Add(item);
+ }
+
+ return newDictionary;
+ }
+
internal override RealmCollectionBase> CreateCollection(Realm realm, CollectionHandleBase handle) => new RealmDictionary(realm, (DictionaryHandle)handle, Metadata);
internal override CollectionHandleBase GetOrCreateHandle() => _dictionaryHandle;
diff --git a/Realm/Realm/DatabaseTypes/RealmList.cs b/Realm/Realm/DatabaseTypes/RealmList.cs
index bb0b79288d..f3cee70daf 100644
--- a/Realm/Realm/DatabaseTypes/RealmList.cs
+++ b/Realm/Realm/DatabaseTypes/RealmList.cs
@@ -90,18 +90,6 @@ internal RealmList(Realm realm, ListHandle adoptedList, Metadata? metadata) : ba
}
}
- internal static RealmList CreateAndAdd(Realm realm, ListHandle handle, RealmValue content)
- {
- var newList = new RealmList(realm, handle, null);
-
- foreach (var item in content.AsList())
- {
- newList.Add(item);
- }
-
- return newList;
- }
-
#region implementing IList members
public void Add(T value)
@@ -211,6 +199,18 @@ internal RealmResults ToResults()
return new RealmResults(Realm, resultsHandle, Metadata);
}
+ internal static RealmList CreateAndAdd(Realm realm, ListHandle handle, RealmValue content)
+ {
+ var newList = new RealmList(realm, handle, null);
+
+ foreach (var item in content.AsList())
+ {
+ newList.Add(item);
+ }
+
+ return newList;
+ }
+
internal override RealmCollectionBase CreateCollection(Realm realm, CollectionHandleBase handle) => new RealmList(realm, (ListHandle)handle, Metadata);
protected override T GetValueAtIndex(int index) => _listHandle.GetValueAtIndex(index, Realm).As();
diff --git a/Realm/Realm/DatabaseTypes/RealmSet.cs b/Realm/Realm/DatabaseTypes/RealmSet.cs
index 50f77ef88e..8933061bcf 100644
--- a/Realm/Realm/DatabaseTypes/RealmSet.cs
+++ b/Realm/Realm/DatabaseTypes/RealmSet.cs
@@ -127,6 +127,18 @@ internal RealmResults ToResults()
return new RealmResults(Realm, resultsHandle, Metadata);
}
+ internal static RealmSet CreateAndAdd(Realm realm, SetHandle handle, RealmValue content)
+ {
+ var newSet = new RealmSet(realm, handle, null);
+
+ foreach (var item in content.AsList())
+ {
+ newSet.Add(item);
+ }
+
+ return newSet;
+ }
+
internal override RealmCollectionBase CreateCollection(Realm realm, CollectionHandleBase handle) => new RealmSet(realm, (SetHandle)handle, Metadata);
internal override CollectionHandleBase GetOrCreateHandle() => _setHandle;
diff --git a/Realm/Realm/DatabaseTypes/RealmValue.cs b/Realm/Realm/DatabaseTypes/RealmValue.cs
index 928714b897..16911c78c2 100644
--- a/Realm/Realm/DatabaseTypes/RealmValue.cs
+++ b/Realm/Realm/DatabaseTypes/RealmValue.cs
@@ -1533,8 +1533,8 @@ public bool Equals(RealmValue other)
RealmValueType.Guid => AsGuid() == other.AsGuid(),
RealmValueType.Object => AsIRealmObject().Equals(other.AsIRealmObject()),
RealmValueType.List => AsList().SequenceEqual(other.AsList()),
- RealmValueType.Set => AsSet().SequenceEqual(other.AsSet()),
- RealmValueType.Dictionary => AsDictionary().SequenceEqual(other.AsDictionary()),
+ RealmValueType.Set => AsSet().SetEquals(other.AsSet()),
+ RealmValueType.Dictionary => AsDictionary().SequenceEqual(other.AsDictionary()), //TODO Check if this is correct
RealmValueType.Null => true,
_ => false,
};
diff --git a/Realm/Realm/Handles/ObjectHandle.cs b/Realm/Realm/Handles/ObjectHandle.cs
index 2f9b9da535..07b8883d58 100644
--- a/Realm/Realm/Handles/ObjectHandle.cs
+++ b/Realm/Realm/Handles/ObjectHandle.cs
@@ -48,6 +48,12 @@ private static class NativeMethods
[DllImport(InteropConfig.DLL_NAME, EntryPoint = "object_set_list_value", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr set_list_value(ObjectHandle handle, IntPtr propertyIndex, out NativeException ex);
+ [DllImport(InteropConfig.DLL_NAME, EntryPoint = "object_set_set_value", CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr set_set_value(ObjectHandle handle, IntPtr propertyIndex, out NativeException ex);
+
+ [DllImport(InteropConfig.DLL_NAME, EntryPoint = "object_set_dictionary_value", CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr set_dictionary_value(ObjectHandle handle, IntPtr propertyIndex, out NativeException ex);
+
[DllImport(InteropConfig.DLL_NAME, EntryPoint = "object_create_embedded", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr create_embedded_link(ObjectHandle handle, IntPtr propertyIndex, out NativeException ex);
@@ -227,8 +233,28 @@ public void SetValue(string propertyName, Metadata metadata, in RealmValue value
var listPtr = NativeMethods.set_list_value(this, propertyIndex, out var listNativeException);
listNativeException.ThrowIfNecessary();
- var listHandle = new ListHandle(Root!, listPtr);
- RealmList.CreateAndAdd(realm, listHandle, value);
+ var handle = new ListHandle(Root!, listPtr);
+ RealmList.CreateAndAdd(realm, handle, value);
+
+ return;
+ }
+ else if (value.Type == RealmValueType.Set)
+ {
+ var setPtr = NativeMethods.set_set_value(this, propertyIndex, out var setNativeException);
+ setNativeException.ThrowIfNecessary();
+
+ var handle = new SetHandle(Root!, setPtr);
+ RealmSet.CreateAndAdd(realm, handle, value);
+
+ return;
+ }
+ else if (value.Type == RealmValueType.Dictionary)
+ {
+ var dictPtr = NativeMethods.set_dictionary_value(this, propertyIndex, out var dictNativeException);
+ dictNativeException.ThrowIfNecessary();
+
+ var handle = new DictionaryHandle(Root!, dictPtr);
+ RealmDictionary.CreateAndAdd(realm, handle, value);
return;
}
diff --git a/Tests/Realm.Tests/Database/RealmValueWithCollections.cs b/Tests/Realm.Tests/Database/RealmValueWithCollections.cs
index a377462bf8..c04cf4de63 100644
--- a/Tests/Realm.Tests/Database/RealmValueWithCollections.cs
+++ b/Tests/Realm.Tests/Database/RealmValueWithCollections.cs
@@ -100,6 +100,8 @@ public void List_WhenSetBeforeBeingManaged_WorksAsIntended()
Assert.That(rv.AsList(), Is.EqualTo(originalList));
}
+ //TODO Add test about setting the list from another "managed" list
+
[Test]
public void List_BuiltWithConstructorMethodOrOperatorOrCreate_WorksTheSame([Values(true, false)] bool isManaged)
{
diff --git a/wrappers/src/marshalling.hpp b/wrappers/src/marshalling.hpp
index 8c9484fbbe..666c95b5f5 100644
--- a/wrappers/src/marshalling.hpp
+++ b/wrappers/src/marshalling.hpp
@@ -146,7 +146,7 @@ typedef struct realm_set {
} realm_set_t;
typedef struct realm_dict {
- Dictionary* dictionary_ptr;
+ object_store::Dictionary* dictionary_ptr;
} realm_dict_t;
typedef struct realm_object_id {
@@ -535,7 +535,7 @@ static inline realm_value_t to_capi(object_store::Set* set)
return val;
}
-static inline realm_value_t to_capi(Dictionary* dictionary)
+static inline realm_value_t to_capi(object_store::Dictionary* dictionary)
{
realm_value_t val{};
val.type = realm_value_type::RLM_TYPE_DICTIONARY;
diff --git a/wrappers/src/object_cs.cpp b/wrappers/src/object_cs.cpp
index 3569488234..f2930de0a4 100644
--- a/wrappers/src/object_cs.cpp
+++ b/wrappers/src/object_cs.cpp
@@ -175,6 +175,30 @@ extern "C" {
});
}
+ REALM_EXPORT object_store::Set* object_set_set_value(Object& object, size_t property_ndx, NativeException::Marshallable& ex)
+ {
+ return handle_errors(ex, [&]() {
+ verify_can_set(object);
+
+ auto prop = get_property(object, property_ndx);
+ object.get_obj().set_collection(prop.column_key, CollectionType::Set);
+
+ return new object_store::Set(object.realm(), object.get_obj(), prop.column_key);
+ });
+ }
+
+ REALM_EXPORT object_store::Dictionary* object_set_dictionary_value(Object& object, size_t property_ndx, NativeException::Marshallable& ex)
+ {
+ return handle_errors(ex, [&]() {
+ verify_can_set(object);
+
+ auto prop = get_property(object, property_ndx);
+ object.get_obj().set_collection(prop.column_key, CollectionType::Dictionary);
+
+ return new object_store::Dictionary(object.realm(), object.get_obj(), prop.column_key);
+ });
+ }
+
REALM_EXPORT Results* object_get_backlinks(Object& object, size_t property_ndx, NativeException::Marshallable& ex)
{
return handle_errors(ex, [&] {
From 013bfb7674f48003ef81e294110844b479a0b61a Mon Sep 17 00:00:00 2001
From: Ferdinando Papale <4850119+papafe@users.noreply.github.com>
Date: Fri, 29 Sep 2023 10:36:49 +0200
Subject: [PATCH 28/88] Added error for sets adding collections
---
Realm/Realm/DatabaseTypes/RealmSet.cs | 5 +++++
Realm/Realm/Extensions/RealmValueExtensions.cs | 9 +++++++++
2 files changed, 14 insertions(+)
diff --git a/Realm/Realm/DatabaseTypes/RealmSet.cs b/Realm/Realm/DatabaseTypes/RealmSet.cs
index 8933061bcf..125e3a057c 100644
--- a/Realm/Realm/DatabaseTypes/RealmSet.cs
+++ b/Realm/Realm/DatabaseTypes/RealmSet.cs
@@ -73,6 +73,11 @@ public bool Add(T value)
var realmValue = Operator.Convert(value);
+ if (realmValue.Type.IsCollection())
+ {
+ throw new InvalidOperationException("Set cannot contain other collections.");
+ }
+
AddToRealmIfNecessary(realmValue);
return _setHandle.Add(realmValue);
}
diff --git a/Realm/Realm/Extensions/RealmValueExtensions.cs b/Realm/Realm/Extensions/RealmValueExtensions.cs
index 0d5245bc73..956f848195 100644
--- a/Realm/Realm/Extensions/RealmValueExtensions.cs
+++ b/Realm/Realm/Extensions/RealmValueExtensions.cs
@@ -31,8 +31,17 @@ internal static class RealmValueExtensions
RealmValueType.Decimal128
};
+ private static readonly HashSet _collectionTypes = new()
+ {
+ RealmValueType.List,
+ RealmValueType.Set,
+ RealmValueType.Dictionary,
+ };
+
public static bool IsNumeric(this RealmValueType type) => _numericTypes.Contains(type);
+ public static bool IsCollection(this RealmValueType type) => _collectionTypes.Contains(type);
+
public static (NativeQueryArgument[] Values, RealmValue.HandlesToCleanup?[] Handles) ToNativeValues(this QueryArgument[] arguments)
{
var nativeArgs = new NativeQueryArgument[arguments.Length];
From 143f27ce6257fc2a478b93b2a70b29a169a2770c Mon Sep 17 00:00:00 2001
From: Ferdinando Papale <4850119+papafe@users.noreply.github.com>
Date: Fri, 29 Sep 2023 13:00:59 +0200
Subject: [PATCH 29/88] Trting to uniform access
---
Realm/Realm/DatabaseTypes/RealmList.cs | 59 +++++++++++------
Realm/Realm/Handles/ListHandle.cs | 84 +++++++++++++++++++-----
Realm/Realm/Handles/ObjectHandle.cs | 3 +-
Realm/Realm/Helpers/CollectionHelpers.cs | 58 ++++++++++++++++
wrappers/src/list_cs.cpp | 44 ++++++++++---
5 files changed, 202 insertions(+), 46 deletions(-)
create mode 100644 Realm/Realm/Helpers/CollectionHelpers.cs
diff --git a/Realm/Realm/DatabaseTypes/RealmList.cs b/Realm/Realm/DatabaseTypes/RealmList.cs
index f3cee70daf..74d66a8dc1 100644
--- a/Realm/Realm/DatabaseTypes/RealmList.cs
+++ b/Realm/Realm/DatabaseTypes/RealmList.cs
@@ -23,6 +23,7 @@
using System.Diagnostics.CodeAnalysis;
using System.Dynamic;
using System.Linq.Expressions;
+using System.Reflection;
using System.Runtime.CompilerServices;
using Realms.Dynamic;
using Realms.Helpers;
@@ -66,10 +67,23 @@ internal RealmList(Realm realm, ListHandle adoptedList, Metadata? metadata) : ba
ValidateIndex(index);
var realmValue = ValidateValueToInsert(value);
- if (realmValue.Type == RealmValueType.List)
+ if (realmValue.Type.IsCollection())
{
- var newListHandle = _listHandle.SetList(index);
- CreateAndAdd(Realm, newListHandle, realmValue);
+ switch (realmValue.Type)
+ {
+ case RealmValueType.List:
+ CollectionHelpers.ListCreateAndPopulate(Realm, _listHandle.SetList(index), realmValue);
+ break;
+ case RealmValueType.Set:
+ CollectionHelpers.SetCreateAndPopulate(Realm, _listHandle.SetSet(index), realmValue);
+ break;
+ case RealmValueType.Dictionary:
+ CollectionHelpers.DictionaryCreatePopulate(Realm, _listHandle.SetDictionary(index), realmValue);
+ break;
+ default:
+ Debug.Fail("Invalid collection type");
+ break;
+ }
return;
}
@@ -96,10 +110,23 @@ public void Add(T value)
{
var realmValue = ValidateValueToInsert(value);
- if (realmValue.Type == RealmValueType.List)
+ if (realmValue.Type.IsCollection())
{
- var newListHandle = _listHandle.AddList();
- CreateAndAdd(Realm, newListHandle, realmValue);
+ switch (realmValue.Type)
+ {
+ case RealmValueType.List:
+ CollectionHelpers.ListCreateAndPopulate(Realm, _listHandle.AddList(), realmValue);
+ break;
+ case RealmValueType.Set:
+ CollectionHelpers.SetCreateAndPopulate(Realm, _listHandle.AddSet(), realmValue);
+ break;
+ case RealmValueType.Dictionary:
+ CollectionHelpers.DictionaryCreatePopulate(Realm, _listHandle.AddDictionary(), realmValue);
+ break;
+ default:
+ Debug.Fail("Invalid collection type");
+ break;
+ }
return;
}
@@ -119,6 +146,10 @@ public void Add(T value)
_listHandle.Add(realmValue);
}
+ private void CreateAndPopulate()
+ {
+ }
+
public override int IndexOf([AllowNull] T value)
{
var realmValue = Operator.Convert(value);
@@ -143,8 +174,8 @@ public void Insert(int index, T value)
if (realmValue.Type == RealmValueType.List)
{
- var newListHandle = _listHandle.InsertList(index);
- CreateAndAdd(Realm, newListHandle, realmValue);
+ var newListHandle = _listHandle.InsertCollection(index, RealmValueType.List);
+ CollectionHelpers.ListCreateAndPopulate(Realm, newListHandle, realmValue);
return;
}
@@ -199,18 +230,6 @@ internal RealmResults ToResults()
return new RealmResults(Realm, resultsHandle, Metadata);
}
- internal static RealmList CreateAndAdd(Realm realm, ListHandle handle, RealmValue content)
- {
- var newList = new RealmList(realm, handle, null);
-
- foreach (var item in content.AsList())
- {
- newList.Add(item);
- }
-
- return newList;
- }
-
internal override RealmCollectionBase CreateCollection(Realm realm, CollectionHandleBase handle) => new RealmList(realm, (ListHandle)handle, Metadata);
protected override T GetValueAtIndex(int index) => _listHandle.GetValueAtIndex(index, Realm).As();
diff --git a/Realm/Realm/Handles/ListHandle.cs b/Realm/Realm/Handles/ListHandle.cs
index 25aa3886e6..e0ed410229 100644
--- a/Realm/Realm/Handles/ListHandle.cs
+++ b/Realm/Realm/Handles/ListHandle.cs
@@ -32,8 +32,8 @@ private static class NativeMethods
[DllImport(InteropConfig.DLL_NAME, EntryPoint = "list_add_embedded", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr add_embedded(ListHandle listHandle, out NativeException ex);
- [DllImport(InteropConfig.DLL_NAME, EntryPoint = "list_add_list", CallingConvention = CallingConvention.Cdecl)]
- public static extern IntPtr add_list(ListHandle listHandle, out NativeException ex);
+ [DllImport(InteropConfig.DLL_NAME, EntryPoint = "list_add_collection", CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr add_collection(ListHandle listHandle, RealmValueType type, out NativeException ex);
[DllImport(InteropConfig.DLL_NAME, EntryPoint = "list_set_value", CallingConvention = CallingConvention.Cdecl)]
public static extern void set_value(ListHandle listHandle, IntPtr targetIndex, PrimitiveValue value, out NativeException ex);
@@ -41,8 +41,8 @@ private static class NativeMethods
[DllImport(InteropConfig.DLL_NAME, EntryPoint = "list_set_embedded", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr set_embedded(ListHandle listHandle, IntPtr targetIndex, out NativeException ex);
- [DllImport(InteropConfig.DLL_NAME, EntryPoint = "list_set_list", CallingConvention = CallingConvention.Cdecl)]
- public static extern IntPtr set_list(ListHandle listHandle, IntPtr targetIndex, out NativeException ex);
+ [DllImport(InteropConfig.DLL_NAME, EntryPoint = "list_set_collection", CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr set_collection(ListHandle listHandle, IntPtr targetIndex, RealmValueType type, out NativeException ex);
[DllImport(InteropConfig.DLL_NAME, EntryPoint = "list_insert_value", CallingConvention = CallingConvention.Cdecl)]
public static extern void insert_value(ListHandle listHandle, IntPtr targetIndex, PrimitiveValue value, out NativeException ex);
@@ -50,8 +50,8 @@ private static class NativeMethods
[DllImport(InteropConfig.DLL_NAME, EntryPoint = "list_insert_embedded", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr insert_embedded(ListHandle listHandle, IntPtr targetIndex, out NativeException ex);
- [DllImport(InteropConfig.DLL_NAME, EntryPoint = "list_insert_list", CallingConvention = CallingConvention.Cdecl)]
- public static extern IntPtr insert_list(ListHandle listHandle, IntPtr targetIndex, out NativeException ex);
+ [DllImport(InteropConfig.DLL_NAME, EntryPoint = "list_insert_collection", CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr insert_collection(ListHandle listHandle, IntPtr targetIndex, RealmValueType type, out NativeException ex);
[DllImport(InteropConfig.DLL_NAME, EntryPoint = "list_get_value", CallingConvention = CallingConvention.Cdecl)]
public static extern void get_value(ListHandle listHandle, IntPtr link_ndx, out PrimitiveValue value, out NativeException ex);
@@ -149,13 +149,31 @@ public ObjectHandle AddEmbedded()
return new ObjectHandle(Root!, result);
}
- public ListHandle AddList()
+ private IntPtr AddCollection(RealmValueType collectionType)
{
EnsureIsOpen();
- var listPtr = NativeMethods.add_list(this, out var nativeException);
+ var collectionPtr = NativeMethods.add_collection(this, collectionType, out var nativeException);
nativeException.ThrowIfNecessary();
- return new ListHandle(Root!, listPtr);
+ return collectionPtr;
+ }
+
+ public ListHandle AddList()
+ {
+ var ptr = AddCollection(RealmValueType.List);
+ return new ListHandle(Root!, ptr);
+ }
+
+ public SetHandle AddSet()
+ {
+ var ptr = AddCollection(RealmValueType.Set);
+ return new SetHandle(Root!, ptr);
+ }
+
+ public DictionaryHandle AddDictionary()
+ {
+ var ptr = AddCollection(RealmValueType.Dictionary);
+ return new DictionaryHandle(Root!, ptr);
}
public void Set(int targetIndex, in RealmValue value)
@@ -177,13 +195,31 @@ public ObjectHandle SetEmbedded(int targetIndex)
return new ObjectHandle(Root!, result);
}
- public ListHandle SetList(int targetIndex)
+ private IntPtr SetCollection(int targetIndex, RealmValueType collectionType)
{
EnsureIsOpen();
- var listPtr = NativeMethods.set_list(this, (IntPtr)targetIndex, out var nativeException);
+ var collectionPtr = NativeMethods.set_collection(this, (IntPtr)targetIndex, collectionType, out var nativeException);
nativeException.ThrowIfNecessary();
- return new ListHandle(Root!, listPtr);
+ return collectionPtr;
+ }
+
+ public ListHandle SetList(int targetIndex)
+ {
+ var ptr = SetCollection(targetIndex, RealmValueType.List);
+ return new ListHandle(Root!, ptr);
+ }
+
+ public SetHandle SetSet(int targetIndex)
+ {
+ var ptr = SetCollection(targetIndex, RealmValueType.Set);
+ return new SetHandle(Root!, ptr);
+ }
+
+ public DictionaryHandle SetDictionary(int targetIndex)
+ {
+ var ptr = SetCollection(targetIndex, RealmValueType.Dictionary);
+ return new DictionaryHandle(Root!, ptr);
}
public void Insert(int targetIndex, in RealmValue value)
@@ -205,13 +241,31 @@ public ObjectHandle InsertEmbedded(int targetIndex)
return new ObjectHandle(Root!, result);
}
- public ListHandle InsertList(int targetIndex)
+ private IntPtr InsertCollection(int targetIndex, RealmValueType collectionType)
{
EnsureIsOpen();
- var listPtr = NativeMethods.insert_list(this, (IntPtr)targetIndex, out var nativeException);
+ var collectionPtr = NativeMethods.insert_collection(this, (IntPtr)targetIndex, collectionType, out var nativeException);
nativeException.ThrowIfNecessary();
- return new ListHandle(Root!, listPtr);
+ return collectionPtr;
+ }
+
+ public ListHandle InsertList(int targetIndex)
+ {
+ var ptr = InsertCollection(targetIndex, RealmValueType.List);
+ return new ListHandle(Root!, ptr);
+ }
+
+ public SetHandle InsertSet(int targetIndex)
+ {
+ var ptr = InsertCollection(targetIndex, RealmValueType.Set);
+ return new SetHandle(Root!, ptr);
+ }
+
+ public DictionaryHandle InsertDictionary(int targetIndex)
+ {
+ var ptr = InsertCollection(targetIndex, RealmValueType.Dictionary);
+ return new DictionaryHandle(Root!, ptr);
}
public int Find(in RealmValue value)
diff --git a/Realm/Realm/Handles/ObjectHandle.cs b/Realm/Realm/Handles/ObjectHandle.cs
index 07b8883d58..d3e48b8113 100644
--- a/Realm/Realm/Handles/ObjectHandle.cs
+++ b/Realm/Realm/Handles/ObjectHandle.cs
@@ -20,6 +20,7 @@
using System.Runtime.InteropServices;
using Realms.Exceptions;
using Realms.Extensions;
+using Realms.Helpers;
using Realms.Native;
using Realms.Schema;
@@ -234,7 +235,7 @@ public void SetValue(string propertyName, Metadata metadata, in RealmValue value
listNativeException.ThrowIfNecessary();
var handle = new ListHandle(Root!, listPtr);
- RealmList.CreateAndAdd(realm, handle, value);
+ CollectionHelpers.ListCreateAndPopulate(realm, handle, value);
return;
}
diff --git a/Realm/Realm/Helpers/CollectionHelpers.cs b/Realm/Realm/Helpers/CollectionHelpers.cs
new file mode 100644
index 0000000000..86864dea9b
--- /dev/null
+++ b/Realm/Realm/Helpers/CollectionHelpers.cs
@@ -0,0 +1,58 @@
+////////////////////////////////////////////////////////////////////////////
+//
+// Copyright 2023 Realm Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License")
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////
+
+namespace Realms.Helpers;
+
+internal static class CollectionHelpers
+{
+ internal static RealmList ListCreateAndPopulate(Realm realm, ListHandle handle, RealmValue content)
+ {
+ var newList = new RealmList(realm, handle, null);
+
+ foreach (var item in content.AsList())
+ {
+ newList.Add(item);
+ }
+
+ return newList;
+ }
+
+ internal static RealmSet SetCreateAndPopulate(Realm realm, SetHandle handle, RealmValue content)
+ {
+ var newSet = new RealmSet(realm, handle, null);
+
+ foreach (var item in content.AsSet())
+ {
+ newSet.Add(item);
+ }
+
+ return newSet;
+ }
+
+ internal static RealmDictionary DictionaryCreatePopulate(Realm realm, DictionaryHandle handle, RealmValue content)
+ {
+ var newDict = new RealmDictionary(realm, handle, null);
+
+ foreach (var item in content.AsDictionary())
+ {
+ newDict.Add(item);
+ }
+
+ return newDict;
+ }
+}
diff --git a/wrappers/src/list_cs.cpp b/wrappers/src/list_cs.cpp
index a25b20ff54..6210d3d24a 100644
--- a/wrappers/src/list_cs.cpp
+++ b/wrappers/src/list_cs.cpp
@@ -83,16 +83,28 @@ REALM_EXPORT Object* list_set_embedded(List& list, size_t list_ndx, NativeExcept
});
}
-REALM_EXPORT List* list_set_list(List& list, size_t list_ndx, NativeException::Marshallable& ex)
+REALM_EXPORT void* list_set_collection(List& list, size_t list_ndx, realm_value_type type, NativeException::Marshallable& ex)
{
- return handle_errors(ex, [&]() {
+ return handle_errors(ex, [&]()-> void*{
if (list_ndx > list.size()) {
throw IndexOutOfRangeException("Insert into RealmList", list_ndx, list.size());
}
- list.set_collection(list_ndx, CollectionType::List);
- return new List(list.get_list(list_ndx));
+ switch (type)
+ {
+ case realm::binding::realm_value_type::RLM_TYPE_LIST:
+ list.set_collection(list_ndx, CollectionType::List);
+ return new List(list.get_list(list_ndx));
+ case realm::binding::realm_value_type::RLM_TYPE_SET:
+ list.set_collection(list_ndx, CollectionType::Set);
+ return new object_store::Set(list.get_set(list_ndx));
+ case realm::binding::realm_value_type::RLM_TYPE_DICTIONARY:
+ list.set_collection(list_ndx, CollectionType::Dictionary);
+ return new object_store::Dictionary(list.get_dictionary(list_ndx));
+ default:
+ REALM_TERMINATE("Invalid collection type");
+ }
});
}
@@ -132,16 +144,28 @@ REALM_EXPORT Object* list_insert_embedded(List& list, size_t list_ndx, NativeExc
});
}
-REALM_EXPORT List* list_insert_list(List& list, size_t list_ndx, NativeException::Marshallable& ex)
+REALM_EXPORT void* list_insert_collection(List& list, size_t list_ndx, realm_value_type type, NativeException::Marshallable& ex)
{
- return handle_errors(ex, [&]() {
+ return handle_errors(ex, [&]()-> void*{
if (list_ndx > list.size()) {
throw IndexOutOfRangeException("Insert into RealmList", list_ndx, list.size());
}
- list.insert_collection(list_ndx, CollectionType::List);
- return new List(list.get_list(list_ndx));
+ switch (type)
+ {
+ case realm::binding::realm_value_type::RLM_TYPE_LIST:
+ list.insert_collection(list_ndx, CollectionType::List);
+ return new List(list.get_list(list_ndx));
+ case realm::binding::realm_value_type::RLM_TYPE_SET:
+ list.insert_collection(list_ndx, CollectionType::Set);
+ return new object_store::Set(list.get_set(list_ndx));
+ case realm::binding::realm_value_type::RLM_TYPE_DICTIONARY:
+ list.insert_collection(list_ndx, CollectionType::Dictionary);
+ return new object_store::Dictionary(list.get_dictionary(list_ndx));
+ default:
+ REALM_TERMINATE("Invalid collection type");
+ }
});
}
@@ -157,9 +181,9 @@ REALM_EXPORT Object* list_add_embedded(List& list, NativeException::Marshallable
});
}
-REALM_EXPORT List* list_add_list(List& list, NativeException::Marshallable& ex)
+REALM_EXPORT void* list_add_collection(List& list, realm_value_type type, NativeException::Marshallable& ex)
{
- return list_insert_list(list, list.size(), ex);
+ return list_insert_collection(list, list.size(), type, ex);
}
REALM_EXPORT void list_get_value(List& list, size_t ndx, realm_value_t* value, NativeException::Marshallable& ex)
From b13f4aab9fcf80ede84f35c223ab232b909875a6 Mon Sep 17 00:00:00 2001
From: Ferdinando Papale <4850119+papafe@users.noreply.github.com>
Date: Fri, 29 Sep 2023 13:51:48 +0200
Subject: [PATCH 30/88] Created common method for collections
---
Realm/Realm/DatabaseTypes/RealmList.cs | 62 +++++++++++---------------
Realm/Realm/Handles/ListHandle.cs | 60 ++-----------------------
2 files changed, 28 insertions(+), 94 deletions(-)
diff --git a/Realm/Realm/DatabaseTypes/RealmList.cs b/Realm/Realm/DatabaseTypes/RealmList.cs
index 74d66a8dc1..2b48d6ab80 100644
--- a/Realm/Realm/DatabaseTypes/RealmList.cs
+++ b/Realm/Realm/DatabaseTypes/RealmList.cs
@@ -69,22 +69,7 @@ internal RealmList(Realm realm, ListHandle adoptedList, Metadata? metadata) : ba
if (realmValue.Type.IsCollection())
{
- switch (realmValue.Type)
- {
- case RealmValueType.List:
- CollectionHelpers.ListCreateAndPopulate(Realm, _listHandle.SetList(index), realmValue);
- break;
- case RealmValueType.Set:
- CollectionHelpers.SetCreateAndPopulate(Realm, _listHandle.SetSet(index), realmValue);
- break;
- case RealmValueType.Dictionary:
- CollectionHelpers.DictionaryCreatePopulate(Realm, _listHandle.SetDictionary(index), realmValue);
- break;
- default:
- Debug.Fail("Invalid collection type");
- break;
- }
-
+ CreateAndPopulate(realmValue, (t) => _listHandle.SetCollection(index, t));
return;
}
@@ -112,22 +97,7 @@ public void Add(T value)
if (realmValue.Type.IsCollection())
{
- switch (realmValue.Type)
- {
- case RealmValueType.List:
- CollectionHelpers.ListCreateAndPopulate(Realm, _listHandle.AddList(), realmValue);
- break;
- case RealmValueType.Set:
- CollectionHelpers.SetCreateAndPopulate(Realm, _listHandle.AddSet(), realmValue);
- break;
- case RealmValueType.Dictionary:
- CollectionHelpers.DictionaryCreatePopulate(Realm, _listHandle.AddDictionary(), realmValue);
- break;
- default:
- Debug.Fail("Invalid collection type");
- break;
- }
-
+ CreateAndPopulate(realmValue, (t) => _listHandle.AddCollection(t));
return;
}
@@ -146,8 +116,28 @@ public void Add(T value)
_listHandle.Add(realmValue);
}
- private void CreateAndPopulate()
+ private void CreateAndPopulate(RealmValue realmValue, Func createPtrFunc)
{
+ var ptr = createPtrFunc(realmValue.Type);
+
+ switch (realmValue.Type)
+ {
+ case RealmValueType.List:
+ var listHandle = new ListHandle(Realm.SharedRealmHandle, ptr);
+ CollectionHelpers.ListCreateAndPopulate(Realm, listHandle, realmValue);
+ break;
+ case RealmValueType.Set:
+ var setHandle = new SetHandle(Realm.SharedRealmHandle, ptr);
+ CollectionHelpers.SetCreateAndPopulate(Realm, setHandle, realmValue);
+ break;
+ case RealmValueType.Dictionary:
+ var dictionaryHandle = new DictionaryHandle(Realm.SharedRealmHandle, ptr);
+ CollectionHelpers.DictionaryCreatePopulate(Realm, dictionaryHandle, realmValue);
+ break;
+ default:
+ Debug.Fail("Invalid collection type");
+ break;
+ }
}
public override int IndexOf([AllowNull] T value)
@@ -172,11 +162,9 @@ public void Insert(int index, T value)
ValidateIndex(index);
var realmValue = ValidateValueToInsert(value);
- if (realmValue.Type == RealmValueType.List)
+ if (realmValue.Type.IsCollection())
{
- var newListHandle = _listHandle.InsertCollection(index, RealmValueType.List);
- CollectionHelpers.ListCreateAndPopulate(Realm, newListHandle, realmValue);
-
+ CreateAndPopulate(realmValue, (t) => _listHandle.InsertCollection(index, t));
return;
}
diff --git a/Realm/Realm/Handles/ListHandle.cs b/Realm/Realm/Handles/ListHandle.cs
index e0ed410229..d4726fb1dd 100644
--- a/Realm/Realm/Handles/ListHandle.cs
+++ b/Realm/Realm/Handles/ListHandle.cs
@@ -149,7 +149,7 @@ public ObjectHandle AddEmbedded()
return new ObjectHandle(Root!, result);
}
- private IntPtr AddCollection(RealmValueType collectionType)
+ public IntPtr AddCollection(RealmValueType collectionType)
{
EnsureIsOpen();
@@ -158,24 +158,6 @@ private IntPtr AddCollection(RealmValueType collectionType)
return collectionPtr;
}
- public ListHandle AddList()
- {
- var ptr = AddCollection(RealmValueType.List);
- return new ListHandle(Root!, ptr);
- }
-
- public SetHandle AddSet()
- {
- var ptr = AddCollection(RealmValueType.Set);
- return new SetHandle(Root!, ptr);
- }
-
- public DictionaryHandle AddDictionary()
- {
- var ptr = AddCollection(RealmValueType.Dictionary);
- return new DictionaryHandle(Root!, ptr);
- }
-
public void Set(int targetIndex, in RealmValue value)
{
EnsureIsOpen();
@@ -195,7 +177,7 @@ public ObjectHandle SetEmbedded(int targetIndex)
return new ObjectHandle(Root!, result);
}
- private IntPtr SetCollection(int targetIndex, RealmValueType collectionType)
+ public IntPtr SetCollection(int targetIndex, RealmValueType collectionType)
{
EnsureIsOpen();
@@ -204,24 +186,6 @@ private IntPtr SetCollection(int targetIndex, RealmValueType collectionType)
return collectionPtr;
}
- public ListHandle SetList(int targetIndex)
- {
- var ptr = SetCollection(targetIndex, RealmValueType.List);
- return new ListHandle(Root!, ptr);
- }
-
- public SetHandle SetSet(int targetIndex)
- {
- var ptr = SetCollection(targetIndex, RealmValueType.Set);
- return new SetHandle(Root!, ptr);
- }
-
- public DictionaryHandle SetDictionary(int targetIndex)
- {
- var ptr = SetCollection(targetIndex, RealmValueType.Dictionary);
- return new DictionaryHandle(Root!, ptr);
- }
-
public void Insert(int targetIndex, in RealmValue value)
{
EnsureIsOpen();
@@ -241,7 +205,7 @@ public ObjectHandle InsertEmbedded(int targetIndex)
return new ObjectHandle(Root!, result);
}
- private IntPtr InsertCollection(int targetIndex, RealmValueType collectionType)
+ public IntPtr InsertCollection(int targetIndex, RealmValueType collectionType)
{
EnsureIsOpen();
@@ -250,24 +214,6 @@ private IntPtr InsertCollection(int targetIndex, RealmValueType collectionType)
return collectionPtr;
}
- public ListHandle InsertList(int targetIndex)
- {
- var ptr = InsertCollection(targetIndex, RealmValueType.List);
- return new ListHandle(Root!, ptr);
- }
-
- public SetHandle InsertSet(int targetIndex)
- {
- var ptr = InsertCollection(targetIndex, RealmValueType.Set);
- return new SetHandle(Root!, ptr);
- }
-
- public DictionaryHandle InsertDictionary(int targetIndex)
- {
- var ptr = InsertCollection(targetIndex, RealmValueType.Dictionary);
- return new DictionaryHandle(Root!, ptr);
- }
-
public int Find(in RealmValue value)
{
EnsureIsOpen();
From bf9aff50112a9ffeff845adc5ec67971e107f1b1 Mon Sep 17 00:00:00 2001
From: Ferdinando Papale <4850119+papafe@users.noreply.github.com>
Date: Mon, 2 Oct 2023 11:10:31 +0200
Subject: [PATCH 31/88] Various improvements [skip-ci]
---
Realm/Realm/DatabaseTypes/RealmDictionary.cs | 48 +++++++---
Realm/Realm/DatabaseTypes/RealmList.cs | 56 ++++++------
Realm/Realm/DatabaseTypes/RealmSet.cs | 12 ---
Realm/Realm/Handles/DictionaryHandle.cs | 44 ++++++++--
Realm/Realm/Handles/ObjectHandle.cs | 4 +-
.../Database/RealmValueWithCollections.cs | 88 ++++++++++++++++++-
wrappers/src/dictionary_cs.cpp | 50 +++++++++++
wrappers/src/list_cs.cpp | 37 +++++---
8 files changed, 264 insertions(+), 75 deletions(-)
diff --git a/Realm/Realm/DatabaseTypes/RealmDictionary.cs b/Realm/Realm/DatabaseTypes/RealmDictionary.cs
index 1e8ba2cc8a..2f37c769a8 100644
--- a/Realm/Realm/DatabaseTypes/RealmDictionary.cs
+++ b/Realm/Realm/DatabaseTypes/RealmDictionary.cs
@@ -65,6 +65,12 @@ public TValue this[string key]
ValidateKey(key);
var realmValue = Operator.Convert(value);
+ if (realmValue.Type.IsCollection())
+ {
+ CreateInternalCollectionAndPopulate(realmValue, () => _dictionaryHandle.SetCollection(key, realmValue.Type));
+ return;
+ }
+
if (_isEmbedded && realmValue.Type != RealmValueType.Null)
{
if (IsDynamic)
@@ -124,6 +130,12 @@ public void Add(string key, TValue value)
ValidateKey(key);
var realmValue = Operator.Convert(value);
+ if (realmValue.Type.IsCollection())
+ {
+ CreateInternalCollectionAndPopulate(realmValue, () => _dictionaryHandle.AddCollection(key, realmValue.Type));
+ return;
+ }
+
if (_isEmbedded && realmValue.Type != RealmValueType.Null)
{
if (IsDynamic)
@@ -225,6 +237,30 @@ private void UnsubscribeFromNotifications()
_deliveredInitialKeyNotification = false;
}
+ private void CreateInternalCollectionAndPopulate(RealmValue realmValue, Func