1
1
import com.github.jasync.sql.db.ConnectionPoolConfiguration
2
+ import com.github.jasync.sql.db.QueryResult
2
3
import com.github.jasync.sql.db.SuspendingConnection
3
4
import com.github.jasync.sql.db.asSuspending
4
5
import 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
12
6
import 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.*
16
8
import io.ktor.server.engine.embeddedServer
9
+ import io.ktor.server.html.*
17
10
import 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 .*
22
15
import kotlinx.html.*
23
16
import 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
26
19
import java.lang.IllegalArgumentException
27
20
import kotlin.random.Random
28
21
import kotlin.random.nextInt
@@ -44,73 +37,48 @@ interface Repository {
44
37
}
45
38
46
39
class 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 = ?"
59
44
}
60
45
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
+
61
55
override suspend fun getWorld (): World {
62
56
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))
64
58
val row = result.rows.first()
65
59
return World (row.getInt(0 )!! , row.getInt(1 )!! )
66
60
}
67
61
68
62
override suspend fun getFortunes (): List <Fortune > {
69
- val results = db.sendPreparedStatement(" select id, message from fortune " )
63
+ val results = db.sendPreparedStatement(FORTUNES_QUERY )
70
64
return results.rows.map { Fortune (it.getInt(0 )!! , it.getString(1 )!! ) }
71
65
}
72
66
73
67
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
+ }
82
79
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()
95
81
}
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)
114
82
}
115
83
}
116
84
@@ -132,7 +100,7 @@ class MainTemplate : Template<HTML> {
132
100
}
133
101
}
134
102
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> {
136
104
override fun HTML.apply () {
137
105
insert(main) {
138
106
content {
@@ -156,13 +124,9 @@ class FortuneTemplate(val fortunes: List<Fortune>, val main: MainTemplate = Main
156
124
fun main (args : Array <String >) {
157
125
val db = when (args.firstOrNull()) {
158
126
" jasync-sql" -> JasyncRepository ()
159
- " reactive-pg" -> ReactivePGRepository ()
160
127
else -> throw IllegalArgumentException (" Must specify a postgres client" )
161
128
}
162
129
163
- val messageSerializer = Message .serializer()
164
- val worldSerializer = World .serializer()
165
-
166
130
val server = embeddedServer(Netty , 8080 , configure = {
167
131
shareWorkGroup = true
168
132
}) {
@@ -174,19 +138,19 @@ fun main(args: Array<String>) {
174
138
175
139
get(" /json" ) {
176
140
call.respondText(
177
- JSON .stringify(messageSerializer, Message (" Hello, World!" )),
141
+ Json .encodeToString( Message (" Hello, World!" )),
178
142
ContentType .Application .Json
179
143
)
180
144
}
181
145
182
146
get(" /db" ) {
183
- call.respondText(JSON .stringify(worldSerializer, db.getWorld()), ContentType .Application .Json )
147
+ call.respondText(Json .encodeToString( db.getWorld()), ContentType .Application .Json )
184
148
}
185
149
186
150
get(" /query/" ) {
187
151
val queries = call.parameters[" queries" ]?.toBoxedInt(1 .. 500 ) ? : 1
188
152
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 )
190
154
}
191
155
192
156
get(" /fortunes" ) {
@@ -204,7 +168,7 @@ fun main(args: Array<String>) {
204
168
205
169
db.updateWorlds(newWorlds)
206
170
207
- call.respondText(JSON .stringify(worldSerializer.list, newWorlds), ContentType .Application .Json )
171
+ call.respondText(Json .encodeToString( newWorlds), ContentType .Application .Json )
208
172
}
209
173
}
210
174
}
0 commit comments