Filling in upsert processor; merged insert and UpsertMethod and binder
To reduce code and increase reusability: created InsertOrUpsertShortcutMethod.kt that holds InsertionMethod and UpsertionMethod; combined the Insert and Upsert binders into InsertOrUpsertMethodBinder.kt; created abstract class that holds Insert and Upsert's adapters; created an InsertionUpsertionMethodProcessorTest.kt that will run the shared tests for both insert and upsert.
Bug: 117855270
Test: InsertionUpsertionMethodProcessorTest.kt
Change-Id: I8fa1211da1882a0ae2b1fe9720886e2d649c82aa
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/processor/DaoProcessor.kt b/room/room-compiler/src/main/kotlin/androidx/room/processor/DaoProcessor.kt
index 104295d..f4f41f4 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/processor/DaoProcessor.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/processor/DaoProcessor.kt
@@ -45,7 +45,7 @@
companion object {
val PROCESSED_ANNOTATIONS = listOf(
Insert::class, Delete::class, Query::class,
- Update::class, RawQuery::class
+ Update::class, Upsert::class, RawQuery::class
)
}
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/processor/DatabaseProcessor.kt b/room/room-compiler/src/main/kotlin/androidx/room/processor/DatabaseProcessor.kt
index 8fcba1b..ffad3f1 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/processor/DatabaseProcessor.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/processor/DatabaseProcessor.kt
@@ -371,7 +371,7 @@
}
}
daoMethods.forEach { daoMethod ->
- daoMethod.dao.shortcutMethods.forEach { method ->
+ daoMethod.dao.deleteOrUpdateShortcutMethods.forEach { method ->
method.entities.forEach {
check(method.element, daoMethod.dao, it.value.entityTypeName)
}
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/processor/MethodProcessorDelegate.kt b/room/room-compiler/src/main/kotlin/androidx/room/processor/MethodProcessorDelegate.kt
index c500f7e..31bd866 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/processor/MethodProcessorDelegate.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/processor/MethodProcessorDelegate.kt
@@ -38,8 +38,7 @@
import androidx.room.solver.shortcut.binder.CallableInsertMethodBinder.Companion.createInsertBinder
import androidx.room.solver.shortcut.binder.CallableUpsertMethodBinder.Companion.createUpsertBinder
import androidx.room.solver.shortcut.binder.DeleteOrUpdateMethodBinder
-import androidx.room.solver.shortcut.binder.InsertMethodBinder
-import androidx.room.solver.shortcut.binder.UpsertMethodBinder
+import androidx.room.solver.shortcut.binder.InsertOrUpsertMethodBinder
import androidx.room.solver.transaction.binder.CoroutineTransactionMethodBinder
import androidx.room.solver.transaction.binder.InstantTransactionMethodBinder
import androidx.room.solver.transaction.binder.TransactionMethodBinder
@@ -89,14 +88,14 @@
abstract fun findInsertMethodBinder(
returnType: XType,
params: List<ShortcutQueryParameter>
- ): InsertMethodBinder
+ ): InsertOrUpsertMethodBinder
abstract fun findDeleteOrUpdateMethodBinder(returnType: XType): DeleteOrUpdateMethodBinder
abstract fun findUpsertMethodBinder(
returnType: XType,
params: List<ShortcutQueryParameter>
- ): UpsertMethodBinder
+ ): InsertOrUpsertMethodBinder
abstract fun findTransactionMethodBinder(
callType: TransactionMethod.CallType
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt b/room/room-compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
index 0b9d0e4..7c08dd0 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
@@ -18,6 +18,7 @@
import androidx.room.Delete
import androidx.room.Insert
+import androidx.room.Upsert
import androidx.room.Query
import androidx.room.RawQuery
import androidx.room.RewriteQueriesToDropUnusedColumns
@@ -42,6 +43,7 @@
val MISSING_INSERT_ANNOTATION = "Insertion methods must be annotated with ${Insert::class.java}"
val MISSING_DELETE_ANNOTATION = "Deletion methods must be annotated with ${Delete::class.java}"
val MISSING_UPDATE_ANNOTATION = "Update methods must be annotated with ${Update::class.java}"
+ val MISSING_UPSERT_ANNOTATION = "Upsertion methods must be annotated with ${Upsert::class.java}"
val MISSING_RAWQUERY_ANNOTATION = "RawQuery methods must be annotated with" +
" ${RawQuery::class.java}"
val INVALID_ON_CONFLICT_VALUE = "On conflict value must be one of @OnConflictStrategy values."
@@ -57,6 +59,8 @@
" methods. It must be bound to a type through base Dao class."
val CANNOT_USE_UNBOUND_GENERICS_IN_INSERTION_METHODS = "Cannot use unbound generics in" +
" insertion methods. It must be bound to a type through base Dao class."
+ val CANNOT_USE_UNBOUND_GENERICS_IN_UPSERTION_METHODS = "Cannot use unbound generics in" +
+ " upsertion methods. It must be bound to a type through base Dao class."
val CANNOT_USE_UNBOUND_GENERICS_IN_ENTITY_FIELDS = "Cannot use unbound fields in entities."
val CANNOT_USE_UNBOUND_GENERICS_IN_DAO_CLASSES = "Cannot use unbound generics in Dao classes." +
" If you are trying to create a base DAO, create a normal class, extend it with type" +
@@ -143,6 +147,9 @@
val INSERTION_DOES_NOT_HAVE_ANY_PARAMETERS_TO_INSERT = "Method annotated with" +
" @Insert but does not have any parameters to insert."
+ val UPSERTION_DOES_NOT_HAVE_ANY_PARAMETERS_TO_UPSERT = "Method annotated with" +
+ " @Upsert but does not have any parameters to insert or update."
+
val DELETION_MISSING_PARAMS = "Method annotated with" +
" @Delete but does not have any parameters to delete."
@@ -179,6 +186,8 @@
val CANNOT_FIND_INSERT_RESULT_ADAPTER = "Not sure how to handle insert method's return type."
+ val CANNOT_FIND_UPSERT_RESULT_ADAPTER = "Not sure how to handle upsert method's return type."
+
val UPDATE_MISSING_PARAMS = "Method annotated with" +
" @Update but does not have any parameters to update."
@@ -774,6 +783,13 @@
"(${primaryKeyNames.joinToString()}) needed to perform an INSERT. If your single " +
"primary key is auto generated then the fields are optional."
+ fun missingPrimaryKeysInPartialEntityForUpsert(
+ partialEntityName: String,
+ primaryKeyNames: List<String>
+ ) = "The partial entity $partialEntityName is missing the primary key fields " +
+ "(${primaryKeyNames.joinToString()}) needed to perform an UPSERT. If your single " +
+ "primary key is auto generated then the fields are optional."
+
fun missingRequiredColumnsInPartialEntity(
partialEntityName: String,
missingColumnNames: List<String>
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 a586df6..7d87c5a 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
@@ -16,15 +16,11 @@
package androidx.room.processor
+import androidx.room.Upsert
import androidx.room.compiler.processing.XMethodElement
import androidx.room.compiler.processing.XType
-import androidx.room.solver.CodeGenScope
-import androidx.room.solver.shortcut.binder.UpsertMethodBinder
-import androidx.room.vo.ShortcutEntity
-import androidx.room.vo.ShortcutQueryParameter
import androidx.room.vo.UpsertionMethod
-import com.squareup.javapoet.FieldSpec
-import com.squareup.javapoet.TypeSpec
+import androidx.room.vo.findFieldByColumnName
class UpsertionMethodProcessor(
baseContext: Context,
@@ -32,21 +28,68 @@
val executableElement: XMethodElement
) {
val context = baseContext.fork(executableElement)
- class StubUpsertMethodBinder : UpsertMethodBinder(null) {
- override fun convertAndReturn(
- parameters: List<ShortcutQueryParameter>,
- upsertionAdapters: Map<String, Pair<FieldSpec, TypeSpec>>,
- dbField: FieldSpec,
- scope: CodeGenScope
- ) {}
- }
fun process(): UpsertionMethod {
+ val delegate = ShortcutMethodProcessor(context, containing, executableElement)
+
+ val annotation = delegate.extractAnnotation(
+ Upsert::class,
+ ProcessorErrors.MISSING_UPSERT_ANNOTATION
+ )
+
+ val returnType = delegate.extractReturnType()
+ val returnTypeName = returnType.typeName
+ context.checker.notUnbound(
+ returnTypeName, executableElement,
+ ProcessorErrors.CANNOT_USE_UNBOUND_GENERICS_IN_UPSERTION_METHODS
+ )
+
+ val (entities, params) = delegate.extractParams(
+ targetEntityType = annotation?.getAsType("entity"),
+ missingParamError = ProcessorErrors.UPSERTION_DOES_NOT_HAVE_ANY_PARAMETERS_TO_UPSERT,
+ onValidatePartialEntity = { entity, pojo ->
+ val missingPrimaryKeys = entity.primaryKey.fields.any {
+ pojo.findFieldByColumnName(it.columnName) == null
+ }
+ context.checker.check(
+ entity.primaryKey.autoGenerateId || !missingPrimaryKeys,
+ executableElement,
+ ProcessorErrors.missingPrimaryKeysInPartialEntityForUpsert(
+ partialEntityName = pojo.typeName.toString(),
+ primaryKeyNames = entity.primaryKey.fields.columnNames
+ )
+ )
+
+ // Verify all non null columns without a default value are in the POJO otherwise
+ // the UPSERT will fail with a NOT NULL constraint.
+ val missingRequiredFields = (entity.fields - entity.primaryKey.fields).filter {
+ it.nonNull && it.defaultValue == null &&
+ pojo.findFieldByColumnName(it.columnName) == null
+ }
+ context.checker.check(
+ missingRequiredFields.isEmpty(),
+ executableElement,
+ ProcessorErrors.missingRequiredColumnsInPartialEntity(
+ partialEntityName = pojo.typeName.toString(),
+ missingColumnNames = missingRequiredFields.map { it.columnName }
+ )
+ )
+ }
+ )
+
+ val methodBinder = delegate.findUpsertMethodBinder(returnType, params)
+ // TODO: (b/240491114) Uncomment code below for UpsertMethodAdapter is implemented
+ /*context.checker.check(
+ methodBinder.adapter != null,
+ executableElement,
+ ProcessorErrors.CANNOT_FIND_UPSERT_RESULT_ADAPTER
+ )*/
+
return UpsertionMethod(
element = executableElement,
- returnType = executableElement.returnType,
- entities = emptyMap<String, ShortcutEntity>(),
- parameters = emptyList<ShortcutQueryParameter>(),
- methodBinder = StubUpsertMethodBinder()
+ returnType = returnType,
+ entities = entities,
+ parameters = params,
+ methodBinder = methodBinder
)
}
}
\ No newline at end of file
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 cc06a34..b7d3188 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
@@ -80,14 +80,12 @@
import androidx.room.solver.query.result.SingleEntityQueryResultAdapter
import androidx.room.solver.query.result.SingleNamedColumnRowAdapter
import androidx.room.solver.shortcut.binder.DeleteOrUpdateMethodBinder
-import androidx.room.solver.shortcut.binder.InsertMethodBinder
-import androidx.room.solver.shortcut.binder.UpsertMethodBinder
+import androidx.room.solver.shortcut.binder.InsertOrUpsertMethodBinder
import androidx.room.solver.shortcut.binderprovider.DeleteOrUpdateMethodBinderProvider
import androidx.room.solver.shortcut.binderprovider.GuavaListenableFutureDeleteOrUpdateMethodBinderProvider
import androidx.room.solver.shortcut.binderprovider.GuavaListenableFutureInsertMethodBinderProvider
import androidx.room.solver.shortcut.binderprovider.GuavaListenableFutureUpsertMethodBinderProvider
-import androidx.room.solver.shortcut.binderprovider.InsertMethodBinderProvider
-import androidx.room.solver.shortcut.binderprovider.UpsertMethodBinderProvider
+import androidx.room.solver.shortcut.binderprovider.InsertOrUpsertMethodBinderProvider
import androidx.room.solver.shortcut.binderprovider.InstantDeleteOrUpdateMethodBinderProvider
import androidx.room.solver.shortcut.binderprovider.InstantInsertMethodBinderProvider
import androidx.room.solver.shortcut.binderprovider.InstantUpsertMethodBinderProvider
@@ -225,8 +223,8 @@
add(InstantPreparedQueryResultBinderProvider(context))
}
- val insertBinderProviders: List<InsertMethodBinderProvider> =
- mutableListOf<InsertMethodBinderProvider>().apply {
+ val insertBinderProviders: List<InsertOrUpsertMethodBinderProvider> =
+ mutableListOf<InsertOrUpsertMethodBinderProvider>().apply {
addAll(RxCallableInsertMethodBinderProvider.getAll(context))
add(GuavaListenableFutureInsertMethodBinderProvider(context))
add(InstantInsertMethodBinderProvider(context))
@@ -239,8 +237,8 @@
add(InstantDeleteOrUpdateMethodBinderProvider(context))
}
- val upsertBinderProviders: List<UpsertMethodBinderProvider> =
- mutableListOf<UpsertMethodBinderProvider>().apply {
+ val upsertBinderProviders: List<InsertOrUpsertMethodBinderProvider> =
+ mutableListOf<InsertOrUpsertMethodBinderProvider>().apply {
addAll(RxCallableUpsertMethodBinderProvider.getAll(context))
add(GuavaListenableFutureUpsertMethodBinderProvider(context))
add(InstantUpsertMethodBinderProvider(context))
@@ -398,7 +396,7 @@
fun findInsertMethodBinder(
typeMirror: XType,
params: List<ShortcutQueryParameter>
- ): InsertMethodBinder {
+ ): InsertOrUpsertMethodBinder {
return insertBinderProviders.first {
it.matches(typeMirror)
}.provide(typeMirror, params)
@@ -407,7 +405,7 @@
fun findUpsertMethodBinder(
typeMirror: XType,
params: List<ShortcutQueryParameter>
- ): UpsertMethodBinder {
+ ): InsertOrUpsertMethodBinder {
return upsertBinderProviders.first {
it.matches(typeMirror)
}.provide(typeMirror, params)
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 c053354..e73004d 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
@@ -36,7 +36,7 @@
val typeArg: XType,
val addStmntBlock: CodeBlock.Builder.(callableImpl: TypeSpec, dbField: FieldSpec) -> Unit,
adapter: InsertMethodAdapter?
-) : InsertMethodBinder(adapter) {
+) : InsertOrUpsertMethodBinder(adapter) {
companion object {
fun createInsertBinder(
@@ -48,15 +48,15 @@
override fun convertAndReturn(
parameters: List<ShortcutQueryParameter>,
- insertionAdapters: Map<String, Pair<FieldSpec, TypeSpec>>,
+ adapters: Map<String, Pair<FieldSpec, Any>>,
dbField: FieldSpec,
scope: CodeGenScope
) {
val adapterScope = scope.fork()
val callableImpl = CallableTypeSpecBuilder(typeArg.typeName) {
- adapter?.createInsertionMethodBody(
+ adapter?.createMethodBody(
parameters = parameters,
- insertionAdapters = insertionAdapters,
+ adapters = adapters,
dbField = dbField,
scope = adapterScope
)
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 37aa163..7040cc4 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
@@ -36,7 +36,7 @@
val typeArg: XType,
val addStmntBlock: CodeBlock.Builder.(callableImpl: TypeSpec, dbField: FieldSpec) -> Unit,
adapter: UpsertMethodAdapter?
-) : UpsertMethodBinder(adapter) {
+) : InsertOrUpsertMethodBinder(adapter) {
companion object {
fun createUpsertBinder(
@@ -48,7 +48,7 @@
override fun convertAndReturn(
parameters: List<ShortcutQueryParameter>,
- upsertionAdapters: Map<String, Pair<FieldSpec, TypeSpec>>,
+ adapters: Map<String, Pair<FieldSpec, Any>>,
dbField: FieldSpec,
scope: CodeGenScope
) {
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/InsertMethodBinder.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/InsertMethodBinder.kt
deleted file mode 100644
index 2a6c3bc..0000000
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/InsertMethodBinder.kt
+++ /dev/null
@@ -1,62 +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.binder
-
-import androidx.room.solver.CodeGenScope
-import androidx.room.solver.shortcut.result.InsertMethodAdapter
-import androidx.room.vo.ShortcutQueryParameter
-import com.squareup.javapoet.FieldSpec
-import com.squareup.javapoet.TypeSpec
-
-/**
- * Connects the insert method, the database and the [InsertMethodAdapter].
- *
- * The default implementation is [InstantInsertMethodBinder] that executes the insert synchronously.
- * If the insert is deferred, rather than synchronously, alternatives implementations can be
- * implemented using this interface (e.g. RxJava, coroutines etc).
- */
-abstract class InsertMethodBinder(val adapter: InsertMethodAdapter?) {
-
- /**
- * Received the insert method parameters, the insertion adapters and generations the code that
- * runs the insert and returns the result.
- *
- * For example, for the DAO method:
- * ```
- * @Insert
- * fun addPublishers(vararg publishers: Publisher): List<Long>
- * ```
- * The following code will be generated:
- *
- * ```
- * __db.beginTransaction();
- * try {
- * List<Long> _result = __insertionAdapterOfPublisher.insertAndReturnIdsList(publishers);
- * __db.setTransactionSuccessful();
- * return _result;
- * } finally {
- * __db.endTransaction();
- * }
- * ```
- */
- abstract fun convertAndReturn(
- parameters: List<ShortcutQueryParameter>,
- insertionAdapters: Map<String, Pair<FieldSpec, TypeSpec>>,
- dbField: FieldSpec,
- scope: CodeGenScope
- )
-}
\ No newline at end of file
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/UpsertMethodBinder.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/InsertOrUpsertMethodBinder.kt
similarity index 73%
rename from room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/UpsertMethodBinder.kt
rename to room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/InsertOrUpsertMethodBinder.kt
index 9ec0168..f909b2a 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/UpsertMethodBinder.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/InsertOrUpsertMethodBinder.kt
@@ -16,19 +16,21 @@
package androidx.room.solver.shortcut.binder
+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
-import com.squareup.javapoet.TypeSpec
+
/**
- * Connects the upsert method, the database and the [UpsertMethodAdapter].
+ * Connects the insert and upsert method, the database and the [InsertMethodAdapter] or [UpsertMethodAdapter].
*/
-abstract class UpsertMethodBinder(val adapter: UpsertMethodAdapter?) {
+abstract class InsertOrUpsertMethodBinder(val adapter: InsertOrUpsertMethodAdapter?) {
/**
- * Received the upsert method parameters, the upsertion adapters and generations the code that
- * runs the upsert and returns the result.
+ * Received an insert or upsert method parameters, their adapters and generations the code that
+ * runs the insert or upsert and returns the result.
*
* For example, for the DAO method:
* ```
@@ -50,7 +52,7 @@
*/
abstract fun convertAndReturn(
parameters: List<ShortcutQueryParameter>,
- upsertionAdapters: Map<String, Pair<FieldSpec, TypeSpec>>,
+ adapters: Map<String, Pair<FieldSpec, Any>>,
dbField: FieldSpec,
scope: CodeGenScope
)
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 b808080..ac4c6cd 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
@@ -22,25 +22,25 @@
import androidx.room.vo.ShortcutQueryParameter
import androidx.room.writer.DaoWriter
import com.squareup.javapoet.FieldSpec
-import com.squareup.javapoet.TypeSpec
/**
* Binder that knows how to write instant (blocking) insert methods.
*/
-class InstantInsertMethodBinder(adapter: InsertMethodAdapter?) : InsertMethodBinder(adapter) {
+class InstantInsertMethodBinder(adapter: InsertMethodAdapter?) :
+ InsertOrUpsertMethodBinder(adapter) {
override fun convertAndReturn(
parameters: List<ShortcutQueryParameter>,
- insertionAdapters: Map<String, Pair<FieldSpec, TypeSpec>>,
+ adapters: Map<String, Pair<FieldSpec, Any>>,
dbField: FieldSpec,
scope: CodeGenScope
) {
scope.builder().apply {
addStatement("$N.assertNotSuspendingTransaction()", DaoWriter.dbField)
}
- adapter?.createInsertionMethodBody(
+ adapter?.createMethodBody(
parameters = parameters,
- insertionAdapters = insertionAdapters,
+ adapters = adapters,
dbField = dbField,
scope = scope
)
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 06860f7..2043db9 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
@@ -22,16 +22,16 @@
import androidx.room.vo.ShortcutQueryParameter
import androidx.room.writer.DaoWriter
import com.squareup.javapoet.FieldSpec
-import com.squareup.javapoet.TypeSpec
/**
* Binder that knows how to write instant (blocking) upsert methods.
*/
-class InstantUpsertMethodBinder(adapter: UpsertMethodAdapter?) : UpsertMethodBinder(adapter) {
+class InstantUpsertMethodBinder(adapter: UpsertMethodAdapter?) :
+ InsertOrUpsertMethodBinder(adapter) {
override fun convertAndReturn(
parameters: List<ShortcutQueryParameter>,
- upsertionAdapters: Map<String, Pair<FieldSpec, TypeSpec>>,
+ adapters: Map<String, Pair<FieldSpec, Any>>,
dbField: FieldSpec,
scope: CodeGenScope
) {
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/GuavaListenableFutureInsertMethodBinderProvider.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/GuavaListenableFutureInsertMethodBinderProvider.kt
index 1b3e17a..d7b7864 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/GuavaListenableFutureInsertMethodBinderProvider.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/GuavaListenableFutureInsertMethodBinderProvider.kt
@@ -25,7 +25,7 @@
import androidx.room.processor.Context
import androidx.room.processor.ProcessorErrors
import androidx.room.solver.shortcut.binder.CallableInsertMethodBinder.Companion.createInsertBinder
-import androidx.room.solver.shortcut.binder.InsertMethodBinder
+import androidx.room.solver.shortcut.binder.InsertOrUpsertMethodBinder
import androidx.room.vo.ShortcutQueryParameter
/**
@@ -33,7 +33,7 @@
*/
class GuavaListenableFutureInsertMethodBinderProvider(
private val context: Context
-) : InsertMethodBinderProvider {
+) : InsertOrUpsertMethodBinderProvider {
private val hasGuavaRoom by lazy {
context.processingEnv.findTypeElement(RoomGuavaTypeNames.GUAVA_ROOM) != null
@@ -46,7 +46,7 @@
override fun provide(
declared: XType,
params: List<ShortcutQueryParameter>
- ): InsertMethodBinder {
+ ): InsertOrUpsertMethodBinder {
if (!hasGuavaRoom) {
context.logger.e(ProcessorErrors.MISSING_ROOM_GUAVA_ARTIFACT)
}
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/GuavaListenableFutureUpsertMethodBinderProvider.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/GuavaListenableFutureUpsertMethodBinderProvider.kt
index 8f8cee0..ab55632 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/GuavaListenableFutureUpsertMethodBinderProvider.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/GuavaListenableFutureUpsertMethodBinderProvider.kt
@@ -25,7 +25,7 @@
import androidx.room.processor.Context
import androidx.room.processor.ProcessorErrors
import androidx.room.solver.shortcut.binder.CallableUpsertMethodBinder.Companion.createUpsertBinder
-import androidx.room.solver.shortcut.binder.UpsertMethodBinder
+import androidx.room.solver.shortcut.binder.InsertOrUpsertMethodBinder
import androidx.room.vo.ShortcutQueryParameter
/**
@@ -33,7 +33,7 @@
*/
class GuavaListenableFutureUpsertMethodBinderProvider(
private val context: Context
-) : UpsertMethodBinderProvider {
+) : InsertOrUpsertMethodBinderProvider {
private val hasGuavaRoom by lazy {
context.processingEnv.findTypeElement(RoomGuavaTypeNames.GUAVA_ROOM) != null
@@ -46,7 +46,7 @@
override fun provide(
declared: XType,
params: List<ShortcutQueryParameter>
- ): UpsertMethodBinder {
+ ): InsertOrUpsertMethodBinder {
if (!hasGuavaRoom) {
context.logger.e(ProcessorErrors.MISSING_ROOM_GUAVA_ARTIFACT)
}
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/InsertMethodBinderProvider.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/InsertOrUpsertMethodBinderProvider.kt
similarity index 70%
rename from room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/InsertMethodBinderProvider.kt
rename to room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/InsertOrUpsertMethodBinderProvider.kt
index 2ef53c7..e9ab381 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/InsertMethodBinderProvider.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/InsertOrUpsertMethodBinderProvider.kt
@@ -17,21 +17,21 @@
package androidx.room.solver.shortcut.binderprovider
import androidx.room.compiler.processing.XType
-import androidx.room.solver.shortcut.binder.InsertMethodBinder
+import androidx.room.solver.shortcut.binder.InsertOrUpsertMethodBinder
import androidx.room.vo.ShortcutQueryParameter
/**
- * Provider for insert method binders.
+ * Provider for insert and upsert method binders.
*/
-interface InsertMethodBinderProvider {
+interface InsertOrUpsertMethodBinderProvider {
/**
- * Check whether the [XType] can be handled by the [InsertMethodBinder]
+ * Check whether the [XType] can be handled by the [InsertOrUpsertMethodBinder]
*/
fun matches(declared: XType): Boolean
/**
- * Provider of [InsertMethodBinder], based on the [XType] and the list of parameters
+ * Provider of [InsertOrUpsertMethodBinder], based on the [XType] and the list of parameters
*/
- fun provide(declared: XType, params: List<ShortcutQueryParameter>): InsertMethodBinder
+ fun provide(declared: XType, params: List<ShortcutQueryParameter>): InsertOrUpsertMethodBinder
}
\ No newline at end of file
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/InstantInsertMethodBinderProvider.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/InstantInsertMethodBinderProvider.kt
index 90261c3..37e14d9 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/InstantInsertMethodBinderProvider.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/InstantInsertMethodBinderProvider.kt
@@ -18,21 +18,22 @@
import androidx.room.compiler.processing.XType
import androidx.room.processor.Context
-import androidx.room.solver.shortcut.binder.InsertMethodBinder
+import androidx.room.solver.shortcut.binder.InsertOrUpsertMethodBinder
import androidx.room.solver.shortcut.binder.InstantInsertMethodBinder
import androidx.room.vo.ShortcutQueryParameter
/**
* Provider for instant (blocking) insert method binder.
*/
-class InstantInsertMethodBinderProvider(private val context: Context) : InsertMethodBinderProvider {
+class InstantInsertMethodBinderProvider(private val context: Context) :
+ InsertOrUpsertMethodBinderProvider {
override fun matches(declared: XType) = true
override fun provide(
declared: XType,
params: List<ShortcutQueryParameter>
- ): InsertMethodBinder {
+ ): InsertOrUpsertMethodBinder {
return InstantInsertMethodBinder(
context.typeAdapterStore.findInsertAdapter(declared, params)
)
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/InstantUpsertMethodBinderProvider.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/InstantUpsertMethodBinderProvider.kt
index 4a3ef91..6f4e8c9 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/InstantUpsertMethodBinderProvider.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/InstantUpsertMethodBinderProvider.kt
@@ -18,21 +18,22 @@
import androidx.room.compiler.processing.XType
import androidx.room.processor.Context
-import androidx.room.solver.shortcut.binder.UpsertMethodBinder
+import androidx.room.solver.shortcut.binder.InsertOrUpsertMethodBinder
import androidx.room.solver.shortcut.binder.InstantUpsertMethodBinder
import androidx.room.vo.ShortcutQueryParameter
/**
* Provider for instant (blocking) upsert method binder.
*/
-class InstantUpsertMethodBinderProvider(private val context: Context) : UpsertMethodBinderProvider {
+class InstantUpsertMethodBinderProvider(private val context: Context) :
+ InsertOrUpsertMethodBinderProvider {
override fun matches(declared: XType) = true
override fun provide(
declared: XType,
params: List<ShortcutQueryParameter>
- ): UpsertMethodBinder {
+ ): InsertOrUpsertMethodBinder {
return InstantUpsertMethodBinder(
context.typeAdapterStore.findUpsertAdapter(declared, params)
)
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/RxCallableInsertMethodBinderProvider.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/RxCallableInsertMethodBinderProvider.kt
index 7f8dfa2..2ccc42a 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/RxCallableInsertMethodBinderProvider.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/RxCallableInsertMethodBinderProvider.kt
@@ -23,7 +23,7 @@
import androidx.room.processor.Context
import androidx.room.solver.RxType
import androidx.room.solver.shortcut.binder.CallableInsertMethodBinder.Companion.createInsertBinder
-import androidx.room.solver.shortcut.binder.InsertMethodBinder
+import androidx.room.solver.shortcut.binder.InsertOrUpsertMethodBinder
import androidx.room.vo.ShortcutQueryParameter
/**
@@ -32,7 +32,7 @@
open class RxCallableInsertMethodBinderProvider internal constructor(
val context: Context,
private val rxType: RxType
-) : InsertMethodBinderProvider {
+) : InsertOrUpsertMethodBinderProvider {
/**
* [Single] and [Maybe] are generics but [Completable] is not so each implementation of this
@@ -50,7 +50,7 @@
override fun provide(
declared: XType,
params: List<ShortcutQueryParameter>
- ): InsertMethodBinder {
+ ): InsertOrUpsertMethodBinder {
val typeArg = extractTypeArg(declared)
val adapter = context.typeAdapterStore.findInsertAdapter(typeArg, params)
return createInsertBinder(typeArg, adapter) { callableImpl, _ ->
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/RxCallableUpsertMethodBinderProvider.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/RxCallableUpsertMethodBinderProvider.kt
index df1911e..21ce3fb 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/RxCallableUpsertMethodBinderProvider.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/RxCallableUpsertMethodBinderProvider.kt
@@ -23,7 +23,7 @@
import androidx.room.processor.Context
import androidx.room.solver.RxType
import androidx.room.solver.shortcut.binder.CallableUpsertMethodBinder
-import androidx.room.solver.shortcut.binder.UpsertMethodBinder
+import androidx.room.solver.shortcut.binder.InsertOrUpsertMethodBinder
import androidx.room.vo.ShortcutQueryParameter
/**
@@ -32,7 +32,7 @@
open class RxCallableUpsertMethodBinderProvider internal constructor(
val context: Context,
private val rxType: RxType
-) : UpsertMethodBinderProvider {
+) : InsertOrUpsertMethodBinderProvider {
/**
* [Single] and [Maybe] are generics but [Completable] is not so each implementation of this
@@ -50,7 +50,7 @@
override fun provide(
declared: XType,
params: List<ShortcutQueryParameter>
- ): UpsertMethodBinder {
+ ): InsertOrUpsertMethodBinder {
val typeArg = extractTypeArg(declared)
val adapter = context.typeAdapterStore.findUpsertAdapter(typeArg, params)
return CallableUpsertMethodBinder.createUpsertBinder(typeArg, adapter) { callableImpl, _ ->
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/UpsertMethodBinderProvider.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/UpsertMethodBinderProvider.kt
deleted file mode 100644
index 0858f92..0000000
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binderprovider/UpsertMethodBinderProvider.kt
+++ /dev/null
@@ -1,37 +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.binderprovider
-
-import androidx.room.compiler.processing.XType
-import androidx.room.solver.shortcut.binder.UpsertMethodBinder
-import androidx.room.vo.ShortcutQueryParameter
-
-/**
- * Provider for upsert method binders.
- */
-interface UpsertMethodBinderProvider {
-
- /**
- * Check whether the [XType] can be handled by the [UpsertMethodBinder]
- */
- fun matches(declared: XType): Boolean
-
- /**
- * Provider of [UpsertMethodBinder], based on the [XType] and the list of parameters
- */
- fun provide(declared: XType, params: List<ShortcutQueryParameter>): UpsertMethodBinder
-}
\ 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
index ad230db..c910e02 100644
--- 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
@@ -33,12 +33,12 @@
import com.squareup.javapoet.FieldSpec
import com.squareup.javapoet.ParameterizedTypeName
import com.squareup.javapoet.TypeName
-import com.squareup.javapoet.TypeSpec
/**
* Class that knows how to generate an insert method body.
*/
-class InsertMethodAdapter private constructor(private val insertionType: InsertionType) {
+class InsertMethodAdapter private constructor(private val insertionType: InsertionType) :
+ InsertOrUpsertMethodAdapter() {
companion object {
fun create(
returnType: XType,
@@ -117,9 +117,9 @@
}
}
- fun createInsertionMethodBody(
+ override fun createMethodBody(
parameters: List<ShortcutQueryParameter>,
- insertionAdapters: Map<String, Pair<FieldSpec, TypeSpec>>,
+ adapters: Map<String, Pair<FieldSpec, Any>>,
dbField: FieldSpec,
scope: CodeGenScope
) {
@@ -138,7 +138,7 @@
beginControlFlow("try").apply {
parameters.forEach { param ->
- val insertionAdapter = insertionAdapters[param.name]?.first
+ 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
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
new file mode 100644
index 0000000..2eeba8b
--- /dev/null
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/result/InsertOrUpsertMethodAdapter.kt
@@ -0,0 +1,33 @@
+/*
+ * 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
+
+/**
+ * Abstract class for insert and update method adapters.
+ */
+abstract class InsertOrUpsertMethodAdapter {
+ abstract 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/solver/shortcut/result/UpsertMethodAdapter.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/result/UpsertMethodAdapter.kt
index a27512f..e45ccea 100644
--- 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
@@ -16,4 +16,16 @@
package androidx.room.solver.shortcut.result
-class UpsertMethodAdapter
\ No newline at end of file
+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/Dao.kt b/room/room-compiler/src/main/kotlin/androidx/room/vo/Dao.kt
index aab6986..f328947 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/vo/Dao.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/vo/Dao.kt
@@ -48,7 +48,7 @@
val typeName: ClassName by lazy { element.className }
- val shortcutMethods: List<ShortcutMethod> by lazy {
+ val deleteOrUpdateShortcutMethods: List<DeleteOrUpdateShortcutMethod> by lazy {
deletionMethods + updateMethods
}
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/vo/ShortcutMethod.kt b/room/room-compiler/src/main/kotlin/androidx/room/vo/DeleteOrUpdateShortcutMethod.kt
similarity index 95%
rename from room/room-compiler/src/main/kotlin/androidx/room/vo/ShortcutMethod.kt
rename to room/room-compiler/src/main/kotlin/androidx/room/vo/DeleteOrUpdateShortcutMethod.kt
index dc4c618..0d04901 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/vo/ShortcutMethod.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/vo/DeleteOrUpdateShortcutMethod.kt
@@ -22,7 +22,7 @@
/**
* Base class for shortcut methods in @DAO.
*/
-abstract class ShortcutMethod(
+abstract class DeleteOrUpdateShortcutMethod(
val element: XMethodElement,
val entities: Map<String, ShortcutEntity>,
val parameters: List<ShortcutQueryParameter>,
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/vo/DeletionMethod.kt b/room/room-compiler/src/main/kotlin/androidx/room/vo/DeletionMethod.kt
index 0d4dbe9..1973273 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/vo/DeletionMethod.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/vo/DeletionMethod.kt
@@ -23,4 +23,4 @@
entities: Map<String, ShortcutEntity>,
parameters: List<ShortcutQueryParameter>,
methodBinder: DeleteOrUpdateMethodBinder?
-) : ShortcutMethod(element, entities, parameters, methodBinder)
+) : DeleteOrUpdateShortcutMethod(element, entities, parameters, methodBinder)
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/vo/ShortcutMethod.kt b/room/room-compiler/src/main/kotlin/androidx/room/vo/InsertOrUpsertShortcutMethod.kt
similarity index 74%
copy from room/room-compiler/src/main/kotlin/androidx/room/vo/ShortcutMethod.kt
copy to room/room-compiler/src/main/kotlin/androidx/room/vo/InsertOrUpsertShortcutMethod.kt
index dc4c618..b4ae888 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/vo/ShortcutMethod.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/vo/InsertOrUpsertShortcutMethod.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright 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.
@@ -15,16 +15,17 @@
*/
package androidx.room.vo
-
import androidx.room.compiler.processing.XMethodElement
-import androidx.room.solver.shortcut.binder.DeleteOrUpdateMethodBinder
+import androidx.room.compiler.processing.XType
+import androidx.room.solver.shortcut.binder.InsertOrUpsertMethodBinder
/**
* Base class for shortcut methods in @DAO.
*/
-abstract class ShortcutMethod(
+abstract class InsertOrUpsertShortcutMethod(
val element: XMethodElement,
val entities: Map<String, ShortcutEntity>,
+ val returnType: XType,
val parameters: List<ShortcutQueryParameter>,
- val methodBinder: DeleteOrUpdateMethodBinder?
-)
+ val methodBinder: InsertOrUpsertMethodBinder?
+)
\ No newline at end of file
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/vo/InsertionMethod.kt b/room/room-compiler/src/main/kotlin/androidx/room/vo/InsertionMethod.kt
index 2260329..9e5cbca3 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/vo/InsertionMethod.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/vo/InsertionMethod.kt
@@ -19,13 +19,13 @@
import androidx.room.OnConflictStrategy
import androidx.room.compiler.processing.XMethodElement
import androidx.room.compiler.processing.XType
-import androidx.room.solver.shortcut.binder.InsertMethodBinder
+import androidx.room.solver.shortcut.binder.InsertOrUpsertMethodBinder
-data class InsertionMethod(
- val element: XMethodElement,
+class InsertionMethod(
+ element: XMethodElement,
@OnConflictStrategy val onConflict: Int,
- val entities: Map<String, ShortcutEntity>,
- val returnType: XType,
- val parameters: List<ShortcutQueryParameter>,
- val methodBinder: InsertMethodBinder
-)
\ No newline at end of file
+ entities: Map<String, ShortcutEntity>,
+ returnType: XType,
+ parameters: List<ShortcutQueryParameter>,
+ methodBinder: InsertOrUpsertMethodBinder
+) : InsertOrUpsertShortcutMethod(element, entities, returnType, parameters, methodBinder)
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 daac19d..1df9af3 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.
+ * 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/UpdateMethod.kt b/room/room-compiler/src/main/kotlin/androidx/room/vo/UpdateMethod.kt
index 28be8f7..bbcc6fa 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/vo/UpdateMethod.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/vo/UpdateMethod.kt
@@ -26,4 +26,4 @@
parameters: List<ShortcutQueryParameter>,
methodBinder: DeleteOrUpdateMethodBinder?,
@OnConflictStrategy val onConflictStrategy: Int
-) : ShortcutMethod(element, entities, parameters, methodBinder)
+) : DeleteOrUpdateShortcutMethod(element, entities, parameters, methodBinder)
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 fd9d44f..76cc0fd 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
@@ -18,12 +18,12 @@
import androidx.room.compiler.processing.XMethodElement
import androidx.room.compiler.processing.XType
-import androidx.room.solver.shortcut.binder.UpsertMethodBinder
+import androidx.room.solver.shortcut.binder.InsertOrUpsertMethodBinder
-data class UpsertionMethod(
- val element: XMethodElement,
- val entities: Map<String, ShortcutEntity>,
- val returnType: XType,
- val parameters: List<ShortcutQueryParameter>,
- val methodBinder: UpsertMethodBinder
- )
\ No newline at end of file
+class UpsertionMethod(
+ element: XMethodElement,
+ entities: Map<String, ShortcutEntity>,
+ returnType: XType,
+ parameters: List<ShortcutQueryParameter>,
+ methodBinder: InsertOrUpsertMethodBinder
+ ) : InsertOrUpsertShortcutMethod(element, entities, returnType, parameters, methodBinder)
\ No newline at end of file
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt b/room/room-compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt
index 14073bf..7a736ef 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt
@@ -45,7 +45,7 @@
import androidx.room.vo.RawQueryMethod
import androidx.room.vo.ReadQueryMethod
import androidx.room.vo.ShortcutEntity
-import androidx.room.vo.ShortcutMethod
+import androidx.room.vo.DeleteOrUpdateShortcutMethod
import androidx.room.vo.TransactionMethod
import androidx.room.vo.UpdateMethod
import androidx.room.vo.WriteQueryMethod
@@ -389,9 +389,10 @@
val scope = CodeGenScope(this)
- method.methodBinder.convertAndReturn(
+ // TODO: (b/240491383) remove methodBinder nullability
+ method.methodBinder?.convertAndReturn(
parameters = method.parameters,
- insertionAdapters = insertionAdapters,
+ adapters = insertionAdapters,
dbField = dbField,
scope = scope
)
@@ -419,7 +420,7 @@
}
}
- private fun <T : ShortcutMethod> createShortcutMethods(
+ private fun <T : DeleteOrUpdateShortcutMethod> createShortcutMethods(
methods: List<T>,
methodPrefix: String,
implCallback: (T, ShortcutEntity) -> TypeSpec
@@ -450,7 +451,7 @@
}
private fun createDeleteOrUpdateMethodBody(
- method: ShortcutMethod,
+ method: DeleteOrUpdateShortcutMethod,
adapters: Map<String, Pair<FieldSpec, TypeSpec>>
): CodeBlock {
if (adapters.isEmpty() || method.methodBinder == null) {
@@ -495,9 +496,9 @@
val scope = CodeGenScope(this)
- method.methodBinder.convertAndReturn(
+ method.methodBinder?.convertAndReturn(
parameters = method.parameters,
- upsertionAdapters = upsertionAdapters,
+ adapters = upsertionAdapters,
dbField = dbField,
scope = scope
)
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/ShortcutMethodProcessorTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/DeleteOrUpdateShortcutMethodProcessorTest.kt
similarity index 99%
rename from room/room-compiler/src/test/kotlin/androidx/room/processor/ShortcutMethodProcessorTest.kt
rename to room/room-compiler/src/test/kotlin/androidx/room/processor/DeleteOrUpdateShortcutMethodProcessorTest.kt
index bbf5cbe..db69a38 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/ShortcutMethodProcessorTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/DeleteOrUpdateShortcutMethodProcessorTest.kt
@@ -32,7 +32,7 @@
import androidx.room.ext.RxJava2TypeNames
import androidx.room.ext.RxJava3TypeNames
import androidx.room.testing.context
-import androidx.room.vo.ShortcutMethod
+import androidx.room.vo.DeleteOrUpdateShortcutMethod
import com.squareup.javapoet.ArrayTypeName
import com.squareup.javapoet.ClassName
import com.squareup.javapoet.ParameterizedTypeName
@@ -45,7 +45,7 @@
/**
* Base test class for shortcut methods.
*/
-abstract class ShortcutMethodProcessorTest<out T : ShortcutMethod>(
+abstract class DeleteOrUpdateShortcutMethodProcessorTest<out T : DeleteOrUpdateShortcutMethod>(
val annotation: KClass<out Annotation>
) {
companion object {
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/DeletionMethodProcessorTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/DeletionMethodProcessorTest.kt
index d1c4ae8..f7184dd 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/DeletionMethodProcessorTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/DeletionMethodProcessorTest.kt
@@ -26,7 +26,8 @@
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
@RunWith(JUnit4::class)
-class DeletionMethodProcessorTest : ShortcutMethodProcessorTest<DeletionMethod>(Delete::class) {
+class DeletionMethodProcessorTest :
+ DeleteOrUpdateShortcutMethodProcessorTest<DeletionMethod>(Delete::class) {
override fun invalidReturnTypeError(): String = CANNOT_FIND_DELETE_RESULT_ADAPTER
override fun noParamsError(): String = DELETION_MISSING_PARAMS
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
new file mode 100644
index 0000000..93b83a8
--- /dev/null
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/InsertOrUpsertShortcutMethodProcessorTest.kt
@@ -0,0 +1,802 @@
+/*
+ * 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.
+ * 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 COMMON
+import androidx.room.Dao
+import androidx.room.compiler.processing.XMethodElement
+import androidx.room.compiler.processing.XType
+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.testing.context
+import androidx.room.vo.InsertOrUpsertShortcutMethod
+import com.squareup.javapoet.ClassName
+import com.squareup.javapoet.TypeName
+import kotlin.reflect.KClass
+import com.google.common.truth.Truth.assertThat
+import com.squareup.javapoet.ArrayTypeName
+import com.squareup.javapoet.ParameterizedTypeName
+import org.junit.Test
+
+/**
+ * Base test class for insert and upsert methods.
+ */
+abstract class InsertOrUpsertShortcutMethodProcessorTest <out T : InsertOrUpsertShortcutMethod>(
+ val annotation: KClass<out Annotation>
+) {
+ 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")
+ }
+
+ @Test
+ fun readNoParams() {
+ singleInsertUpsertShortcutMethod(
+ """
+ @${annotation.java.canonicalName}
+ abstract public void foo();
+ """
+ ) { insertionUpsertion, invocation ->
+
+ assertThat(insertionUpsertion.element.jvmName).isEqualTo("foo")
+ assertThat(insertionUpsertion.parameters.size).isEqualTo(0)
+ assertThat(insertionUpsertion.returnType.typeName).isEqualTo(TypeName.VOID)
+ assertThat(insertionUpsertion.entities.size).isEqualTo(0)
+ invocation.assertCompilationResult {
+ hasErrorContaining(noParamsError())
+ }
+ }
+ }
+
+ @Test
+ fun notAnEntity() {
+ singleInsertUpsertShortcutMethod(
+ """
+ @${annotation.java.canonicalName}
+ abstract public void foo(NotAnEntity notValid);
+ """
+ ) { insertionUpsertion, invocation ->
+ assertThat(insertionUpsertion.element.jvmName).isEqualTo("foo")
+ assertThat(insertionUpsertion.parameters.size).isEqualTo(1)
+ assertThat(insertionUpsertion.entities.size).isEqualTo(0)
+ invocation.assertCompilationResult {
+ hasErrorContaining(
+ ProcessorErrors.CANNOT_FIND_ENTITY_FOR_SHORTCUT_QUERY_PARAMETER
+ )
+ }
+ }
+ }
+
+ abstract fun noParamsError(): String
+
+ @Test
+ fun single() {
+ singleInsertUpsertShortcutMethod(
+ """
+ @${annotation.java.canonicalName}
+ abstract public long foo(User user);
+ """
+ ) { insertionUpsertion, _ ->
+
+ assertThat(insertionUpsertion.element.jvmName).isEqualTo("foo")
+ assertThat(insertionUpsertion.parameters.size).isEqualTo(1)
+
+ val param = insertionUpsertion.parameters.first()
+ assertThat(param.type.typeName)
+ .isEqualTo(USER_TYPE_NAME)
+
+ assertThat(param.pojoType?.typeName)
+ .isEqualTo(USER_TYPE_NAME)
+
+ assertThat(insertionUpsertion.entities["user"]?.isPartialEntity)
+ .isEqualTo(false)
+
+ assertThat(insertionUpsertion.entities["user"]?.pojo?.typeName)
+ .isEqualTo(ClassName.get("foo.bar", "User") as TypeName)
+
+ assertThat(insertionUpsertion.returnType.typeName)
+ .isEqualTo(TypeName.LONG)
+ }
+ }
+ @Test
+ fun two() {
+ singleInsertUpsertShortcutMethod(
+ """
+ @${annotation.java.canonicalName}
+ abstract public void foo(User u1, User u2);
+ """
+ ) { insertionUpsertion, _ ->
+ assertThat(insertionUpsertion.element.jvmName).isEqualTo("foo")
+
+ assertThat(insertionUpsertion.parameters.size).isEqualTo(2)
+ insertionUpsertion.parameters.forEach {
+ assertThat(it.type.typeName).isEqualTo(USER_TYPE_NAME)
+ assertThat(it.pojoType?.typeName).isEqualTo(USER_TYPE_NAME)
+ }
+ assertThat(insertionUpsertion.entities.size)
+ .isEqualTo(2)
+
+ assertThat(insertionUpsertion.entities["u1"]?.pojo?.typeName)
+ .isEqualTo(USER_TYPE_NAME)
+
+ assertThat(insertionUpsertion.entities["u2"]?.pojo?.typeName)
+ .isEqualTo(USER_TYPE_NAME)
+
+ assertThat(insertionUpsertion.parameters.map { it.name })
+ .isEqualTo(listOf("u1", "u2"))
+
+ assertThat(insertionUpsertion.returnType.typeName)
+ .isEqualTo(TypeName.VOID)
+ }
+ }
+
+ @Test
+ fun list() {
+ singleInsertUpsertShortcutMethod(
+ """
+ @${annotation.java.canonicalName}
+ abstract public List<Long> insertUsers(List<User> users);
+ """
+ ) { insertionUpsertion, _ ->
+ assertThat(insertionUpsertion.element.jvmName).isEqualTo("insertUsers")
+ assertThat(insertionUpsertion.parameters.size).isEqualTo(1)
+ val param = insertionUpsertion.parameters.first()
+ assertThat(param.type.typeName)
+ .isEqualTo(
+ ParameterizedTypeName.get(
+ ClassName.get("java.util", "List"),
+ USER_TYPE_NAME
+ ) as TypeName
+ )
+
+ assertThat(param.pojoType?.typeName)
+ .isEqualTo(USER_TYPE_NAME)
+
+ assertThat(insertionUpsertion.entities.size).isEqualTo(1)
+
+ assertThat(insertionUpsertion.entities["users"]?.pojo?.typeName)
+ .isEqualTo(USER_TYPE_NAME)
+
+ assertThat(insertionUpsertion.returnType.typeName)
+ .isEqualTo(
+ ParameterizedTypeName.get(
+ ClassName.get("java.util", "List"),
+ ClassName.get("java.lang", "Long")
+ ) as TypeName
+ )
+ }
+ }
+
+ @Test
+ fun array() {
+ singleInsertUpsertShortcutMethod(
+ """
+ @${annotation.java.canonicalName}
+ abstract public void insertUsers(User[] users);
+ """
+ ) { insertionUpsertion, _ ->
+ assertThat(insertionUpsertion.element.jvmName).isEqualTo("insertUsers")
+ assertThat(insertionUpsertion.parameters.size).isEqualTo(1)
+ val param = insertionUpsertion.parameters.first()
+ assertThat(param.type.typeName)
+ .isEqualTo(ArrayTypeName.of(COMMON.USER_TYPE_NAME) as TypeName)
+
+ assertThat(insertionUpsertion.entities.size).isEqualTo(1)
+
+ assertThat(insertionUpsertion.entities["users"]?.pojo?.typeName)
+ .isEqualTo(USER_TYPE_NAME)
+
+ assertThat(insertionUpsertion.returnType.typeName)
+ .isEqualTo(TypeName.VOID)
+ }
+ }
+
+ @Test
+ fun set() {
+ singleInsertUpsertShortcutMethod(
+ """
+ @${annotation.java.canonicalName}
+ abstract public void insertUsers(Set<User> users);
+ """
+ ) { insertionUpsertion, _ ->
+ assertThat(insertionUpsertion.element.jvmName).isEqualTo("insertUsers")
+ assertThat(insertionUpsertion.parameters.size).isEqualTo(1)
+ val param = insertionUpsertion.parameters.first()
+ assertThat(param.type.typeName)
+ .isEqualTo(
+ ParameterizedTypeName.get(
+ ClassName.get("java.util", "Set"),
+ COMMON.USER_TYPE_NAME
+ ) as TypeName
+ )
+
+ assertThat(insertionUpsertion.entities.size).isEqualTo(1)
+
+ assertThat(insertionUpsertion.entities["users"]?.pojo?.typeName)
+ .isEqualTo(USER_TYPE_NAME)
+
+ assertThat(insertionUpsertion.returnType.typeName).isEqualTo(TypeName.VOID)
+ }
+ }
+
+ @Test
+ fun queue() {
+ singleInsertUpsertShortcutMethod(
+ """
+ @${annotation.java.canonicalName}
+ abstract public void insertUsers(Queue<User> users);
+ """
+ ) { insertionUpsertion, _ ->
+ assertThat(insertionUpsertion.element.jvmName).isEqualTo("insertUsers")
+ assertThat(insertionUpsertion.parameters.size).isEqualTo(1)
+ val param = insertionUpsertion.parameters.first()
+ assertThat(param.type.typeName)
+ .isEqualTo(
+ ParameterizedTypeName.get(
+ ClassName.get("java.util", "Queue"),
+ USER_TYPE_NAME
+ ) as TypeName
+ )
+
+ assertThat(insertionUpsertion.entities.size).isEqualTo(1)
+
+ assertThat(insertionUpsertion.entities["users"]?.pojo?.typeName)
+ .isEqualTo(USER_TYPE_NAME)
+
+ assertThat(insertionUpsertion.returnType.typeName).isEqualTo(TypeName.VOID)
+ }
+ }
+
+ @Test
+ fun iterable() {
+ singleInsertUpsertShortcutMethod(
+ """
+ @${annotation.java.canonicalName}
+ abstract public void insert(Iterable<User> users);
+ """
+ ) { insertionUpsertion, _ ->
+ assertThat(insertionUpsertion.element.jvmName).isEqualTo("insert")
+ assertThat(insertionUpsertion.parameters.size).isEqualTo(1)
+ val param = insertionUpsertion.parameters.first()
+ assertThat(param.type.typeName)
+ .isEqualTo(
+ ParameterizedTypeName.get(
+ ClassName.get("java.lang", "Iterable"),
+ USER_TYPE_NAME
+ ) as TypeName
+ )
+
+ assertThat(insertionUpsertion.entities.size).isEqualTo(1)
+
+ assertThat(insertionUpsertion.entities["users"]?.pojo?.typeName)
+ .isEqualTo(USER_TYPE_NAME)
+
+ assertThat(insertionUpsertion.returnType.typeName).isEqualTo(TypeName.VOID)
+ }
+ }
+
+ @Test
+ fun customCollection() {
+ singleInsertUpsertShortcutMethod(
+ """
+ static class MyList<Irrelevant, Item> extends ArrayList<Item> {}
+ @${annotation.java.canonicalName}
+ abstract public void insert(MyList<String, User> users);
+ """
+ ) { insertionUpsertion, _ ->
+ assertThat(insertionUpsertion.element.jvmName).isEqualTo("insert")
+ assertThat(insertionUpsertion.parameters.size).isEqualTo(1)
+ val param = insertionUpsertion.parameters.first()
+ assertThat(param.type.typeName)
+ .isEqualTo(
+ ParameterizedTypeName.get(
+ ClassName.get("foo.bar", "MyClass.MyList"),
+ CommonTypeNames.STRING, USER_TYPE_NAME
+ ) as TypeName
+ )
+
+ assertThat(insertionUpsertion.entities.size).isEqualTo(1)
+
+ assertThat(insertionUpsertion.entities["users"]?.pojo?.typeName)
+ .isEqualTo(USER_TYPE_NAME)
+
+ assertThat(insertionUpsertion.returnType.typeName).isEqualTo(TypeName.VOID)
+ }
+ }
+
+ @Test
+ fun differentTypes() {
+ singleInsertUpsertShortcutMethod(
+ """
+ @${annotation.java.canonicalName}
+ abstract public void foo(User u1, Book b1);
+ """
+ ) { insertionUpsertion, _ ->
+ assertThat(insertionUpsertion.parameters.size).isEqualTo(2)
+ assertThat(insertionUpsertion.parameters[0].type.typeName.toString())
+ .isEqualTo("foo.bar.User")
+
+ assertThat(insertionUpsertion.parameters[1].type.typeName.toString())
+ .isEqualTo("foo.bar.Book")
+
+ assertThat(insertionUpsertion.parameters.map { it.name }).isEqualTo(listOf("u1", "b1"))
+
+ assertThat(insertionUpsertion.returnType.typeName).isEqualTo(TypeName.VOID)
+
+ assertThat(insertionUpsertion.entities.size).isEqualTo(2)
+
+ assertThat(insertionUpsertion.entities["u1"]?.pojo?.typeName)
+ .isEqualTo(USER_TYPE_NAME)
+
+ assertThat(insertionUpsertion.entities["b1"]?.pojo?.typeName)
+ .isEqualTo(BOOK_TYPE_NAME)
+ }
+ }
+
+ // TODO: Add in the return type tests when upsertionMethodAdapter is implemented
+ @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;
+ }
+ """
+ )
+ singleInsertUpsertShortcutMethod(
+ """
+ @${annotation.java.canonicalName}(entity = User.class)
+ abstract public long foo(Username username);
+ """,
+ additionalSources = listOf(usernameSource)
+ ) { insertionUpsertion, _ ->
+ assertThat(insertionUpsertion.element.jvmName).isEqualTo("foo")
+ assertThat(insertionUpsertion.parameters.size).isEqualTo(1)
+
+ val param = insertionUpsertion.parameters.first()
+
+ assertThat(param.type.typeName).isEqualTo(USERNAME_TYPE_NAME)
+
+ assertThat(param.pojoType?.typeName).isEqualTo(USERNAME_TYPE_NAME)
+
+ assertThat(insertionUpsertion.entities.size).isEqualTo(1)
+
+ assertThat(insertionUpsertion.entities["username"]?.isPartialEntity)
+ .isEqualTo(true)
+
+ assertThat(insertionUpsertion.entities["username"]?.entityTypeName)
+ .isEqualTo(USER_TYPE_NAME)
+
+ assertThat(insertionUpsertion.entities["username"]?.pojo?.typeName)
+ .isEqualTo(USERNAME_TYPE_NAME)
+ }
+ }
+
+ @Test
+ fun targetEntitySameAsPojo() {
+ singleInsertUpsertShortcutMethod(
+ """
+ @${annotation.java.canonicalName}(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;
+ }
+ """
+ )
+ singleInsertUpsertShortcutMethod(
+ """
+ @${annotation.java.canonicalName}(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;
+ }
+ """
+ )
+ singleInsertUpsertShortcutMethod(
+ """
+ @${annotation.java.canonicalName}(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;
+ }
+ """
+ )
+ singleInsertUpsertShortcutMethod(
+ """
+ @${annotation.java.canonicalName}(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;
+ }
+ """
+ )
+ singleInsertUpsertShortcutMethod(
+ """
+ @${annotation.java.canonicalName}(entity = Pet.class)
+ abstract public long foo(PetName petName);
+ """,
+ additionalSources = listOf(petNameSource, petSource)
+ ) { _, invocation ->
+ invocation.assertCompilationResult {
+ hasErrorContaining(missingPrimaryKey(
+ "foo.bar.PetName",
+ listOf("petId"))
+ )
+ }
+ }
+ }
+
+ abstract fun missingPrimaryKey(partialEntityName: String, primaryKeyName: List<String>):
+ String
+
+ @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;
+ }
+ """
+ )
+ singleInsertUpsertShortcutMethod(
+ """
+ @${annotation.java.canonicalName}(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;
+ }
+ """
+ )
+ singleInsertUpsertShortcutMethod(
+ """
+ @${annotation.java.canonicalName}(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;
+ }
+ """
+ )
+ singleInsertUpsertShortcutMethod(
+ """
+ @${annotation.java.canonicalName}(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;
+ }
+ """
+ )
+ singleInsertUpsertShortcutMethod(
+ """
+ @${annotation.java.canonicalName}(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;
+ }
+ """
+ )
+ singleInsertUpsertShortcutMethod(
+ """
+ @${annotation.java.canonicalName}(entity = User.class)
+ abstract public long foo(UserPets userPets);
+ """,
+ additionalSources = listOf(userPetsSource, petSource)
+ ) { _, invocation ->
+ invocation.assertCompilationResult {
+ hasErrorContaining(
+ ProcessorErrors.INVALID_RELATION_IN_PARTIAL_ENTITY
+ )
+ }
+ }
+ }
+
+ abstract fun process(
+ baseContext: Context,
+ containing: XType,
+ executableElement: XMethodElement
+ ): T
+
+ fun singleInsertUpsertShortcutMethod(
+ vararg input: String,
+ additionalSources: List<Source> = emptyList(),
+ handler: (T, 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(annotation)
+ }.toList()
+ )
+ }.first { it.second.isNotEmpty() }
+ val processed = process(
+ baseContext = invocation.context,
+ containing = owner.type,
+ executableElement = methods.first()
+ )
+ handler(processed, invocation)
+ }
+ }
+}
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 ffa2e8fa..7891b39 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
@@ -415,7 +415,8 @@
abstract public $type foo(User user);
"""
) { insertion, invocation ->
- assertThat(insertion.methodBinder.adapter, `is`(nullValue()))
+ // TODO: (b/240491383) remove methodBinder nullability
+ assertThat(insertion.methodBinder?.adapter, `is`(nullValue()))
invocation.assertCompilationResult {
hasErrorContaining(
ProcessorErrors.CANNOT_FIND_INSERT_RESULT_ADAPTER
@@ -440,7 +441,8 @@
abstract public $type foo(User user);
"""
) { insertion, invocation ->
- assertThat(insertion.methodBinder.adapter, `is`(nullValue()))
+ // TODO: (b/240491383) remove methodBinder nullability
+ assertThat(insertion.methodBinder?.adapter, `is`(nullValue()))
invocation.assertCompilationResult {
hasErrorContaining(
ProcessorErrors.CANNOT_FIND_INSERT_RESULT_ADAPTER
@@ -464,7 +466,8 @@
abstract public $type foo(User... user);
"""
) { insertion, invocation ->
- assertThat(insertion.methodBinder.adapter, `is`(nullValue()))
+ // TODO: (b/240491383) remove methodBinder nullability
+ assertThat(insertion.methodBinder?.adapter, `is`(nullValue()))
invocation.assertCompilationResult {
hasErrorContaining(
ProcessorErrors.CANNOT_FIND_INSERT_RESULT_ADAPTER
@@ -488,7 +491,8 @@
abstract public $type foo(User user1, User user2);
"""
) { insertion, invocation ->
- assertThat(insertion.methodBinder.adapter, `is`(nullValue()))
+ // TODO: (b/240491383) remove methodBinder nullability
+ assertThat(insertion.methodBinder?.adapter, `is`(nullValue()))
invocation.assertCompilationResult {
hasErrorContaining(
ProcessorErrors.CANNOT_FIND_INSERT_RESULT_ADAPTER
@@ -563,7 +567,7 @@
abstract public ${pair.first} foo(User$dots user);
"""
) { insertion, _ ->
- assertThat(insertion.methodBinder.adapter, `is`(notNullValue()))
+ assertThat(insertion.methodBinder?.adapter, `is`(notNullValue()))
}
}
}
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
new file mode 100644
index 0000000..2f1b27f
--- /dev/null
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/NewInsertionMethodProcessorTest.kt
@@ -0,0 +1,102 @@
+/*
+ * 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/UpdateMethodProcessorTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/UpdateMethodProcessorTest.kt
index e2a264a..9a2d2c1 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/UpdateMethodProcessorTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/UpdateMethodProcessorTest.kt
@@ -31,7 +31,8 @@
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
@RunWith(JUnit4::class)
-class UpdateMethodProcessorTest : ShortcutMethodProcessorTest<UpdateMethod>(Update::class) {
+class UpdateMethodProcessorTest :
+ DeleteOrUpdateShortcutMethodProcessorTest<UpdateMethod>(Update::class) {
override fun invalidReturnTypeError(): String = CANNOT_FIND_UPDATE_RESULT_ADAPTER
override fun noParamsError(): String = UPDATE_MISSING_PARAMS
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
new file mode 100644
index 0000000..4370d53
--- /dev/null
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/UpsertionMethodProcessorTest.kt
@@ -0,0 +1,48 @@
+/*
+ * 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.Upsert
+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.vo.UpsertionMethod
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
+@RunWith(JUnit4::class)
+class UpsertionMethodProcessorTest :
+ InsertOrUpsertShortcutMethodProcessorTest<UpsertionMethod>(Upsert::class) {
+ override fun noParamsError(): String = UPSERTION_DOES_NOT_HAVE_ANY_PARAMETERS_TO_UPSERT
+
+ override fun missingPrimaryKey(partialEntityName: String, primaryKeyName: List<String>):
+ String {
+ return ProcessorErrors.missingPrimaryKeysInPartialEntityForUpsert(
+ partialEntityName,
+ primaryKeyName
+ )
+ }
+
+ override fun process(
+ baseContext: Context,
+ containing: XType,
+ executableElement: XMethodElement
+ ): UpsertionMethod {
+ return UpsertionMethodProcessor(baseContext, containing, executableElement).process()
+ }
+}