Can't reference on binary primaryKey
Hello, Is it a bug, that I can't reference on binary primaryKey ? Here is my case:
object Books : Table() {
val hash = binary("hash", 16).primaryKey()
val title = varchar("title", 256)
val author = varchar("author", 64)
val rating = integer("rating")
val goodreadsId = integer("goodreadsId").nullable()
}
and Quote references Book by it's hash
object Quotes : Table() {
val text = text("text").primaryKey()
val author = varchar("author", 64)
val bookHash = (binary("bookHash", 16) references Books.hash).nullable()
^^^^^^^^^^
}
And I'm getting error
None of the following substitutions
receiver: Column<ByteArray> arguments: (Column<ByteArray>)
receiver: Column<ByteArray> arguments: (Column<Comparable<Nothing>>)
receiver: Column<ByteArray> arguments: (Column<Comparable<ByteArray>>)
can be applied to
receiver: Column<ByteArray> arguments: (Column<ByteArray>)
Simple workaround would be replace binary(16) with varchar(32), but I just want to know.
Btw. here is how the hash is calculated using md5 function (I want to guarantee that only one book identified by title and author exists in the database), I wanted to use combined primaryKeys, but I couldn't figure out how to create references with them either
data class Book(
val title: String,
val author: String,
val rating: Int,
val goodreadsId: Int? = null,
) {
val hash: ByteArray = DigestUtils.md5(title + author)
}
At the moment only comparable types are allowed to be referenced, so as a workaround you could define your own function:
fun Column<ByteArray>.references(ref: Column<ByteArray>, onDelete: ReferenceOption? = null, onUpdate: ReferenceOption? = null) : Column<ByteArray> = apply {
referee = ref
this.onUpdate = onUpdate
this.onDelete = onDelete
}
To ensure that the only one title+author exists in database you could define a unique index for that field and use simple auto-increment field as a primary key.
Another option is to put DigestUtils.md5(title + author) as a clientDefault{ } value on a hash column.
@Tapac thanks for answer, could you please describe how clientDefault{ } works ? I cant find any documentation about it.
clientDefault function will be invoked before insert new value into a database if no explicit value was provided and value generated by a function will be inserted instead of null. But I'm not sure that it will be possible to receive values from another column.
Also, you could look for EntityHook object, but there is no documentation too :(
@Tapac For now I will stick with my current implementation of manually computing md5 hadh. But thank you very much for your help :).
Same issue.
I tried to create a column like this:
val id = binary("id", 8)
and made a reference in another table:
val userId = reference("userId", UserTable.id)
To make this work I had to create the following function:
fun Table.reference(name: String, refColumn: Column<ByteArray>): Column<ByteArray> {
return binary(name, (refColumn.columnType as BinaryColumnType).length)
}