sqlc-dev/sqlc-gen-kotlin

Nullable Postgres Enum fails to compile and nullpointers

Opened this issue · 0 comments

Environment

  • Engine: postgresql
  • Plugin: sqlc-gen-kotlin_1.2.0.wasm / 22b437ecaea66417bbd3b958339d9868ba89368ce542c936c37305acf373104b
  • sqlc version: 1.28.0

Issue

Setup

I have the following migration.

CREATE TYPE mood AS ENUM ('happy', 'sad', 'angry');

ALTER TABLE IF EXISTS people ADD COLUMN mood mood;

I have the following queries.

-- name: ListPeople :many
SELECT id, name, mood
FROM people;

-- name: CreatePerson :exec
INSERT INTO people (name, age, mood)
VALUES ($1, $2, $3);

Generated Code

The generated models

enum class Mood(val value: String) {
  HAPPY("happy"),
  SAD("sad"),
  ANGRY("angry");

  companion object {
    private val map = Mood.values().associateBy(Mood::value)
    fun lookup(value: String) = map[value]
  }
}

data class Person (
  val id: Int,
  val name: String,
  val age: Int,
  val email: String?,
  val createdAt: LocalDateTime?,
  val mood: Mood?
)

Generated queries

  @Throws(SQLException::class)
  override fun createPerson(
      name: String,
      age: Int,
      mood: Mood?) {
    conn.prepareStatement(createPerson).use { stmt ->
      stmt.setString(1, name)
          stmt.setInt(2, age)
          stmt.setObject(3, mood.value, Types.OTHER)

      stmt.execute()
    }
  }

  @Throws(SQLException::class)
  override fun listPeople(): List<ListPeopleRow> {
    return conn.prepareStatement(listPeople).use { stmt ->
      
      val results = stmt.executeQuery()
      val ret = mutableListOf<ListPeopleRow>()
      while (results.next()) {
          ret.add(ListPeopleRow(
                results.getInt(1),
                results.getString(2),
                Mood.lookup(results.getString(3))!!
            ))
      }
      ret
    }

Errors

Compile Error

In the function createPerson since mood is nullable, we need to do mood?.value instead of mood.value. Kotlin will fail to compile.

Runtime Nullpointer

When calling listPeople(..), a nullpointer exception will be thrown. This is because

  • results.getString(3) is returning null and Mood.lookup(..) does not allow the argument to be nullable. The function signature is lookup(value: String)
  • If the lookup(..) function is updated to accept nullable, it will still throw an error because of the !! on Mood.lookup(results.getString(3))!! since null will be returned from lookup(..)

Proposed changes

  • If the enum is nullable, ensure we use ?. to get the value
  • Update the generated lookup(..) to accept nullable, if the column is nullable
  • If the column is nullable, do not add the !! when selecting the column

I have manually updated the generated code to do the above and things work for me.