SQLiteOpenHelperWriter.kt revision cf4d34906517d8ced296a96e50339c926a7dfdcd
1d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar/*
2d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar * Copyright (C) 2016 The Android Open Source Project
3d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar *
4d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
5d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar * you may not use this file except in compliance with the License.
6d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar * You may obtain a copy of the License at
7d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar *
8d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
9d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar *
10d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar * Unless required by applicable law or agreed to in writing, software
11d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
12d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar * See the License for the specific language governing permissions and
14d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar * limitations under the License.
15d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar */
16d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar
1764db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarpackage android.arch.persistence.room.writer
18d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar
1964db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.ext.L
2064db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.ext.N
2164db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.ext.RoomTypeNames
2264db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.ext.S
2364db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.ext.SupportDbTypeNames
2464db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.ext.T
2564db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.solver.CodeGenScope
2664db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.vo.Database
2764db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.vo.Entity
28cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Arakiimport android.support.annotation.VisibleForTesting
29d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyarimport com.squareup.javapoet.MethodSpec
30d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyarimport com.squareup.javapoet.ParameterSpec
31d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyarimport com.squareup.javapoet.TypeSpec
32a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyarimport javax.lang.model.element.Modifier.PROTECTED
33d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyarimport javax.lang.model.element.Modifier.PUBLIC
34d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar
35d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar/**
36d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar * Create an open helper using SupportSQLiteOpenHelperFactory
37d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar */
38d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyarclass SQLiteOpenHelperWriter(val database : Database) {
39d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar    fun write(outVar : String, configuration : ParameterSpec, scope: CodeGenScope) {
40d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar        scope.builder().apply {
41d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar            val sqliteConfigVar = scope.getTmpVar("_sqliteConfig")
42d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar            val callbackVar = scope.getTmpVar("_openCallback")
43a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar            addStatement("final $T $L = new $T($N, $L, $S)",
44d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar                    SupportDbTypeNames.SQLITE_OPEN_HELPER_CALLBACK,
453a433f7ddbffa6131883cc3b23fc80edf54add19Yigit Boyar                    callbackVar, RoomTypeNames.OPEN_HELPER, configuration,
463a433f7ddbffa6131883cc3b23fc80edf54add19Yigit Boyar                    createOpenCallback(scope), database.identityHash)
47d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar            // build configuration
48d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar            addStatement(
49d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar                    """
50d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar                    final $T $L = $T.builder($N.context)
51d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar                    .name($N.name)
52a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                    .version($L)
53d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar                    .callback($L)
54d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar                    .build()
55d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar                    """.trimIndent(),
56d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar                    SupportDbTypeNames.SQLITE_OPEN_HELPER_CONFIG, sqliteConfigVar,
57d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar                    SupportDbTypeNames.SQLITE_OPEN_HELPER_CONFIG,
58a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                    configuration, configuration, database.version, callbackVar)
59d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar            addStatement("final $T $N = $N.sqliteOpenHelperFactory.create($L)",
60d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar                    SupportDbTypeNames.SQLITE_OPEN_HELPER, outVar,
61d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar                    configuration, sqliteConfigVar)
62d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar        }
63d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar    }
64d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar
653a433f7ddbffa6131883cc3b23fc80edf54add19Yigit Boyar    private fun createOpenCallback(scope: CodeGenScope) : TypeSpec {
66d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar        return TypeSpec.anonymousClassBuilder("").apply {
67a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar            superclass(RoomTypeNames.OPEN_HELPER_DELEGATE)
68a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar            addMethod(createCreateAllTables())
69a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar            addMethod(createDropAllTables())
70cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki            addMethod(createOnCreate(scope.fork()))
71cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki            addMethod(createOnOpen(scope.fork()))
723a433f7ddbffa6131883cc3b23fc80edf54add19Yigit Boyar            addMethod(createValidateMigration(scope.fork()))
73a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar        }.build()
74a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar    }
75a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar
763a433f7ddbffa6131883cc3b23fc80edf54add19Yigit Boyar    private fun createValidateMigration(scope: CodeGenScope): MethodSpec {
77a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar        return MethodSpec.methodBuilder("validateMigration").apply {
78a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar            addModifiers(PROTECTED)
793a433f7ddbffa6131883cc3b23fc80edf54add19Yigit Boyar            val dbParam = ParameterSpec.builder(SupportDbTypeNames.DB, "_db").build()
803a433f7ddbffa6131883cc3b23fc80edf54add19Yigit Boyar            addParameter(dbParam)
813a433f7ddbffa6131883cc3b23fc80edf54add19Yigit Boyar            database.entities.forEach { entity ->
823a433f7ddbffa6131883cc3b23fc80edf54add19Yigit Boyar                val methodScope = scope.fork()
833a433f7ddbffa6131883cc3b23fc80edf54add19Yigit Boyar                TableInfoValidationWriter(entity).write(dbParam, methodScope)
843a433f7ddbffa6131883cc3b23fc80edf54add19Yigit Boyar                addCode(methodScope.builder().build())
853a433f7ddbffa6131883cc3b23fc80edf54add19Yigit Boyar            }
8634e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        }.build()
8734e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    }
8834e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar
89cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki    private fun createOnCreate(scope: CodeGenScope): MethodSpec {
90cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki        return MethodSpec.methodBuilder("onCreate").apply {
91cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki            addModifiers(PROTECTED)
92cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki            addParameter(SupportDbTypeNames.DB, "_db")
93cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki            invokeCallbacks(scope, "onCreate")
94cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki        }.build()
95cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki    }
96cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki
97cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki    private fun createOnOpen(scope: CodeGenScope): MethodSpec {
9834e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        return MethodSpec.methodBuilder("onOpen").apply {
9934e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar            addModifiers(PUBLIC)
10034e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar            addParameter(SupportDbTypeNames.DB, "_db")
101fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyar            addStatement("mDatabase = _db")
1020045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            if (database.enableForeignKeys) {
1030045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar                addStatement("_db.execSQL($S)", "PRAGMA foreign_keys = ON")
1040045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar            }
10534e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar            addStatement("internalInitInvalidationTracker(_db)")
106cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki            invokeCallbacks(scope, "onOpen")
107d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar        }.build()
108d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar    }
109d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar
110a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar    private fun createCreateAllTables() : MethodSpec {
111a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar        return MethodSpec.methodBuilder("createAllTables").apply {
112d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar            addModifiers(PUBLIC)
113d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar            addParameter(SupportDbTypeNames.DB, "_db")
114a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar            database.bundle.buildCreateQueries().forEach {
115a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar                addStatement("_db.execSQL($S)", it)
116a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar            }
117d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar        }.build()
118d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar    }
119d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar
120a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar    private fun createDropAllTables() : MethodSpec {
121a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar        return MethodSpec.methodBuilder("dropAllTables").apply {
122d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar            addModifiers(PUBLIC)
123d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar            addParameter(SupportDbTypeNames.DB, "_db")
124c678b3a4eebc102a1a3b5923c5e07478c0eecae3Yigit Boyar            database.entities.forEach {
125c678b3a4eebc102a1a3b5923c5e07478c0eecae3Yigit Boyar                addStatement("_db.execSQL($S)", createDropTableQuery(it))
126c678b3a4eebc102a1a3b5923c5e07478c0eecae3Yigit Boyar            }
127d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar        }.build()
128d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar    }
129d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar
130cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki    private fun MethodSpec.Builder.invokeCallbacks(scope: CodeGenScope, methodName: String) {
131cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki        val iVar = scope.getTmpVar("_i")
132cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki        val sizeVar = scope.getTmpVar("_size")
133cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki        beginControlFlow("if (mCallbacks != null)").apply {
134cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki            beginControlFlow("for (int $N = 0, $N = mCallbacks.size(); $N < $N; $N++)",
135cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki                    iVar, sizeVar, iVar, sizeVar, iVar).apply {
136cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki                addStatement("mCallbacks.get($N).$N(_db)", iVar, methodName)
137cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki            }
138cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki            endControlFlow()
139cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki        }
140cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki        endControlFlow()
141cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki    }
142cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki
143c678b3a4eebc102a1a3b5923c5e07478c0eecae3Yigit Boyar    @VisibleForTesting
144c678b3a4eebc102a1a3b5923c5e07478c0eecae3Yigit Boyar    fun createQuery(entity : Entity) : String {
14588865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar        return entity.createTableQuery
146c678b3a4eebc102a1a3b5923c5e07478c0eecae3Yigit Boyar    }
147c678b3a4eebc102a1a3b5923c5e07478c0eecae3Yigit Boyar
148c678b3a4eebc102a1a3b5923c5e07478c0eecae3Yigit Boyar    @VisibleForTesting
149c678b3a4eebc102a1a3b5923c5e07478c0eecae3Yigit Boyar    fun createDropTableQuery(entity: Entity) : String {
150c678b3a4eebc102a1a3b5923c5e07478c0eecae3Yigit Boyar        return "DROP TABLE IF EXISTS `${entity.tableName}`"
151c678b3a4eebc102a1a3b5923c5e07478c0eecae3Yigit Boyar    }
152d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar}
153