JetBrains / Exposed

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

Support for Testcontainers in JDBC URL #1669

Open lns-ross opened 1 year ago

lns-ross commented 1 year ago

Is it possible to use a testcontainers-targeted JDBC URL? That is, a URL that uses "jdbc:tc:" as the URL scheme/prefix. Also supporting the container target version after the dialect.

For example: jdbc:tc:postgresql:15.1-alpine:///databasename

I wasn't able to find any docs or issues related to this. Nor could I find any examples of its use with Exposed.

A quick look at the Exposed code seems to indicate it would NOT support this. But I may not have looked close enough.

TIA.

edeak commented 1 year ago

I'm using TC with exposed as the following:

val mysqlContainer = MySQLContainer(DockerImageName.parse("mysql:5.7.34"))
        .withDatabaseName("test")
        .withUsername("root")
        .withPassword("root")
        .also { it.start() }

 val database = HikariConfig().apply {
    it.driverClassName = "org.mariadb.jdbc.Driver"
    it.username = this.username
    it.password = password
    it.jdbcUrl ="jdbc:mariadb://${mysqlContainer.host}:${mysqlContainer.firstMappedPort}/${mysqlContainer.databaseName}"
}.let { 
    Database.connect(HikariDataSource(it))
}
lns-ross commented 1 year ago

Yeah. That's one of the ways we did it with the PG container class but required us to know DB type ahead of time.

We ended up using a HikariDataSource directly with:

  jdbcUrl = "jdbc:tc:.."
  driverClassName = "org.testcontainers.jdbc.ContainerDatabaseDriver"

to give us an auto-detected container type for our needs.

However, having Exposed detect this style of jdbc URL and doing it would be a bonus as we would not need to intercept it to construct things directly. Especially since the ':tc:' URL's are so well defined.

This is more of a wish for an enhancement than anything else.

AlexeySoshin commented 1 year ago

Hi @ntr-ross , Could you elaborate a bit more on how you'd like that feature to work in general?

Would you invoke something like:

Database.connect(
        "jdbc:tc:postgresql:15.1-alpine:///databasename",
        user = ...,
        password = ...
    )
lns-ross commented 1 year ago

That was the sort of usage we were looking at. Basically the ability to switch to a test container simply by altering the jdbc URL supplied in a config setup.

I don't know the implications but since TC is also an 'interceptor'-style URL (and well-defined) that you could use the presence of 'jdbc:tc:' to determine the need for the TC driver (if it hasn't been specified already) and then use the prefix without the ':tc:' or the version to determine dialect. But that may be over-complicating things.

It was the error when using both the 'jdbc:tc:...' URL and the TC driver name in the connect() call that confounded us the most.

As I say in my previous post we got around it by forcing HikariDataSource all the time. But others may trip across this same issue in the future.

AlexeySoshin commented 1 year ago

@lns-ross Thank you. Would be helpful if you'd take a look at https://github.com/JetBrains/Exposed/pull/1680 and let me know if that solves your issues, as currently I don't have a TestContainers setup.

lns-ross commented 1 year ago

@AlexeySoshin Thx, that seems like it will work. It is obviously limited to just those two dialects (see below ***).

Not sure if this is what you meant about 'not having a setup', but if you have docker available (local or remote) attached is a minimal gradle project ( test-exposed-tc.zip) that should allow you to test using TC. It tries both the indirect-thru-Hikari mode (which works) and the direct URL mode (which fails).

*** Here's a list of the currently supported containers. Interesting quirk, TC doesn't recognize the 'pgsql' dialect via URL (testcontainers/testcontainers-java#6424) but is quite happy to launch one manually with the appropriate driver using the PostgeSQLContainer. Go figure.