com.dbobjekts.metadata.ColumnFactory.kt Maven / Gradle / Ivy
package com.dbobjekts.metadata
import com.dbobjekts.api.AnyColumn
import com.dbobjekts.api.exception.CodeGenerationException
import com.dbobjekts.api.exception.StatementExecutionException
import com.dbobjekts.metadata.column.*
import java.lang.reflect.Constructor
import java.math.BigDecimal
import java.sql.Blob
import java.sql.Clob
import java.sql.SQLXML
import java.time.Instant
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.OffsetDateTime
import java.time.ZonedDateTime
object ColumnFactory {
private val table = DefaultTable
private const val DUMMY = "dummy"
val VARCHAR = VarcharColumn(table, DUMMY)
val VARCHAR_NIL = NullableVarcharColumn(table, DUMMY)
val LONG = LongColumn(table, DUMMY)
val LONG_NIL = NullableLongColumn(table, DUMMY)
val INTEGER = IntegerColumn(table, DUMMY)
val INTEGER_NIL = NullableIntegerColumn(table, DUMMY)
val SHORT = ShortColumn(table, DUMMY)
val SHORT_NIL = NullableShortColumn(table, DUMMY)
val BYTE_ARRAY = ByteArrayColumn(table, DUMMY)
val BYTE_ARRAY_NIL = NullableByteArrayColumn(table, DUMMY)
val BLOB = BlobColumn(table, DUMMY)
val BLOB_NIL = NullableBlobColumn(table, DUMMY)
val CLOB = ClobColumn(table, DUMMY)
val CLOB_NIL = NullableClobColumn(table, DUMMY)
val BYTE = ByteColumn(table, DUMMY)
val BYTE_NIL = NullableByteColumn(table, DUMMY)
val BOOLEAN = BooleanColumn(table, DUMMY)
val BOOLEAN_NIL = NullableBooleanColumn(table, DUMMY)
val NUMBER_AS_BOOLEAN = NumberAsBooleanColumn(table, DUMMY)
val NUMBER_AS_BOOLEAN_NIL = NullableNumberAsBooleanColumn(table, DUMMY)
val DOUBLE = DoubleColumn(table, DUMMY)
val DOUBLE_NIL = NullableDoubleColumn(table, DUMMY)
val FLOAT = FloatColumn(table, DUMMY)
val FLOAT_NIL = NullableFloatColumn(table, DUMMY)
val BIGDECIMAL = BigDecimalColumn(table, DUMMY)
val BIGDECIMAL_NIL = NullableBigDecimalColumn(table, DUMMY)
val DATE = DateColumn(table, DUMMY)
val DATE_NIL = NullableDateColumn(table, DUMMY)
val DATETIME = DateTimeColumn(table, DUMMY)
val DATETIME_NIL = NullableDateTimeColumn(table, DUMMY)
val TIME = TimeColumn(table, DUMMY)
val TIME_NIL = NullableTimeColumn(table, DUMMY)
val TIMESTAMP = TimeStampColumn(table, DUMMY)
val TIMESTAMP_NIL = NullableTimeStampColumn(table, DUMMY)
val OFFSET_DATETIME = OffsetDateTimeColumn(table, DUMMY)
val OFFSET_DATETIME_NIL = NullableOffsetDateTimeColumn(table, DUMMY)
val SQLXML = XMLColumn(table, DUMMY)
val SQLXML_NIL = NullableXMLColumn(table, DUMMY)
val AUTOKEY_LONG = AutoKeyLongColumn(table, DUMMY)
val AUTOKEY_INTEGER = AutoKeyIntegerColumn(table, DUMMY)
val SEQUENCE_LONG = SequenceKeyLongColumn(table, DUMMY, "")
val SEQUENCE_INTEGER = SequenceKeyIntegerColumn(table, DUMMY, "")
val FOREIGN_KEY_LONG = ForeignKeyLongColumn(table, DUMMY, LONG)
val FOREIGN_KEY_LONG_NIL = OptionalForeignKeyLongColumn(table, DUMMY, LONG)
val FOREIGN_KEY_INT = ForeignKeyIntColumn(table, DUMMY, INTEGER)
val FOREIGN_KEY_INT_NIL = OptionalForeignKeyIntColumn(table, DUMMY, INTEGER)
val FOREIGN_KEY_VARCHAR = ForeignKeyVarcharColumn(table, DUMMY, VARCHAR)
val FOREIGN_KEY_VARCHAR_NIL = OptionalForeignKeyVarcharColumn(table, DUMMY, VARCHAR)
fun varcharColumn(nullable: Boolean = false): Column = if (nullable) VARCHAR_NIL else VARCHAR
fun longColumn(nullable: Boolean = false): Column = if (nullable) LONG_NIL else LONG
fun integerColumn(nullable: Boolean = false): Column = if (nullable) INTEGER_NIL else INTEGER
fun shortColumn(nullable: Boolean = false): Column = if (nullable) SHORT_NIL else SHORT
fun byteArrayColumn(nullable: Boolean = false): Column = if (nullable) BYTE_ARRAY_NIL else BYTE_ARRAY
fun blobColumn(nullable: Boolean = false): Column = if (nullable) BLOB_NIL else BLOB
fun clobColumn(nullable: Boolean = false): Column = if (nullable) CLOB_NIL else CLOB
fun byteColumn(nullable: Boolean = false): Column = if (nullable) BYTE_NIL else BYTE
fun booleanColumn(nullable: Boolean = false): Column = if (nullable) BOOLEAN_NIL else BOOLEAN
fun numberAsBooleanColumn(nullable: Boolean = false): Column = if (nullable) NUMBER_AS_BOOLEAN_NIL else NUMBER_AS_BOOLEAN
fun doubleColumn(nullable: Boolean = false): Column = if (nullable) DOUBLE_NIL else DOUBLE
fun floatColumn(nullable: Boolean = false): Column = if (nullable) FLOAT_NIL else FLOAT
fun bigDecimalColumn(nullable: Boolean = false): Column = if (nullable) BIGDECIMAL_NIL else BIGDECIMAL
fun dateColumn(nullable: Boolean = false): Column = if (nullable) DATE_NIL else DATE
fun dateTimeColumn(nullable: Boolean = false): Column = if (nullable) DATETIME_NIL else DATETIME
fun timeColumn(nullable: Boolean = false): Column = if (nullable) TIME_NIL else TIME
fun timeStampColumn(nullable: Boolean = false): Column = if (nullable) TIMESTAMP_NIL else TIMESTAMP
fun offsetDateTimeColumn(nullable: Boolean = false): Column =
if (nullable) OFFSET_DATETIME_NIL else OFFSET_DATETIME
fun xmlColumn(nullable: Boolean = false): Column = if (nullable) SQLXML_NIL else SQLXML
@Suppress("UNCHECKED_CAST")
fun > forClass(clz: Class): C {
return getConstructor(clz).newInstance(table, DUMMY, null) as C
}
@Suppress("UNCHECKED_CAST")
fun > forClassAsNullable(clz: Class): C {
return getConstructor(clz).newInstance(table, DUMMY, null) as C
}
@Suppress("UNCHECKED_CAST")
internal fun nullableColumn(col: NonNullableColumn): NullableColumn {
val clz = col::class.java
val pkg = clz.packageName
return createColumnInstance(col, "$pkg.Nullable${clz.simpleName}") as NullableColumn
}
@Suppress("UNCHECKED_CAST")
internal fun distinctClone(col: Column): Column {
val clz = col::class.java
val pkg = clz.packageName
return createColumnInstance(col, "$pkg.${clz.simpleName}", AggregateType.DISTINCT) as Column
}
private fun createColumnInstance(col: AnyColumn, newName: String, aggregateType: AggregateType? = null): Any {
val nullableClass = getColumnClass(newName)
val constructor = getConstructor(nullableClass)
try {
return constructor.newInstance(col.table, col.nameInTable, aggregateType ?: col.aggregateType)
} catch (e: Exception) {
throw CodeGenerationException("Error generating new instance of $newName", e)
}
}
private fun getColumnClass(newName: String): Class<*> {
try {
return Class.forName(newName)
} catch (e: Exception) {
throw CodeGenerationException(
"Unable to obtain Class reference for $newName. " +
"Make sure it exists", e
)
}
}
private fun getConstructor(clz: Class<*>): Constructor<*> {
return clz.constructors
.filter {
it.parameterCount == 3
&& it.parameters[0].type == Table::class.java
&& it.parameters[1].type == String::class.java
&& it.parameters[2].type == AggregateType::class.java
}
.firstOrNull()
?: throw CodeGenerationException("Class $clz does not define a constructor with (table: Table, name: String, aggregateType: AggregateType")
}
@Suppress("UNCHECKED_CAST")
fun getColumnForValue(value: T): Column =
when (value) {
is Int -> INTEGER
is Double -> DOUBLE
is Long -> LONG
is String -> VARCHAR
is LocalDateTime -> DATETIME
is LocalDate -> DATE
is ZonedDateTime -> OFFSET_DATETIME
is Boolean -> BOOLEAN
else -> throw StatementExecutionException("Type $value not supported for parameter: only Int, Long, Double, Date or String")
} as Column
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy