
com.squareup.sqldelight.SqliteCompiler.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of compiler Show documentation
Show all versions of compiler Show documentation
Common code shared between the Gradle and IntelliJ plugin
/*
* Copyright (C) 2016 Square, Inc.
*
* 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.squareup.sqldelight
import com.squareup.javapoet.ClassName
import com.squareup.javapoet.FieldSpec
import com.squareup.javapoet.JavaFile
import com.squareup.javapoet.MethodSpec
import com.squareup.javapoet.NameAllocator
import com.squareup.javapoet.TypeSpec
import com.squareup.sqldelight.model.Table
import com.squareup.sqldelight.model.body
import com.squareup.sqldelight.model.constantName
import com.squareup.sqldelight.model.identifier
import com.squareup.sqldelight.model.isNullable
import com.squareup.sqldelight.model.javaType
import com.squareup.sqldelight.model.methodName
import com.squareup.sqldelight.model.pathAsType
import com.squareup.sqldelight.model.pathFileName
import com.squareup.sqldelight.model.pathPackage
import com.squareup.sqldelight.model.sqliteName
import com.squareup.sqldelight.model.sqliteText
import com.squareup.sqldelight.validation.QueryResults
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.io.PrintStream
import java.util.LinkedHashMap
import java.util.Locale.US
import javax.lang.model.element.Modifier.ABSTRACT
import javax.lang.model.element.Modifier.FINAL
import javax.lang.model.element.Modifier.PUBLIC
import javax.lang.model.element.Modifier.STATIC
class SqliteCompiler {
private val nameAllocators = LinkedHashMap()
private fun write(
parseContext: SqliteParser.ParseContext,
queryResultsList: List,
relativePath: String,
projectPath: String
): Status {
try {
val className = interfaceName(relativePath.pathFileName())
val typeSpec = TypeSpec.interfaceBuilder(className)
.addModifiers(PUBLIC)
queryResultsList.filter { it.requiresType }.forEach { queryResults ->
typeSpec.addType(queryResults.generateInterface())
typeSpec.addType(queryResults.generateCreator())
typeSpec.addType(MapperSpec.builder(nameAllocators, queryResults).build())
}
queryResultsList.flatMap { it.views.values }.distinctBy { it.queryName }.forEach { queryResults ->
typeSpec.addType(queryResults.generateInterface())
typeSpec.addType(queryResults.generateCreator())
}
queryResultsList.filter { it.singleView }
.map { it.views.values.first() }
.distinctBy { it.queryName }
.forEach { queryResults ->
typeSpec.addType(MapperSpec.builder(nameAllocators, queryResults).build())
}
var table: Table? = null
if (parseContext.sql_stmt_list().create_table_stmt() != null) {
table = Table(relativePath.pathAsType(),
parseContext.sql_stmt_list().create_table_stmt(), nameAllocators)
typeSpec.addField(FieldSpec.builder(String::class.java, TABLE_NAME)
.addModifiers(PUBLIC, STATIC, FINAL)
.initializer("\$S", table.name)
.build())
.addType(table.creatorInterface())
.addType(MapperSpec.builder(table).build())
for (column in table.column_def()) {
if (column.constantName(table.nameAllocator) == TABLE_NAME
|| column.constantName(table.nameAllocator) == CREATE_TABLE) {
throw SqlitePluginException(column.column_name(),
"Column name '${column.sqliteName}' forbidden")
}
typeSpec.addField(FieldSpec.builder(String::class.java, column.constantName(table.nameAllocator))
.addModifiers(PUBLIC, STATIC, FINAL)
.initializer("\$S", column.sqliteName)
.build())
val methodSpec = MethodSpec.methodBuilder(column.methodName(table.nameAllocator))
.returns(column.javaType)
.addModifiers(PUBLIC, ABSTRACT)
if (!column.javaType.isPrimitive) {
methodSpec.addAnnotation(if (column.isNullable) NULLABLE else NON_NULL)
}
typeSpec.addMethod(methodSpec.build())
}
typeSpec.addField(FieldSpec.builder(String::class.java, CREATE_TABLE)
.addModifiers(PUBLIC, STATIC, FINAL)
.initializer("\"\"\n + \$S", table.sqliteText()) // Start SQL on wrapped line.
.build())
typeSpec.addType(MarshalSpec.builder(table).build())
}
typeSpec.addType(
FactorySpec.builder(table, queryResultsList, relativePath.pathAsType(), nameAllocators)
.build())
parseContext.sql_stmt_list().sql_stmt().forEach {
if (it.identifier == CREATE_TABLE) {
throw SqlitePluginException(it.sql_stmt_name(), "'CREATE_TABLE' identifier is reserved")
}
typeSpec.addField(FieldSpec.builder(String::class.java, it.identifier)
.addModifiers(PUBLIC, STATIC, FINAL)
.initializer("\"\"\n + \$S", it.body().sqliteText()) // Start SQL on wrapped line.
.build())
}
val javaFile = JavaFile.builder(relativePath.pathPackage(), typeSpec.build()).build()
val buildDirectory = File(File(projectPath, "build"), SqliteCompiler.OUTPUT_DIRECTORY)
val packageDirectory = File(buildDirectory, relativePath.substringBeforeLast(File.separatorChar))
packageDirectory.mkdirs()
val outputFile = File(packageDirectory, className + ".java")
outputFile.createNewFile()
javaFile.writeTo(PrintStream(FileOutputStream(outputFile)))
return Status.Success(parseContext, outputFile)
} catch (e: SqlitePluginException) {
return Status.Failure(e.originatingElement, e.message)
} catch (e: IOException) {
return Status.Failure(parseContext, e.message ?: "IOException occurred")
}
}
companion object {
const val TABLE_NAME = "TABLE_NAME"
const val CREATE_TABLE = "CREATE_TABLE"
const val FILE_EXTENSION = "sq"
val OUTPUT_DIRECTORY = "generated${File.separatorChar}source${File.separatorChar}sqldelight"
val NULLABLE = ClassName.get("android.support.annotation", "Nullable")
val NON_NULL = ClassName.get("android.support.annotation", "NonNull")
val COLUMN_ADAPTER_TYPE = ClassName.get("com.squareup.sqldelight", "ColumnAdapter")
fun interfaceName(sqliteFileName: String) = sqliteFileName + "Model"
fun constantName(name: String) = name.toUpperCase(US)
fun write(
parseContext: SqliteParser.ParseContext,
queryResultsList: List,
relativePath: String,
projectPath: String
) = SqliteCompiler().write(parseContext, queryResultsList, relativePath, projectPath)
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy