Merge "Implement Tests for Upsertion Writer and unified the names for methods in EntityUpsertionAdapter." into androidx-main
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/EntityUpsertionAdapterTest.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/EntityUpsertionAdapterTest.java
index 5e6b2fa..36bd106 100644
--- a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/EntityUpsertionAdapterTest.java
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/EntityUpsertionAdapterTest.java
@@ -145,10 +145,10 @@
     public void testUpsertReturnIds() {
         Pet[] testPets = TestUtil.createPetsForUser(0, 1, 10);
         Pet[] testPets2 = TestUtil.createPetsForUser(0, 5, 9);
-        long[] result = mUpsertionAdapter.upsertAndReturnIdArray(testPets);
+        long[] result = mUpsertionAdapter.upsertAndReturnIdsArray(testPets);
         long[] check = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
         assertThat(result[3]).isEqualTo(check[3]);
-        long[] testResult = mUpsertionAdapter.upsertAndReturnIdArray(testPets2);
+        long[] testResult = mUpsertionAdapter.upsertAndReturnIdsArray(testPets2);
         assertThat(testResult[8]).isEqualTo(13);
         assertThat(testResult[2]).isEqualTo(-1);
     }
diff --git a/room/room-compiler/src/test/data/daoWriter/input/UpsertDao.java b/room/room-compiler/src/test/data/daoWriter/input/UpsertDao.java
new file mode 100644
index 0000000..3ab3e06
--- /dev/null
+++ b/room/room-compiler/src/test/data/daoWriter/input/UpsertDao.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2022 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 foo.bar;
+import androidx.room.*;
+import java.util.List;
+
+@Dao
+interface UpsertDao {
+    @Upsert
+    void upsertUser(User user);
+    @Upsert
+    void upsertUsers(User user1, List<User> others);
+    @Upsert
+    void upsertUsers(User[] users);
+    @Upsert
+    void upsertTwoUsers(User userOne, User userTwo);
+    @Upsert
+    void upsertUserAndBook(User user, Book book);
+    @Upsert
+    long upsertAndReturnId(User user);
+    @Upsert
+    long[] upsertAndReturnIdsArray(User[] users);
+}
\ No newline at end of file
diff --git a/room/room-compiler/src/test/data/daoWriter/output/UpsertDao.java b/room/room-compiler/src/test/data/daoWriter/output/UpsertDao.java
new file mode 100644
index 0000000..b3a0a27
--- /dev/null
+++ b/room/room-compiler/src/test/data/daoWriter/output/UpsertDao.java
@@ -0,0 +1,189 @@
+package foo.bar;
+
+import androidx.room.EntityDeletionOrUpdateAdapter;
+import androidx.room.EntityInsertionAdapter;
+import androidx.room.EntityUpsertionAdapter;
+import androidx.room.RoomDatabase;
+import androidx.sqlite.db.SupportSQLiteStatement;
+import java.lang.Class;
+import java.lang.Override;
+import java.lang.String;
+import java.lang.SuppressWarnings;
+import java.util.Collections;
+import java.util.List;
+import javax.annotation.processing.Generated;
+
+@Generated("androidx.room.RoomProcessor")
+@SuppressWarnings({"unchecked", "deprecation"})
+public final class UpsertDao_Impl implements UpsertDao {
+    private final RoomDatabase __db;
+
+    private final EntityUpsertionAdapter<User> __upsertionAdapterOfUser;
+
+    private final EntityUpsertionAdapter<Book> __upsertionAdapterOfBook;
+
+    public UpsertDao_Impl(RoomDatabase __db) {
+        this.__db = __db;
+        this.__upsertionAdapterOfUser = new EntityUpsertionAdapter<User>(new EntityInsertionAdapter<User>(__db) {
+                    @Override
+                    public String createQuery() {
+                        return "INSERT INTO `User` (`uid`,`name`,`lastName`,`ageColumn`) VALUES (?,?,?,?)";
+                    }
+
+                    @Override
+                    public void bind(SupportSQLiteStatement stmt, User value) {
+                        stmt.bindLong(1, value.uid);
+                        if (value.name == null) {
+                            stmt.bindNull(2);
+                        } else {
+                            stmt.bindString(2, value.name);
+                        }
+                        if (value.getLastName() == null) {
+                            stmt.bindNull(3);
+                        } else {
+                            stmt.bindString(3, value.getLastName());
+                        }
+                        stmt.bindLong(4, value.age);
+                    }
+                }, new EntityDeletionOrUpdateAdapter<User>(__db) {
+                    @Override
+                    public String createQuery() {
+                        return "UPDATE `User` SET `uid` = ?,`name` = ?,`lastName` = ?,`ageColumn` = ? WHERE `uid` = ?";
+                    }
+
+                    @Override
+                    public void bind(SupportSQLiteStatement stmt, User value) {
+                        stmt.bindLong(1, value.uid);
+                        if (value.name == null) {
+                            stmt.bindNull(2);
+                        } else {
+                            stmt.bindString(2, value.name);
+                        }
+                        if (value.getLastName() == null) {
+                            stmt.bindNull(3);
+                        } else {
+                            stmt.bindString(3, value.getLastName());
+                        }
+                        stmt.bindLong(4, value.age);
+                        stmt.bindLong(5, value.uid);
+                    }
+        });
+        this.__upsertionAdapterOfBook = new EntityUpsertionAdapter<Book>(new EntityInsertionAdapter<Book>(__db) {
+                    @Override
+                    public String createQuery() {
+                        return "INSERT INTO `Book` (`bookId`,`uid`) VALUES (?,?)";
+                    }
+
+                    @Override
+                    public void bind(SupportSQLiteStatement stmt, Book value) {
+                        stmt.bindLong(1, value.bookId);
+                        stmt.bindLong(2, value.uid);
+                    }
+                }, new EntityDeletionOrUpdateAdapter<Book>(__db) {
+                    @Override
+                    public String createQuery() {
+                        return "UPDATE `Book` SET `bookId` = ?,`uid` = ? WHERE `bookId` = ?";
+                    }
+
+                    @Override
+                    public void bind(SupportSQLiteStatement stmt, Book value) {
+                        stmt.bindLong(1, value.bookId);
+                        stmt.bindLong(2, value.uid);
+                        stmt.bindLong(3, value.bookId);
+                    }
+        });
+    }
+
+    @Override
+    public void upsertUser(final User user) {
+        __db.assertNotSuspendingTransaction();
+        __db.beginTransaction();
+        try {
+            __upsertionAdapterOfUser.upsert(user);
+            __db.setTransactionSuccessful();
+        } finally {
+            __db.endTransaction();
+        }
+    }
+
+    @Override
+    public void upsertUsers(final User user1, final List<User> others) {
+        __db.assertNotSuspendingTransaction();
+        __db.beginTransaction();
+        try {
+            __upsertionAdapterOfUser.upsert(user1);
+            __upsertionAdapterOfUser.upsert(others);
+            __db.setTransactionSuccessful();
+        } finally {
+            __db.endTransaction();
+        }
+    }
+
+    @Override
+    public void upsertUsers(final User[] users) {
+        __db.assertNotSuspendingTransaction();
+        __db.beginTransaction();
+        try {
+            __upsertionAdapterOfUser.upsert(users);
+            __db.setTransactionSuccessful();
+        } finally {
+            __db.endTransaction();
+        }
+    }
+
+    @Override
+    public void upsertTwoUsers(final User userOne, final User userTwo) {
+        __db.assertNotSuspendingTransaction();
+        __db.beginTransaction();
+        try {
+            __upsertionAdapterOfUser.upsert(userOne);
+            __upsertionAdapterOfUser.upsert(userTwo);
+            __db.setTransactionSuccessful();
+        } finally {
+            __db.endTransaction();
+        }
+    }
+
+    @Override
+    public void upsertUserAndBook(final User user, final Book book) {
+        __db.assertNotSuspendingTransaction();
+        __db.beginTransaction();
+        try {
+            __upsertionAdapterOfUser.upsert(user);
+            __upsertionAdapterOfBook.upsert(book);
+            __db.setTransactionSuccessful();
+        } finally {
+            __db.endTransaction();
+        }
+    }
+
+    @Override
+    public long upsertAndReturnId(final User user) {
+        __db.assertNotSuspendingTransaction();
+        __db.beginTransaction();
+        try {
+            long _result = __upsertionAdapterOfUser.upsertAndReturnId(user);
+            __db.setTransactionSuccessful();
+            return _result;
+        } finally {
+            __db.endTransaction();
+        }
+    }
+
+    @Override
+    public long[] upsertAndReturnIdsArray(final User[] users) {
+        __db.assertNotSuspendingTransaction();
+        __db.beginTransaction();
+        try {
+            long[] _result = __upsertionAdapterOfUser.upsertAndReturnIdsArray(users);
+            __db.setTransactionSuccessful();
+            return _result;
+        } finally {
+            __db.endTransaction();
+        }
+    }
+
+    public static List<Class<?>> getRequiredConverters() {
+        return Collections.emptyList();
+    }
+}
\ No newline at end of file
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/writer/DaoWriterTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/writer/DaoWriterTest.kt
index fceff5a..26108ee 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/writer/DaoWriterTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/writer/DaoWriterTest.kt
@@ -124,6 +124,25 @@
         }
     }
 
+    @Test
+    fun upsertDao() {
+        singleDao(
+            loadTestSource(
+                fileName = "daoWriter/input/UpsertDao.java",
+                qName = "foo.bar.UpsertDao"
+            )
+        ) {
+            it.assertCompilationResult {
+                generatedSource(
+                    loadTestSource(
+                        fileName = "daoWriter/output/UpsertDao.java",
+                        qName = "foo.bar.UpsertDao_Impl"
+                    )
+                )
+            }
+        }
+    }
+
     private fun singleDao(
         vararg inputs: Source,
         handler: (XTestInvocation) -> Unit
diff --git a/room/room-runtime/api/restricted_current.txt b/room/room-runtime/api/restricted_current.txt
index b066005..ed8b0bc 100644
--- a/room/room-runtime/api/restricted_current.txt
+++ b/room/room-runtime/api/restricted_current.txt
@@ -62,11 +62,11 @@
     method public void upsert(T![] entities);
     method public void upsert(Iterable<? extends T> entities);
     method public long upsertAndReturnId(T? entity);
-    method public long[] upsertAndReturnIdArray(T![] entities);
-    method public long[] upsertAndReturnIdArray(java.util.Collection<? extends T> entities);
-    method public Long![] upsertAndReturnIdArrayBox(T![] entities);
-    method public Long![] upsertAndReturnIdArrayBox(java.util.Collection<? extends T> entities);
-    method public java.util.List<java.lang.Long> upsertAndReturnIdList(T![] entities);
+    method public long[] upsertAndReturnIdsArray(T![] entities);
+    method public long[] upsertAndReturnIdsArray(java.util.Collection<? extends T> entities);
+    method public Long![] upsertAndReturnIdsArrayBox(T![] entities);
+    method public Long![] upsertAndReturnIdsArrayBox(java.util.Collection<? extends T> entities);
+    method public java.util.List<java.lang.Long> upsertAndReturnIdsList(T![] entities);
   }
 
   public class InvalidationTracker {
diff --git a/room/room-runtime/src/main/java/androidx/room/EntityUpsertionAdapter.kt b/room/room-runtime/src/main/java/androidx/room/EntityUpsertionAdapter.kt
index 16674b7..52502db 100644
--- a/room/room-runtime/src/main/java/androidx/room/EntityUpsertionAdapter.kt
+++ b/room/room-runtime/src/main/java/androidx/room/EntityUpsertionAdapter.kt
@@ -99,7 +99,7 @@
      * @param entities Entities to upsert
      * @return The SQLite row ids, for entities that are not inserted the row id returned will be -1
      */
-    fun upsertAndReturnIdArray(entities: Array<T>): LongArray {
+    fun upsertAndReturnIdsArray(entities: Array<T>): LongArray {
         return LongArray(entities.size) { index ->
             try {
                 insertionAdapter.insertAndReturnId(entities[index])
@@ -110,20 +110,20 @@
         }
     }
 
-    fun upsertAndReturnIdArray(entities: Collection<T>): LongArray {
+    fun upsertAndReturnIdsArray(entities: Collection<T>): LongArray {
         val iterator = entities.iterator()
         return LongArray(entities.size) {
             val entity = iterator.next()
             try {
-                    insertionAdapter.insertAndReturnId(entity)
-                } catch (ex: SQLiteConstraintException) {
-                    updateAdapter.handle(entity)
-                    -1
-                }
+                insertionAdapter.insertAndReturnId(entity)
+            } catch (ex: SQLiteConstraintException) {
+                updateAdapter.handle(entity)
+                -1
             }
+        }
     }
 
-    fun upsertAndReturnIdList(entities: Array<T>): List<Long> {
+    fun upsertAndReturnIdsList(entities: Array<T>): List<Long> {
         return buildList<Long> {
             entities.forEach { entity ->
                 try {
@@ -136,7 +136,7 @@
         }
     }
 
-    fun upsertAndReturnIdArrayBox(entities: Array<T>): Array<Long?> {
+    fun upsertAndReturnIdsArrayBox(entities: Array<T>): Array<Long?> {
         return Array<Long?>(entities.size) { index ->
             try {
                 insertionAdapter.insertAndReturnId(entities[index])
@@ -147,7 +147,7 @@
         }
     }
 
-    fun upsertAndReturnIdArrayBox(entities: Collection<T>): Array<Long?> {
+    fun upsertAndReturnIdsArrayBox(entities: Collection<T>): Array<Long?> {
         val iterator = entities.iterator()
         return Array<Long?>(entities.size) {
             val entity = iterator.next()