Skip to content

Feature Enhancement: support for postgres enums #12

@DALDEI

Description

@DALDEI

Current project I am using postgres for the first time.
Having used Mysql Enums in the past, and being a fan of typed data -- I ended up with a postgres style enum. Turns out its not quite so easy to use -- in the db, jdbc, sql2o or vok-orm
But not impossible --

This is what I did to make it work for me -- there may well be much better ways.
First off -- the naive thing to assume is "It just works" -- the error one gets attemping to put a Enum value into a query or insert is not obvious -- it is a side effect of postgress exposing somewhat the fact that enums are user defined types but not enough to use them :)
So you get an error about the expression expecting a user defined type but being given a varying.
( google saved the day again )

To work around -- one needs to explicitly add a cast to the SQL. I used a custom SQL (thank you for assuming that one needs to do that sometimes !!!) like this:
This is a simple generic function that updates 1 property of a kotlin class into 1 field in a DB table.
Called like

    field = MyEnumValue
    update( ::field )  // for normal fields
    update(::field, "::my_user_defined_type" ) // for enums and other convertable user types

  fun update(property : KMutableProperty0<*>,cast:String="" /* for status enum */) = db {
    con.createQuery("UPDATE devices SET ${property.name} = :value${cast} WHERE id = :id")
      .addParameter( "value" , property.getter.call() )
      .addParameter("id", id )
      .executeUpdate()

The relevant bit is the "${cast}" which will insert the "::my_user_defined_type" to create ":value::my_user_defined_type"

I wasn't sure how well vok or sql2o would handle this expressing given that it includes a ":" -- but it did.

To READ the DB with the enum I made a custom converter -- I didnt put the effort into making it fully generic -- the reified types and kotlin enum reflection is a bit subtle and under-implemented.
SO I hard coded the single enum "ConversionState" -- a creative author should be able to extend this genericly

   VokOrm.dataSourceConfig.apply {
  ... configuration code ...
... then this call 
   registerEnumConverter( object : EnumConverterFactory {
      override fun <E : Enum<out Enum<*>>?> newConverter(enumClass : Class<E>?) : Converter<E> =
        object : Converter<E> {
          override fun toDatabaseParam(v : E) : Any = (v as ConversionState).name

          override fun convert(v : Any?) : E = ConversionState.valueOf(v.toString()) as E

        }
    })
}


Metadata

Metadata

Assignees

Labels

bugSomething isn't workingwaiting for upstreamThis is a bug in a library dependency

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions