All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.lenses.jdbc4.resultset.AvroSchemaResultSetMetaData.kt Maven / Gradle / Ivy

There is a newer version: 3.0.2
Show newest version
package io.lenses.jdbc4.resultset

import io.lenses.jdbc4.AvroSchemas
import io.lenses.jdbc4.IWrapper
import org.apache.avro.LogicalTypes
import org.apache.avro.Schema
import java.sql.ResultSetMetaData
import java.sql.SQLException

class AvroSchemaResultSetMetaData(private val schema: Schema) : ResultSetMetaData, io.lenses.jdbc4.IWrapper {

  override fun getTableName(column: Int): String = schema.name

  override fun isNullable(column: Int): Int {
    return when (schemaForIndex(column).isNullable) {
      true -> ResultSetMetaData.columnNullable
      false -> ResultSetMetaData.columnNullableUnknown
    }
  }

  override fun isWrapperFor(iface: Class<*>?): Boolean = _isWrapperFor(iface)
  override fun  unwrap(iface: Class): T = _unwrap(iface)
  override fun isDefinitelyWritable(column: Int): Boolean = false

  override fun isSearchable(column: Int): Boolean = true

  override fun getPrecision(column: Int): Int {
    val schema = schemaForIndex(column)
    return when (typeForIndex(column)) {
      Schema.Type.BYTES ->
        when (schema.logicalType) {
          is LogicalTypes.Decimal -> (schema.logicalType as LogicalTypes.Decimal).precision
          else -> 0
        }
      Schema.Type.FIXED -> schema.fixedSize
      Schema.Type.STRING -> Int.MAX_VALUE
      else -> 0
    }
  }

  override fun isCaseSensitive(column: Int): Boolean = true

  override fun getScale(column: Int): Int {
    return when (typeForIndex(column)) {
      Schema.Type.BYTES -> {
        when (val logicalType = schemaForIndex(column).logicalType) {
          is LogicalTypes.Decimal -> logicalType.scale
          else -> 0
        }
      }
      else -> 0
    }
  }

  // required "" when not supported
  override fun getSchemaName(column: Int): String = ""

  // required "" when not supported
  override fun getCatalogName(column: Int): String = ""

  override fun getColumnClassName(column: Int): String {
    val type = typeForIndex(column)
    return io.lenses.jdbc4.AvroSchemas.jvmClassName(type)
  }

  override fun getColumnType(column: Int): Int {
    val schema = schemaForIndex(column)
    return AvroSchemas.sqlType(schema)
  }

  override fun isCurrency(column: Int): Boolean = false

  override fun getColumnName(column: Int): String = getColumnLabel(column)
  override fun getColumnLabel(column: Int): String {
    return when (schema.type) {
      Schema.Type.RECORD -> schema.fields[column - 1].name()
      else -> "unnamed"
    }
  }

  override fun isWritable(column: Int): Boolean = false

  override fun isReadOnly(column: Int): Boolean = true

  override fun isSigned(column: Int): Boolean {
    val type = typeForIndex(column)
    val schema = schemaForIndex(column)
    return when (type) {
      Schema.Type.BYTES ->
        when (schema.logicalType) {
          is LogicalTypes.Decimal -> true
          else -> false
        }
      Schema.Type.DOUBLE -> true
      Schema.Type.FLOAT -> true
      Schema.Type.INT ->
        when (schema.logicalType) {
          is LogicalTypes.TimeMillis -> false
          is LogicalTypes.Date -> false
          else -> true
        }
      Schema.Type.LONG ->
        when (schema.logicalType) {
          is LogicalTypes.TimestampMillis -> false
          is LogicalTypes.TimestampMicros -> false
          is LogicalTypes.TimeMicros -> false
          else -> true
        }
      else -> false
    }
  }

  override fun getColumnTypeName(column: Int): String = typeForIndex(column).name

  private fun schemaForIndex(index: Int): Schema {
    return when (schema.type) {
      Schema.Type.RECORD -> {
        if (index < 1 || index > schema.fields.size)
          throw IndexOutOfBoundsException("Index $index is out of bounds; note: JDBC drivers are 1-indexed")
        schema.fields[index - 1].schema()
      }
      else -> {
        if (index != 1)
          throw IndexOutOfBoundsException("Index $index is out of bounds; note: JDBC drivers are 1-indexed")
        schema
      }
    }
  }

  private fun typeForIndex(index: Int): Schema.Type {
    return when (schema.type) {
      Schema.Type.RECORD -> {
        if (index < 1 || index > schema.fields.size)
          throw IndexOutOfBoundsException("Index $index is out of bounds; note: JDBC drivers are 1-indexed")
        schema.fields[index - 1].schema().type
      }
      else -> {
        if (index != 1)
          throw IndexOutOfBoundsException("Index $index is out of bounds; note: JDBC drivers are 1-indexed")
        schema.type
      }
    }
  }

  override fun isAutoIncrement(column: Int): Boolean = false

  override fun getColumnDisplaySize(column: Int): Int = 0

  override fun getColumnCount(): Int {
    // can be a record or a single field
    return when (schema.type) {
      Schema.Type.RECORD -> schema.fields.size
      else -> 1
    }
  }

  // returns the index for a given column label
  // 1-indexed
  internal fun indexForLabel(label: String): Int {
    val index = schema.fields.indexOfFirst { it.name() == label }
    if (index < 0 || index > schema.fields.size - 1)
      throw SQLException("Unknown column $label")
    return index + 1
  }

  // returns the field for a given column label
  internal fun fieldForLabel(label: String): Schema.Field {
    return schema.fields.find { it.name() == label } ?: throw SQLException("Unknown column $label")
  }
}

fun ResultSetMetaData.indexForLabel(label: String): Int = when (this) {
  is AvroSchemaResultSetMetaData -> this.indexForLabel(label)
  else -> throw UnsupportedOperationException()
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy