1 /* <lambda>null2 * Copyright (C) 2016 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.query.result 18 19 import androidx.room.compiler.codegen.XCodeBlock 20 import androidx.room.compiler.codegen.XFunSpec 21 import androidx.room.compiler.codegen.XMemberName.Companion.packageMember 22 import androidx.room.compiler.codegen.XTypeName 23 import androidx.room.compiler.codegen.compat.XConverters.toString 24 import androidx.room.compiler.processing.XType 25 import androidx.room.ext.ArrayLiteral 26 import androidx.room.ext.CommonTypeNames 27 import androidx.room.ext.RoomTypeNames.STATEMENT_UTIL 28 import androidx.room.ext.SQLiteDriverTypeNames 29 import androidx.room.solver.CodeGenScope 30 import androidx.room.vo.ColumnIndexVar 31 import androidx.room.vo.Entity 32 import androidx.room.vo.columnNames 33 import androidx.room.writer.EntityStatementConverterWriter 34 35 class EntityRowAdapter(val entity: Entity, out: XType) : QueryMappedRowAdapter(out) { 36 override val mapping = EntityMapping(entity) 37 38 private lateinit var functionSpec: XFunSpec 39 40 private var stmtDelegateVarName: String? = null 41 42 private val indexAdapter = 43 object : IndexAdapter { 44 45 private var indexVars: List<ColumnIndexVar>? = null 46 47 override fun onStatementReady(stmtVarName: String, scope: CodeGenScope) { 48 indexVars = 49 entity.columnNames.map { columnName -> 50 val packageMember = STATEMENT_UTIL.packageMember("getColumnIndex") 51 ColumnIndexVar( 52 column = columnName, 53 indexVar = 54 XCodeBlock.of("%M(%L, %S)", packageMember, stmtVarName, columnName) 55 // indexVar expects a string, and that depends on the language. 56 // We should change the function signature to accept XCodeBlock. 57 .toString(scope.language) 58 ) 59 } 60 } 61 62 override fun getIndexVars() = indexVars ?: emptyList() 63 } 64 65 override fun onStatementReady( 66 stmtVarName: String, 67 scope: CodeGenScope, 68 indices: List<ColumnIndexVar> 69 ) { 70 // Check if given indices are the default ones, i.e. onStatementReady() was called without 71 // an indices argument and these are the default parameter ones, which means a wrapped 72 // statement is not needed since the generated entity statement converter has access to the 73 // original statement. 74 if (indices.isNotEmpty() && indices != indexAdapter.getIndexVars()) { 75 // Due to entity converter code being shared and using getColumnIndex() we can't 76 // generate code that uses the mapping directly. Instead we create a wrapped statement 77 // that is solely used in the shared converter function and whose getColumnIndex() is 78 // overridden to return the resolved column index. 79 stmtDelegateVarName = scope.getTmpVar("_wrappedStmt") 80 val entityColumnNamesParam = 81 ArrayLiteral(CommonTypeNames.STRING, *entity.columnNames.toTypedArray()) 82 val entityColumnIndicesParam = 83 ArrayLiteral(XTypeName.PRIMITIVE_INT, *indices.map { it.indexVar }.toTypedArray()) 84 val wrapperTypeName = SQLiteDriverTypeNames.STATEMENT 85 val packageMember = STATEMENT_UTIL.packageMember("wrapMappedColumns") 86 scope.builder.addLocalVariable( 87 checkNotNull(stmtDelegateVarName), 88 wrapperTypeName, 89 assignExpr = 90 XCodeBlock.of( 91 "%M(%L, %L, %L)", 92 packageMember, 93 stmtVarName, 94 entityColumnNamesParam, 95 entityColumnIndicesParam 96 ) 97 ) 98 } 99 functionSpec = 100 scope.writer.getOrCreateFunction(EntityStatementConverterWriter(entity = entity)) 101 } 102 103 override fun convert(outVarName: String, stmtVarName: String, scope: CodeGenScope) { 104 scope.builder.addStatement( 105 "%L = %N(%L)", 106 outVarName, 107 functionSpec, 108 stmtDelegateVarName ?: stmtVarName 109 ) 110 } 111 112 override fun getDefaultIndexAdapter() = indexAdapter 113 114 data class EntityMapping(val entity: Entity) : Mapping() { 115 override val usedColumns: List<String> = entity.columnNames 116 } 117 } 118