JetBrains / Exposed

Kotlin SQL Framework
http://jetbrains.github.io/Exposed/
Apache License 2.0
8.36k stars 695 forks source link

prepareSql requires that Database.connect() has already been called #527

Open sazzer opened 5 years ago

sazzer commented 5 years ago

I'm trying to use Exposed as a SQL DSL, but not as a means to execute the SQL.

The FAQ implies that this is possible: https://github.com/JetBrains/Exposed/wiki/FAQ#q-how-to-get-a-plain-sql-query-which-will-be-executed

However, actually doing it throws:

java.lang.IllegalStateException: Please call Database.connect() before using this code

    at org.jetbrains.exposed.sql.transactions.NotInitializedManager.currentOrNull(TransactionApi.kt:34)
    at org.jetbrains.exposed.sql.transactions.TransactionManager$Companion.currentOrNull(TransactionApi.kt:74)
    at org.jetbrains.exposed.sql.transactions.TransactionManager$Companion.current(TransactionApi.kt:76)
    at org.jetbrains.exposed.sql.Column.toSQL(Column.kt:32)
    at org.jetbrains.exposed.sql.Query$prepareSQL$$inlined$buildString$lambda$1.invoke(Query.kt:169)
    at org.jetbrains.exposed.sql.Query$prepareSQL$$inlined$buildString$lambda$1.invoke(Query.kt:84)
    at kotlin.text.StringsKt__StringBuilderKt.appendElement(StringBuilder.kt:58)
    at kotlin.collections.CollectionsKt___CollectionsKt.joinTo(_Collections.kt:2291)
    at kotlin.collections.CollectionsKt___CollectionsKt.joinToString(_Collections.kt:2308)
    at kotlin.collections.CollectionsKt___CollectionsKt.joinToString$default(_Collections.kt:2307)
    at org.jetbrains.exposed.sql.Query.prepareSQL(Query.kt:169)

My code for this is simply:

object AttributesTable : Table() {
    val id = uuid("attribute_id").primaryKey()
    val version = uuid("version")
    val created = datetime("created")
    val updated = datetime("updated")
    val name = text("name")
    val description = text("name")
}

        val sql = AttributesTable.select { AttributesTable.id.eq(id) }.prepareSQL(QueryBuilder(false))
Tapac commented 5 years ago

It's impossible to prepare sql without knowing the dialect and database settings like keywords, quotation parameters and much more. So you have to call Database.connect(). You can use H2 in-memory database for such cases.

sazzer commented 5 years ago

This could be handled by telling the query builder the dialect to use, and not depend on access to the database just to build the SQL.

In my case I'm using Spring JdbcTemplate and so don't ever actually access the DataSource. However, this would also be useful, for example, if you are generating SQL constants that you want to reuse often. (And I'm sure many other reasons)

Tapac commented 5 years ago

You may try to make a fake connection with unworking jdbc-url (with a proper prefix to detect dialect, like jdbc:mysql:unexisting:3306). It should work unless jdbc driver will require some instance-specific data.

alexbezhan commented 3 years ago

It also requires active transaction, which it should not require, because nothing actually is being executed at the moment of sql generation.

LimmaPaulus commented 3 years ago

I would appreciate way to set dialect without specifying connection. Exposed could be used as great standalone SQL-generator in environments where queries are run afterwards with some other system.