Skip to content

Instantly share code, notes, and snippets.

@felix19350
Last active July 15, 2023 12:42
Show Gist options
  • Select an option

  • Save felix19350/bcb39e50820dcc6872f624d2e925dd9a to your computer and use it in GitHub Desktop.

Select an option

Save felix19350/bcb39e50820dcc6872f624d2e925dd9a to your computer and use it in GitHub Desktop.

Revisions

  1. felix19350 revised this gist Feb 21, 2019. 1 changed file with 6 additions and 6 deletions.
    12 changes: 6 additions & 6 deletions ktor-full-example.kt
    Original file line number Diff line number Diff line change
    @@ -27,7 +27,7 @@ data class CreateMyAppUserCommand(val email: String, val realName: String)
    // Core service definition
    internal interface MyAppUserService {
    suspend fun list(): List<MyAppUser>
    suspend fun create(email: String, realName: String): MyAppUser
    suspend fun create(newUserCmd: CreateMyAppUserCommand): MyAppUser
    }

    // Data store connection setup shennanigans
    @@ -80,11 +80,11 @@ internal class MyAppUserServiceImpl(private val dbc: DatastoreConnection) : MyAp
    }
    }

    override suspend fun create(email: String, realName: String): MyAppUser {
    override suspend fun create(newUserCmd: CreateMyAppUserCommand): MyAppUser {
    return dbc.query {
    MyAppUserDAO.new {
    this.email = email
    this.realName = realName
    this.email = newUserCmd.email
    this.realName = newUserCmd.realName
    }.toModel()
    }
    }
    @@ -100,8 +100,8 @@ fun Route.sampleApi() {
    }

    post("/myUsers") {
    val command: CreateMyAppUserCommand = call.receive()
    val newUser = service.create(command.email, command.realName)
    //Don't forget to validate the input...
    val newUser = service.create(call.receive())
    call.respond(HttpStatusCode.OK, newUser)
    }
    }
  2. felix19350 created this gist Feb 21, 2019.
    107 changes: 107 additions & 0 deletions ktor-full-example.kt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,107 @@
    package org.example

    import com.zaxxer.hikari.HikariConfig
    import com.zaxxer.hikari.HikariDataSource
    import io.ktor.application.call
    import io.ktor.http.HttpStatusCode
    import io.ktor.request.receive
    import io.ktor.response.respond
    import io.ktor.routing.Route
    import io.ktor.routing.get
    import io.ktor.routing.post
    import kotlinx.coroutines.experimental.Dispatchers
    import kotlinx.coroutines.experimental.withContext
    import org.jetbrains.exposed.dao.EntityID
    import org.jetbrains.exposed.dao.LongEntity
    import org.jetbrains.exposed.dao.LongEntityClass
    import org.jetbrains.exposed.dao.LongIdTable
    import org.jetbrains.exposed.sql.Database
    import org.jetbrains.exposed.sql.transactions.transaction
    import javax.sql.DataSource

    // Data model - data classes for input and output formats
    data class MyAppUser(val email: String, val realName: String)

    data class CreateMyAppUserCommand(val email: String, val realName: String)

    // Core service definition
    internal interface MyAppUserService {
    suspend fun list(): List<MyAppUser>
    suspend fun create(email: String, realName: String): MyAppUser
    }

    // Data store connection setup shennanigans
    fun quickNDirtyDb(): DataSource {
    return HikariDataSource(HikariConfig().apply {
    poolName = "HIKARI-POOL"
    driverClassName = "org.h2.Driver"
    jdbcUrl = "jdbc:h2:mem:test"
    maximumPoolSize = 5
    isAutoCommit = false
    transactionIsolation = "TRANSACTION_READ_COMMITTED"
    validate()
    })
    }

    class DatastoreConnection(private val dataSource: DataSource) {
    private val database: Database by lazy {
    Database.connect(dataSource)
    }

    suspend fun <T> query(block: () -> T): T = withContext(Dispatchers.IO) {
    transaction(database) {
    block()
    }
    }
    }

    // Object relational mapping
    internal object MyAppUserTable : LongIdTable("my_app_user_table") {
    val email = varchar("user_email", 255).uniqueIndex()
    val realName = varchar("real_name", 255)
    }

    internal class MyAppUserDAO(id: EntityID<Long>) : LongEntity(id) {
    companion object : LongEntityClass<MyAppUserDAO>(MyAppUserTable)

    var email by MyAppUserTable.email
    var realName by MyAppUserTable.realName

    fun toModel(): MyAppUser {
    return MyAppUser(email, realName)
    }
    }

    // Service implementation for datastore of choice
    internal class MyAppUserServiceImpl(private val dbc: DatastoreConnection) : MyAppUserService {
    override suspend fun list(): List<MyAppUser> {
    return dbc.query {
    MyAppUserDAO.all().map { it.toModel() }
    }
    }

    override suspend fun create(email: String, realName: String): MyAppUser {
    return dbc.query {
    MyAppUserDAO.new {
    this.email = email
    this.realName = realName
    }.toModel()
    }
    }
    }

    //REST-ish API
    fun Route.sampleApi() {

    val service: MyAppUserService = MyAppUserServiceImpl(DatastoreConnection(quickNDirtyDb()))

    get("/myUsers") {
    call.respond(HttpStatusCode.OK, service.list())
    }

    post("/myUsers") {
    val command: CreateMyAppUserCommand = call.receive()
    val newUser = service.create(command.email, command.realName)
    call.respond(HttpStatusCode.OK, newUser)
    }
    }