Hi, I have a styling question related to data clas...
# getting-started
o
Hi, I have a styling question related to data classes and copy method.
Copy code
val connectionUri = "jdbc:postgresql://$host:$port/$database?user=$username&password=$password"

val connection = PostgreSQLConnectionBuilder.createConnectionPool(connectionUri) { it.copy(
        connectionCreateTimeout = 1
)}
I am writing a lib and I want to configure a connection. Configuration is a data class and all are vals. Can I avoid the
it.copy
in the code above (call the copy somehow in the lib), or is there an apply method?
Connection configuration is something like this:
Copy code
data class ConnectionPoolConfiguration @JvmOverloads constructor(
        val host: String = "localhost",
        val port: Int = 5432,
        val database: String? = null,
        val username: String = "dbuser",
        val password: String? = null,
       val connectionCreateTimeout: Long? = null
)
so I cannot mutate it, that is why I am using the
it.copy
do you think of another alternative?
d
copy
is the right tool here. Why don't you want to use it?
o
just to make it a nicer DSL
d
If you want a nice DSL you'd have to write something with actual `var`s if you want regular assignments.
o
I like the configuration to be immutable
I wish to somehow call copy from the lib, on parameters I get from the user šŸ¤”
d
Can you show what kind of syntax you want?
o
Copy code
PostgreSQLConnectionBuilder.createConnectionPool(connectionUri) { 
        connectionCreateTimeout = 1
}
to override specific values
d
You must have a
var
somewhere to achieve that syntax. It doesn't have to be in the actual connection properties, you can have a temporary mutable object
But what's wrong with
Copy code
PostgreSQLConnectionBuilder.createConnectionPool(connectionUri, ConnectionProperties(createTimeout = 1))
?
o
the first part
PostgreSQLConnectionBuilder.createConnectionPool(connectionUri)
is building a default configuration and I would like to be able to override some of the properties later, so I need to use that object
n
you could use a mutable variant of the ConnectionPool in the lambda, but then make it immutable and return that
o
is there a simple way to do that without cloning the class?
d
Could you please post the signature of
createConnectionPool
?
(I totally agree copying doesn’t feel great)
o
it looks like that:
Copy code
@JvmStatic
    fun createConnectionPool(url: String,
                             configurator: (ConnectionPoolConfiguration) -> ConnectionPoolConfiguration = { it }): ConnectionPool<MySQLConnection> {
        val configuration = URLParser.parseOrDie(url)
        val connectionPoolConfiguration = configurator(with(configuration) {
            ConnectionPoolConfiguration(
                    username = username,
                    host = host,
                    port = port,
                    password = password,
                    database = database,
                    ssl = ssl,
                    charset = charset,
                    maximumMessageSize = maximumMessageSize,
                    allocator = allocator,
                    queryTimeout = queryTimeout?.toMillis()
            )})
        return ConnectionPool(
                MySQLConnectionFactory(connectionPoolConfiguration.connectionConfiguration),
                connectionPoolConfiguration.poolConfiguration,
                connectionPoolConfiguration.executionContext
        )
    }
d
Even if it may feel a bit more fiddly I would pass just ConnectionPoolConfiguration as a parameter forcing the caller to build the object as it needs. I’ve seen may times using it.copy in a way that feels dealing with ā€œmutableā€ objects. As an end user of the library I would like to be in control and pass the configuration in šŸ˜€ It would be great if someone else can come up with a better solution
āž• 1
d
I think provide overloads of createConnectionPool function with the most common things a user might want to set, and if they need more flexibility, just pass in the configuration object. If it wouldn't need java interop you could always have defaults for all the function params and let the user choose what to provide... @oshai
Behind the scenes, the overloads create the immutable configuration onject with sensible defaults
o
Can you give an example?
d
Another possibility is to have a builder class like: https://github.com/ktorio/ktor/blob/master/ktor-server/ktor-server-host-common/src/io/ktor/server/engine/ApplicationEngineEnvironment.kt But what I meant previously was something like this: https://github.com/ktorio/ktor/blob/master/ktor-server/ktor-server-host-common/src/io/ktor/server/engine/EmbeddedServer.kt (except that you can have an overload to just provide the whole config object, or you could make it mutable like Ktor..) I think the second is better, because most of your configs are going to be supplied in most cases (database, user, password, host), port can maybe be guessed by implementation 3306 mysql, 5431 postgres... but should optionally be provided, the rest could have reasonable defaults or be provided with config object. @oshai
o
a builder is a valid option altough I thought we don't need that anymore with kotlin šŸ˜‰