Hi all! I wish to create some custom column types,...
# exposed
j
Hi all! I wish to create some custom column types, mainly to wrap inline classes for UUID's. I have multiple classes that wrap a UUID, and I was wondering that if there is any guide to help me through it? I could copy paste and adjust the UUIDColumnType, but I was wondering, is it somehow possible to wrap something around it?
Does this look any good?
Copy code
/**
 * Copy paste UUIDColumnType and map to UUIDWrapper instead of UUID
 */
class WrappedUUIDColumnType<T : UUIDWrapper> constructor(
    private val uuidToWrapper: (com.klitsie.pubquiz.common.util.UUID) -> T
) : ColumnType() {

    override fun sqlType(): String = currentDialect.dataTypeProvider.uuidType()

    override fun valueFromDB(value: Any): T = when {
        value is UUID -> value
        value is ByteArray -> ByteBuffer.wrap(value).let { b -> UUID(b.long, b.long) }
        value is String && value.matches(uuidRegexp) -> UUID.fromString(value)
        value is String -> ByteBuffer.wrap(value.toByteArray()).let { b -> UUID(b.long, b.long) }
        else -> error("Unexpected value of type UUID: $value of ${value::class.qualifiedName}")
    }.asUUID().let { uuidToWrapper(it) }

    override fun notNullValueToDB(value: Any): Any =
        currentDialect.dataTypeProvider.uuidToDB(valueToUUID(value))

    override fun nonNullValueToString(value: Any): String = "'${valueToUUID(value)}'"

    private fun valueToUUID(value: Any): UUID = when (value) {
        is UUIDWrapper -> value.uuid.asUUID()
        is UUID -> value
        is String -> UUID.fromString(value)
        is ByteArray -> ByteBuffer.wrap(value).let { UUID(it.long, it.long) }
        else -> error("Unexpected value of type UUID: ${value.javaClass.canonicalName}")
    }

    companion object {
        private val uuidRegexp = Regex(
            "[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}",
            RegexOption.IGNORE_CASE
        )
    }
}

/**
 * For every different uuid wrapper, create function
 */
fun Table.userId(name: String): Column<UserId> =
    registerColumn(name, WrappedUUIDColumnType { UserId(it) })

fun Table.teamId(name: String): Column<TeamId> =
    registerColumn(name, WrappedUUIDColumnType { TeamId(it) })

fun Table.eventId(name: String): Column<EventId> =
    registerColumn(name, WrappedUUIDColumnType { EventId(it) })
The uuid class I use is a multiplatform implementation btw, so I cannot just directly use java.util.UUID
e
what is the functionality you rely on for using UUID besides it’s uniqueness? If nothing, I recommend to store it as a plain
TEXT
j
Can you explain why you would use a TEXT to store a UUID? I am using uuids everywhere because of uniqueness, so why wouldn't I use the specific type for that? Doesn't using uuid also make sure it uses only the amount of space it is required to store a uuid? And I have some protection from people trying to put in random crap into the database
e
when you store it you don’t rely on any uuid functionality. You could just simply use UUID in memory, convert it to a string before persist and when reading back, parse it to uuid and you can work with it towards.
j
But what would be the benefit of that?
e
you simplify your code a lot.
but anyways, that was just a suggestion, feel free to do whatever you feel is convenient
j
Yeah it is a copy paste of the exposed uuid column type, with added wrapping. So I am not afraid of the complexity (I trust the library authors :D ), I am more interested in what the best way is to deal with inline classes (even if it is just wrapping a string)
113 Views