Skip to content

Instantly share code, notes, and snippets.

@grv87
Forked from paulschuetz/CrudRepositoryProposal.kt
Last active December 9, 2021 01:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save grv87/2a4969dc1277e43df4d22032919a0026 to your computer and use it in GitHub Desktop.
Save grv87/2a4969dc1277e43df4d22032919a0026 to your computer and use it in GitHub Desktop.
Exposed 0.30.2 CrudRepository Proposal
import java.util.UUID
import org.jetbrains.exposed.dao.id.IdTable
import org.jetbrains.exposed.sql.Op
import org.jetbrains.exposed.sql.ResultRow
import org.jetbrains.exposed.sql.SqlExpressionBuilder
import org.jetbrains.exposed.sql.deleteWhere
import org.jetbrains.exposed.sql.insert
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.statements.UpdateBuilder
import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.sql.update
interface Entity<ID> {
val id: ID
}
abstract class CrudRepository <DOMAIN_ID, DOMAIN : Entity<DOMAIN_ID>, DB_ID : Comparable<DB_ID>, TABLE : IdTable<DB_ID>> {
abstract val table: TABLE
abstract fun TABLE.toDomain(row: ResultRow): DOMAIN
abstract fun toRow(domain: DOMAIN): TABLE.(UpdateBuilder<Int>) -> Unit
abstract fun idToDb(id: DOMAIN_ID): DB_ID
abstract fun idFromDb(id: DB_ID): DOMAIN_ID
private fun match(id: DOMAIN_ID): SqlExpressionBuilder.() -> Op<Boolean> = {
table.id eq idToDb(id)
}
/**
* 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: DOMAIN_ID): DOMAIN? = transaction {
table.select(where = match(id)).singleOrNull()?.let { table.toDomain(it) }
}
/**
* Simply retrieves all records.
*/
fun getAll(): List<DOMAIN> = transaction {
table.selectAll().map { table.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 {
val id = domain.id
table.insert {
toRow(domain)
it[table.id] = idToDb(id)
}
get(id)
}
/**
* 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 {
val id = domain.id
table.update(where = match(id), body = toRow(domain))
.let {
if(it == 0) null else get(id)
}
}
/**
* 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: DOMAIN_ID): DOMAIN_ID? = transaction {
table.deleteWhere(op = match(id)).let {
if(it == 0) null else id
}
}
}
// Our Domain Object
data class Person(
override val id: UUID,
val userName: String,
val givenName: String,
val familyName: String,
val email: String
) : Entity<UUID>
// Our Table Definition
object Persons : IdTable<String>("persons") {
override val id = varchar("identityId", 36).entityId()
val userName = varchar("userName", 64)
val givenName = varchar("givenName", 64)
val familyName = varchar("familyName", 64)
val email = varchar("email", 64)
override val primaryKey = PrimaryKey(id)
}
// Exemplaratory CrudRepository for managing Persons :-)
object PersonRepository : CrudRepository<UUID, Person, String, Persons>() {
override val table = Persons
override fun Persons.toDomain(row: ResultRow): Person {
return Person(
idFromDb(row[id].value),
row[userName],
row[givenName],
row[familyName],
row[email]
)
}
override fun toRow(domain: Person): Persons.(UpdateBuilder<Int>) -> Unit = {
it[userName] = domain.userName
it[givenName] = domain.givenName
it[familyName] = domain.familyName
it[email] = domain.email
}
override fun idToDb(id: UUID): String = id.toString()
override fun idFromDb(id: String): UUID = UUID.fromString(id)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment