Lastly, how would a List<Int> parameter in a...
# komapper
d
Lastly, how would a List<Int> parameter in a KomapperCommand be rendered in
unnest(/*listParam*/::int[])
?
t
It will be converted as follows:
unnest(?::int[])
d
It was converted to unnest((1,2,3)) on a dryRun...
So I tried:
Copy code
@JvmInline
value class CastedIntList(val list: String) {
    constructor(list: List<Int>) : this(
        list.joinToString(separator = ",")
    )
    constructor(vararg values: Int) : this(
        values.joinToString(separator = ",")
    )

    val size: Int get() = list.split(",").size
}
And the template still removed the ::int[] cast and gave me: unnest('1,2,3')...
OH... it removes it because it thinks the cast is part of my default value
/*list.list*/1::int[]
(which is probably wrong anyways)... when I did:
/*list.list*/'1'::int[]
it worked! But it would still be nice to not have to make that value class for this....
Now that I think of it, sqlWithArgs is not really an indication of anything, it really depends on the library running the sql... if it expects a list in this case, it will get one, I guess that's what you meant in your answer...
So if I need to Unit test this I'd need to test against what my JasyncDatabase is expecting... but then how would R2dbcDatabase or other implementations react?
t
The
dryRun
calls
R2dbcDataType.toString
for each bound value. Link to the code If you want to customize the
toString
result, you might consider creating a user-defined data type. Documentation on user-defined data types
d
Yeah, well in my case, I have my JasyncDatabase implementation that doesn't do that... just my Unit test using R2dbcDatabase for dryRun... so I guess I'll need to test the
sql
and
args
instead of
sqlWithArgs
...
@Toshihiro Nakamura Now I really don't understand...
Copy code
val result = QueryDsl.execute(AddSongsToPlaylist(
            1,
            listOf(1, 2, 3)
        )).dryRun(dbConfig)

        expectThat(result.args).isEqualTo(listOf(
            Value(1, typeOf<Int>()),
            Value(3, typeOf<Int>()),
            Value(1, typeOf<Int>()),
            Value(listOf(1, 2, 3), typeOf<List<Int>>()),
            Value(1, typeOf<Int>()),
        ))
is failing, I'm getting a Value for each element in the list instead...
Is that also because of dryRun running in the r2dbcDatabase implementation?
This is when I went back to using the list instead of my value class... (it seems like Jasync does allow receiving a list as a parameter for this kind of usage...) In the bind() generated for the command it DOES bind the List... not the individual values.
Maybe the
DryRunStatement
does return the list and not the individual values and I don't need to worry?
Copy code
private suspend fun queryResult(context: TemplateSelectContext): QueryResult {
        val runner = TemplateSelectRunner(context)
        val stmt = runner.dryRun(config)

        val result = try {
            if (stmt.args.isEmpty())
                conn.sendQuery(stmt.sql)
            else
                conn.sendPreparedStatement(
                    stmt.sql,
                    stmt.args.map { it.any }
                )
        } catch (e: Exception) {
            logger.error { "Error running: ${context.sql} with params: ${context.printArgs()}" }

            throw e
        }
        return result
    }
From my
JasyncQueryVisitor
t
With only this information, I can’t determine why your test is failing.
DryRunResult.args
returns the bound values. For example, if you bind a List, it returns the List itself, not the individual elements within it.
@dave08 I misunderstood. Subtypes of Iterable, like List, are bound by their elements. This behavior is designed with binding to an IN clause in mind. If you’d like to bind multiple elements together, could you consider using another type, such as an array?
d
That would be a bit confusing... to make such a difference -- a user wouldn't really be able to guess such behaviour. Apart from the fact that what I'm passing around is really a List...
You generate
IN (?, ?, ?...)
in the sql?
t
Yes, when a List is bound, Komapper generates
?, ?, ?
d
🤔 I guess I'm a bit stuck here if in
DryRunStatement
I get separate Value's for each entry... unless this only happens in DryRunResult?
t
How about binding an array instead of a list? You could convert it back to a list after retrieving it from
DryRunResult.args
.
unless this only happens in DryRunResult?
No, this behavior is the same even without using
DryRunResult
.
🤕 1
d
Well it could be a workaround, but I would have preferred to receive the actual type binded... are there other thing modified when passed down to DryRunResult, or is this the only one?
t
Only subtypes of
Iterable
are given special treatment during binding.
Strictly speaking,
Value
classes are also given special treatment, with their internal types being used. See also https://github.com/komapper/komapper/blob/v3.1.0/komapper-template/src/main/kotlin/org/komapper/template/TwoWayTemplateStatementBuilder.kt#L122-L167
d
I understand now... thanks! I guess it would have been harder to support IN otherwise... I'll have to find some better idea for this, or just use the Array workaround 🤷🏼‍♂️.