11import com.github.jasync.sql.db.ConnectionPoolConfiguration
2+ import com.github.jasync.sql.db.QueryResult
23import com.github.jasync.sql.db.SuspendingConnection
34import com.github.jasync.sql.db.asSuspending
45import com.github.jasync.sql.db.postgresql.PostgreSQLConnectionBuilder
5- import io.ktor.application.call
6- import io.ktor.application.install
7- import io.ktor.features.DefaultHeaders
8- import io.ktor.html.Placeholder
9- import io.ktor.html.Template
10- import io.ktor.html.insert
11- import io.ktor.html.respondHtmlTemplate
126import io.ktor.http.ContentType
13- import io.ktor.response.respondText
14- import io.ktor.routing.get
15- import io.ktor.routing.routing
7+ import io.ktor.server.application.*
168import io.ktor.server.engine.embeddedServer
9+ import io.ktor.server.html.*
1710import io.ktor.server.netty.Netty
18- import io.reactiverse.kotlin.pgclient.getConnectionAwait
19- import io.reactiverse.kotlin.pgclient.preparedBatchAwait
20- import io.reactiverse.kotlin.pgclient.preparedQueryAwait
21- import io.reactiverse.pgclient .*
11+ import io.ktor.server.plugins.defaultheaders.*
12+ import io.ktor.server.response.*
13+ import io.ktor.server.routing.*
14+ import kotlinx.coroutines .*
2215import kotlinx.html.*
2316import kotlinx.serialization.Serializable
24- import kotlinx.serialization.json.JSON
25- import kotlinx.serialization.list
17+ import kotlinx.serialization.encodeToString
18+ import kotlinx.serialization.json.Json
2619import java.lang.IllegalArgumentException
2720import kotlin.random.Random
2821import kotlin.random.nextInt
@@ -44,73 +37,48 @@ interface Repository {
4437}
4538
4639class JasyncRepository () : Repository {
47- private val dbConfig: ConnectionPoolConfiguration
48- private val db: SuspendingConnection
49-
50- init {
51- dbConfig = ConnectionPoolConfiguration (
52- " tfb-database" ,
53- database = " hello_world" ,
54- username = " benchmarkdbuser" ,
55- password = " benchmarkdbpass" ,
56- maxActiveConnections = 64
57- )
58- db = PostgreSQLConnectionBuilder .createConnectionPool(dbConfig).asSuspending
40+ companion object {
41+ const val WORLD_QUERY = " select id, randomNumber from world where id = ?"
42+ const val FORTUNES_QUERY = " select id, message from fortune"
43+ const val UPDATE_QUERY = " update world set randomNumber = ? where id = ?"
5944 }
6045
46+ private val dbConfig: ConnectionPoolConfiguration = ConnectionPoolConfiguration (
47+ " tfb-database" ,
48+ database = " hello_world" ,
49+ username = " benchmarkdbuser" ,
50+ password = " benchmarkdbpass" ,
51+ maxActiveConnections = 64
52+ )
53+ private val db: SuspendingConnection = PostgreSQLConnectionBuilder .createConnectionPool(dbConfig).asSuspending
54+
6155 override suspend fun getWorld (): World {
6256 val worldId = rand.nextInt(1 , 10000 )
63- val result = db.sendPreparedStatement(" select id, randomNumber from world where id = ? " , listOf (worldId))
57+ val result = db.sendPreparedStatement(WORLD_QUERY , listOf (worldId))
6458 val row = result.rows.first()
6559 return World (row.getInt(0 )!! , row.getInt(1 )!! )
6660 }
6761
6862 override suspend fun getFortunes (): List <Fortune > {
69- val results = db.sendPreparedStatement(" select id, message from fortune " )
63+ val results = db.sendPreparedStatement(FORTUNES_QUERY )
7064 return results.rows.map { Fortune (it.getInt(0 )!! , it.getString(1 )!! ) }
7165 }
7266
7367 override suspend fun updateWorlds (worlds : List <World >) {
74- worlds.forEach { world ->
75- db.sendPreparedStatement(
76- " update world set randomNumber = ? where id = ?" ,
77- listOf (world.randomNumber, world.id)
78- )
79- }
80- }
81- }
68+ coroutineScope {
69+ val jobs = ArrayList <Deferred <QueryResult >>(worlds.size)
70+ worlds.forEach { world ->
71+ val deferred = async(Dispatchers .IO ) {
72+ db.sendPreparedStatement(
73+ UPDATE_QUERY ,
74+ listOf (world.randomNumber, world.id)
75+ )
76+ }
77+ jobs.add(deferred)
78+ }
8279
83- class ReactivePGRepository : Repository {
84- private val db: PgPool
85-
86- init {
87- val poolOptions = PgPoolOptions ()
88- poolOptions.apply {
89- host = " tfb-database"
90- database = " hello_world"
91- user = " benchmarkdbuser"
92- password = " benchmarkdbpass"
93- maxSize = 64
94- cachePreparedStatements = true
80+ jobs.awaitAll()
9581 }
96- db = PgClient .pool(poolOptions)
97- }
98-
99- override suspend fun getFortunes (): List <Fortune > {
100- val results = db.preparedQueryAwait(" select id, message from fortune" )
101- return results.map { Fortune (it.getInteger(0 ), it.getString(1 )) }
102- }
103-
104- override suspend fun getWorld (): World {
105- val worldId = rand.nextInt(1 , 10000 )
106- val result = db.preparedQueryAwait(" select id, randomNumber from world where id = $1" , Tuple .of(worldId))
107- val row = result.first()
108- return World (row.getInteger(0 ), row.getInteger(1 )!! )
109- }
110-
111- override suspend fun updateWorlds (worlds : List <World >) {
112- val batch = worlds.map { Tuple .of(it.id, it.randomNumber) }
113- db.preparedBatchAwait(" update world set randomNumber = $1 where id = $2" , batch)
11482 }
11583}
11684
@@ -132,7 +100,7 @@ class MainTemplate : Template<HTML> {
132100 }
133101}
134102
135- class FortuneTemplate (val fortunes : List <Fortune >, val main : MainTemplate = MainTemplate ()) : Template<HTML> {
103+ class FortuneTemplate (private val fortunes : List <Fortune >, private val main : MainTemplate = MainTemplate ()) : Template<HTML> {
136104 override fun HTML.apply () {
137105 insert(main) {
138106 content {
@@ -156,13 +124,9 @@ class FortuneTemplate(val fortunes: List<Fortune>, val main: MainTemplate = Main
156124fun main (args : Array <String >) {
157125 val db = when (args.firstOrNull()) {
158126 " jasync-sql" -> JasyncRepository ()
159- " reactive-pg" -> ReactivePGRepository ()
160127 else -> throw IllegalArgumentException (" Must specify a postgres client" )
161128 }
162129
163- val messageSerializer = Message .serializer()
164- val worldSerializer = World .serializer()
165-
166130 val server = embeddedServer(Netty , 8080 , configure = {
167131 shareWorkGroup = true
168132 }) {
@@ -174,19 +138,19 @@ fun main(args: Array<String>) {
174138
175139 get(" /json" ) {
176140 call.respondText(
177- JSON .stringify(messageSerializer, Message (" Hello, World!" )),
141+ Json .encodeToString( Message (" Hello, World!" )),
178142 ContentType .Application .Json
179143 )
180144 }
181145
182146 get(" /db" ) {
183- call.respondText(JSON .stringify(worldSerializer, db.getWorld()), ContentType .Application .Json )
147+ call.respondText(Json .encodeToString( db.getWorld()), ContentType .Application .Json )
184148 }
185149
186150 get(" /query/" ) {
187151 val queries = call.parameters[" queries" ]?.toBoxedInt(1 .. 500 ) ? : 1
188152 val worlds = (1 .. queries).map { db.getWorld() }
189- call.respondText(JSON .stringify(worldSerializer.list, worlds), ContentType .Application .Json )
153+ call.respondText(Json .encodeToString( worlds), ContentType .Application .Json )
190154 }
191155
192156 get(" /fortunes" ) {
@@ -204,7 +168,7 @@ fun main(args: Array<String>) {
204168
205169 db.updateWorlds(newWorlds)
206170
207- call.respondText(JSON .stringify(worldSerializer.list, newWorlds), ContentType .Application .Json )
171+ call.respondText(Json .encodeToString( newWorlds), ContentType .Application .Json )
208172 }
209173 }
210174 }
0 commit comments