[go: nahoru, domu]

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;
+    }
+}