提问人:Chris 提问时间:11/15/2023 更新时间:11/15/2023 访问量:27
如何使用Jooq根据包含的工作Java代码使用Kotlin创建动态条件生成器?
How can I use Jooq to create a dynamic Condition generator using Kotlin based on included working Java code?
问:
我想将Jooq与Kotlin语言一起使用,以创建一种动态生成Jooq Condition对象的方法。
我想将Jooq Field对象放在从String到TableField(Jooq类)的Kotlin地图中。我想从这个映射中提取值,并使用它们来构建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,我会得到编译错误,我很确定这是由于 Map 上的“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 代码一样)?
答:
0赞
Lukas Eder
11/15/2023
#1
解决型式安全问题
Kotlin 没有 Java 的原始类型等价物,但你总是可以像这样不安全的强制转换:
.and((idField as Field<String>).eq("myId"))
.and((createTimeField as Field<Instant>).lt(Instant.ofEpochMilli(123456)))
或者,您不使用简单的映射,而是编写一个更复杂的实用程序(包装映射)来处理键入。
解决实际问题的替代方法
您的实际问题似乎是在您的架构中具有可重用的列。您可以声明一个接口,从任何表返回这些列,并让生成的表使用生成器策略或匹配器策略扩展此接口。
F.D.(英语:F.D.)
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
评论
0赞
Chris
11/15/2023
感谢您的回复!我已经在使用 Jooq 生成器来生成我的表类、字段等。例如,上面是 from 在生成的表类中。也许我之前应该更清楚:我需要做的是接受来自 API 的字符串标识符,例如“tag_id”,并能够查找相应的 TableField 以在 WHERE 子句中动态使用。这就是查找 String to TableField Map 的原因。有没有一种类型安全的 Kotlin 方法可以做到这一点?TAG_ID
TableField<TagV2Record, String?>
createField(DSL.name("tag_id"), SQLDataType.CLOB.nullable(false), this, "")
0赞
Chris
11/16/2023
我能够使用未经检查的演员表来使其工作。我这样做了: .编译器警告: 。我不确定是否有更好的方法可以做到这一点(对任何想法持开放态度)。我的一个朋友告诉我要读 youtrack.jetbrains.com/issue/KT-41062/......了解更多背景知识。我还没有消化它,但它是 Kotlin 功能请求,所以不会解决这个问题。(API_STRING_TO_JOOQ_FIELD_MAP[it.fieldName]!! as Field<Any>).eq(it.value)
Unchecked cast: TableField<out UpdatableRecordImpl<*>, *> to Field<Any>
评论