Skip to content

Commit eb9611f

Browse files
authored
Sets - dynamic realms (#7472)
1 parent 8f83a97 commit eb9611f

15 files changed

+713
-12
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
### Enhancements
77
* Allow `insert` and `insertOrUpdate` operations on `RealmObject` or `RealmObject` collections containing `RealmDictionary` or `RealmSet` fields.
88
* Added support for `RealmDictionary` in `DynamicRealmObject` with `setDictionary(String fieldName, RealmDictionary<?> dictionary)`, `getDictionary(String fieldName, Class<?> primitiveType)`, and `getDictionary(String fieldName)`.
9+
* Added support for `RealmSet` in `DynamicRealmObject` with `setRealmSet(String fieldName, RealmSet<?> realmSet)`, `getRealmSet(String fieldName, Class<?> primitiveType)`, and `getRealmSet(String fieldName)`.
910

1011
### Fixed
1112
* Removed wrong `@Nullable` annotation on `RealmQuery.maxRealmAny()`.

realm/realm-library/src/androidTest/kotlin/io/realm/ManagedSetTester.kt

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ import kotlin.test.*
3535
*/
3636
class ManagedSetTester<T : Any>(
3737
private val testerName: String,
38+
private val setFieldName: String,
39+
private val setFieldClass: Class<T>,
3840
private val realmAnyType: RealmAny.Type? = null,
3941
private val setGetter: KFunction1<SetAllTypes, RealmSet<T>>,
4042
private val setSetter: KFunction2<SetAllTypes, RealmSet<T>, Unit>,
@@ -354,6 +356,40 @@ class ManagedSetTester<T : Any>(
354356
}
355357
}
356358

359+
override fun dynamic() {
360+
// Create a set from a immutable schema context
361+
val set = initAndAssertEmptySet(id = "id")
362+
realm.executeTransaction {
363+
set.addAll(initializedSet)
364+
}
365+
366+
val dynamicRealm = DynamicRealm.getInstance(realm.configuration)
367+
val dynamicObject: DynamicRealmObject = dynamicRealm.where(SetAllTypes.NAME).equalTo(AllTypes.FIELD_STRING, "id").findFirst()!!
368+
val dynamicSet = dynamicObject.getRealmSet(setFieldName, setFieldClass)
369+
370+
// Access the previous set from a mutable context
371+
assertSetContainsSet(initializedSet, dynamicSet)
372+
373+
// Update the set with a new value
374+
dynamicRealm.executeTransaction {
375+
dynamicSet.add(notPresentValue)
376+
}
377+
378+
assertSetContainsSet(initializedSet.plus(notPresentValue), dynamicSet)
379+
380+
// Try to replace the whole set by a new one
381+
dynamicRealm.executeTransaction {
382+
dynamicObject.setRealmSet(setFieldName, RealmSet<T>().apply {
383+
add(notPresentValue)
384+
})
385+
}
386+
387+
assertSetContainsSet(listOf(notPresentValue), dynamicSet)
388+
assertEquals(1, dynamicObject.get<RealmSet<T>>(setFieldName).size)
389+
390+
dynamicRealm.close()
391+
}
392+
357393
override fun insert() {
358394
doInsertTest(initializedSet)
359395
}
@@ -1032,6 +1068,8 @@ fun managedSetFactory(): List<SetTester> {
10321068
SetSupportedType.LONG ->
10331069
ManagedSetTester<Long>(
10341070
testerName = "Long",
1071+
setFieldClass = Long::class.javaObjectType,
1072+
setFieldName = "columnLongSet",
10351073
setGetter = SetAllTypes::getColumnLongSet,
10361074
setSetter = SetAllTypes::setColumnLongSet,
10371075
requiredSetGetter = SetAllTypes::getColumnRequiredLongSet,
@@ -1045,6 +1083,8 @@ fun managedSetFactory(): List<SetTester> {
10451083
SetSupportedType.INTEGER ->
10461084
ManagedSetTester<Int>(
10471085
testerName = "Integer",
1086+
setFieldClass = Int::class.javaObjectType,
1087+
setFieldName = "columnIntegerSet",
10481088
setGetter = SetAllTypes::getColumnIntegerSet,
10491089
setSetter = SetAllTypes::setColumnIntegerSet,
10501090
requiredSetGetter = SetAllTypes::getColumnRequiredIntegerSet,
@@ -1058,6 +1098,8 @@ fun managedSetFactory(): List<SetTester> {
10581098
SetSupportedType.SHORT ->
10591099
ManagedSetTester<Short>(
10601100
testerName = "Short",
1101+
setFieldClass = Short::class.javaObjectType,
1102+
setFieldName = "columnShortSet",
10611103
setGetter = SetAllTypes::getColumnShortSet,
10621104
setSetter = SetAllTypes::setColumnShortSet,
10631105
requiredSetGetter = SetAllTypes::getColumnRequiredShortSet,
@@ -1071,6 +1113,8 @@ fun managedSetFactory(): List<SetTester> {
10711113
SetSupportedType.BYTE ->
10721114
ManagedSetTester<Byte>(
10731115
testerName = "Byte",
1116+
setFieldClass = Byte::class.javaObjectType,
1117+
setFieldName = "columnByteSet",
10741118
setGetter = SetAllTypes::getColumnByteSet,
10751119
setSetter = SetAllTypes::setColumnByteSet,
10761120
requiredSetGetter = SetAllTypes::getColumnRequiredByteSet,
@@ -1084,6 +1128,8 @@ fun managedSetFactory(): List<SetTester> {
10841128
SetSupportedType.FLOAT ->
10851129
ManagedSetTester<Float>(
10861130
testerName = "Float",
1131+
setFieldClass = Float::class.javaObjectType,
1132+
setFieldName = "columnFloatSet",
10871133
setGetter = SetAllTypes::getColumnFloatSet,
10881134
setSetter = SetAllTypes::setColumnFloatSet,
10891135
requiredSetGetter = SetAllTypes::getColumnRequiredFloatSet,
@@ -1097,6 +1143,8 @@ fun managedSetFactory(): List<SetTester> {
10971143
SetSupportedType.DOUBLE ->
10981144
ManagedSetTester<Double>(
10991145
testerName = "Double",
1146+
setFieldClass = Double::class.javaObjectType,
1147+
setFieldName = "columnDoubleSet",
11001148
setGetter = SetAllTypes::getColumnDoubleSet,
11011149
setSetter = SetAllTypes::setColumnDoubleSet,
11021150
requiredSetGetter = SetAllTypes::getColumnRequiredDoubleSet,
@@ -1110,6 +1158,8 @@ fun managedSetFactory(): List<SetTester> {
11101158
SetSupportedType.STRING ->
11111159
ManagedSetTester<String>(
11121160
testerName = "String",
1161+
setFieldClass = String::class.javaObjectType,
1162+
setFieldName = "columnStringSet",
11131163
setGetter = SetAllTypes::getColumnStringSet,
11141164
setSetter = SetAllTypes::setColumnStringSet,
11151165
requiredSetGetter = SetAllTypes::getColumnRequiredStringSet,
@@ -1123,6 +1173,8 @@ fun managedSetFactory(): List<SetTester> {
11231173
SetSupportedType.BOOLEAN ->
11241174
ManagedSetTester<Boolean>(
11251175
testerName = "Boolean",
1176+
setFieldClass = Boolean::class.javaObjectType,
1177+
setFieldName = "columnBooleanSet",
11261178
setGetter = SetAllTypes::getColumnBooleanSet,
11271179
setSetter = SetAllTypes::setColumnBooleanSet,
11281180
requiredSetGetter = SetAllTypes::getColumnRequiredBooleanSet,
@@ -1136,6 +1188,8 @@ fun managedSetFactory(): List<SetTester> {
11361188
SetSupportedType.DATE ->
11371189
ManagedSetTester<Date>(
11381190
testerName = "Date",
1191+
setFieldClass = Date::class.javaObjectType,
1192+
setFieldName = "columnDateSet",
11391193
setGetter = SetAllTypes::getColumnDateSet,
11401194
setSetter = SetAllTypes::setColumnDateSet,
11411195
requiredSetGetter = SetAllTypes::getColumnRequiredDateSet,
@@ -1149,6 +1203,8 @@ fun managedSetFactory(): List<SetTester> {
11491203
SetSupportedType.DECIMAL128 ->
11501204
ManagedSetTester<Decimal128>(
11511205
testerName = "Decimal128",
1206+
setFieldClass = Decimal128::class.javaObjectType,
1207+
setFieldName = "columnDecimal128Set",
11521208
setGetter = SetAllTypes::getColumnDecimal128Set,
11531209
setSetter = SetAllTypes::setColumnDecimal128Set,
11541210
requiredSetGetter = SetAllTypes::getColumnRequiredDecimal128Set,
@@ -1162,6 +1218,8 @@ fun managedSetFactory(): List<SetTester> {
11621218
SetSupportedType.BINARY ->
11631219
ManagedSetTester<ByteArray>(
11641220
testerName = "Binary",
1221+
setFieldClass = ByteArray::class.javaObjectType,
1222+
setFieldName = "columnBinarySet",
11651223
setGetter = SetAllTypes::getColumnBinarySet,
11661224
setSetter = SetAllTypes::setColumnBinarySet,
11671225
requiredSetGetter = SetAllTypes::getColumnRequiredBinarySet,
@@ -1178,6 +1236,8 @@ fun managedSetFactory(): List<SetTester> {
11781236
SetSupportedType.OBJECT_ID ->
11791237
ManagedSetTester<ObjectId>(
11801238
testerName = "ObjectId",
1239+
setFieldClass = ObjectId::class.javaObjectType,
1240+
setFieldName = "columnObjectIdSet",
11811241
setGetter = SetAllTypes::getColumnObjectIdSet,
11821242
setSetter = SetAllTypes::setColumnObjectIdSet,
11831243
requiredSetGetter = SetAllTypes::getColumnRequiredObjectIdSet,
@@ -1192,6 +1252,8 @@ fun managedSetFactory(): List<SetTester> {
11921252
SetSupportedType.UUID ->
11931253
ManagedSetTester<UUID>(
11941254
testerName = "UUID",
1255+
setFieldClass = UUID::class.javaObjectType,
1256+
setFieldName = "columnUUIDSet",
11951257
setGetter = SetAllTypes::getColumnUUIDSet,
11961258
setSetter = SetAllTypes::setColumnUUIDSet,
11971259
requiredSetGetter = SetAllTypes::getColumnRequiredUUIDSet,
@@ -1206,6 +1268,8 @@ fun managedSetFactory(): List<SetTester> {
12061268
SetSupportedType.LINK ->
12071269
RealmModelManagedSetTester<DogPrimaryKey>(
12081270
testerName = "LINK",
1271+
setFieldClass = DogPrimaryKey::class.java,
1272+
setFieldName = "columnRealmModelSet",
12091273
setGetter = SetAllTypes::getColumnRealmModelSet,
12101274
setSetter = SetAllTypes::setColumnRealmModelSet,
12111275
managedSetGetter = SetContainerClass::myRealmModelSet,
@@ -1251,6 +1315,8 @@ fun managedSetFactory(): List<SetTester> {
12511315
RealmAny.Type.OBJECT -> RealmModelManagedSetTester<RealmAny>(
12521316
testerName = "MIXED-${realmAnyType.name}",
12531317
realmAnyType = realmAnyType,
1318+
setFieldClass = RealmAny::class.java,
1319+
setFieldName = "columnRealmAnySet",
12541320
setGetter = SetAllTypes::getColumnRealmAnySet,
12551321
setSetter = SetAllTypes::setColumnRealmAnySet,
12561322
managedSetGetter = SetContainerClass::myRealmAnySet,
@@ -1304,6 +1370,8 @@ fun managedSetFactory(): List<SetTester> {
13041370
else -> ManagedSetTester<RealmAny>(
13051371
testerName = "MIXED-${realmAnyType.name}",
13061372
realmAnyType = realmAnyType,
1373+
setFieldClass = RealmAny::class.java,
1374+
setFieldName = "columnRealmAnySet",
13071375
setGetter = SetAllTypes::getColumnRealmAnySet,
13081376
setSetter = SetAllTypes::setColumnRealmAnySet,
13091377
managedSetGetter = SetContainerClass::myRealmAnySet,

realm/realm-library/src/androidTest/kotlin/io/realm/NoPKRealmModelSetTester.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,8 @@ class NoPKRealmModelSetTester<T : RealmModel>(
202202
}
203203
}
204204

205+
override fun dynamic() = Unit // Not tested
206+
205207
override fun containsAll() {
206208
val set = initAndAssertEmptySet(id = "id")
207209

realm/realm-library/src/androidTest/kotlin/io/realm/NullMixedSetTester.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,8 @@ class NullRealmAnySetTester(
229229

230230
override fun setters() = Unit // Not tested
231231

232+
override fun dynamic() = Unit // Not tested
233+
232234
override fun addRealmChangeListener() = Unit
233235

234236
override fun removeSetChangeListener() = Unit

realm/realm-library/src/androidTest/kotlin/io/realm/ParameterizedSetTests.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ class ParameterizedSetTests(
8888
tester.contains()
8989
}
9090

91+
@Test
92+
fun dynamic() {
93+
tester.dynamic()
94+
}
95+
9196
@Test
9297
fun iterator() {
9398
tester.iterator()
@@ -239,6 +244,7 @@ interface SetTester : GenericTester {
239244
fun add()
240245
fun remove()
241246
fun containsAll()
247+
fun dynamic()
242248
fun insert()
243249
fun insertList()
244250
fun insertOrUpdate()

realm/realm-library/src/androidTest/kotlin/io/realm/RealmModelManagedSetTester.kt

Lines changed: 104 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,10 @@
1616

1717
package io.realm
1818

19-
import io.realm.entities.DogPrimaryKey
20-
import io.realm.entities.SetContainerClass
19+
import io.realm.entities.*
2120
import io.realm.kotlin.createObject
2221
import io.realm.rule.BlockingLooperThread
2322
import java.lang.IllegalArgumentException
24-
import io.realm.entities.SetAllTypes
25-
import io.realm.entities.SetAllTypesPrimaryKey
2623
import kotlin.reflect.KFunction1
2724
import kotlin.reflect.KFunction2
2825
import kotlin.reflect.KMutableProperty1
@@ -37,6 +34,8 @@ import kotlin.test.*
3734
*/
3835
class RealmModelManagedSetTester<T : Any>(
3936
private val testerName: String,
37+
private val setFieldName: String,
38+
private val setFieldClass: Class<T>,
4039
private val realmAnyType: RealmAny.Type? = null,
4140
private val setGetter: KFunction1<SetAllTypes, RealmSet<T>>,
4241
private val setSetter: KFunction2<SetAllTypes, RealmSet<T>, Unit>,
@@ -81,6 +80,8 @@ class RealmModelManagedSetTester<T : Any>(
8180

8281
this.managedTester = ManagedSetTester(
8382
testerName = testerName,
83+
setFieldClass = setFieldClass,
84+
setFieldName = setFieldName,
8485
realmAnyType = realmAnyType,
8586
setGetter = setGetter,
8687
setSetter = setSetter,
@@ -148,6 +149,105 @@ class RealmModelManagedSetTester<T : Any>(
148149

149150
override fun toArrayWithParameter() = managedTester.toArrayWithParameter()
150151

152+
override fun dynamic() {
153+
if (realmAnyType != null) {
154+
dynamicRealmAnyTest()
155+
} else {
156+
dynamicObjectTest()
157+
}
158+
}
159+
160+
private fun toDynamicRealmAny(realm: DynamicRealm, value: RealmAny): RealmAny {
161+
val id = value.asRealmModel(DogPrimaryKey::class.java).id
162+
return RealmAny.valueOf(realm.where(DogPrimaryKey.CLASS_NAME).equalTo(DogPrimaryKey.ID, id).findFirst()!!)
163+
}
164+
165+
private fun dynamicRealmAnyTest() {
166+
// Create a set from a immutable schema context
167+
val set = initAndAssertEmptySet()
168+
realm.executeTransaction {
169+
set.addAll(unmanagedInitializedSet)
170+
}
171+
172+
val dynamicRealm = DynamicRealm.getInstance(realm.configuration)
173+
val dynamicObject: DynamicRealmObject = dynamicRealm.where(SetAllTypes.NAME)
174+
.equalTo(AllTypes.FIELD_STRING, "unmanaged").findFirst()!!
175+
val dynamicSet: RealmSet<RealmAny> = dynamicObject.getRealmSet(setFieldName, setFieldClass) as RealmSet<RealmAny>
176+
177+
// Access the previous set from a mutable context
178+
assertEquals(3, dynamicSet.size)
179+
180+
// Update the set with a new value
181+
dynamicRealm.executeTransaction {
182+
dynamicSet.add(toDynamicRealmAny(dynamicRealm, unmanagedNotPresentValue as RealmAny))
183+
}
184+
185+
assertEquals(4, dynamicSet.size)
186+
187+
// Try to replace the whole set by a new one
188+
dynamicRealm.executeTransaction {
189+
dynamicObject.setRealmSet(setFieldName, RealmSet<RealmAny>().apply {
190+
add(toDynamicRealmAny(dynamicRealm, unmanagedNotPresentValue as RealmAny))
191+
})
192+
}
193+
194+
assertEquals(1, dynamicObject.getRealmSet(setFieldName, setFieldClass).size)
195+
196+
dynamicRealm.close()
197+
}
198+
199+
private fun dynamicObjectTest() {
200+
// Create a set from a immutable schema context
201+
val set = initAndAssertEmptySet()
202+
realm.executeTransaction {
203+
set.addAll(unmanagedInitializedSet)
204+
}
205+
206+
val dynamicRealm = DynamicRealm.getInstance(realm.configuration)
207+
val dynamicObject: DynamicRealmObject =
208+
dynamicRealm.where(SetAllTypes.NAME).equalTo(AllTypes.FIELD_STRING, "unmanaged").findFirst()!!
209+
val dynamicSet = dynamicObject.getRealmSet(setFieldName)
210+
211+
// Access the previous set from a mutable context
212+
set.forEach { value ->
213+
if (RealmObject.isValid(value as DogPrimaryKey)) {
214+
val managedObject =
215+
dynamicRealm.where(DogPrimaryKey.CLASS_NAME).equalTo(DogPrimaryKey.ID, (value as DogPrimaryKey).id)
216+
.findFirst()!!
217+
assertTrue(dynamicSet.contains(managedObject))
218+
}
219+
}
220+
221+
// Update the set with a new value
222+
dynamicRealm.executeTransaction {
223+
val notPresentManaged = dynamicRealm.where(DogPrimaryKey.CLASS_NAME)
224+
.equalTo(DogPrimaryKey.ID, (unmanagedNotPresentValue as DogPrimaryKey).id).findFirst()!!
225+
dynamicSet.add(notPresentManaged)
226+
}
227+
228+
set.plus(unmanagedNotPresentValue).forEach { value ->
229+
if (RealmObject.isValid(value as DogPrimaryKey)) {
230+
val managedObject =
231+
dynamicRealm.where(DogPrimaryKey.CLASS_NAME).equalTo(DogPrimaryKey.ID, (value as DogPrimaryKey).id)
232+
.findFirst()!!
233+
assertTrue(dynamicSet.contains(managedObject))
234+
}
235+
}
236+
237+
// Try to replace the whole set by a new one
238+
dynamicRealm.executeTransaction {
239+
val notPresentManaged = dynamicRealm.where(DogPrimaryKey.CLASS_NAME)
240+
.equalTo(DogPrimaryKey.ID, (unmanagedNotPresentValue as DogPrimaryKey).id).findFirst()!!
241+
dynamicObject.setRealmSet(setFieldName, RealmSet<DynamicRealmObject>().apply {
242+
add(notPresentManaged)
243+
})
244+
}
245+
246+
assertEquals(1, dynamicObject.get<RealmSet<T>>(setFieldName).size)
247+
248+
dynamicRealm.close()
249+
}
250+
151251
override fun add() {
152252
// Test with managed objects
153253
managedTester.add()

realm/realm-library/src/androidTest/kotlin/io/realm/UnmanagedSetTester.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ class UnmanagedSetTester<T : Any>(
144144
assertTrue(differentRealmSet.isEmpty())
145145
}
146146

147+
override fun dynamic() = Unit // Not applicable
148+
147149
override fun insert() = Unit // Not applicable
148150

149151
override fun insertList() = Unit // Not applicable

realm/realm-library/src/androidTest/kotlin/io/realm/entities/SetAllTypes.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import io.realm.annotations.Required;
2929

3030
public class SetAllTypes extends RealmObject {
31+
public static final String NAME = "SetAllTypes";
3132

3233
private RealmSet<Boolean> columnBooleanSet;
3334
private RealmSet<String> columnStringSet;

0 commit comments

Comments
 (0)