【问题标题】:jOOQ query expression type-safety without custom converter没有自定义转换器的 jOOQ 查询表达式类型安全
【发布时间】:2020-07-04 22:39:45
【问题描述】:

我正在尝试使用 Kotlin 的扩展函数以类型安全的方式通过 PostgreSQL 的全文搜索扩展 jOOQ。

我的问题是 DSL.function 不“知道”我的自定义类/类型 TsQuery 和 TsVector 并引发异常。 Function 类本身没有公共构造函数。

org.jooq.exception.SQLDialectNotSupportedException:方言 DEFAULT 不支持类型类 jooq.fulltext.TsVector

class TsQuery

class TsVector

fun Field<String>.toTsVector(searchConfig: String): Field<TsVector> {
    return DSL.function(
        "to_tsvector",
        TsVector::class.java,
        DSL.inline(searchConfig),
        DSL.coalesce(this, "")
    )!!
}

fun String.toTsQuery(searchConfig: String): Field<TsQuery> {
    return DSL.function(
        "to_tsquery",
        TsQuery::class.java,
        DSL.inline(searchConfig),
        DSL.value(this)
    )!!
}

fun Field<TsVector>.tsMatches(query: Field<TsQuery>): Condition {
    return DSL.condition(
        "{0} @@ {1}",
        this,
        query
    )!!
}

fun Field<TsVector>.tsRank(query: Field<TsQuery>): Field<Double> {
    return DSL.function(
        "ts_rank",
        Double::class.java,
        this,
        query
    )!!
}

如果我将 TsQuery 和 TsVector 替换为 String 则它可以工作,但我会丢失输入。 我只想将它们用于查询构建,我不需要能够将这些类型解析/转换为 Kotlin。

【问题讨论】:

    标签: postgresql generics kotlin jooq


    【解决方案1】:

    虽然您可以使用内部类(例如 DefaultDataType (as in your own answer) 来实现此功能,但您不应该这样做,因为您的解决方案可能会在未来的任何次要版本甚至补丁版本中中断。

    在 jOOQ 中引入对新数据类型的支持的正确方法是实现 a converter or even better, a binding。绑定将允许您影响 jOOQ 如何将变量绑定到准备好的语句,以及它如何从结果集中读取它们。

    您的 toTsVector() 方法将如下所示(请原谅任何 Kotlin 错误,我是 Java 人):

    fun Field<String>.toTsVector(searchConfig: String): Field<TsVector> {
        return DSL.function(
            "to_tsvector",
            SQLDataType.OTHER.asConvertedDataType(MyTsVectorBinding()),
            DSL.inline(searchConfig),
            DSL.coalesce(this, "")
        )!!
    }
    

    现在可以实现了(我用的是Java,因为没有kotlin-fu,不过没关系):

    class MyTsVectorBinding implements Binding<Object, TsVector> {
        // ...
    }
    

    【讨论】:

    • 谢谢。我希望我可以避免创建转换器/绑定,因为我不打算在我的应用程序代码中实际使用 TsVectorTsQuery 类型的对象 - 理想情况下,我会将这两个对象保留为接口。
    【解决方案2】:

    即使不创建自定义转换器,也可以直接创建 DefaultDataType 对象。

    fun Field<String>.toTsVector(searchConfig: String): Field<TsVector> {
    
        return DSL.function(
            "to_tsvector",
            DefaultDataType(
                SQLDialect.POSTGRES,
                TsVector::class.java,
                "ts_vector"
            ),
            DSL.inline(searchConfig),
            DSL.coalesce(this, "")
        )!!
    }
    
    fun String.toTsQuery(searchConfig: String): Field<TsQuery> {
        return DSL.function(
            "to_tsquery",
            DefaultDataType(
                SQLDialect.POSTGRES,
                TsQuery::class.java,
                "ts_vector"
            ),
            DSL.inline(searchConfig),
            DSL.value(this)
        )!!
    }
    
    fun Field<TsVector>.tsMatches(query: Field<TsQuery>): Condition {
        return DSL.condition(
            "{0} @@ {1}",
            this,
            query
        )!!
    }
    
    fun Field<TsVector>.tsRank(query: Field<TsQuery>): Field<Double> {
        return DSL.function(
            "ts_rank",
            Double::class.java,
            this,
            query
        )!!
    }
    

    我在这方面花费的时间比我应该做的要多,我没有看到 the jOOQ manual 中提到的 DefaultDataType,所以可能有更好的方法我不知道。

    【讨论】:

      猜你喜欢
      • 2015-09-04
      • 2013-05-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-28
      • 2021-02-09
      • 2013-09-01
      • 2014-05-17
      相关资源
      最近更新 更多