1 /* <lambda>null2 * Copyright 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.room.solver.prepared.result 18 19 import androidx.room.compiler.codegen.CodeLanguage 20 import androidx.room.compiler.codegen.XCodeBlock.Builder.Companion.applyTo 21 import androidx.room.compiler.codegen.XMemberName.Companion.packageMember 22 import androidx.room.compiler.codegen.XPropertySpec 23 import androidx.room.compiler.processing.XType 24 import androidx.room.compiler.processing.isInt 25 import androidx.room.compiler.processing.isKotlinUnit 26 import androidx.room.compiler.processing.isLong 27 import androidx.room.compiler.processing.isVoid 28 import androidx.room.compiler.processing.isVoidObject 29 import androidx.room.ext.KotlinTypeNames 30 import androidx.room.ext.RoomTypeNames 31 import androidx.room.parser.QueryType 32 import androidx.room.solver.CodeGenScope 33 import androidx.room.solver.prepared.binder.PreparedQueryResultBinder 34 35 /** 36 * An adapter for [PreparedQueryResultBinder] that executes queries with INSERT, UPDATE or DELETE 37 * statements. 38 */ 39 class PreparedQueryResultAdapter(private val returnType: XType, private val queryType: QueryType) { 40 companion object { 41 fun create(returnType: XType, queryType: QueryType) = 42 if (isValidReturnType(returnType, queryType)) { 43 PreparedQueryResultAdapter(returnType, queryType) 44 } else { 45 null 46 } 47 48 private fun isValidReturnType(returnType: XType, queryType: QueryType): Boolean { 49 if (returnType.isVoid() || returnType.isVoidObject() || returnType.isKotlinUnit()) { 50 return true 51 } else { 52 return when (queryType) { 53 QueryType.INSERT -> returnType.isLong() 54 QueryType.UPDATE, 55 QueryType.DELETE -> returnType.isInt() 56 else -> false 57 } 58 } 59 } 60 } 61 62 fun executeAndReturn( 63 stmtQueryVal: String, 64 preparedStmtProperty: XPropertySpec?, 65 dbProperty: XPropertySpec, 66 scope: CodeGenScope 67 ) { 68 scope.builder.apply { 69 val stmtMethod = 70 if (queryType == QueryType.INSERT) { 71 "executeInsert" 72 } else { 73 "executeUpdateDelete" 74 } 75 if (preparedStmtProperty != null) { 76 beginControlFlow("try") 77 } 78 addStatement("%N.beginTransaction()", dbProperty) 79 beginControlFlow("try").apply { 80 if (returnType.isVoid() || returnType.isVoidObject() || returnType.isKotlinUnit()) { 81 addStatement("%L.%L()", stmtQueryVal, stmtMethod) 82 addStatement("%N.setTransactionSuccessful()", dbProperty) 83 if (returnType.isVoidObject()) { 84 addStatement("return null") 85 } else if (returnType.isKotlinUnit()) { 86 applyTo(CodeLanguage.JAVA) { 87 addStatement("return %T.INSTANCE", KotlinTypeNames.UNIT) 88 } 89 } 90 } else { 91 val resultVar = scope.getTmpVar("_result") 92 addLocalVal( 93 resultVar, 94 returnType.asTypeName(), 95 "%L.%L()", 96 stmtQueryVal, 97 stmtMethod 98 ) 99 addStatement("%N.setTransactionSuccessful()", dbProperty) 100 addStatement("return %L", resultVar) 101 } 102 } 103 nextControlFlow("finally").apply { addStatement("%N.endTransaction()", dbProperty) } 104 endControlFlow() 105 if (preparedStmtProperty != null) { 106 nextControlFlow("finally") 107 addStatement("%N.release(%L)", preparedStmtProperty, stmtQueryVal) 108 endControlFlow() 109 } 110 } 111 } 112 113 fun executeAndReturn(connectionVar: String, statementVar: String, scope: CodeGenScope) { 114 scope.builder.applyTo { language -> 115 addStatement("%L.step()", statementVar) 116 val returnPrefix = 117 when (language) { 118 CodeLanguage.JAVA -> "return " 119 CodeLanguage.KOTLIN -> "" 120 } 121 if (returnType.isVoid() || returnType.isVoidObject() || returnType.isKotlinUnit()) { 122 if (returnType.isVoidObject()) { 123 addStatement("${returnPrefix}null") 124 } else if (returnType.isVoid() && language == CodeLanguage.JAVA) { 125 addStatement("return null") 126 } else if (returnType.isKotlinUnit() && language == CodeLanguage.JAVA) { 127 addStatement("return %T.INSTANCE", KotlinTypeNames.UNIT) 128 } 129 } else { 130 val returnFunctionName = 131 when (queryType) { 132 QueryType.INSERT -> "getLastInsertedRowId" 133 QueryType.UPDATE, 134 QueryType.DELETE -> "getTotalChangedRows" 135 else -> error("No return function name for query type $queryType") 136 } 137 addStatement( 138 "$returnPrefix%M(%L)", 139 RoomTypeNames.CONNECTION_UTIL.packageMember(returnFunctionName), 140 connectionVar 141 ) 142 } 143 } 144 } 145 } 146