如何使用 Jooq 基于包含的工作 Java 代码使用 Kotlin 创建动态条件生成器?

问题描述 投票:0回答:1

我想使用 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 代码一样)?

java sql kotlin generics jooq
1个回答
0
投票

解决类型安全问题

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
引用,并安全地从其中取消引用您的列(假设列存在)。

© www.soinside.com 2019 - 2024. All rights reserved.