没有自定义转换器的 jOOQ 查询表达式类型安全
jOOQ query expression type-safety without custom converter
我正在尝试使用 Kotlin 的扩展函数以类型安全的方式使用 PostgreSQL 的全文搜索扩展 jOOQ。
我的问题是 DSL.function 没有 "know" 我的自定义 classes/types TsQuery 和 TsVector 并抛出异常。函数 class 本身没有 public 构造函数。
org.jooq.exception.SQLDialectNotSupportedException: Type class jooq.fulltext.TsVector is not supported in dialect DEFAULT
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 则它可以工作,但我松散了输入。
我只想将它们用于查询构建,我不需要能够 parse/convert 这些类型 to/from Kotlin。
即使不创建自定义转换器,也可以直接创建 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,所以可能有更好的方法我不知道。
虽然您可以使用内部 类 使其工作,例如 DefaultDataType
(),但您不应该这样做,因为您的解决方案可能会在未来的任何次要版本中中断,甚至补丁发布。
在 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> {
// ...
}
我正在尝试使用 Kotlin 的扩展函数以类型安全的方式使用 PostgreSQL 的全文搜索扩展 jOOQ。
我的问题是 DSL.function 没有 "know" 我的自定义 classes/types TsQuery 和 TsVector 并抛出异常。函数 class 本身没有 public 构造函数。
org.jooq.exception.SQLDialectNotSupportedException: Type class jooq.fulltext.TsVector is not supported in dialect DEFAULT
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 则它可以工作,但我松散了输入。 我只想将它们用于查询构建,我不需要能够 parse/convert 这些类型 to/from Kotlin。
即使不创建自定义转换器,也可以直接创建 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,所以可能有更好的方法我不知道。
虽然您可以使用内部 类 使其工作,例如 DefaultDataType
(
在 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> {
// ...
}