Hello, I would like to share a field between multi...
# exposed
h
Hello, I would like to share a field between multiple tables and enforce the same naming and type (like a
creationDate
field for instance, or a
metadata
field referencing a different table). I am using a DAO approach and I was hopping to do something like :
Copy code
abstract class TableWithMetadata(name: String) : LongIdTable(name) {
    val creationDate = datetime("creation_date")
}


object DataTable : TableWithMetadata("data") {
    val title = varchar("title", length = MAX_STRING_LENGTH)
}
with
Copy code
abstract class DbDtoWithMetadata<T: TableWithMetadata>(id: EntityID<Long>) : LongEntity(id) {
    var creationDate by T.creationDate
}


class DataDbDto(id: EntityID<Long>) : DbDtoWithMetadata<DataTable>(id) {

    companion object : LongEntityClass<DataDbDto>(DataTable)

    var title by DataTable.title
}
and call it like that :
Copy code
transaction {
    DataDbDto.new {
        creationDate = LocalDateTime.now() // Or find a more generic way, so it applies automagically to all DbDto extending DbDtoWithMetadata
        title = data.title
    }
}
but this doesn't work due to a compilation error in
DbDtoWithMetadata
:
Type parameter 'T' cannot have or inherit a companion object, so it cannot be on the left-hand side of a dot.
Do you have a workaround or a better way to handle this use case ?
c
Hi @Helene Ballet For the entities, you could adjust the class signatures:
Copy code
abstract class DbDtoWithMetadata(
    id: EntityID<Long>,
    table: TableWithMetadata
) : LongEntity(id) {
    var creationDate by table.creationDate
}

class DataDbDto(id: EntityID<Long>) : DbDtoWithMetadata(id, DataTable) { }
For the automatic
creationDate
, there are some options depending on what you need or prefer: • Override `new()`:
Copy code
companion object : LongEntityClass<DataDbDto>(DataTable) {
    override fun new(id: Long?, init: DataDbDto.() -> Unit): DataDbDto {
        return super.new(id) {
            creationDate = LocalDateTime.now()
            init()
        }
    }
}
• Register the column with the default initializing function:
Copy code
datetime("creation_date").clientDefault { LocalDateTime.now() }
Here is a related section in the docs that shows an example of one way to set up abstract base entities.
h
Thank you so much, the part with
abstract class DbDtoWithMetadata
having
TableWithMetadata
as a parameter is exactly what I needed 🙏 Though I like the idea of overriding
new()
, I didn't want to do it for each implementation of
DbDtoWithMetadata
. I ended up going with a solution I found in the doc you linked, using
defaultExpression()
:
Copy code
abstract class TableWithMetadata(name: String) : LongIdTable(name) {
    val creationDate = datetime("creation_date").defaultExpression(CurrentDateTime)
}
👍 1
The hook to listen to entity changes is really interesting to know about, but I think it may be overkill for what I'm currently doing