Merge "Merged insert and upsert adapters; piped adapter to processor" into androidx-main
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/UpsertTest.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/UpsertTest.kt
index db917ab..28b2d34 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/UpsertTest.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/UpsertTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 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.
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/processor/UpsertionMethodProcessor.kt b/room/room-compiler/src/main/kotlin/androidx/room/processor/UpsertionMethodProcessor.kt
index 7d87c5a..e45bf90 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/processor/UpsertionMethodProcessor.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/processor/UpsertionMethodProcessor.kt
@@ -77,12 +77,11 @@
)
val methodBinder = delegate.findUpsertMethodBinder(returnType, params)
- // TODO: (b/240491114) Uncomment code below for UpsertMethodAdapter is implemented
- /*context.checker.check(
+ context.checker.check(
methodBinder.adapter != null,
executableElement,
ProcessorErrors.CANNOT_FIND_UPSERT_RESULT_ADAPTER
- )*/
+ )
return UpsertionMethod(
element = executableElement,
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt
index b7d3188..8662073 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt
@@ -93,8 +93,7 @@
import androidx.room.solver.shortcut.binderprovider.RxCallableInsertMethodBinderProvider
import androidx.room.solver.shortcut.binderprovider.RxCallableUpsertMethodBinderProvider
import androidx.room.solver.shortcut.result.DeleteOrUpdateMethodAdapter
-import androidx.room.solver.shortcut.result.InsertMethodAdapter
-import androidx.room.solver.shortcut.result.UpsertMethodAdapter
+import androidx.room.solver.shortcut.result.InsertOrUpsertMethodAdapter
import androidx.room.solver.types.BoxedBooleanToBoxedIntConverter
import androidx.room.solver.types.BoxedPrimitiveColumnTypeAdapter
import androidx.room.solver.types.ByteArrayColumnTypeAdapter
@@ -448,17 +447,15 @@
fun findInsertAdapter(
typeMirror: XType,
params: List<ShortcutQueryParameter>
- ): InsertMethodAdapter? {
- return InsertMethodAdapter.create(typeMirror, params)
+ ): InsertOrUpsertMethodAdapter? {
+ return InsertOrUpsertMethodAdapter.createInsert(typeMirror, params)
}
- @Suppress("UNUSED_PARAMETER") // param will be used in a future change
fun findUpsertAdapter(
typeMirror: XType,
params: List<ShortcutQueryParameter>
- ): UpsertMethodAdapter? {
- // TODO: change for UpsertMethodAdapter when bind has been created
- return null
+ ): InsertOrUpsertMethodAdapter? {
+ return InsertOrUpsertMethodAdapter.createUpsert(typeMirror, params)
}
fun findQueryResultAdapter(
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/CallableInsertMethodBinder.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/CallableInsertMethodBinder.kt
index e73004d..a4601ad 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/CallableInsertMethodBinder.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/CallableInsertMethodBinder.kt
@@ -19,7 +19,7 @@
import androidx.room.ext.CallableTypeSpecBuilder
import androidx.room.compiler.processing.XType
import androidx.room.solver.CodeGenScope
-import androidx.room.solver.shortcut.result.InsertMethodAdapter
+import androidx.room.solver.shortcut.result.InsertOrUpsertMethodAdapter
import androidx.room.vo.ShortcutQueryParameter
import com.squareup.javapoet.CodeBlock
import com.squareup.javapoet.FieldSpec
@@ -29,19 +29,19 @@
* Binder for deferred insert methods.
*
* This binder will create a Callable implementation that delegates to the
- * [InsertMethodAdapter]. Usage of the Callable impl is then delegate to the [addStmntBlock]
+ * [InsertOrUpsertMethodAdapter]. Usage of the Callable impl is then delegate to the [addStmntBlock]
* function.
*/
class CallableInsertMethodBinder(
val typeArg: XType,
val addStmntBlock: CodeBlock.Builder.(callableImpl: TypeSpec, dbField: FieldSpec) -> Unit,
- adapter: InsertMethodAdapter?
+ adapter: InsertOrUpsertMethodAdapter?
) : InsertOrUpsertMethodBinder(adapter) {
companion object {
fun createInsertBinder(
typeArg: XType,
- adapter: InsertMethodAdapter?,
+ adapter: InsertOrUpsertMethodAdapter?,
addCodeBlock: CodeBlock.Builder.(callableImpl: TypeSpec, dbField: FieldSpec) -> Unit
) = CallableInsertMethodBinder(typeArg, addCodeBlock, adapter)
}
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/CallableUpsertMethodBinder.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/CallableUpsertMethodBinder.kt
index 7040cc4..b579df0 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/CallableUpsertMethodBinder.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/CallableUpsertMethodBinder.kt
@@ -19,7 +19,7 @@
import androidx.room.ext.CallableTypeSpecBuilder
import androidx.room.compiler.processing.XType
import androidx.room.solver.CodeGenScope
-import androidx.room.solver.shortcut.result.UpsertMethodAdapter
+import androidx.room.solver.shortcut.result.InsertOrUpsertMethodAdapter
import androidx.room.vo.ShortcutQueryParameter
import com.squareup.javapoet.CodeBlock
import com.squareup.javapoet.FieldSpec
@@ -29,19 +29,19 @@
* Binder for deferred upsert methods.
*
* This binder will create a Callable implementation that delegates to the
- * [UpsertMethodAdapter]. Usage of the Callable impl is then delegate to the [addStmntBlock]
+ * [InsertOrUpsertMethodAdapter]. Usage of the Callable impl is then delegate to the [addStmntBlock]
* function.
*/
class CallableUpsertMethodBinder(
val typeArg: XType,
val addStmntBlock: CodeBlock.Builder.(callableImpl: TypeSpec, dbField: FieldSpec) -> Unit,
- adapter: UpsertMethodAdapter?
+ adapter: InsertOrUpsertMethodAdapter?
) : InsertOrUpsertMethodBinder(adapter) {
companion object {
fun createUpsertBinder(
typeArg: XType,
- adapter: UpsertMethodAdapter?,
+ adapter: InsertOrUpsertMethodAdapter?,
addCodeBlock: CodeBlock.Builder.(callableImpl: TypeSpec, dbField: FieldSpec) -> Unit
) = CallableUpsertMethodBinder(typeArg, addCodeBlock, adapter)
}
@@ -54,7 +54,12 @@
) {
val adapterScope = scope.fork()
val callableImpl = CallableTypeSpecBuilder(typeArg.typeName) {
- // TODO add the createMethodBody in UpsertMethodAdapter
+ adapter?.createMethodBody(
+ parameters = parameters,
+ adapters = adapters,
+ dbField = dbField,
+ scope = adapterScope
+ )
addCode(adapterScope.generate())
}.build()
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/InsertOrUpsertMethodBinder.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/InsertOrUpsertMethodBinder.kt
index f909b2a..0fa0ae0 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/InsertOrUpsertMethodBinder.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/InsertOrUpsertMethodBinder.kt
@@ -18,13 +18,11 @@
import androidx.room.solver.shortcut.result.InsertOrUpsertMethodAdapter
import androidx.room.solver.CodeGenScope
-import androidx.room.solver.shortcut.result.InsertMethodAdapter
-import androidx.room.solver.shortcut.result.UpsertMethodAdapter
import androidx.room.vo.ShortcutQueryParameter
import com.squareup.javapoet.FieldSpec
/**
- * Connects the insert and upsert method, the database and the [InsertMethodAdapter] or [UpsertMethodAdapter].
+ * Connects the insert and upsert method, the database and the [InsertOrUpsertMethodAdapter].
*/
abstract class InsertOrUpsertMethodBinder(val adapter: InsertOrUpsertMethodAdapter?) {
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/InstantInsertMethodBinder.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/InstantInsertMethodBinder.kt
index ac4c6cd..8e3aa51 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/InstantInsertMethodBinder.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/InstantInsertMethodBinder.kt
@@ -18,7 +18,7 @@
import androidx.room.ext.N
import androidx.room.solver.CodeGenScope
-import androidx.room.solver.shortcut.result.InsertMethodAdapter
+import androidx.room.solver.shortcut.result.InsertOrUpsertMethodAdapter
import androidx.room.vo.ShortcutQueryParameter
import androidx.room.writer.DaoWriter
import com.squareup.javapoet.FieldSpec
@@ -26,7 +26,7 @@
/**
* Binder that knows how to write instant (blocking) insert methods.
*/
-class InstantInsertMethodBinder(adapter: InsertMethodAdapter?) :
+class InstantInsertMethodBinder(adapter: InsertOrUpsertMethodAdapter?) :
InsertOrUpsertMethodBinder(adapter) {
override fun convertAndReturn(
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/InstantUpsertMethodBinder.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/InstantUpsertMethodBinder.kt
index 2043db9..bc6f811 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/InstantUpsertMethodBinder.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/InstantUpsertMethodBinder.kt
@@ -18,7 +18,7 @@
import androidx.room.ext.N
import androidx.room.solver.CodeGenScope
-import androidx.room.solver.shortcut.result.UpsertMethodAdapter
+import androidx.room.solver.shortcut.result.InsertOrUpsertMethodAdapter
import androidx.room.vo.ShortcutQueryParameter
import androidx.room.writer.DaoWriter
import com.squareup.javapoet.FieldSpec
@@ -26,7 +26,7 @@
/**
* Binder that knows how to write instant (blocking) upsert methods.
*/
-class InstantUpsertMethodBinder(adapter: UpsertMethodAdapter?) :
+class InstantUpsertMethodBinder(adapter: InsertOrUpsertMethodAdapter?) :
InsertOrUpsertMethodBinder(adapter) {
override fun convertAndReturn(
@@ -38,6 +38,11 @@
scope.builder().apply {
addStatement("$N.assertNotSuspendingTransaction()", DaoWriter.dbField)
}
- // TODO: createUpsertionMethodBody
+ adapter?.createMethodBody(
+ parameters = parameters,
+ adapters = adapters,
+ dbField = dbField,
+ scope = scope
+ )
}
}
\ No newline at end of file
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/result/InsertMethodAdapter.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/result/InsertMethodAdapter.kt
deleted file mode 100644
index c910e02..0000000
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/result/InsertMethodAdapter.kt
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright 2018 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.solver.shortcut.result
-
-import androidx.room.compiler.processing.XType
-import androidx.room.compiler.processing.isArray
-import androidx.room.compiler.processing.isKotlinUnit
-import androidx.room.compiler.processing.isLong
-import androidx.room.compiler.processing.isVoid
-import androidx.room.compiler.processing.isVoidObject
-import androidx.room.ext.KotlinTypeNames
-import androidx.room.ext.L
-import androidx.room.ext.N
-import androidx.room.ext.T
-import androidx.room.ext.typeName
-import androidx.room.solver.CodeGenScope
-import androidx.room.vo.ShortcutQueryParameter
-import com.squareup.javapoet.ArrayTypeName
-import com.squareup.javapoet.FieldSpec
-import com.squareup.javapoet.ParameterizedTypeName
-import com.squareup.javapoet.TypeName
-
-/**
- * Class that knows how to generate an insert method body.
- */
-class InsertMethodAdapter private constructor(private val insertionType: InsertionType) :
- InsertOrUpsertMethodAdapter() {
- companion object {
- fun create(
- returnType: XType,
- params: List<ShortcutQueryParameter>
- ): InsertMethodAdapter? {
- val insertionType = getInsertionType(returnType)
- if (insertionType != null && isInsertValid(insertionType, params)) {
- return InsertMethodAdapter(insertionType)
- }
- return null
- }
-
- private fun isInsertValid(
- insertionType: InsertionType?,
- params: List<ShortcutQueryParameter>
- ): Boolean {
- if (insertionType == null) {
- return false
- }
- if (params.isEmpty() || params.size > 1) {
- return insertionType == InsertionType.INSERT_VOID ||
- insertionType == InsertionType.INSERT_UNIT
- }
- return if (params.first().isMultiple) {
- insertionType in MULTIPLE_ITEM_SET
- } else {
- insertionType == InsertionType.INSERT_VOID ||
- insertionType == InsertionType.INSERT_VOID_OBJECT ||
- insertionType == InsertionType.INSERT_UNIT ||
- insertionType == InsertionType.INSERT_SINGLE_ID
- }
- }
-
- private val MULTIPLE_ITEM_SET by lazy {
- setOf(
- InsertionType.INSERT_VOID,
- InsertionType.INSERT_VOID_OBJECT,
- InsertionType.INSERT_UNIT,
- InsertionType.INSERT_ID_ARRAY,
- InsertionType.INSERT_ID_ARRAY_BOX,
- InsertionType.INSERT_ID_LIST
- )
- }
-
- @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
- private fun getInsertionType(returnType: XType): InsertionType? {
- return if (returnType.isVoid()) {
- InsertionType.INSERT_VOID
- } else if (returnType.isVoidObject()) {
- InsertionType.INSERT_VOID_OBJECT
- } else if (returnType.isKotlinUnit()) {
- InsertionType.INSERT_UNIT
- } else if (returnType.isArray()) {
- val param = returnType.componentType
- if (param.isLong()) {
- if (param.typeName == TypeName.LONG) {
- InsertionType.INSERT_ID_ARRAY
- } else {
- InsertionType.INSERT_ID_ARRAY_BOX
- }
- } else {
- null
- }
- } else if (returnType.isList()) {
- val param = returnType.typeArguments.first()
- if (param.isLong()) {
- InsertionType.INSERT_ID_LIST
- } else {
- null
- }
- } else if (returnType.isLong()) {
- InsertionType.INSERT_SINGLE_ID
- } else {
- null
- }
- }
- }
-
- override fun createMethodBody(
- parameters: List<ShortcutQueryParameter>,
- adapters: Map<String, Pair<FieldSpec, Any>>,
- dbField: FieldSpec,
- scope: CodeGenScope
- ) {
- scope.builder().apply {
- // TODO assert thread
- // TODO collect results
- addStatement("$N.beginTransaction()", dbField)
- val needsResultVar = insertionType != InsertionType.INSERT_VOID &&
- insertionType != InsertionType.INSERT_VOID_OBJECT &&
- insertionType != InsertionType.INSERT_UNIT
- val resultVar = if (needsResultVar) {
- scope.getTmpVar("_result")
- } else {
- null
- }
-
- beginControlFlow("try").apply {
- parameters.forEach { param ->
- val insertionAdapter = adapters[param.name]?.first
- if (needsResultVar) {
- // if it has more than 1 parameter, we would've already printed the error
- // so we don't care about re-declaring the variable here
- addStatement(
- "$T $L = $N.$L($L)",
- insertionType.returnTypeName, resultVar,
- insertionAdapter, insertionType.methodName,
- param.name
- )
- } else {
- addStatement(
- "$N.$L($L)", insertionAdapter, insertionType.methodName,
- param.name
- )
- }
- }
- addStatement("$N.setTransactionSuccessful()", dbField)
- if (needsResultVar) {
- addStatement("return $L", resultVar)
- } else if (insertionType == InsertionType.INSERT_VOID_OBJECT) {
- addStatement("return null")
- } else if (insertionType == InsertionType.INSERT_UNIT) {
- addStatement("return $T.INSTANCE", KotlinTypeNames.UNIT)
- }
- }
- nextControlFlow("finally").apply {
- addStatement("$N.endTransaction()", dbField)
- }
- endControlFlow()
- }
- }
-
- enum class InsertionType(
- // methodName matches EntityInsertionAdapter methods
- val methodName: String,
- val returnTypeName: TypeName
- ) {
- INSERT_VOID("insert", TypeName.VOID), // return void
- INSERT_VOID_OBJECT("insert", TypeName.VOID), // return void
- INSERT_UNIT("insert", KotlinTypeNames.UNIT), // return kotlin.Unit.INSTANCE
- INSERT_SINGLE_ID("insertAndReturnId", TypeName.LONG), // return long
- INSERT_ID_ARRAY(
- "insertAndReturnIdsArray",
- ArrayTypeName.of(TypeName.LONG)
- ), // return long[]
- INSERT_ID_ARRAY_BOX(
- "insertAndReturnIdsArrayBox",
- ArrayTypeName.of(TypeName.LONG.box())
- ), // return Long[]
- INSERT_ID_LIST(
- "insertAndReturnIdsList", // return List<Long>
- ParameterizedTypeName.get(List::class.typeName, TypeName.LONG.box())
- ),
- }
-}
\ No newline at end of file
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/result/InsertOrUpsertMethodAdapter.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/result/InsertOrUpsertMethodAdapter.kt
index 2eeba8b..9d06985 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/result/InsertOrUpsertMethodAdapter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/result/InsertOrUpsertMethodAdapter.kt
@@ -16,18 +16,204 @@
package androidx.room.solver.shortcut.result
+import androidx.room.compiler.processing.XType
+import androidx.room.compiler.processing.isArray
+import androidx.room.compiler.processing.isKotlinUnit
+import androidx.room.compiler.processing.isLong
+import androidx.room.compiler.processing.isVoid
+import androidx.room.compiler.processing.isVoidObject
+import androidx.room.ext.KotlinTypeNames
+import androidx.room.ext.L
+import androidx.room.ext.N
+import androidx.room.ext.T
+import androidx.room.ext.typeName
import androidx.room.solver.CodeGenScope
import androidx.room.vo.ShortcutQueryParameter
+import com.squareup.javapoet.ArrayTypeName
import com.squareup.javapoet.FieldSpec
+import com.squareup.javapoet.ParameterizedTypeName
+import com.squareup.javapoet.TypeName
-/**
- * Abstract class for insert and update method adapters.
- */
-abstract class InsertOrUpsertMethodAdapter {
- abstract fun createMethodBody(
+class InsertOrUpsertMethodAdapter private constructor(private val methodType: MethodType) {
+ companion object {
+ fun createInsert(
+ returnType: XType,
+ params: List<ShortcutQueryParameter>
+ ): InsertOrUpsertMethodAdapter? {
+ val methodReturnType = getReturnType(returnType)
+ if (methodReturnType != null && isReturnValid(methodReturnType, params)) {
+ val methodType = InsertMethodType(methodReturnType)
+ return InsertOrUpsertMethodAdapter(methodType)
+ }
+ return null
+ }
+
+ fun createUpsert(
+ returnType: XType,
+ params: List<ShortcutQueryParameter>
+ ): InsertOrUpsertMethodAdapter? {
+ val methodReturnType = getReturnType(returnType)
+ if (methodReturnType != null && isReturnValid(methodReturnType, params)) {
+ val methodType = UpsertMethodType(methodReturnType)
+ return InsertOrUpsertMethodAdapter(methodType)
+ }
+ return null
+ }
+
+ private fun isReturnValid(
+ returnType: ReturnType,
+ params: List<ShortcutQueryParameter>
+ ): Boolean {
+ if (params.isEmpty() || params.size > 1) {
+ return returnType == ReturnType.VOID ||
+ returnType == ReturnType.UNIT
+ }
+ return if (params.first().isMultiple) {
+ returnType in MULTIPLE_ITEM_SET
+ } else {
+ returnType == ReturnType.VOID ||
+ returnType == ReturnType.VOID_OBJECT ||
+ returnType == ReturnType.UNIT ||
+ returnType == ReturnType.SINGLE_ID
+ }
+ }
+
+ private val MULTIPLE_ITEM_SET by lazy {
+ setOf(
+ ReturnType.VOID,
+ ReturnType.VOID_OBJECT,
+ ReturnType.UNIT,
+ ReturnType.ID_ARRAY,
+ ReturnType.ID_ARRAY_BOX,
+ ReturnType.ID_LIST
+ )
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
+ private fun getReturnType(returnType: XType): ReturnType? {
+ return if (returnType.isVoid()) {
+ ReturnType.VOID
+ } else if (returnType.isVoidObject()) {
+ ReturnType.VOID_OBJECT
+ } else if (returnType.isKotlinUnit()) {
+ ReturnType.UNIT
+ } else if (returnType.isArray()) {
+ val param = returnType.componentType
+ if (param.isLong()) {
+ if (param.typeName == TypeName.LONG) {
+ ReturnType.ID_ARRAY
+ } else {
+ ReturnType.ID_ARRAY_BOX
+ }
+ } else {
+ null
+ }
+ } else if (returnType.isList()) {
+ val param = returnType.typeArguments.first()
+ if (param.isLong()) {
+ ReturnType.ID_LIST
+ } else {
+ null
+ }
+ } else if (returnType.isLong()) {
+ ReturnType.SINGLE_ID
+ } else {
+ null
+ }
+ }
+ }
+
+ fun createMethodBody(
parameters: List<ShortcutQueryParameter>,
adapters: Map<String, Pair<FieldSpec, Any>>,
dbField: FieldSpec,
scope: CodeGenScope
- )
+ ) {
+
+ scope.builder().apply {
+ val methodName = methodType.methodName
+ val methodReturnType = methodType.returnType
+
+ // TODO assert thread
+ // TODO collect results
+ addStatement("$N.beginTransaction()", dbField)
+ val needsResultVar = methodReturnType != ReturnType.VOID &&
+ methodReturnType != ReturnType.VOID_OBJECT &&
+ methodReturnType != ReturnType.UNIT
+ val resultVar = if (needsResultVar) {
+ scope.getTmpVar("_result")
+ } else {
+ null
+ }
+
+ beginControlFlow("try").apply {
+ parameters.forEach { param ->
+ val upsertionAdapter = adapters[param.name]?.first
+ if (needsResultVar) {
+ // if it has more than 1 parameter, we would've already printed the error
+ // so we don't care about re-declaring the variable here
+ addStatement(
+ "$T $L = $N.$L($L)",
+ methodReturnType.returnTypeName, resultVar,
+ upsertionAdapter, methodName,
+ param.name
+ )
+ } else {
+ addStatement(
+ "$N.$L($L)", upsertionAdapter, methodName,
+ param.name
+ )
+ }
+ }
+ addStatement("$N.setTransactionSuccessful()", dbField)
+ if (needsResultVar) {
+ addStatement("return $L", resultVar)
+ } else if (methodReturnType == ReturnType.VOID_OBJECT) {
+ addStatement("return null")
+ } else if (methodReturnType == ReturnType.UNIT) {
+ addStatement("return $T.INSTANCE", KotlinTypeNames.UNIT)
+ }
+ }
+ nextControlFlow("finally").apply {
+ addStatement("$N.endTransaction()", dbField)
+ }
+ endControlFlow()
+ }
+ }
+
+ sealed class MethodType(
+ val returnType: ReturnType
+ ) {
+ abstract val methodName: String
+ }
+
+ class InsertMethodType(returnType: ReturnType) : MethodType(returnType) {
+ override val methodName = "insert" + returnType.methodSuffix
+ }
+
+ class UpsertMethodType(returnType: ReturnType) : MethodType(returnType) {
+ override val methodName = "upsert" + returnType.methodSuffix
+ }
+
+ enum class ReturnType(
+ val methodSuffix: String,
+ val returnTypeName: TypeName
+ ) {
+ VOID("", TypeName.VOID), // return void
+ VOID_OBJECT("", TypeName.VOID), // return void
+ UNIT("", KotlinTypeNames.UNIT), // return kotlin.Unit.INSTANCE
+ SINGLE_ID("AndReturnId", TypeName.LONG), // return long
+ ID_ARRAY(
+ "AndReturnIdsArray",
+ ArrayTypeName.of(TypeName.LONG)
+ ), // return long[]
+ ID_ARRAY_BOX(
+ "AndReturnIdsArrayBox",
+ ArrayTypeName.of(TypeName.LONG.box())
+ ), // return Long[]
+ ID_LIST(
+ "AndReturnIdsList",
+ ParameterizedTypeName.get(List::class.typeName, TypeName.LONG.box())
+ ), // return List<Long>
+ }
}
\ No newline at end of file
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/result/UpsertMethodAdapter.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/result/UpsertMethodAdapter.kt
deleted file mode 100644
index e45ccea..0000000
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/result/UpsertMethodAdapter.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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 androidx.room.solver.shortcut.result
-
-import androidx.room.solver.CodeGenScope
-import androidx.room.vo.ShortcutQueryParameter
-import com.squareup.javapoet.FieldSpec
-
-class UpsertMethodAdapter : InsertOrUpsertMethodAdapter() {
- override fun createMethodBody(
- parameters: List<ShortcutQueryParameter>,
- adapters: Map<String, Pair<FieldSpec, Any>>,
- dbField: FieldSpec,
- scope: CodeGenScope
- ) {
- }
-}
\ No newline at end of file
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/vo/ShortcutQueryParameter.kt b/room/room-compiler/src/main/kotlin/androidx/room/vo/ShortcutQueryParameter.kt
index 1df9af3..ae942bd 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/vo/ShortcutQueryParameter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/vo/ShortcutQueryParameter.kt
@@ -20,7 +20,7 @@
import androidx.room.compiler.processing.XVariableElement
/**
- * Parameters used in DAO methods that are annotated with Insert, Delete, Update. and Upsert
+ * Parameters used in DAO methods that are annotated with Insert, Delete, Update, and Upsert.
*/
data class ShortcutQueryParameter(
val element: XVariableElement,
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/vo/UpsertionMethod.kt b/room/room-compiler/src/main/kotlin/androidx/room/vo/UpsertionMethod.kt
index 76cc0fd..7fcdd72 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/vo/UpsertionMethod.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/vo/UpsertionMethod.kt
@@ -26,4 +26,4 @@
returnType: XType,
parameters: List<ShortcutQueryParameter>,
methodBinder: InsertOrUpsertMethodBinder
- ) : InsertOrUpsertShortcutMethod(element, entities, returnType, parameters, methodBinder)
\ No newline at end of file
+ ) : InsertOrUpsertShortcutMethod(element, entities, returnType, parameters, methodBinder)
\ No newline at end of file
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/InsertOrUpsertShortcutMethodProcessorTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/InsertOrUpsertShortcutMethodProcessorTest.kt
index 93b83a8..a1aee1e 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/InsertOrUpsertShortcutMethodProcessorTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/InsertOrUpsertShortcutMethodProcessorTest.kt
@@ -25,6 +25,9 @@
import androidx.room.compiler.processing.util.XTestInvocation
import androidx.room.compiler.processing.util.runProcessorTest
import androidx.room.ext.CommonTypeNames
+import androidx.room.ext.RxJava2TypeNames
+import androidx.room.ext.RxJava3TypeNames
+import androidx.room.solver.shortcut.result.InsertOrUpsertMethodAdapter
import androidx.room.testing.context
import androidx.room.vo.InsertOrUpsertShortcutMethod
import com.squareup.javapoet.ClassName
@@ -373,7 +376,178 @@
}
}
- // TODO: Add in the return type tests when upsertionMethodAdapter is implemented
+ @Test
+ fun invalidReturnType() {
+ listOf(
+ "int",
+ "${RxJava2TypeNames.SINGLE}<Int>",
+ "${RxJava2TypeNames.MAYBE}<Int>",
+ "${RxJava2TypeNames.SINGLE}<String>",
+ "${RxJava2TypeNames.MAYBE}<String>",
+ "${RxJava2TypeNames.SINGLE}<User>",
+ "${RxJava2TypeNames.MAYBE}<User>"
+ ).forEach { type ->
+ singleInsertUpsertShortcutMethod(
+ """
+ @${annotation.java.canonicalName}
+ abstract public $type foo(User user);
+ """
+ ) { insertionUpsertion, invocation ->
+ // TODO: (b/240491383) remove methodBinder nullability
+ assertThat(insertionUpsertion.methodBinder?.adapter).isNull()
+
+ invocation.assertCompilationResult {
+ hasErrorContaining(noAdapter())
+ }
+ }
+ }
+ }
+
+ @Test
+ fun mismatchedReturnType() {
+ listOf(
+ "long[]",
+ "Long[]",
+ "List<Long>",
+ "${RxJava2TypeNames.SINGLE}<List<Long>>",
+ "${RxJava2TypeNames.MAYBE}<List<Long>>"
+ ).forEach { type ->
+ singleInsertUpsertShortcutMethod(
+ """
+ @${annotation.java.canonicalName}
+ abstract public $type foo(User user);
+ """
+ ) { insertionUpsertion, invocation ->
+ // TODO: (b/240491383) remove methodBinder nullability
+ assertThat(insertionUpsertion.methodBinder?.adapter).isNull()
+
+ invocation.assertCompilationResult {
+ hasErrorContaining(noAdapter())
+ }
+ }
+ }
+ }
+
+ @Test
+ fun mismatchedReturnType2() {
+ listOf(
+ "long",
+ "Long",
+ "${RxJava2TypeNames.SINGLE}<Long>",
+ "${RxJava2TypeNames.MAYBE}<Long>"
+ ).forEach { type ->
+ singleInsertUpsertShortcutMethod(
+ """
+ @${annotation.java.canonicalName}
+ abstract public $type foo(User... user);
+ """
+ ) { insertionUpsertion, invocation ->
+ // TODO: (b/240491383) remove methodBinder nullability
+ assertThat(insertionUpsertion.methodBinder?.adapter).isNull()
+
+ invocation.assertCompilationResult {
+ hasErrorContaining(noAdapter())
+ }
+ }
+ }
+ }
+
+ @Test
+ fun mismatchedReturnType3() {
+ listOf(
+ "long",
+ "Long",
+ "${RxJava2TypeNames.SINGLE}<Long>",
+ "${RxJava2TypeNames.MAYBE}<Long>"
+ ).forEach { type ->
+ singleInsertUpsertShortcutMethod(
+ """
+ @${annotation.java.canonicalName}
+ abstract public $type foo(User user1, User user2);
+ """
+ ) { insertionUpsertion, invocation ->
+ // TODO: (b/240491383) remove methodBinder nullability
+ assertThat(insertionUpsertion.methodBinder?.adapter).isNull()
+
+ invocation.assertCompilationResult {
+ hasErrorContaining(noAdapter())
+ }
+ }
+ }
+ }
+
+ @Test
+ fun validReturnTypes() {
+ listOf(
+ Pair("void", InsertOrUpsertMethodAdapter.ReturnType.VOID),
+ Pair("long", InsertOrUpsertMethodAdapter.ReturnType.SINGLE_ID),
+ Pair("long[]", InsertOrUpsertMethodAdapter.ReturnType.ID_ARRAY),
+ Pair("Long[]", InsertOrUpsertMethodAdapter.ReturnType.ID_ARRAY_BOX),
+ Pair("List<Long>", InsertOrUpsertMethodAdapter.ReturnType.ID_LIST),
+ Pair(
+ RxJava2TypeNames.COMPLETABLE,
+ InsertOrUpsertMethodAdapter.ReturnType.VOID_OBJECT
+ ),
+ Pair(
+ "${RxJava2TypeNames.SINGLE}<Long>",
+ InsertOrUpsertMethodAdapter.ReturnType.SINGLE_ID
+ ),
+ Pair(
+ "${RxJava2TypeNames.SINGLE}<List<Long>>",
+ InsertOrUpsertMethodAdapter.ReturnType.ID_LIST
+ ),
+ Pair(
+ "${RxJava2TypeNames.MAYBE}<Long>",
+ InsertOrUpsertMethodAdapter.ReturnType.SINGLE_ID
+ ),
+ Pair(
+ "${RxJava2TypeNames.MAYBE}<List<Long>>",
+ InsertOrUpsertMethodAdapter.ReturnType.ID_LIST
+ ),
+ Pair(
+ RxJava3TypeNames.COMPLETABLE,
+ InsertOrUpsertMethodAdapter.ReturnType.VOID_OBJECT
+ ),
+ Pair(
+ "${RxJava3TypeNames.SINGLE}<Long>",
+ InsertOrUpsertMethodAdapter.ReturnType.SINGLE_ID
+ ),
+ Pair(
+ "${RxJava3TypeNames.SINGLE}<List<Long>>",
+ InsertOrUpsertMethodAdapter.ReturnType.ID_LIST
+ ),
+ Pair(
+ "${RxJava3TypeNames.MAYBE}<Long>",
+ InsertOrUpsertMethodAdapter.ReturnType.SINGLE_ID
+ ),
+ Pair(
+ "${RxJava3TypeNames.MAYBE}<List<Long>>",
+ InsertOrUpsertMethodAdapter.ReturnType.ID_LIST
+ )
+ ).forEach { pair ->
+ val dots = if (pair.second in setOf(
+ InsertOrUpsertMethodAdapter.ReturnType.ID_LIST,
+ InsertOrUpsertMethodAdapter.ReturnType.ID_ARRAY,
+ InsertOrUpsertMethodAdapter.ReturnType.ID_ARRAY_BOX
+ )
+ ) {
+ "..."
+ } else {
+ ""
+ }
+ singleInsertUpsertShortcutMethod(
+ """
+ @${annotation.java.canonicalName}
+ abstract public ${pair.first} foo(User$dots user);
+ """
+ ) { insertionUpsertion, _ ->
+ assertThat(insertionUpsertion.methodBinder?.adapter).isNotNull()
+ }
+ }
+ }
+
+ abstract fun noAdapter(): String
+
@Test
fun targetEntitySingle() {
val usernameSource = Source.java(
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/InsertionMethodProcessorTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/InsertionMethodProcessorTest.kt
index 7891b39..a968514 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/InsertionMethodProcessorTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/InsertionMethodProcessorTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 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.
@@ -16,354 +16,49 @@
package androidx.room.processor
-import COMMON
-import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
-import androidx.room.compiler.processing.XTypeElement
-import androidx.room.compiler.processing.util.Source
-import androidx.room.compiler.processing.util.XTestInvocation
-import androidx.room.compiler.processing.util.runProcessorTest
-import androidx.room.ext.CommonTypeNames
-import androidx.room.ext.GuavaUtilConcurrentTypeNames
-import androidx.room.ext.KotlinTypeNames
-import androidx.room.ext.LifecyclesTypeNames
-import androidx.room.ext.ReactiveStreamsTypeNames
-import androidx.room.ext.RxJava2TypeNames
-import androidx.room.ext.RxJava3TypeNames
-import androidx.room.solver.shortcut.result.InsertMethodAdapter
-import androidx.room.testing.context
+import androidx.room.compiler.processing.XMethodElement
+import androidx.room.compiler.processing.XType
+import androidx.room.processor.ProcessorErrors.INSERTION_DOES_NOT_HAVE_ANY_PARAMETERS_TO_INSERT
+import androidx.room.processor.ProcessorErrors.CANNOT_FIND_INSERT_RESULT_ADAPTER
import androidx.room.vo.InsertionMethod
-import com.squareup.javapoet.ArrayTypeName
-import com.squareup.javapoet.ClassName
-import com.squareup.javapoet.ParameterizedTypeName
-import com.squareup.javapoet.TypeName
-import org.hamcrest.CoreMatchers.`is`
-import org.hamcrest.CoreMatchers.notNullValue
-import org.hamcrest.CoreMatchers.nullValue
-import org.hamcrest.MatcherAssert.assertThat
+import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
@RunWith(JUnit4::class)
-class InsertionMethodProcessorTest {
- companion object {
- const val DAO_PREFIX = """
- package foo.bar;
- import androidx.room.*;
- import java.util.*;
- @Dao
- abstract class MyClass {
- """
- const val DAO_PREFIX_KT = """
- package foo.bar
- import androidx.room.*
- import java.util.*
- import io.reactivex.*
- io.reactivex.rxjava3.core.*
- androidx.lifecycle.*
- com.google.common.util.concurrent.*
- org.reactivestreams.*
- kotlinx.coroutines.flow.*
-
- @Dao
- abstract class MyClass {
- """
- const val DAO_SUFFIX = "}"
- val USER_TYPE_NAME: TypeName = COMMON.USER_TYPE_NAME
- val USERNAME_TYPE_NAME: TypeName = ClassName.get("foo.bar", "Username")
- val BOOK_TYPE_NAME: TypeName = ClassName.get("foo.bar", "Book")
+class InsertionMethodProcessorTest :
+ InsertOrUpsertShortcutMethodProcessorTest<InsertionMethod>(Insert::class) {
+ override fun noParamsError(): String = INSERTION_DOES_NOT_HAVE_ANY_PARAMETERS_TO_INSERT
+
+ override fun missingPrimaryKey(partialEntityName: String, primaryKeyName: List<String>):
+ String {
+ return ProcessorErrors.missingPrimaryKeysInPartialEntityForInsert(
+ partialEntityName,
+ primaryKeyName
+ )
}
- @Test
- fun readNoParams() {
- singleInsertMethod(
- """
- @Insert
- abstract public void foo();
- """
- ) { insertion, invocation ->
- assertThat(insertion.element.jvmName, `is`("foo"))
- assertThat(insertion.parameters.size, `is`(0))
- assertThat(insertion.returnType.typeName, `is`(TypeName.VOID))
- assertThat(insertion.entities.size, `is`(0))
- invocation.assertCompilationResult {
- hasErrorContaining(
- ProcessorErrors.INSERTION_DOES_NOT_HAVE_ANY_PARAMETERS_TO_INSERT
- )
- }
- }
- }
-
- @Test
- fun insertSingle() {
- singleInsertMethod(
- """
- @Insert
- abstract public long foo(User user);
- """
- ) { insertion, _ ->
- assertThat(insertion.element.jvmName, `is`("foo"))
- assertThat(insertion.parameters.size, `is`(1))
- val param = insertion.parameters.first()
- assertThat(param.type.typeName, `is`(USER_TYPE_NAME))
- assertThat(param.pojoType?.typeName, `is`(USER_TYPE_NAME))
- assertThat(insertion.entities["user"]?.isPartialEntity, `is`(false))
- assertThat(
- insertion.entities["user"]?.pojo?.typeName,
- `is`(ClassName.get("foo.bar", "User") as TypeName)
- )
- assertThat(insertion.returnType.typeName, `is`(TypeName.LONG))
- }
- }
-
- @Test
- fun insertNotAnEntity() {
- singleInsertMethod(
- """
- @Insert
- abstract public void foo(NotAnEntity notValid);
- """
- ) { insertion, invocation ->
- assertThat(insertion.element.jvmName, `is`("foo"))
- assertThat(insertion.parameters.size, `is`(1))
- assertThat(insertion.entities.size, `is`(0))
- invocation.assertCompilationResult {
- hasErrorContaining(
- ProcessorErrors.CANNOT_FIND_ENTITY_FOR_SHORTCUT_QUERY_PARAMETER
- )
- }
- }
- }
-
- @Test
- fun insertTwo() {
- singleInsertMethod(
- """
- @Insert
- abstract public void foo(User u1, User u2);
- """
- ) { insertion, _ ->
- assertThat(insertion.element.jvmName, `is`("foo"))
-
- assertThat(insertion.parameters.size, `is`(2))
- insertion.parameters.forEach {
- assertThat(it.type.typeName, `is`(USER_TYPE_NAME))
- assertThat(it.pojoType?.typeName, `is`(USER_TYPE_NAME))
- }
- assertThat(insertion.entities.size, `is`(2))
- assertThat(insertion.entities["u1"]?.pojo?.typeName, `is`(USER_TYPE_NAME))
- assertThat(insertion.entities["u2"]?.pojo?.typeName, `is`(USER_TYPE_NAME))
- assertThat(insertion.parameters.map { it.name }, `is`(listOf("u1", "u2")))
- assertThat(insertion.returnType.typeName, `is`(TypeName.VOID))
- }
- }
-
- @Test
- fun insertList() {
- singleInsertMethod(
- """
- @Insert
- abstract public List<Long> insertUsers(List<User> users);
- """
- ) { insertion, _ ->
- assertThat(insertion.element.jvmName, `is`("insertUsers"))
- assertThat(insertion.parameters.size, `is`(1))
- val param = insertion.parameters.first()
- assertThat(
- param.type.typeName,
- `is`(
- ParameterizedTypeName.get(
- ClassName.get("java.util", "List"),
- USER_TYPE_NAME
- ) as TypeName
- )
- )
- assertThat(param.pojoType?.typeName, `is`(USER_TYPE_NAME))
- assertThat(insertion.entities.size, `is`(1))
- assertThat(insertion.entities["users"]?.pojo?.typeName, `is`(USER_TYPE_NAME))
- assertThat(
- insertion.returnType.typeName,
- `is`(
- ParameterizedTypeName.get(
- ClassName.get("java.util", "List"),
- ClassName.get("java.lang", "Long")
- ) as TypeName
- )
- )
- }
- }
-
- @Test
- fun insertArray() {
- singleInsertMethod(
- """
- @Insert
- abstract public void insertUsers(User[] users);
- """
- ) { insertion, _ ->
- assertThat(insertion.element.jvmName, `is`("insertUsers"))
- assertThat(insertion.parameters.size, `is`(1))
- val param = insertion.parameters.first()
- assertThat(
- param.type.typeName,
- `is`(
- ArrayTypeName.of(COMMON.USER_TYPE_NAME) as TypeName
- )
- )
- assertThat(insertion.entities.size, `is`(1))
- assertThat(insertion.entities["users"]?.pojo?.typeName, `is`(USER_TYPE_NAME))
- assertThat(insertion.returnType.typeName, `is`(TypeName.VOID))
- }
- }
-
- @Test
- fun insertSet() {
- singleInsertMethod(
- """
- @Insert
- abstract public void insertUsers(Set<User> users);
- """
- ) { insertion, _ ->
- assertThat(insertion.element.jvmName, `is`("insertUsers"))
- assertThat(insertion.parameters.size, `is`(1))
- val param = insertion.parameters.first()
- assertThat(
- param.type.typeName,
- `is`(
- ParameterizedTypeName.get(
- ClassName.get("java.util", "Set"),
- COMMON.USER_TYPE_NAME
- ) as TypeName
- )
- )
- assertThat(insertion.entities.size, `is`(1))
- assertThat(insertion.entities["users"]?.pojo?.typeName, `is`(USER_TYPE_NAME))
- assertThat(insertion.returnType.typeName, `is`(TypeName.VOID))
- }
- }
-
- @Test
- fun insertQueue() {
- singleInsertMethod(
- """
- @Insert
- abstract public void insertUsers(Queue<User> users);
- """
- ) { insertion, _ ->
- assertThat(insertion.element.jvmName, `is`("insertUsers"))
- assertThat(insertion.parameters.size, `is`(1))
- val param = insertion.parameters.first()
- assertThat(
- param.type.typeName,
- `is`(
- ParameterizedTypeName.get(
- ClassName.get("java.util", "Queue"),
- USER_TYPE_NAME
- ) as TypeName
- )
- )
- assertThat(insertion.entities.size, `is`(1))
- assertThat(insertion.entities["users"]?.pojo?.typeName, `is`(USER_TYPE_NAME))
- assertThat(insertion.returnType.typeName, `is`(TypeName.VOID))
- }
- }
-
- @Test
- fun insertIterable() {
- singleInsertMethod(
- """
- @Insert
- abstract public void insert(Iterable<User> users);
- """
- ) { insertion, _ ->
- assertThat(insertion.element.jvmName, `is`("insert"))
- assertThat(insertion.parameters.size, `is`(1))
- val param = insertion.parameters.first()
- assertThat(
- param.type.typeName,
- `is`(
- ParameterizedTypeName.get(
- ClassName.get("java.lang", "Iterable"),
- USER_TYPE_NAME
- ) as TypeName
- )
- )
- assertThat(insertion.entities.size, `is`(1))
- assertThat(insertion.entities["users"]?.pojo?.typeName, `is`(USER_TYPE_NAME))
- assertThat(insertion.returnType.typeName, `is`(TypeName.VOID))
- }
- }
-
- @Test
- fun insertCustomCollection() {
- singleInsertMethod(
- """
- static class MyList<Irrelevant, Item> extends ArrayList<Item> {}
- @Insert
- abstract public void insert(MyList<String, User> users);
- """
- ) { insertion, _ ->
- assertThat(insertion.element.jvmName, `is`("insert"))
- assertThat(insertion.parameters.size, `is`(1))
- val param = insertion.parameters.first()
- assertThat(
- param.type.typeName,
- `is`(
- ParameterizedTypeName.get(
- ClassName.get("foo.bar", "MyClass.MyList"),
- CommonTypeNames.STRING, USER_TYPE_NAME
- ) as TypeName
- )
- )
- assertThat(insertion.entities.size, `is`(1))
- assertThat(insertion.entities["users"]?.pojo?.typeName, `is`(USER_TYPE_NAME))
- assertThat(insertion.returnType.typeName, `is`(TypeName.VOID))
- }
- }
-
- @Test
- fun insertDifferentTypes() {
- singleInsertMethod(
- """
- @Insert
- abstract public void foo(User u1, Book b1);
- """
- ) { insertion, _ ->
- assertThat(insertion.parameters.size, `is`(2))
- assertThat(
- insertion.parameters[0].type.typeName.toString(),
- `is`("foo.bar.User")
- )
- assertThat(
- insertion.parameters[1].type.typeName.toString(),
- `is`("foo.bar.Book")
- )
- assertThat(insertion.parameters.map { it.name }, `is`(listOf("u1", "b1")))
- assertThat(insertion.returnType.typeName, `is`(TypeName.VOID))
- assertThat(insertion.entities.size, `is`(2))
- assertThat(insertion.entities["u1"]?.pojo?.typeName, `is`(USER_TYPE_NAME))
- assertThat(insertion.entities["b1"]?.pojo?.typeName, `is`(BOOK_TYPE_NAME))
- }
- }
+ override fun noAdapter(): String = CANNOT_FIND_INSERT_RESULT_ADAPTER
@Test
fun onConflict_Default() {
- singleInsertMethod(
+ singleInsertUpsertShortcutMethod(
"""
@Insert
abstract public void foo(User user);
"""
) { insertion, _ ->
- assertThat(insertion.onConflict, `is`(OnConflictStrategy.ABORT))
+ assertThat(insertion.onConflict).isEqualTo(OnConflictStrategy.ABORT)
}
}
@Test
fun onConflict_Invalid() {
- singleInsertMethod(
+ singleInsertUpsertShortcutMethod(
"""
@Insert(onConflict = -1)
abstract public void foo(User user);
@@ -387,672 +82,22 @@
Pair("FAIL", 4),
Pair("IGNORE", 5)
).forEach { pair ->
- singleInsertMethod(
+ singleInsertUpsertShortcutMethod(
"""
@Insert(onConflict=OnConflictStrategy.${pair.first})
abstract public void foo(User user);
"""
) { insertion, _ ->
- assertThat(insertion.onConflict, `is`(pair.second))
+ assertThat(insertion.onConflict).isEqualTo(pair.second)
}
}
}
- @Test
- fun invalidReturnType() {
- listOf(
- "int",
- "${RxJava2TypeNames.SINGLE}<Int>",
- "${RxJava2TypeNames.MAYBE}<Int>",
- "${RxJava2TypeNames.SINGLE}<String>",
- "${RxJava2TypeNames.MAYBE}<String>",
- "${RxJava2TypeNames.SINGLE}<User>",
- "${RxJava2TypeNames.MAYBE}<User>"
- ).forEach { type ->
- singleInsertMethod(
- """
- @Insert
- abstract public $type foo(User user);
- """
- ) { insertion, invocation ->
- // TODO: (b/240491383) remove methodBinder nullability
- assertThat(insertion.methodBinder?.adapter, `is`(nullValue()))
- invocation.assertCompilationResult {
- hasErrorContaining(
- ProcessorErrors.CANNOT_FIND_INSERT_RESULT_ADAPTER
- )
- }
- }
- }
- }
-
- @Test
- fun mismatchedReturnType() {
- listOf(
- "long[]",
- "Long[]",
- "List<Long>",
- "${RxJava2TypeNames.SINGLE}<List<Long>>",
- "${RxJava2TypeNames.MAYBE}<List<Long>>"
- ).forEach { type ->
- singleInsertMethod(
- """
- @Insert
- abstract public $type foo(User user);
- """
- ) { insertion, invocation ->
- // TODO: (b/240491383) remove methodBinder nullability
- assertThat(insertion.methodBinder?.adapter, `is`(nullValue()))
- invocation.assertCompilationResult {
- hasErrorContaining(
- ProcessorErrors.CANNOT_FIND_INSERT_RESULT_ADAPTER
- )
- }
- }
- }
- }
-
- @Test
- fun mismatchedReturnType2() {
- listOf(
- "long",
- "Long",
- "${RxJava2TypeNames.SINGLE}<Long>",
- "${RxJava2TypeNames.MAYBE}<Long>"
- ).forEach { type ->
- singleInsertMethod(
- """
- @Insert
- abstract public $type foo(User... user);
- """
- ) { insertion, invocation ->
- // TODO: (b/240491383) remove methodBinder nullability
- assertThat(insertion.methodBinder?.adapter, `is`(nullValue()))
- invocation.assertCompilationResult {
- hasErrorContaining(
- ProcessorErrors.CANNOT_FIND_INSERT_RESULT_ADAPTER
- )
- }
- }
- }
- }
-
- @Test
- fun mismatchedReturnType3() {
- listOf(
- "long",
- "Long",
- "${RxJava2TypeNames.SINGLE}<Long>",
- "${RxJava2TypeNames.MAYBE}<Long>"
- ).forEach { type ->
- singleInsertMethod(
- """
- @Insert
- abstract public $type foo(User user1, User user2);
- """
- ) { insertion, invocation ->
- // TODO: (b/240491383) remove methodBinder nullability
- assertThat(insertion.methodBinder?.adapter, `is`(nullValue()))
- invocation.assertCompilationResult {
- hasErrorContaining(
- ProcessorErrors.CANNOT_FIND_INSERT_RESULT_ADAPTER
- )
- }
- }
- }
- }
-
- @Test
- fun validReturnTypes() {
- listOf(
- Pair("void", InsertMethodAdapter.InsertionType.INSERT_VOID),
- Pair("long", InsertMethodAdapter.InsertionType.INSERT_SINGLE_ID),
- Pair("long[]", InsertMethodAdapter.InsertionType.INSERT_ID_ARRAY),
- Pair("Long[]", InsertMethodAdapter.InsertionType.INSERT_ID_ARRAY_BOX),
- Pair("List<Long>", InsertMethodAdapter.InsertionType.INSERT_ID_LIST),
- Pair(
- RxJava2TypeNames.COMPLETABLE,
- InsertMethodAdapter.InsertionType.INSERT_VOID_OBJECT
- ),
- Pair(
- "${RxJava2TypeNames.SINGLE}<Long>",
- InsertMethodAdapter.InsertionType.INSERT_SINGLE_ID
- ),
- Pair(
- "${RxJava2TypeNames.SINGLE}<List<Long>>",
- InsertMethodAdapter.InsertionType.INSERT_ID_LIST
- ),
- Pair(
- "${RxJava2TypeNames.MAYBE}<Long>",
- InsertMethodAdapter.InsertionType.INSERT_SINGLE_ID
- ),
- Pair(
- "${RxJava2TypeNames.MAYBE}<List<Long>>",
- InsertMethodAdapter.InsertionType.INSERT_ID_LIST
- ),
- Pair(
- RxJava3TypeNames.COMPLETABLE,
- InsertMethodAdapter.InsertionType.INSERT_VOID_OBJECT
- ),
- Pair(
- "${RxJava3TypeNames.SINGLE}<Long>",
- InsertMethodAdapter.InsertionType.INSERT_SINGLE_ID
- ),
- Pair(
- "${RxJava3TypeNames.SINGLE}<List<Long>>",
- InsertMethodAdapter.InsertionType.INSERT_ID_LIST
- ),
- Pair(
- "${RxJava3TypeNames.MAYBE}<Long>",
- InsertMethodAdapter.InsertionType.INSERT_SINGLE_ID
- ),
- Pair(
- "${RxJava3TypeNames.MAYBE}<List<Long>>",
- InsertMethodAdapter.InsertionType.INSERT_ID_LIST
- )
- ).forEach { pair ->
- val dots = if (pair.second in setOf(
- InsertMethodAdapter.InsertionType.INSERT_ID_LIST,
- InsertMethodAdapter.InsertionType.INSERT_ID_ARRAY,
- InsertMethodAdapter.InsertionType.INSERT_ID_ARRAY_BOX
- )
- ) {
- "..."
- } else {
- ""
- }
- singleInsertMethod(
- """
- @Insert
- abstract public ${pair.first} foo(User$dots user);
- """
- ) { insertion, _ ->
- assertThat(insertion.methodBinder?.adapter, `is`(notNullValue()))
- }
- }
- }
-
- @Test
- fun targetEntitySingle() {
- val usernameSource = Source.java(
- "foo.bar.Username",
- """
- package foo.bar;
- import androidx.room.*;
-
- public class Username {
- int uid;
- String name;
- @ColumnInfo(name = "ageColumn")
- int age;
- }
- """
- )
- singleInsertMethod(
- """
- @Insert(entity = User.class)
- abstract public long foo(Username username);
- """,
- additionalSources = listOf(usernameSource)
- ) { insertion, _ ->
- assertThat(insertion.element.jvmName, `is`("foo"))
- assertThat(insertion.parameters.size, `is`(1))
- val param = insertion.parameters.first()
- assertThat(param.type.typeName, `is`(USERNAME_TYPE_NAME))
- assertThat(param.pojoType?.typeName, `is`(USERNAME_TYPE_NAME))
- assertThat(insertion.entities.size, `is`(1))
- assertThat(insertion.entities["username"]?.isPartialEntity, `is`(true))
- assertThat(insertion.entities["username"]?.entityTypeName, `is`(USER_TYPE_NAME))
- assertThat(insertion.entities["username"]?.pojo?.typeName, `is`(USERNAME_TYPE_NAME))
- }
- }
-
- @Test
- fun targetEntitySameAsPojo() {
- singleInsertMethod(
- """
- @Insert(entity = User.class)
- abstract public long foo(User user);
- """
- ) { _, _ ->
- }
- }
-
- @Test
- fun targetEntityTwo() {
- val usernameSource = Source.java(
- "foo.bar.Username",
- """
- package foo.bar;
- import androidx.room.*;
-
- public class Username {
- int uid;
- String name;
- @ColumnInfo(name = "ageColumn")
- int age;
- }
- """
- )
- singleInsertMethod(
- """
- @Insert(entity = User.class)
- abstract public void foo(Username usernameA, Username usernameB);
- """,
- additionalSources = listOf(usernameSource)
- ) { _, _ ->
- }
- }
-
- @Test
- fun targetEntityMissingRequiredColumn() {
- val usernameSource = Source.java(
- "foo.bar.Username",
- """
- package foo.bar;
- import androidx.room.*;
-
- public class Username {
- int uid;
- String name;
- }
- """
- )
- singleInsertMethod(
- """
- @Insert(entity = User.class)
- abstract public void foo(Username username);
- """,
- additionalSources = listOf(usernameSource)
- ) { _, invocation ->
- invocation.assertCompilationResult {
- hasErrorContaining(
- ProcessorErrors.missingRequiredColumnsInPartialEntity(
- partialEntityName = USERNAME_TYPE_NAME.toString(),
- missingColumnNames = listOf("ageColumn")
- )
- )
- }
- }
- }
-
- @Test
- fun targetEntityColumnDefaultValue() {
- val petNameSource = Source.java(
- "foo.bar.PetName",
- """
- package foo.bar;
- import androidx.room.*;
-
- public class PetName {
- @ColumnInfo(name = "name")
- String string;
- }
- """
- )
- val petSource = Source.java(
- "foo.bar.Pet",
- """
- package foo.bar;
- import androidx.room.*;
-
- @Entity
- public class Pet {
- @PrimaryKey(autoGenerate = true)
- int petId;
- String name;
- @ColumnInfo(defaultValue = "0")
- int age;
- }
- """
- )
- singleInsertMethod(
- """
- @Insert(entity = Pet.class)
- abstract public long foo(PetName petName);
- """,
- additionalSources = listOf(petNameSource, petSource)
- ) { _, _ ->
- }
- }
-
- @Test
- fun targetEntityMissingPrimaryKey() {
- val petNameSource = Source.java(
- "foo.bar.PetName",
- """
- package foo.bar;
- import androidx.room.*;
-
- public class PetName {
- @ColumnInfo(name = "name")
- String string;
- }
- """
- )
- val petSource = Source.java(
- "foo.bar.Pet",
- """
- package foo.bar;
- import androidx.room.*;
-
- @Entity
- public class Pet {
- @PrimaryKey
- int petId;
- String name;
- }
- """
- )
- singleInsertMethod(
- """
- @Insert(entity = Pet.class)
- abstract public long foo(PetName petName);
- """,
- additionalSources = listOf(petNameSource, petSource)
- ) { _, invocation ->
- invocation.assertCompilationResult {
- hasErrorContaining(
- ProcessorErrors.missingPrimaryKeysInPartialEntityForInsert(
- partialEntityName = "foo.bar.PetName",
- primaryKeyNames = listOf("petId")
- )
- )
- }
- }
- }
-
- @Test
- fun targetEntityAutoGeneratedPrimaryKey() {
- val petNameSource = Source.java(
- "foo.bar.PetName",
- """
- package foo.bar;
- import androidx.room.*;
-
- public class PetName {
- @ColumnInfo(name = "name")
- String string;
- }
- """
- )
- val petSource = Source.java(
- "foo.bar.Pet",
- """
- package foo.bar;
- import androidx.room.*;
-
- @Entity
- public class Pet {
- @PrimaryKey(autoGenerate = true)
- int petId;
- String name;
- }
- """
- )
- singleInsertMethod(
- """
- @Insert(entity = Pet.class)
- abstract public long foo(PetName petName);
- """,
- additionalSources = listOf(petNameSource, petSource)
- ) { _, _ ->
- }
- }
-
- @Test
- fun targetEntityExtraColumn() {
- val usernameSource = Source.java(
- "foo.bar.Username",
- """
- package foo.bar;
- import androidx.room.*;
-
- public class Username {
- int uid;
- String name;
- long extraField;
- }
- """
- )
- singleInsertMethod(
- """
- @Insert(entity = User.class)
- abstract public long foo(Username username);
- """,
- additionalSources = listOf(usernameSource)
- ) { _, invocation ->
- invocation.assertCompilationResult {
- hasErrorContaining(
- ProcessorErrors.cannotFindAsEntityField("foo.bar.User")
- )
- }
- }
- }
-
- @Test
- fun targetEntityExtraColumnIgnored() {
- val usernameSource = Source.java(
- "foo.bar.Username",
- """
- package foo.bar;
- import androidx.room.*;
-
- public class Username {
- int uid;
- String name;
- @ColumnInfo(name = "ageColumn")
- int age;
- @Ignore
- long extraField;
- }
- """
- )
- singleInsertMethod(
- """
- @Insert(entity = User.class)
- abstract public long foo(Username username);
- """,
- additionalSources = listOf(usernameSource)
- ) { _, _ ->
- }
- }
-
- @Test
- fun targetEntityWithEmbedded() {
- val usernameSource = Source.java(
- "foo.bar.Username",
- """
- package foo.bar;
- import androidx.room.*;
-
- public class Username {
- int uid;
- @Embedded
- Fullname name;
- @ColumnInfo(name = "ageColumn")
- int age;
- }
- """
- )
- val fullnameSource = Source.java(
- "foo.bar.Fullname",
- """
- package foo.bar;
- import androidx.room.*;
-
- public class Fullname {
- @ColumnInfo(name = "name")
- String firstName;
- String lastName;
- }
- """
- )
- singleInsertMethod(
- """
- @Insert(entity = User.class)
- abstract public long foo(Username username);
- """,
- additionalSources = listOf(usernameSource, fullnameSource)
- ) { _, _ ->
- }
- }
-
- @Test
- fun targetEntityWithRelation() {
- val userPetsSource = Source.java(
- "foo.bar.UserPets",
- """
- package foo.bar;
- import androidx.room.*;
- import java.util.List;
-
- public class UserPets {
- int uid;
- @Relation(parentColumn = "uid", entityColumn = "ownerId")
- List<Pet> pets;
- }
- """
- )
- val petSource = Source.java(
- "foo.bar.Pet",
- """
- package foo.bar;
- import androidx.room.*;
-
- @Entity
- public class Pet {
- @PrimaryKey
- int petId;
- int ownerId;
- }
- """
- )
- singleInsertMethod(
- """
- @Insert(entity = User.class)
- abstract public long foo(UserPets userPets);
- """,
- additionalSources = listOf(userPetsSource, petSource)
- ) { _, invocation ->
- invocation.assertCompilationResult {
- hasErrorContaining(
- ProcessorErrors.INVALID_RELATION_IN_PARTIAL_ENTITY
- )
- }
- }
- }
-
- @Test
- fun suspendReturnsDeferredType() {
- listOf(
- "${RxJava2TypeNames.FLOWABLE}<Int>",
- "${RxJava2TypeNames.OBSERVABLE}<Int>",
- "${RxJava2TypeNames.MAYBE}<Int>",
- "${RxJava2TypeNames.SINGLE}<Int>",
- "${RxJava2TypeNames.COMPLETABLE}",
- "${RxJava3TypeNames.FLOWABLE}<Int>",
- "${RxJava3TypeNames.OBSERVABLE}<Int>",
- "${RxJava3TypeNames.MAYBE}<Int>",
- "${RxJava3TypeNames.SINGLE}<Int>",
- "${RxJava3TypeNames.COMPLETABLE}",
- "${LifecyclesTypeNames.LIVE_DATA}<Int>",
- "${LifecyclesTypeNames.COMPUTABLE_LIVE_DATA}<Int>",
- "${GuavaUtilConcurrentTypeNames.LISTENABLE_FUTURE}<Int>",
- "${ReactiveStreamsTypeNames.PUBLISHER}<Int>",
- "${KotlinTypeNames.FLOW}<Int>"
- ).forEach { type ->
- singleInsertMethodKotlin(
- """
- @Insert
- abstract suspend fun foo(user: User): $type
- """
- ) { _, invocation ->
- invocation.assertCompilationResult {
- val rawTypeName = type.substringBefore("<")
- hasErrorContaining(ProcessorErrors.suspendReturnsDeferredType(rawTypeName))
- }
- }
- }
- }
-
- fun singleInsertMethod(
- vararg input: String,
- additionalSources: List<Source> = emptyList(),
- handler: (InsertionMethod, XTestInvocation) -> Unit
- ) {
- val inputSource = Source.java(
- "foo.bar.MyClass",
- DAO_PREFIX + input.joinToString("\n") + DAO_SUFFIX
- )
- val commonSources = listOf(
- COMMON.USER, COMMON.BOOK, COMMON.NOT_AN_ENTITY, COMMON.RX2_COMPLETABLE,
- COMMON.RX2_MAYBE, COMMON.RX2_SINGLE, COMMON.RX3_COMPLETABLE,
- COMMON.RX3_MAYBE, COMMON.RX3_SINGLE
- )
-
- runProcessorTest(
- sources = commonSources + additionalSources + inputSource
- ) { invocation ->
- val (owner, methods) = invocation.roundEnv
- .getElementsAnnotatedWith(Dao::class.qualifiedName!!)
- .filterIsInstance<XTypeElement>()
- .map {
- Pair(
- it,
- it.getAllMethods().filter {
- it.hasAnnotation(Insert::class)
- }.toList()
- )
- }.first { it.second.isNotEmpty() }
- val processor = InsertionMethodProcessor(
- baseContext = invocation.context,
- containing = owner.type,
- executableElement = methods.first()
- )
- val processed = processor.process()
- handler(processed, invocation)
- }
- }
-
- fun singleInsertMethodKotlin(
- vararg input: String,
- additionalSources: List<Source> = emptyList(),
- handler: (InsertionMethod, XTestInvocation) -> Unit
- ) {
- val inputSource = Source.kotlin(
- "MyClass.kt",
- DAO_PREFIX_KT + input.joinToString("\n") + DAO_SUFFIX
- )
- val commonSources = listOf(
- COMMON.USER, COMMON.BOOK, COMMON.NOT_AN_ENTITY, COMMON.RX2_COMPLETABLE,
- COMMON.RX2_MAYBE, COMMON.RX2_SINGLE, COMMON.RX2_FLOWABLE, COMMON.RX2_OBSERVABLE,
- COMMON.RX3_COMPLETABLE, COMMON.RX3_MAYBE, COMMON.RX3_SINGLE, COMMON.RX3_FLOWABLE,
- COMMON.RX3_OBSERVABLE, COMMON.LISTENABLE_FUTURE, COMMON.LIVE_DATA,
- COMMON.COMPUTABLE_LIVE_DATA, COMMON.PUBLISHER, COMMON.FLOW, COMMON.GUAVA_ROOM
- )
-
- runProcessorTest(
- sources = commonSources + additionalSources + inputSource
- ) { invocation ->
- val (owner, methods) = invocation.roundEnv
- .getElementsAnnotatedWith(Dao::class.qualifiedName!!)
- .filterIsInstance<XTypeElement>()
- .map {
- Pair(
- it,
- it.getAllMethods().filter {
- it.hasAnnotation(Insert::class)
- }.toList()
- )
- }.first { it.second.isNotEmpty() }
- val processor = InsertionMethodProcessor(
- baseContext = invocation.context,
- containing = owner.type,
- executableElement = methods.first()
- )
- val processed = processor.process()
- handler(processed, invocation)
- }
+ override fun process(
+ baseContext: Context,
+ containing: XType,
+ executableElement: XMethodElement
+ ): InsertionMethod {
+ return InsertionMethodProcessor(baseContext, containing, executableElement).process()
}
}
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/NewInsertionMethodProcessorTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/NewInsertionMethodProcessorTest.kt
deleted file mode 100644
index 2f1b27f..0000000
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/NewInsertionMethodProcessorTest.kt
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2017 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.processor
-
-import androidx.room.Insert
-import androidx.room.OnConflictStrategy
-import androidx.room.compiler.processing.XMethodElement
-import androidx.room.compiler.processing.XType
-import androidx.room.processor.ProcessorErrors.INSERTION_DOES_NOT_HAVE_ANY_PARAMETERS_TO_INSERT
-import androidx.room.vo.InsertionMethod
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-// TODO: Rename NewInsertionMethodProcessorTest.kt to InsertionMethodProcessorTest (remove old file)
-
-@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
-@RunWith(JUnit4::class)
-class NewInsertionMethodProcessorTest :
- InsertOrUpsertShortcutMethodProcessorTest<InsertionMethod>(Insert::class) {
- override fun noParamsError(): String = INSERTION_DOES_NOT_HAVE_ANY_PARAMETERS_TO_INSERT
-
- override fun missingPrimaryKey(partialEntityName: String, primaryKeyName: List<String>):
- String {
- return ProcessorErrors.missingPrimaryKeysInPartialEntityForInsert(
- partialEntityName,
- primaryKeyName
- )
- }
-
- @Test
- fun onConflict_Default() {
- singleInsertUpsertShortcutMethod(
- """
- @Insert
- abstract public void foo(User user);
- """
- ) { insertion, _ ->
- assertThat(insertion.onConflict).isEqualTo(OnConflictStrategy.ABORT)
- }
- }
-
- @Test
- fun onConflict_Invalid() {
- singleInsertUpsertShortcutMethod(
- """
- @Insert(onConflict = -1)
- abstract public void foo(User user);
- """
- ) { _, invocation ->
- invocation.assertCompilationResult {
- hasErrorContaining(
- ProcessorErrors.INVALID_ON_CONFLICT_VALUE
- )
- }
- }
- }
-
- @Test
- fun onConflict_EachValue() {
- listOf(
- Pair("NONE", 0),
- Pair("REPLACE", 1),
- Pair("ROLLBACK", 2),
- Pair("ABORT", 3),
- Pair("FAIL", 4),
- Pair("IGNORE", 5)
- ).forEach { pair ->
- singleInsertUpsertShortcutMethod(
- """
- @Insert(onConflict=OnConflictStrategy.${pair.first})
- abstract public void foo(User user);
- """
- ) { insertion, _ ->
- assertThat(insertion.onConflict).isEqualTo(pair.second)
- }
- }
- }
-
- override fun process(
- baseContext: Context,
- containing: XType,
- executableElement: XMethodElement
- ): InsertionMethod {
- return InsertionMethodProcessor(baseContext, containing, executableElement).process()
- }
-}
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/UpsertionMethodProcessorTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/UpsertionMethodProcessorTest.kt
index 4370d53..26ecca7 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/UpsertionMethodProcessorTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/UpsertionMethodProcessorTest.kt
@@ -20,6 +20,7 @@
import androidx.room.compiler.processing.XMethodElement
import androidx.room.compiler.processing.XType
import androidx.room.processor.ProcessorErrors.UPSERTION_DOES_NOT_HAVE_ANY_PARAMETERS_TO_UPSERT
+import androidx.room.processor.ProcessorErrors.CANNOT_FIND_UPSERT_RESULT_ADAPTER
import androidx.room.vo.UpsertionMethod
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -38,6 +39,8 @@
)
}
+ override fun noAdapter(): String = CANNOT_FIND_UPSERT_RESULT_ADAPTER
+
override fun process(
baseContext: Context,
containing: XType,