Skip to content

Instantly share code, notes, and snippets.

@paulschuetz
Last active March 17, 2024 17:56
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save paulschuetz/a1f0d63d01a5435b2118941c35838f3d to your computer and use it in GitHub Desktop.
Save paulschuetz/a1f0d63d01a5435b2118941c35838f3d to your computer and use it in GitHub Desktop.
Exposed 0.30.2 CrudRepository Proposal
abstract class CrudRepository <ID, DOMAIN, TABLE : Table> {
abstract val table: TABLE
abstract fun toDomain(row: ResultRow): DOMAIN
abstract fun toRow(domain: DOMAIN): TABLE.(InsertStatement<Number>) -> Unit
abstract fun match(id: ID): SqlExpressionBuilder.() -> Op<Boolean>
abstract fun extractId(domain: DOMAIN): ID
abstract fun updateRow(domain: DOMAIN): TABLE.(UpdateStatement) -> Unit
/**
* Get a particular record by its ID.
*
* @param id The ID of the record to retrieve.
* @return The domain object which corresponds to the specified ID if operation was successful or null otherwise.
*/
fun get(id: ID): DOMAIN? = transaction {
table.select(where = match(id)).singleOrNull()?.let { toDomain(it) }
}
/**
* Simply retrieves all records.
*/
fun getAll(): List<DOMAIN> = transaction {
table.selectAll().map { toDomain(it) }
}
/**
* Creates a new record.
*
* @param domain The object to be created in its domain form.
* @return The newly created record if operation was successful or null otherwise.
*/
fun create(domain: DOMAIN): DOMAIN? = transaction {
table.insert(toRow(domain)).let {
it.resultedValues?.singleOrNull()?.let { toDomain(it) }
}
}
/**
* Updates an existing record.
*
* @param domain The domain object which will be updated.
* @return The freshly updated domain object if operation was successful or null otherwise.
*/
fun update(domain: DOMAIN): DOMAIN? = transaction {
table.update(where = match(extractId(domain)), body = updateRow(domain))
.let {
if(it == 0) null else get(extractId(domain))
}
}
/**
* Deletes the single record which corresponds to the specified ID.
*
* @param id The ID of the record to be deleted.
* @return The ID of the deleted record if operation was successful or null otherwise.
*/
fun delete(id: ID): ID? = transaction {
table.deleteWhere(op = match(id)).let {
if(it == 0) null else id
}
}
}
// Our Domain Object
data class Person(
val identityId: UUID,
val userName: String,
val givenName: String,
val familyName: String,
val email: String
)
// Our Table Definition
object Persons : Table("persons") {
val identityId = varchar("identityId", 36)
val userName = varchar("userName", 64)
val givenName = varchar("givenName", 64)
val familyName = varchar("familyName", 64)
val email = varchar("email", 64)
override val primaryKey = PrimaryKey(identityId)
}
// Exemplaratory CrudRepositry for managing Persons :-)
object PersonRepository : CrudRepository<UUID, Person, Persons>() {
override val table = Persons
override fun toDomain(row: ResultRow): Person {
return Person(
identityId = UUID.fromString(row[Persons.identityId]),
userName = row[Persons.userName],
givenName = row[Persons.givenName],
familyName = row[Persons.familyName],
email = row[Persons.email]
)
}
override fun toRow(domain: Person): Persons.(InsertStatement<Number>) -> Unit = {
it[identityId] = domain.identityId.toString()
it[userName] = domain.userName
it[givenName] = domain.givenName
it[familyName] = domain.familyName
it[email] = domain.email
}
override fun updateRow(domain: Person): Persons.(UpdateStatement) -> Unit = {
it[userName] = domain.userName
it[givenName] = domain.givenName
it[familyName] = domain.familyName
it[email] = domain.email
}
override fun match(id: UUID): SqlExpressionBuilder.() -> Op<Boolean> = {
Persons.identityId eq id.toString()
}
override fun extractId(domain: Person): UUID = domain.identityId
}
@mbunderline76
Copy link

really helpful, thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment