Безопасность типов выражений запросов jOOQ без специального конвертера - PullRequest
1 голос
/ 24 марта 2020

Я пытаюсь расширить jOOQ с помощью полнотекстового поиска PostgreSQL безопасным шрифтом, используя функции расширения Kotlin.

Моя проблема в том, что DSL.function не "знает" "мои пользовательские классы / типы TsQuery и TsVector и создает исключение. Сам класс Function не имеет конструктора publi c.

org.jooq.exception.SQLDialectNotSupportedException: класс типа jooq.fulltext.TsVector не поддерживается в диалекте 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, то это сработает, но я потерял набор текста. Я хочу использовать их только для построения запросов, мне не нужно иметь возможность анализировать / преобразовывать эти типы в / из Kotlin.

Ответы [ 2 ]

1 голос
/ 25 марта 2020

Хотя вы можете заставить это работать, используя внутренние классы, такие как DefaultDataType ( как в вашем собственном ответе ), вы не должны этого делать, так как ваше решение может сломаться в любом будущем небольшом выпуске или даже выпуск патча.

Правильный способ внедрить поддержку новых типов данных в jOOQ - реализовать конвертер или, что еще лучше, привязку . Привязка позволит вам влиять на то, как jOOQ связывает переменные с подготовленными операторами и как она читает их из наборов результатов.

Ваш метод toTsVector() будет выглядеть так (извините за любые ошибки Kotlin, я ' m * 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> {
    // ...
}
1 голос
/ 24 марта 2020

Создание объекта 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
    )!!
}

Я потратил на это гораздо больше времени, чем следовало бы, и я не вижу DefaultDataType, упомянутого в Руководство jOOQ так что, может быть, есть лучший способ, о котором я не знаю.

...