com.zeoflow.depot.vo.Database.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of depot-compiler Show documentation
Show all versions of depot-compiler Show documentation
The Depot persistence library provides an abstraction layer over SQLite to allow for more robust database access while using the full power of SQLite.
The newest version!
/*
* Copyright (C) 2021 ZeoFlow SRL
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.zeoflow.depot.vo
import com.zeoflow.depot.compiler.processing.XType
import com.zeoflow.depot.compiler.processing.XTypeElement
import com.zeoflow.depot.migration.bundle.SchemaBundle
import com.squareup.javapoet.ClassName
import com.zeoflow.depot.DepotMasterTable
import org.apache.commons.codec.digest.DigestUtils
import java.io.File
/**
* Holds information about a class annotated with Database.
*/
data class Database(
val element: XTypeElement,
val type: XType,
val entities: List,
val views: List,
val daoMethods: List,
val version: Int,
val exportSchema: Boolean,
val enableForeignKeys: Boolean
) {
// This variable will be set once auto-migrations are processed given the DatabaseBundle from
// this object. This is necessary for tracking the versions involved in the auto-migration.
lateinit var autoMigrations: List
val typeName: ClassName by lazy { element.className }
private val implClassName by lazy {
"${typeName.simpleNames().joinToString("_")}_Impl"
}
val implTypeName: ClassName by lazy {
ClassName.get(typeName.packageName(), implClassName)
}
val bundle by lazy {
com.zeoflow.depot.migration.bundle.DatabaseBundle(
version, identityHash, entities.map(Entity::toBundle),
views.map(DatabaseView::toBundle),
listOf(
DepotMasterTable.CREATE_QUERY,
DepotMasterTable.createInsertQuery(identityHash)
)
)
}
/**
* Create a has that identifies this database definition so that at runtime we can check to
* ensure developer didn't forget to update the version.
*/
val identityHash: String by lazy {
val idKey = SchemaIdentityKey()
idKey.appendSorted(entities)
idKey.appendSorted(views)
idKey.hash()
}
val legacyIdentityHash: String by lazy {
val entityDescriptions = entities
.sortedBy { it.tableName }
.map { it.createTableQuery }
val indexDescriptions = entities
.flatMap { entity ->
entity.indices.map { index ->
// For legacy purposes we need to remove the later added 'IF NOT EXISTS'
// part of the create statement, otherwise old valid legacy hashes stop
// being accepted even though the schema has not changed. b/139306173
if (index.unique) {
"CREATE UNIQUE INDEX"
} else {
// The extra space between 'CREATE' and 'INDEX' is on purpose, this
// is a typo we have to live with.
"CREATE INDEX"
} + index.createQuery(entity.tableName).substringAfter("IF NOT EXISTS")
}
}
val viewDescriptions = views
.sortedBy { it.viewName }
.map { it.viewName + it.query.original }
val input = (entityDescriptions + indexDescriptions + viewDescriptions)
.joinToString("¯\\_(ツ)_/¯")
DigestUtils.md5Hex(input)
}
fun exportSchema(file: File) {
val schemaBundle =
com.zeoflow.depot.migration.bundle.SchemaBundle(SchemaBundle.LATEST_FORMAT, bundle)
if (file.exists()) {
val existing = try {
file.inputStream().use {
com.zeoflow.depot.migration.bundle.SchemaBundle.deserialize(it)
}
} catch (th: Throwable) {
throw IllegalStateException(
"""
Cannot parse existing schema file: ${file.absolutePath}.
If you've modified the file, you might've broken the JSON format, try
deleting the file and re-running the compiler.
If you've not modified the file, please file a bug at
https://issuetracker.google.com/issues/new?component=413107&template=1096568
with a sample app to reproduce the issue.
""".trimIndent()
)
}
if (existing.isSchemaEqual(schemaBundle)) {
return
}
}
com.zeoflow.depot.migration.bundle.SchemaBundle.serialize(schemaBundle, file)
}
}