Skip to content

Commit 6b060ff

Browse files
authored
Sets - support insert operation (#7463)
1 parent e450a52 commit 6b060ff

File tree

9 files changed

+142
-35
lines changed

9 files changed

+142
-35
lines changed

realm/realm-annotations-processor/src/main/java/io/realm/processor/RealmProxyClassGenerator.kt

Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1588,9 +1588,52 @@ class RealmProxyClassGenerator(private val processingEnvironment: ProcessingEnvi
15881588
endControlFlow()
15891589
endControlFlow()
15901590
}
1591-
Utils.isRealmSet(field) -> {
1592-
// TODO: sets
1593-
emitSingleLineComment("TODO: Set")
1591+
Utils.isRealmModelSet(field) -> {
1592+
val genericType: TypeMirror = Utils.getGenericType(field)!!
1593+
val isEmbedded = Utils.isFieldTypeEmbedded(genericType, classCollection)
1594+
emitEmptyLine()
1595+
emitStatement("RealmSet<${genericType}> ${fieldName}Set = ((${interfaceName}) object).${getter}()")
1596+
beginControlFlow("if (${fieldName}Set != null)")
1597+
emitStatement("OsSet ${fieldName}OsSet = new OsSet(table.getUncheckedRow(objKey), columnInfo.${fieldName}ColKey)")
1598+
beginControlFlow("for (${genericType} ${fieldName}Item: ${fieldName}Set)")
1599+
emitStatement("Long cacheItemIndex${fieldName} = cache.get(${fieldName}Item)")
1600+
if (isEmbedded) {
1601+
emitStatement("throw new IllegalArgumentException(\"Embedded objects can only have one parent pointing to them. This object was already copied, so another object is pointing to it: \" + cacheItemIndex${fieldName}.toString())")
1602+
} else {
1603+
beginControlFlow("if (cacheItemIndex${fieldName} == null)")
1604+
emitStatement("cacheItemIndex${fieldName} = ${Utils.getSetGenericProxyClassSimpleName(field)}.insert(realm, ${fieldName}Item, cache)")
1605+
endControlFlow()
1606+
emitStatement("${fieldName}OsSet.addRow(cacheItemIndex${fieldName})")
1607+
}
1608+
endControlFlow()
1609+
endControlFlow()
1610+
}
1611+
Utils.isRealmValueSet(field) -> {
1612+
val genericType = Utils.getGenericTypeQualifiedName(field)
1613+
emitEmptyLine()
1614+
emitStatement("RealmSet<${genericType}> ${fieldName}Set = ((${interfaceName}) object).${getter}()")
1615+
beginControlFlow("if (${fieldName}Set != null)")
1616+
emitStatement("OsSet ${fieldName}OsSet = new OsSet(table.getUncheckedRow(objKey), columnInfo.${fieldName}ColKey)")
1617+
beginControlFlow("for (${genericType} ${fieldName}Item: ${fieldName}Set)")
1618+
beginControlFlow("if (${fieldName}Item == null)")
1619+
emitStatement(fieldName + "OsSet.add(($genericType) null)")
1620+
nextControlFlow("else")
1621+
emitStatement("${fieldName}OsSet.add(${fieldName}Item)")
1622+
endControlFlow()
1623+
endControlFlow()
1624+
endControlFlow()
1625+
}
1626+
Utils.isRealmAnySet(field) -> {
1627+
emitEmptyLine()
1628+
1629+
emitStatement("RealmSet<RealmAny> ${fieldName}UnmanagedSet = ((${interfaceName}) object).${getter}()")
1630+
beginControlFlow("if (${fieldName}UnmanagedSet != null)")
1631+
emitStatement("OsSet ${fieldName}OsSet = new OsSet(table.getUncheckedRow(objKey), columnInfo.${fieldName}ColKey)")
1632+
beginControlFlow("for (RealmAny realmAnyItem: ${fieldName}UnmanagedSet)")
1633+
emitStatement("realmAnyItem = ProxyUtils.insert(realmAnyItem, realm, cache)")
1634+
emitStatement("${fieldName}OsSet.addRealmAny(realmAnyItem.getNativePtr())")
1635+
endControlFlow()
1636+
endControlFlow()
15941637
}
15951638
else -> {
15961639
if (metadata.primaryKey !== field) {
@@ -1617,14 +1660,6 @@ class RealmProxyClassGenerator(private val processingEnvironment: ProcessingEnvi
16171660
val args = if (metadata.embedded) embeddedArgs else topLevelArgs
16181661
beginMethod("long","insert", EnumSet.of(Modifier.PUBLIC, Modifier.STATIC), *args)
16191662

1620-
// Throw if model contains a set field until we add support for it
1621-
if (containsSet(metadata.fields)) {
1622-
emitStatement("throw new UnsupportedOperationException(\"Calls to 'insert' with RealmModels containing RealmSet properties are not supported yet.\")")
1623-
endMethod()
1624-
emitEmptyLine()
1625-
return@apply
1626-
}
1627-
16281663
// If object is already in the Realm there is nothing to update, unless it is an embedded
16291664
// object. In which case we always update the underlying object.
16301665
if (!metadata.embedded) {
@@ -1664,14 +1699,6 @@ class RealmProxyClassGenerator(private val processingEnvironment: ProcessingEnvi
16641699
val args = if (metadata.embedded) embeddedArgs else topLevelArgs
16651700

16661701
beginMethod("void", "insert", EnumSet.of(Modifier.PUBLIC, Modifier.STATIC), *args)
1667-
// Throw if model contains a set field until we add support for it
1668-
if (containsSet(metadata.fields)) {
1669-
emitStatement("throw new UnsupportedOperationException(\"Calls to 'insert' with RealmModels containing RealmSet properties are not supported yet.\")")
1670-
endMethod()
1671-
emitEmptyLine()
1672-
return@apply
1673-
}
1674-
16751702
emitStatement("Table table = realm.getTable(%s.class)", qualifiedJavaClassName)
16761703
emitStatement("long tableNativePtr = table.getNativePtr()")
16771704
emitStatement("%s columnInfo = (%s) realm.getSchema().getColumnInfo(%s.class)", columnInfoClassName(), columnInfoClassName(), qualifiedJavaClassName)

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

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,58 @@ class ManagedSetTester<T : Any>(
354354
}
355355
}
356356

357+
override fun insert() {
358+
doInsertTest(initializedSet)
359+
}
360+
361+
// Separate method to allow calls from RealmModelSetManagedTester with unmanaged realm objects
362+
fun doInsertTest(expectedSet: List<T?>) {
363+
// Instantiate container and set Set on container
364+
val manualInstance = SetAllTypes().apply {
365+
setSetter.call(this, RealmSet<T>().init(expectedSet))
366+
}
367+
368+
// Insert into Realm
369+
realm.executeTransaction {
370+
realm.insert(manualInstance)
371+
}
372+
373+
// Get set from container from Realm
374+
val allTypesObject = realm.where<SetAllTypes>().findFirst()
375+
assertNotNull(allTypesObject)
376+
val set: RealmSet<T> = setGetter.call(allTypesObject)
377+
378+
assertFalse(set.isEmpty())
379+
assertSetContainsSet(expectedSet, set)
380+
}
381+
382+
override fun insertList() {
383+
doInsertListTest(initializedSet)
384+
}
385+
386+
// Separate method to allow calls from RealmModelSetManagedTester with unmanaged realm objects
387+
fun doInsertListTest(expectedSet: List<T?>) {
388+
// Instantiate container and set Set on container
389+
val manualInstance = SetAllTypes().apply {
390+
setSetter.call(this, RealmSet<T>().init(expectedSet))
391+
}
392+
393+
val emptyInstace = SetAllTypes()
394+
395+
// Insert into Realm
396+
realm.executeTransaction {
397+
realm.insert(listOf(emptyInstace, manualInstance))
398+
}
399+
400+
// Get set from container from Realm
401+
val allTypesObject = realm.where<SetAllTypes>().findAll()[1]
402+
assertNotNull(allTypesObject)
403+
val set: RealmSet<T> = setGetter.call(allTypesObject)
404+
405+
assertFalse(set.isEmpty())
406+
assertSetContainsSet(expectedSet, set)
407+
}
408+
357409
override fun copyToRealm() {
358410
doCopyToRealmTest(initializedSet)
359411
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ class NoPKRealmModelSetTester<T : RealmModel>(
126126
}
127127
}
128128

129+
override fun insert() = Unit // Not tested
130+
131+
override fun insertList() = Unit // Not tested
132+
129133
override fun copyToRealm() = Unit // Not tested
130134

131135
override fun copyToRealmOrUpdate() = Unit // Not tested

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ class NullRealmAnySetTester(
5050

5151
override fun isFrozen() = Unit // Tested in frozen
5252

53+
override fun insert() = Unit // Not applicable
54+
55+
override fun insertList() = Unit // Not applicable
56+
5357
override fun copyToRealm() = Unit // Not applicable
5458

5559
override fun copyToRealmOrUpdate() = Unit // Not applicable

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,16 @@ class ParameterizedSetTests(
113113
tester.remove()
114114
}
115115

116+
@Test
117+
fun insert() {
118+
tester.insert()
119+
}
120+
121+
@Test
122+
fun insertList() {
123+
tester.insertList()
124+
}
125+
116126
@Test
117127
fun copyToRealm() {
118128
tester.copyToRealm()
@@ -219,6 +229,8 @@ interface SetTester : GenericTester {
219229
fun add()
220230
fun remove()
221231
fun containsAll()
232+
fun insert()
233+
fun insertList()
222234
fun copyToRealm()
223235
fun copyToRealmOrUpdate()
224236
fun addAll()

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,26 @@ class RealmModelManagedSetTester<T : Any>(
199199
}
200200
}
201201

202+
override fun insert() {
203+
// This specific test case needs unmanaged objects on PK models
204+
realm.executeTransaction {
205+
deleteObjects(managedInitializedSet)
206+
}
207+
208+
// Call with unmanaged objects
209+
managedTester.doInsertTest(unmanagedInitializedSet)
210+
}
211+
212+
override fun insertList() {
213+
// This specific test case needs unmanaged objects on PK models
214+
realm.executeTransaction {
215+
deleteObjects(managedInitializedSet)
216+
}
217+
218+
// Call with unmanaged objects
219+
managedTester.doInsertListTest(unmanagedInitializedSet)
220+
}
221+
202222
override fun copyToRealm() {
203223
// This specific test case needs unmanaged objects on PK models
204224
realm.executeTransaction {

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

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -240,16 +240,6 @@ class SetMiscTests {
240240
realm.close()
241241
}
242242

243-
@Test
244-
fun insert_unsupportedOperation() {
245-
realm = Realm.getInstance(configFactory.createConfiguration())
246-
realm.executeTransaction {
247-
assertFailsWith<UnsupportedOperationException> {
248-
realm.insert(SetContainerMigrationClass())
249-
}
250-
}
251-
}
252-
253243
@Test
254244
fun insertOrUpdate_unsupportedOperation() {
255245
realm = Realm.getInstance(configFactory.createConfiguration())

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

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

147+
override fun insert() = Unit // Not applicable
148+
149+
override fun insertList() = Unit // Not applicable
150+
147151
override fun copyToRealm() = Unit // Not applicable
148152

149153
override fun copyToRealmOrUpdate() = Unit // Not applicable

realm/realm-library/src/main/java/io/realm/Realm.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,9 +1243,6 @@ public <E extends RealmModel> List<E> copyToRealm(Iterable<E> objects, ImportFla
12431243
* @param objects RealmObjects to insert.
12441244
* @throws IllegalStateException if the corresponding Realm is closed, called from an incorrect thread or not in a
12451245
* transaction.
1246-
* @throws UnsupportedOperationException if the object to insert contains a {@link RealmSet}.
1247-
* @see #copyToRealm(Iterable, ImportFlag...)
1248-
* @see RealmSet
12491246
*/
12501247
public void insert(Collection<? extends RealmModel> objects) {
12511248
checkIfValidAndInTransaction();
@@ -1282,9 +1279,6 @@ public void insert(Collection<? extends RealmModel> objects) {
12821279
* transaction.
12831280
* @throws io.realm.exceptions.RealmPrimaryKeyConstraintException if two objects with the same primary key is
12841281
* inserted or if a primary key value already exists in the Realm.
1285-
* @throws UnsupportedOperationException if the object to insert contains a {@link RealmSet}.
1286-
* @see #copyToRealm(RealmModel, ImportFlag...)
1287-
* @see RealmSet
12881282
*/
12891283
public void insert(RealmModel object) {
12901284
checkIfValidAndInTransaction();

0 commit comments

Comments
 (0)