14f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar/*
24f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar * Copyright (C) 2016 The Android Open Source Project
34f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar *
44f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
54f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar * you may not use this file except in compliance with the License.
64f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar * You may obtain a copy of the License at
74f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar *
84f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
94f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar *
104f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar * Unless required by applicable law or agreed to in writing, software
114f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
124f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar * See the License for the specific language governing permissions and
144f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar * limitations under the License.
154f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar */
164f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar
17bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viverettepackage androidx.room.writer
184f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar
19bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.room.ext.L
20bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.room.ext.RoomTypeNames
21bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.room.ext.S
22bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.room.ext.SupportDbTypeNames
23bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.room.solver.CodeGenScope
24bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.room.vo.Entity
25bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.room.vo.FieldWithIndex
264f0db7db556b473393dfc31bba5ea67def574877Yigit Boyarimport com.squareup.javapoet.ClassName
274f0db7db556b473393dfc31bba5ea67def574877Yigit Boyarimport com.squareup.javapoet.MethodSpec
284f0db7db556b473393dfc31bba5ea67def574877Yigit Boyarimport com.squareup.javapoet.ParameterSpec
294f0db7db556b473393dfc31bba5ea67def574877Yigit Boyarimport com.squareup.javapoet.ParameterizedTypeName
304f0db7db556b473393dfc31bba5ea67def574877Yigit Boyarimport com.squareup.javapoet.TypeName
314f0db7db556b473393dfc31bba5ea67def574877Yigit Boyarimport com.squareup.javapoet.TypeSpec
324f0db7db556b473393dfc31bba5ea67def574877Yigit Boyarimport javax.lang.model.element.Modifier.PUBLIC
334f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar
344f0db7db556b473393dfc31bba5ea67def574877Yigit Boyarclass EntityInsertionAdapterWriter(val entity: Entity, val onConflict: String) {
356f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas    fun createAnonymous(classWriter: ClassWriter, dbParam: String): TypeSpec {
364f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar        @Suppress("RemoveSingleExpressionStringTemplate")
374f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar        return TypeSpec.anonymousClassBuilder("$L", dbParam).apply {
384f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar            superclass(
394f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar                    ParameterizedTypeName.get(RoomTypeNames.INSERTION_ADAPTER, entity.typeName)
404f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar            )
412c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar
422c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar            // If there is an auto-increment primary key with primitive type, we consider 0 as
432c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar            // not set. For such fields, we must generate a slightly different insertion SQL.
442c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar            val primitiveAutoGenerateField = if (entity.primaryKey.autoGenerateId) {
452c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar                entity.primaryKey.fields.firstOrNull()?.let { field ->
462c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar                    field.statementBinder?.typeMirror()?.let { binderType ->
472c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar                        if (binderType.kind.isPrimitive) {
482c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar                            field
492c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar                        } else {
502c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar                            null
512c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar                        }
522c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar                    }
532c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar                }
542c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar            } else {
552c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar                null
562c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar            }
573db6d309415576ef0080c29705dc30496636a986Yigit Boyar            addMethod(MethodSpec.methodBuilder("createQuery").apply {
584f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar                addAnnotation(Override::class.java)
594f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar                returns(ClassName.get("java.lang", "String"))
604f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar                addModifiers(PUBLIC)
614f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar                val query =
624f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar                        "INSERT OR $onConflict INTO `${entity.tableName}`(" +
634f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar                                entity.fields.joinToString(",") {
644f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar                                    "`${it.columnName}`"
654f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar                                } + ") VALUES (" +
664f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar                                entity.fields.joinToString(",") {
672c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar                                    if (primitiveAutoGenerateField == it) {
682c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar                                        "nullif(?, 0)"
692c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar                                    } else {
702c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar                                        "?"
712c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar                                    }
724f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar                                } + ")"
734f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar                addStatement("return $S", query)
744f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar            }.build())
754f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar            addMethod(MethodSpec.methodBuilder("bind").apply {
76645abf12d5a13dae5c2271cedd0563a580871a2bYigit Boyar                val bindScope = CodeGenScope(classWriter)
774f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar                addAnnotation(Override::class.java)
784f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar                val stmtParam = "stmt"
794f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar                addParameter(ParameterSpec.builder(SupportDbTypeNames.SQLITE_STMT,
804f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar                        stmtParam).build())
814f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar                val valueParam = "value"
824f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar                addParameter(ParameterSpec.builder(entity.typeName, valueParam).build())
834f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar                returns(TypeName.VOID)
844f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar                addModifiers(PUBLIC)
85f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar                val mapped = FieldWithIndex.byOrder(entity.fields)
8696cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                FieldReadWriteWriter.bindToStatement(
8796cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                        ownerVar = valueParam,
8896cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                        stmtParamVar = stmtParam,
8996cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                        fieldsWithIndices = mapped,
9096cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                        scope = bindScope
9196cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                )
924f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar                addCode(bindScope.builder().build())
934f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar            }.build())
944f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar        }.build()
954f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar    }
96e2476a0cdc340c8071c938132b2c77b8349c5a01Yigit Boyar}
97