1 /* <lambda>null2 * Copyright (C) 2017 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.writer 18 19 import androidx.room.compiler.codegen.VisibilityModifier 20 import androidx.room.compiler.codegen.XFunSpec 21 import androidx.room.compiler.codegen.XTypeSpec 22 import androidx.room.ext.CommonTypeNames 23 import androidx.room.ext.RoomTypeNames 24 import androidx.room.ext.SQLiteDriverTypeNames 25 import androidx.room.solver.CodeGenScope 26 import androidx.room.vo.DataClass 27 import androidx.room.vo.Properties 28 import androidx.room.vo.PropertyWithIndex 29 import androidx.room.vo.ShortcutEntity 30 import androidx.room.vo.columnNames 31 32 class EntityUpdateAdapterWriter 33 private constructor( 34 val tableName: String, 35 val dataClass: DataClass, 36 val primaryKeyFields: Properties, 37 val onConflict: String 38 ) { 39 companion object { 40 fun create(entity: ShortcutEntity, onConflict: String) = 41 EntityUpdateAdapterWriter( 42 tableName = entity.tableName, 43 dataClass = entity.dataClass, 44 primaryKeyFields = entity.primaryKey.properties, 45 onConflict = onConflict 46 ) 47 } 48 49 fun createAnonymous(typeWriter: TypeWriter): XTypeSpec { 50 return XTypeSpec.anonymousClassBuilder() 51 .apply { 52 superclass( 53 RoomTypeNames.DELETE_OR_UPDATE_ADAPTER.parametrizedBy(dataClass.typeName) 54 ) 55 addFunction( 56 XFunSpec.builder( 57 name = "createQuery", 58 visibility = VisibilityModifier.PROTECTED, 59 isOverride = true 60 ) 61 .apply { 62 returns(CommonTypeNames.STRING) 63 val dataClassCols = 64 dataClass.columnNames.joinToString(",") { "`$it` = ?" } 65 val pkFieldsCols = 66 primaryKeyFields.columnNames.joinToString(" AND ") { "`$it` = ?" } 67 val query = buildString { 68 if (onConflict.isNotEmpty()) { 69 append("UPDATE OR $onConflict `$tableName` SET") 70 } else { 71 append("UPDATE `$tableName` SET") 72 } 73 append(" $dataClassCols") 74 append(" WHERE") 75 append(" $pkFieldsCols") 76 } 77 addStatement("return %S", query) 78 } 79 .build() 80 ) 81 addFunction( 82 XFunSpec.builder( 83 name = "bind", 84 visibility = VisibilityModifier.PROTECTED, 85 isOverride = true 86 ) 87 .apply { 88 val stmtParam = "statement" 89 addParameter(stmtParam, SQLiteDriverTypeNames.STATEMENT) 90 val entityParam = "entity" 91 addParameter(entityParam, dataClass.typeName) 92 val mappedField = PropertyWithIndex.byOrder(dataClass.properties) 93 val bindScope = CodeGenScope(writer = typeWriter) 94 PropertyReadWriteWriter.bindToStatement( 95 ownerVar = entityParam, 96 stmtParamVar = stmtParam, 97 propertiesWithIndices = mappedField, 98 scope = bindScope 99 ) 100 val pkeyStart = dataClass.properties.size 101 val mappedPrimaryKeys = 102 primaryKeyFields.mapIndexed { index, field -> 103 PropertyWithIndex( 104 property = field, 105 indexVar = "${pkeyStart + index + 1}", 106 alwaysExists = true 107 ) 108 } 109 PropertyReadWriteWriter.bindToStatement( 110 ownerVar = entityParam, 111 stmtParamVar = stmtParam, 112 propertiesWithIndices = mappedPrimaryKeys, 113 scope = bindScope 114 ) 115 addCode(bindScope.generate()) 116 } 117 .build() 118 ) 119 } 120 .build() 121 } 122 } 123