【发布时间】:2020-06-08 13:39:18
【问题描述】:
给定一个使用 Kotlin 版本 1.3.61 和 JOOQ 版本 3.13.1 的系统,这样的方法可以正常构建 union 查询:
val selectCommonPart = coalesce(sum(field(name("amount"), Long::class.java)), ZERO)
.`as`(field(name("totalAmount")))
var whereCommonPart: Condition = trueCondition().and(field(name("Id")).eq(Id)) // Id comes as a parameter
var query = dsl.selectQuery()
query.addSelect(selectCommonPart)
query.addFrom(table("${tableName(startDate)}")) // `startDate` is a `LocalDate`, `tableName()` generates the table name as String
query.addConditions(whereCommonPart)
// `endDate` is also a `LocalDate`, can be either equal to `startDate` or after
if (endDate.isAfter(startDate)) {
for (date in Stream.iterate(startDate.plusDays(1), { d: LocalDate -> d.plusDays(1) })
.limit(ChronoUnit.DAYS.between(startDate, endDate))
.collect(Collectors.toList())) {
val unionQuery = dsl.selectQuery()
unionQuery.addSelect(selectCommonPart)
unionQuery.addFrom(table("public.${tableName(date)}"))
unionQuery.addConditions(whereCommonPart)
// Here `union` is inferred correctly
query.union(dsl.select(selectCommonPart)
.from("public.public.${tableName(date)}")
.where(whereCommonPart))
}
}
但是,如果我以如下方法隔离 dsl.select(...) 部分:
private fun buildSelect(selectCommonPart: Field<*>, whereCommonPart: Condition, date: LocalDate): Select<*> {
var query = dsl.selectQuery()
query.addSelect(selectCommonPart)
query.addFrom(table("public.${tableName(date)}"))
query.addConditions(whereCommonPart)
return query
}
并修改循环使用:
// Remove this part
/* var query = dsl.selectQuery()
query.addSelect(selectCommonPart)
query.addFrom(table("${tableName(startDate)}")) // `startDate` is a `LocalDate`, `tableName()` generates the table name as String
query.addConditions(whereCommonPart) */
// Add this part
var query = buildSelect(selectCommonPart, whereCommonPart, startDate)
if (endDate.isAfter(startDate)) {
for (date in Stream.iterate(startDate.plusDays(1), { d: LocalDate -> d.plusDays(1) })
.limit(ChronoUnit.DAYS.between(startDate, endDate))
.collect(Collectors.toList())) {
// This gives an inference error
query.union(buildSelect(selectCommonPart, whereCommonPart, date))
}
}
我有一个推理错误。 Kotlin 将union 解析为这种方法:
/**
* Returns a set containing all distinct elements from both collections.
*
* The returned set preserves the element iteration order of the original collection.
* Those elements of the [other] collection that are unique are iterated in the end
* in the order of the [other] collection.
*
* To get a set containing all elements that are contained in both collections use [intersect].
*/
public infix fun <T> Iterable<T>.union(other: Iterable<T>): Set<T> {
val set = this.toMutableSet()
set.addAll(other)
return set
}
我想改用 JOOQ 的 Select<*> 的 union:
public interface Select<R extends Record> extends ResultQuery<R>, TableLike<R>, FieldLike {
/**
* Apply the <code>UNION</code> set operation.
*/
@Support
Select<R> union(Select<? extends R> select);
我应该怎么做才能推断出正确的union 方法?
【问题讨论】:
-
我的 Kotlin-fu 不是很好,所以我无法解释为什么会发生这种情况,但是推断函数返回类型而不是显式提供它们真的是最佳实践吗?特别是当涉及到像 jOOQ 这样的复杂类型系统时(a jOOQ
ResultQueryextendsIterable)?据我回忆,在 Scala 中,人们通常会显式声明函数返回类型 -
@LukasEder 已经尝试过了,有许多不同的返回类型。他们都在某个时候推断出
Iterable。 -
我已将您的代码复制到我的项目中,但没有看到所描述的行为,在我的情况下执行了 Select.union。您是否在运行时遇到问题或如何检测到它?您是否尝试执行代码并检查执行了哪个联合?
-
@MaximPopov 我的代码甚至无法编译,因为 Kotlin 将变形解析为 Kotlin 标准库。你是如何运行它的?
-
我没有做任何特别的事情,只是复制了你的代码。请在此处查看我的测试示例 github.com/makcpop/sof-kotlin-jooq 。它可以在您的 PC 上运行吗?