我想使用 Jooq 和 Kotlin 语言来创建一种动态生成 Jooq Condition 对象的方法。
我想将 Jooq Field 对象放入 Kotlin Map 中,从 String 到 TableField(一个 Jooq 类)。我想从该映射中提取值并使用它们来构建 Condition 对象。
我有一个使用 Java 的简单概念证明,我以单元测试的形式编写了它。该代码看起来像这样(省略了导入和类,但这就是想法。
private static final Map<String, TableField> FIELDS = Map.of(
"tagId", TagV2Table.Companion.getTAG_V2().getTAG_ID(),
"createdDate", ApplicationTable.Companion.getAPPLICATION().getCREATED_DATE()
);
@Test
void testDynamicGeneration() {
TableField idField = FIELDS.get("tagId");
TableField createTimeField = FIELDS.get("createdDate");
final Condition condition = noCondition()
.and(idField.eq("myId"))
.and(createTimeField.lt(Instant.ofEpochMilli(123456)));
final String expected = "(\n" +
" \"public\".\"tag_v2\".\"tag_id\" = 'myId'\n" +
" and \"public\".\"application\".\"created_date\" < timestamp with time zone '1970-01-01 00:02:03.456+00:00'\n" +
")";
assertEquals(expected, condition.toString());
创建的条件是“预期”中的条件,这就是我想要的。
如果我尝试将相同的代码翻译成 Kotlin,我会收到编译错误,我很确定这是由于地图上的“out”造成的。但我不知道如何解决它。这是我编写的等效 Kotlin 代码:
private companion object {
// The IntelliJ inferred type is:
// Map<String, TableField<out UpdatableRecordImpl<*>, out Any?>>
// AFAICT, the "out" of "out Any?" is making the ".eq" and ".lt" functions unavailable
// because it's unsafe.
val fields = mapOf(
"tagId" to TAG_V2.TAG_ID,
"createdDate" to APPLICATION.CREATED_DATE,
)
}
@Test
fun testDynamicGenerationKotlin() {
val idField = fields["tagId"]
val createTimeField = fields["createdDate"]
val condition = noCondition()
// .eq and .lt "None of the following functions can be called with the arguments supplied"
// and the accepted arguments are all Nothing
.and(idField.eq("myId"))
.and(createTimeField.lt(Instant.ofEpochMilli(123456)))
}
问题在于,功能
.eq(...)
和 .lt(...)
在从地图中拉出的对象 idField
和 createTimeField
上不可用。
有没有办法让我声明这个 Map 以便 Kotlin 代码可以工作(就像 Java 代码一样)?
Kotlin 没有相当于 Java 的原始类型,但你总是可以像这样进行不安全的转换:
.and((idField as Field<String>).eq("myId"))
.and((createTimeField as Field<Instant>).lt(Instant.ofEpochMilli(123456)))
或者,您不使用简单的地图,而是编写一个更复杂的实用程序(包装地图)来处理输入。
您的实际问题似乎是在您的架构中具有可重用的列。您可以声明一个从任何表返回这些列的接口,并让生成的表使用生成器策略或匹配器策略扩展此接口。
例如
interface MyJooqTable<R : Record> : Table<R> {
fun tagId(): Field<String> = field("tag_id", SQLDataType.STRING)
fun createdDate(): Field<Instant> = field("CREATED_DATE", SQLDataType.INSTANT)
}
现在,您可以传递对实用程序的
MyJooqTable
引用,并安全地从其中取消引用您的列(假设列存在)。