Merge "Update RelationWriter to not expect an ArrayMap-like data structure." into androidx-master-dev
diff --git a/room/compiler/src/main/kotlin/androidx/room/writer/RelationCollectorMethodWriter.kt b/room/compiler/src/main/kotlin/androidx/room/writer/RelationCollectorMethodWriter.kt
index aab76fd..b4860c4 100644
--- a/room/compiler/src/main/kotlin/androidx/room/writer/RelationCollectorMethodWriter.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/writer/RelationCollectorMethodWriter.kt
@@ -70,6 +70,8 @@
scope.builder().apply {
val usingLongSparseArray =
collector.mapTypeName.rawType == CollectionTypeNames.LONG_SPARSE_ARRAY
+ val usingArrayMap =
+ collector.mapTypeName.rawType == CollectionTypeNames.ARRAY_MAP
if (usingLongSparseArray) {
beginControlFlow("if ($N.isEmpty())", param)
} else {
@@ -89,24 +91,34 @@
addStatement("$T $L = new $T($L.MAX_BIND_PARAMETER_CNT)",
collector.mapTypeName, tmpMapVar,
collector.mapTypeName, RoomTypeNames.ROOM_DB)
- val mapIndexVar = scope.getTmpVar("_mapIndex")
val tmpIndexVar = scope.getTmpVar("_tmpIndex")
- val limitVar = scope.getTmpVar("_limit")
- addStatement("$T $L = 0", TypeName.INT, mapIndexVar)
addStatement("$T $L = 0", TypeName.INT, tmpIndexVar)
- addStatement("final $T $L = $N.size()", TypeName.INT, limitVar, param)
- beginControlFlow("while($L < $L)", mapIndexVar, limitVar).apply {
- addStatement("$L.put($N.keyAt($L), $N.valueAt($L))",
+ if (usingLongSparseArray || usingArrayMap) {
+ val mapIndexVar = scope.getTmpVar("_mapIndex")
+ val limitVar = scope.getTmpVar("_limit")
+ addStatement("$T $L = 0", TypeName.INT, mapIndexVar)
+ addStatement("final $T $L = $N.size()", TypeName.INT, limitVar, param)
+ beginControlFlow("while($L < $L)", mapIndexVar, limitVar).apply {
+ addStatement("$L.put($N.keyAt($L), $N.valueAt($L))",
tmpMapVar, param, mapIndexVar, param, mapIndexVar)
- addStatement("$L++", mapIndexVar)
+ addStatement("$L++", mapIndexVar)
+ }
+ } else {
+ val mapKeyVar = scope.getTmpVar("_mapKey")
+ beginControlFlow("for($T $L : $L)",
+ collector.keyTypeName, mapKeyVar, KEY_SET_VARIABLE).apply {
+ addStatement("$L.put($L, $N.get($L))",
+ tmpMapVar, mapKeyVar, param, mapKeyVar)
+ }
+ }.apply {
addStatement("$L++", tmpIndexVar)
beginControlFlow("if($L == $T.MAX_BIND_PARAMETER_CNT)",
- tmpIndexVar, RoomTypeNames.ROOM_DB).apply {
+ tmpIndexVar, RoomTypeNames.ROOM_DB).apply {
// recursively load that batch
addStatement("$L($L)", methodName, tmpMapVar)
// clear nukes the backing data hence we create a new one
addStatement("$L = new $T($T.MAX_BIND_PARAMETER_CNT)",
- tmpMapVar, collector.mapTypeName, RoomTypeNames.ROOM_DB)
+ tmpMapVar, collector.mapTypeName, RoomTypeNames.ROOM_DB)
addStatement("$L = 0", tmpIndexVar)
}.endControlFlow()
}.endControlFlow()
diff --git a/room/integration-tests/noappcompattestapp/build.gradle b/room/integration-tests/noappcompattestapp/build.gradle
index ace9e6b..7f71429 100644
--- a/room/integration-tests/noappcompattestapp/build.gradle
+++ b/room/integration-tests/noappcompattestapp/build.gradle
@@ -24,6 +24,7 @@
dependencies {
implementation(project(":room:room-runtime"))
annotationProcessor project(":room:room-compiler")
+ androidTestAnnotationProcessor project(":room:room-compiler")
androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
androidTestImplementation(ANDROIDX_TEST_CORE)
androidTestImplementation(ANDROIDX_TEST_RUNNER)
diff --git a/room/integration-tests/noappcompattestapp/src/androidTest/java/androidx/room/integration/noappcompat/BareRelationDatabaseTest.java b/room/integration-tests/noappcompattestapp/src/androidTest/java/androidx/room/integration/noappcompat/BareRelationDatabaseTest.java
new file mode 100644
index 0000000..ff1230b
--- /dev/null
+++ b/room/integration-tests/noappcompattestapp/src/androidTest/java/androidx/room/integration/noappcompat/BareRelationDatabaseTest.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package androidx.room.integration.noappcompat;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import androidx.room.Dao;
+import androidx.room.Database;
+import androidx.room.Embedded;
+import androidx.room.Entity;
+import androidx.room.Insert;
+import androidx.room.PrimaryKey;
+import androidx.room.Query;
+import androidx.room.Relation;
+import androidx.room.Room;
+import androidx.room.RoomDatabase;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+// More than a simple read & write, this test that we generate correct relationship collector
+// code that doesn't use androidx.collection
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+@SuppressWarnings("WeakerAccess") // to avoid naming field with m
+public class BareRelationDatabaseTest {
+
+ @Test
+ public void simpleReadWrite() {
+ RelationDatabase db = Room.inMemoryDatabaseBuilder(
+ ApplicationProvider.getApplicationContext(), RelationDatabase.class)
+ .build();
+ UserPetDao dao = db.getDao();
+ dao.insertUser(new User(1L));
+ dao.insertPet(new Pet(1L, 1L));
+ dao.insertPet(new Pet(2L, 1L));
+
+ UserAndPets result = dao.getUserWithPets(1);
+ assertThat(result.user.userId, is(1L));
+ assertThat(result.pets.size(), is(2));
+ assertThat(result.pets.get(0).petId, is(1L));
+ assertThat(result.pets.get(1).petId, is(2L));
+ }
+
+ @Database(entities = {User.class, Pet.class}, version = 1, exportSchema = false)
+ abstract static class RelationDatabase extends RoomDatabase {
+ abstract UserPetDao getDao();
+ }
+
+ @Dao
+ interface UserPetDao {
+ @Query("SELECT * FROM User WHERE userId = :id")
+ UserAndPets getUserWithPets(long id);
+
+ @Insert
+ void insertUser(User user);
+
+ @Insert
+ void insertPet(Pet pet);
+ }
+
+ @Entity
+ static class User {
+ @PrimaryKey
+ public long userId;
+
+ User(long userId) {
+ this.userId = userId;
+ }
+ }
+
+ @Entity
+ static class Pet {
+ @PrimaryKey
+ public long petId;
+ public long ownerId;
+
+ Pet(long petId, long ownerId) {
+ this.petId = petId;
+ this.ownerId = ownerId;
+ }
+ }
+
+ static class UserAndPets {
+ @Embedded
+ public User user;
+ @Relation(parentColumn = "userId", entityColumn = "ownerId")
+ public List<Pet> pets;
+ }
+}