18bad027c789d3fb3da8e68fa0154f2a24ccc2865Yigit Boyar/* 28bad027c789d3fb3da8e68fa0154f2a24ccc2865Yigit Boyar * Copyright (C) 2016 The Android Open Source Project 38bad027c789d3fb3da8e68fa0154f2a24ccc2865Yigit Boyar * 48bad027c789d3fb3da8e68fa0154f2a24ccc2865Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License"); 58bad027c789d3fb3da8e68fa0154f2a24ccc2865Yigit Boyar * you may not use this file except in compliance with the License. 68bad027c789d3fb3da8e68fa0154f2a24ccc2865Yigit Boyar * You may obtain a copy of the License at 78bad027c789d3fb3da8e68fa0154f2a24ccc2865Yigit Boyar * 88bad027c789d3fb3da8e68fa0154f2a24ccc2865Yigit Boyar * http://www.apache.org/licenses/LICENSE-2.0 98bad027c789d3fb3da8e68fa0154f2a24ccc2865Yigit Boyar * 108bad027c789d3fb3da8e68fa0154f2a24ccc2865Yigit Boyar * Unless required by applicable law or agreed to in writing, software 118bad027c789d3fb3da8e68fa0154f2a24ccc2865Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS, 128bad027c789d3fb3da8e68fa0154f2a24ccc2865Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138bad027c789d3fb3da8e68fa0154f2a24ccc2865Yigit Boyar * See the License for the specific language governing permissions and 148bad027c789d3fb3da8e68fa0154f2a24ccc2865Yigit Boyar * limitations under the License. 158bad027c789d3fb3da8e68fa0154f2a24ccc2865Yigit Boyar */ 168bad027c789d3fb3da8e68fa0154f2a24ccc2865Yigit Boyar 17bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viverettepackage androidx.room.vo 188bad027c789d3fb3da8e68fa0154f2a24ccc2865Yigit Boyar 19bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.room.RoomMasterTable 20bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.room.migration.bundle.DatabaseBundle 21bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.room.migration.bundle.SchemaBundle 22d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyarimport com.squareup.javapoet.ClassName 23fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyarimport org.apache.commons.codec.digest.DigestUtils 24a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyarimport java.io.File 25aa82fce1d73394bdc7f4c2510cf94a3572032b24Yigit Boyarimport javax.lang.model.element.TypeElement 26d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyarimport javax.lang.model.type.TypeMirror 278bad027c789d3fb3da8e68fa0154f2a24ccc2865Yigit Boyar 288bad027c789d3fb3da8e68fa0154f2a24ccc2865Yigit Boyar/** 298bad027c789d3fb3da8e68fa0154f2a24ccc2865Yigit Boyar * Holds information about a class annotated with Database. 308bad027c789d3fb3da8e68fa0154f2a24ccc2865Yigit Boyar */ 31a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyardata class Database(val element: TypeElement, 32a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar val type: TypeMirror, 33a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar val entities: List<Entity>, 34a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar val daoMethods: List<DaoMethod>, 35a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar val version: Int, 360045a1c980b44c882f4ece571a0a113d36bbf0fbYigit Boyar val exportSchema: Boolean, 376f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas val enableForeignKeys: Boolean) { 38a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar val typeName: ClassName by lazy { ClassName.get(element) } 39d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar 40dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar private val implClassName by lazy { 41dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar "${typeName.simpleNames().joinToString("_")}_Impl" 42d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar } 43d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar 44a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar val implTypeName: ClassName by lazy { 45d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar ClassName.get(typeName.packageName(), implClassName) 46d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar } 47fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyar 48a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar val bundle by lazy { 49a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar DatabaseBundle(version, identityHash, entities.map(Entity::toBundle), 50a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar listOf(RoomMasterTable.CREATE_QUERY, 51a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar RoomMasterTable.createInsertQuery(identityHash))) 52a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar } 53a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar 54fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyar /** 55fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyar * Create a has that identifies this database definition so that at runtime we can check to 56fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyar * ensure developer didn't forget to update the version. 57fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyar */ 58a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar val identityHash: String by lazy { 59e5ed537fe6f14f0bbb43ddef605ed22f09714142Yigit Boyar val idKey = SchemaIdentityKey() 60e5ed537fe6f14f0bbb43ddef605ed22f09714142Yigit Boyar idKey.appendSorted(entities) 61e5ed537fe6f14f0bbb43ddef605ed22f09714142Yigit Boyar idKey.hash() 62e5ed537fe6f14f0bbb43ddef605ed22f09714142Yigit Boyar } 63e5ed537fe6f14f0bbb43ddef605ed22f09714142Yigit Boyar 64e5ed537fe6f14f0bbb43ddef605ed22f09714142Yigit Boyar val legacyIdentityHash: String by lazy { 65fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyar val entityDescriptions = entities 66fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyar .sortedBy { it.tableName } 67fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyar .map { it.createTableQuery } 68fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyar val indexDescriptions = entities 69fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyar .flatMap { entity -> 70fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyar entity.indices.map { index -> 71fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyar index.createQuery(entity.tableName) 72fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyar } 73fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyar } 74fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyar val input = (entityDescriptions + indexDescriptions).joinToString("¯\\_(ツ)_/¯") 75fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyar DigestUtils.md5Hex(input) 76fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyar } 77a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar 78a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar fun exportSchema(file: File) { 79a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar val schemaBundle = SchemaBundle(SchemaBundle.LATEST_FORMAT, bundle) 80e5ed537fe6f14f0bbb43ddef605ed22f09714142Yigit Boyar if (file.exists()) { 81e5ed537fe6f14f0bbb43ddef605ed22f09714142Yigit Boyar val existing = file.inputStream().use { 82e5ed537fe6f14f0bbb43ddef605ed22f09714142Yigit Boyar SchemaBundle.deserialize(it) 83e5ed537fe6f14f0bbb43ddef605ed22f09714142Yigit Boyar } 84e5ed537fe6f14f0bbb43ddef605ed22f09714142Yigit Boyar if (existing.isSchemaEqual(schemaBundle)) { 85e5ed537fe6f14f0bbb43ddef605ed22f09714142Yigit Boyar return 86e5ed537fe6f14f0bbb43ddef605ed22f09714142Yigit Boyar } 87e5ed537fe6f14f0bbb43ddef605ed22f09714142Yigit Boyar } 88a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar SchemaBundle.serialize(schemaBundle, file) 89a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar } 90d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar} 91