com.zeoflow.depot.DatabaseProcessingStep.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
import com.zeoflow.depot.compiler.processing.XElement
import com.zeoflow.depot.compiler.processing.XProcessingEnv
import com.zeoflow.depot.compiler.processing.XProcessingStep
import com.zeoflow.depot.compiler.processing.XTypeElement
import com.zeoflow.depot.processor.Context
import com.zeoflow.depot.processor.DatabaseProcessor
import com.zeoflow.depot.processor.MissingTypeException
import com.zeoflow.depot.processor.ProcessorErrors
import com.zeoflow.depot.vo.DaoMethod
import com.zeoflow.depot.vo.Warning
import com.zeoflow.depot.writer.AutoMigrationWriter
import com.zeoflow.depot.writer.DaoWriter
import com.zeoflow.depot.writer.DatabaseWriter
import java.io.File
class DatabaseProcessingStep : XProcessingStep {
override fun process(
env: XProcessingEnv,
elementsByAnnotation: Map>
): Set {
val context = Context(env)
val rejectedElements = mutableSetOf()
val databases = elementsByAnnotation[com.zeoflow.depot.Database::class.qualifiedName]
?.filterIsInstance()
?.mapNotNull {
try {
DatabaseProcessor(
context,
it
).process()
} catch (ex: MissingTypeException) {
// Abandon processing this database class since it needed a type element
// that is missing. It is possible that the type will be generated by a
// further annotation processing round, so we will try again by adding
// this class element to a deferred set.
rejectedElements.add(it)
null
}
}
val daoMethodsMap = databases?.flatMap { db -> db.daoMethods.map { it to db } }?.toMap()
daoMethodsMap?.let {
prepareDaosForWriting(databases, it.keys.toList())
it.forEach { (daoMethod, db) ->
DaoWriter(
daoMethod.dao,
db.element,
context.processingEnv
)
.write(context.processingEnv)
}
}
databases?.forEach { db ->
DatabaseWriter(db).write(context.processingEnv)
if (db.exportSchema) {
val schemaOutFolder = context.schemaOutFolder
if (schemaOutFolder == null) {
context.logger.w(
Warning.MISSING_SCHEMA_LOCATION, db.element,
ProcessorErrors.MISSING_SCHEMA_EXPORT_DIRECTORY
)
} else {
if (!schemaOutFolder.exists()) {
schemaOutFolder.mkdirs()
}
val qName = db.element.qualifiedName
val dbSchemaFolder = File(schemaOutFolder, qName)
if (!dbSchemaFolder.exists()) {
dbSchemaFolder.mkdirs()
}
db.exportSchema(
File(
dbSchemaFolder,
"${db.version}.json"
)
)
}
}
db.autoMigrations.forEach { autoMigration ->
AutoMigrationWriter(db.element, autoMigration).write(context.processingEnv)
}
}
return rejectedElements
}
override fun annotations(): Set {
return mutableSetOf(com.zeoflow.depot.Database::class.qualifiedName!!)
}
/**
* Traverses all dao methods and assigns them suffix if they are used in multiple databases.
*/
private fun prepareDaosForWriting(
databases: List,
daoMethods: List
) {
daoMethods.groupBy { it.dao.typeName }
// if used only in 1 database, nothing to do.
.filter { entry -> entry.value.size > 1 }
.forEach { entry ->
entry.value.groupBy { daoMethod ->
// first suffix guess: Database's simple name
val db = databases.first { db -> db.daoMethods.contains(daoMethod) }
db.typeName.simpleName()
}.forEach { (dbName, methods) ->
if (methods.size == 1) {
// good, db names do not clash, use db name as suffix
methods.first().dao.setSuffix(dbName)
} else {
// ok looks like a dao is used in 2 different databases both of
// which have the same name. enumerate.
methods.forEachIndexed { index, method ->
method.dao.setSuffix("${dbName}_$index")
}
}
}
}
}
}