Whilst performing a WHERE clause operation on a custom Postgres "object type" I ended up the following PSQLException.

Exception

org.postgresql.util.PSQLException: ERROR: operator does not exist: rate = character varying
  Hint: No operator matches the given name and argument types. You might need to add explicit type casts.

I have followed the Ktorm official guides here but, there is no mention of custom Postgres types. Any pointers/help would be highly appreciated. See code below to reproduce:

Thank you.

  1. Example test that would produce the above exception
internal class SuppliersInstanceDAOTest {


    @Test
    fun shouldReturnInstanceSequence() {

        val database = Database.connect("jdbc:postgresql://localhost:5432/mydb", user = "postgres", password = "superpassword")

        val instanceDate: LocalDate = LocalDate.of(2019, 4, 1)
        database.withSchemaTransaction("suppliers") {
            database.from(SuppliersInstanceTable)
                .select(SuppliersInstanceTable.instanceSeq)
                .whereWithConditions {
                // The following line causes "ERROR: operator does not exist: rate = character varying"
                    it += SuppliersInstanceTable.rate eq Rate.DAILY
                }.asIterable()
                .first()
                .getInt(1)
        }
        
    }
}
  1. Schema
-- Note the special custom enum object type here that I cannot do anything about
CREATE TYPE suppliers.rate AS ENUM
    ('Daily', 'Byweekly');

CREATE TABLE suppliers.instance
(
    rate suppliers.rate NOT NULL,
    instance_value integer NOT NULL
)

TABLESPACE pg_default;

  1. Kotlin's Ktorms Entities and bindings

enum class Rate(val value: String) {
    DAILY("Daily"),
    BIWEEKLY("Byweekly")
}

interface SuppliersInstance : Entity<SuppliersInstance> {
    companion object : Entity.Factory<SuppliersInstance>()
    val rate: Rate
    val instanceSeq: Int
}

object SuppliersInstanceTable : Table<SuppliersInstance>("instance") {
    val rate = enum("rate", typeRef<Rate>()).primaryKey().bindTo { it.rate } // <-- Suspect
    //val rate = enum<Rate>("rate", typeRef()).primaryKey().bindTo { it.rate } // Failed too

    val instanceSeq = int("instance_value").primaryKey().bindTo { it.instanceSeq }
}
1

There are 1 answers

0
DaddyMoe On

After seeking help from the maintainers of Ktorm, it turns out there is support in the newer version of ktorm for native Postgressql enum object types. In my case I needed pgEnum instead of the default ktrom enum function that converts the enums to varchar causing the clash in types in Postressql:

Reference here for pgEnum

However, note at the time of writing ktorm's pgEnum function is only in ktorm v3.2.x +. The latest version available in Jcentral and mavenCentral maven repositories is v3.1.0. This is because there is also a group name change from me.liuwj.ktorm to org.ktorm in the latest version. So upgrading would also mean changing the group name in your dependencies for the new group name to match the maven repos. This was a seamless upgrade for my project and the new pgEnum worked in my use case.

For my code examples above, this would mean swapping this

object SuppliersInstanceTable : Table<SuppliersInstance>("instance") {
    val rate = enum("rate", typeRef<Rate>()).primaryKey().bindTo { it.rate } <---
    ...
}

For


object SuppliersInstanceTable : Table<SuppliersInstance>("instance") {
    val rate = pgEnum<Rate>("rate").primaryKey().bindTo { it.rate } <---
    ...
}