Skip to content

Commit 0ab5a4f

Browse files
hjelpemetoder for å hente data
1 parent ec25eb8 commit 0ab5a4f

File tree

2 files changed

+80
-16
lines changed
  • sql-dsl/src
    • main/kotlin/com/github/navikt/tbd_libs/sql_dsl
    • test/kotlin/com/github/navikt/tbd_libs/sql_dsl

2 files changed

+80
-16
lines changed

sql-dsl/src/main/kotlin/com/github/navikt/tbd_libs/sql_dsl/Query.kt

+66
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import java.time.ZoneId
1212
import java.time.ZonedDateTime
1313
import java.util.*
1414
import javax.sql.DataSource
15+
import kotlin.contracts.ExperimentalContracts
16+
import kotlin.contracts.contract
1517

1618
fun <R> DataSource.connection(block: Connection.() -> R): R {
1719
return connection.use(block)
@@ -48,6 +50,70 @@ fun <R> ResultSet.map(map: (ResultSet) -> R?): List<R?> {
4850

4951
fun <R> ResultSet.mapNotNull(map: (ResultSet) -> R?): List<R> = map(map).filterNotNull()
5052

53+
@OptIn(ExperimentalContracts::class)
54+
private fun <T : Any> checkNotNull(columnIdentifier: Any, value: T?): T {
55+
contract {
56+
returns() implies (value != null)
57+
}
58+
return checkNotNull(value) { "Column <$columnIdentifier> was null." }
59+
}
60+
61+
fun ResultSet.stringOrNull(columnName: String): String? = getString(columnName)
62+
fun ResultSet.string(columnName: String): String = checkNotNull(columnName, stringOrNull(columnName))
63+
fun ResultSet.stringOrNull(column: Int): String? = getString(column)
64+
fun ResultSet.string(column: Int): String = checkNotNull(column, stringOrNull(column))
65+
66+
fun ResultSet.longOrNull(columnName: String): Long? = getLong(columnName)
67+
fun ResultSet.long(columnName: String): Long = checkNotNull(columnName, longOrNull(columnName))
68+
fun ResultSet.longOrNull(column: Int): Long? = getLong(column)
69+
fun ResultSet.long(column: Int): Long = checkNotNull(column, longOrNull(column))
70+
71+
fun ResultSet.intOrNull(columnName: String): Int? = getInt(columnName)
72+
fun ResultSet.int(columnName: String): Int = checkNotNull(columnName, intOrNull(columnName))
73+
fun ResultSet.intOrNull(column: Int): Int? = getInt(column)
74+
fun ResultSet.int(column: Int): Int = checkNotNull(column, intOrNull(column))
75+
76+
fun ResultSet.doubleOrNull(columnName: String): Double? = getDouble(columnName)
77+
fun ResultSet.double(columnName: String): Double = checkNotNull(columnName, doubleOrNull(columnName))
78+
fun ResultSet.doubleOrNull(column: Int): Double? = getDouble(column)
79+
fun ResultSet.double(column: Int): Double = checkNotNull(column, doubleOrNull(column))
80+
81+
fun ResultSet.booleanOrNull(columnName: String): Boolean? = getBoolean(columnName)
82+
fun ResultSet.boolean(columnName: String): Boolean = checkNotNull(columnName, booleanOrNull(columnName))
83+
fun ResultSet.booleanOrNull(column: Int): Boolean? = getBoolean(column)
84+
fun ResultSet.boolean(column: Int): Boolean = checkNotNull(column, booleanOrNull(column))
85+
86+
fun ResultSet.uuidOrNull(columnName: String): UUID? = getObject(columnName, UUID::class.java)
87+
fun ResultSet.uuid(columnName: String): UUID = checkNotNull(columnName, uuidOrNull(columnName))
88+
fun ResultSet.uuidOrNull(column: Int): UUID? = getObject(column, UUID::class.java)
89+
fun ResultSet.uuid(column: Int): UUID = checkNotNull(column, uuidOrNull(column))
90+
91+
/*
92+
relevant dokumentasjon: https://jdbc.postgresql.org/documentation/query/#using-java-8-date-and-time-classes
93+
94+
TIMESTAMP bør mappes til/fra LocalDateTime siden postgres ikke gjør noen tolkning av tidssone.
95+
hvis du vet at du kun inserter utc så kan du i teorien hente ut en OffsetDateTime fra kolonnen siden fravær av tidssone tolkes som UTC.
96+
men dette er en ganske svak antagelse.
97+
98+
tl;dr: lagre ALT med timestamptz og Instant/OffsetDateTime så slipper du å tenke mer på det!
99+
100+
TIMESTAMPTZ (TIMESTAMP WITH TIME ZONE) bør mappes til/fra OffsetDateTime (som i tur kan tolkes som Instant osv)
101+
*/
102+
fun ResultSet.offsetDateTimeOrNull(columnName: String): OffsetDateTime? = getObject(columnName, OffsetDateTime::class.java)
103+
fun ResultSet.offsetDateTime(columnName: String): OffsetDateTime = checkNotNull(offsetDateTimeOrNull(columnName))
104+
fun ResultSet.offsetDateTimeOrNull(column: Int): OffsetDateTime? = getObject(column, OffsetDateTime::class.java)
105+
fun ResultSet.offsetDateTime(column: Int): OffsetDateTime = checkNotNull(offsetDateTimeOrNull(column))
106+
107+
fun ResultSet.localDateTimeOrNull(columnName: String): LocalDateTime? = getObject(columnName, LocalDateTime::class.java)
108+
fun ResultSet.localDateTime(columnName: String): LocalDateTime = checkNotNull(localDateTimeOrNull(columnName))
109+
fun ResultSet.localDateTimeOrNull(column: Int): LocalDateTime? = getObject(column, LocalDateTime::class.java)
110+
fun ResultSet.localDateTime(column: Int): LocalDateTime = checkNotNull(localDateTimeOrNull(column))
111+
112+
fun ResultSet.localDateOrNull(columnName: String): LocalDate? = getObject(columnName, LocalDate::class.java)
113+
fun ResultSet.localDate(columnName: String): LocalDate = checkNotNull(localDateOrNull(columnName))
114+
fun ResultSet.localDateOrNull(column: Int): LocalDate? = getObject(column, LocalDate::class.java)
115+
fun ResultSet.localDate(column: Int): LocalDate = checkNotNull(localDateOrNull(column))
116+
51117
fun <R> Connection.transaction(block: Connection.() -> R): R {
52118
return try {
53119
autoCommit = false

sql-dsl/src/test/kotlin/com/github/navikt/tbd_libs/sql_dsl/QueryTest.kt

+14-16
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ import java.sql.Connection
55
import java.sql.ResultSet
66
import java.time.Instant
77
import java.time.LocalDate
8-
import java.time.LocalDateTime
9-
import java.time.OffsetDateTime
108
import java.time.ZoneOffset
119
import java.time.temporal.ChronoUnit.MILLIS
1210
import java.time.temporal.Temporal
@@ -25,7 +23,7 @@ class QueryTest {
2523
val hansId = connection.createName("hans")
2624
val nullId = connection.createName(null)
2725

28-
val mapName = { rs: ResultSet -> rs.getString("name") }
26+
val mapName = { rs: ResultSet -> rs.stringOrNull("name") }
2927
assertEquals("hans", connection.name(hansId).single(mapName))
3028
assertThrows<IllegalStateException> { assertEquals(null, connection.name(nullId).single(mapName)) }
3129
assertThrows<NoSuchElementException> { assertEquals(null, connection.name(1000).single(mapName)) }
@@ -36,7 +34,7 @@ class QueryTest {
3634
val hansId = connection.createName("hans")
3735
val nullId = connection.createName(null)
3836

39-
val mapName = { rs: ResultSet -> rs.getString("name") }
37+
val mapName = { rs: ResultSet -> rs.stringOrNull("name") }
4038
assertEquals("hans", connection.name(hansId).singleOrNull(mapName))
4139
assertEquals(null, connection.name(nullId).singleOrNull(mapName))
4240
assertThrows<NoSuchElementException> { connection.name(1000).singleOrNull(mapName) }
@@ -47,7 +45,7 @@ class QueryTest {
4745
val hansId = connection.createName("hans")
4846
val nullId = connection.createName(null)
4947

50-
val mapName = { rs: ResultSet -> rs.getString("name") }
48+
val mapName = { rs: ResultSet -> rs.stringOrNull("name") }
5149
assertEquals("hans", connection.name(hansId).firstOrNull(mapName))
5250
assertEquals(null, connection.name(nullId).firstOrNull(mapName))
5351
assertEquals(null, connection.name(1000).firstOrNull(mapName))
@@ -58,7 +56,7 @@ class QueryTest {
5856
connection.createName("hans")
5957
connection.createName(null)
6058

61-
val mapName = { rs: ResultSet -> rs.getString("name") }
59+
val mapName = { rs: ResultSet -> rs.stringOrNull("name") }
6260
val names = connection.prepareStatement("select name from name").use {
6361
it.executeQuery().map(mapName)
6462
}
@@ -71,7 +69,7 @@ class QueryTest {
7169
connection.createName("hans")
7270
connection.createName(null)
7371

74-
val mapName = { rs: ResultSet -> rs.getString("name") }
72+
val mapName = { rs: ResultSet -> rs.stringOrNull("name") }
7573
val names = connection.prepareStatement("select name from name").use {
7674
it.executeQuery().mapNotNull(mapName)
7775
}
@@ -107,7 +105,7 @@ class QueryTest {
107105
withParameter("id", id)
108106
withParameter("navn", "hans")
109107
}.use {
110-
it.executeQuery().single { rs -> rs.getString("name") }
108+
it.executeQuery().single { rs -> rs.string("name") }
111109
}
112110
assertEquals("hans", navn)
113111
}
@@ -153,15 +151,15 @@ class QueryTest {
153151
connection.prepareStatementWithNamedParameters("select name from name where name = ANY(:navn)") {
154152
withParameter("navn", listOf("hans", "trude"))
155153
}.use {
156-
it.executeQuery().mapNotNull { rs -> rs.getString("name") }
154+
it.executeQuery().mapNotNull { rs -> rs.string("name") }
157155
}.also { navn ->
158156
assertEquals(listOf("hans", "trude"), navn)
159157
}
160158

161159
connection.prepareStatementWithNamedParameters("select name from name where id = ANY(:ider)") {
162160
withParameter("ider", listOf(hansId, trudeId))
163161
}.use {
164-
it.executeQuery().mapNotNull { rs -> rs.getString("name") }
162+
it.executeQuery().mapNotNull { rs -> rs.string("name") }
165163
}.also { navn ->
166164
assertEquals(listOf("hans", "trude"), navn)
167165
}
@@ -180,7 +178,7 @@ class QueryTest {
180178
}.use { it.execute() }
181179

182180
val result = connection.prepareStatement("select id from uuidtest").use {
183-
it.executeQuery().single { rs -> rs.getObject("id", UUID::class.java) }
181+
it.executeQuery().single { rs -> rs.uuid("id") }
184182
}
185183

186184
assertEquals(id, result)
@@ -198,7 +196,7 @@ class QueryTest {
198196
}.use { it.execute() }
199197

200198
val result = connection.prepareStatement("select dato from datotest").use {
201-
it.executeQuery().single { rs -> rs.getObject("dato", LocalDate::class.java) }
199+
it.executeQuery().single { rs -> rs.localDate("dato") }
202200
}
203201

204202
assertEquals(dato, result)
@@ -215,7 +213,7 @@ class QueryTest {
215213
val tidspunkt = connection.prepareStatementWithNamedParameters("select created_tz from name where name = :navn") {
216214
withParameter("navn", "trude")
217215
}.use {
218-
it.executeQuery().single { rs -> rs.getObject("created_tz", OffsetDateTime::class.java) }
216+
it.executeQuery().single { rs -> rs.offsetDateTime("created_tz") }
219217
}.toInstant()
220218

221219
assertEquals(instant.truncatedTo(MILLIS), tidspunkt.truncatedTo(MILLIS))
@@ -237,11 +235,11 @@ class QueryTest {
237235
}
238236
}
239237

240-
hentTidspunkt { rs -> rs.getObject("created_ts", OffsetDateTime::class.java) }
238+
hentTidspunkt { rs -> rs.offsetDateTime("created_ts") }
241239
.toInstant()
242240
.also { tidspunkt -> assertEquals(instant.truncatedTo(MILLIS), tidspunkt.truncatedTo(MILLIS)) }
243241

244-
hentTidspunkt { rs -> rs.getObject("created_ts", LocalDateTime::class.java) }
242+
hentTidspunkt { rs -> rs.localDateTime("created_ts") }
245243
.toInstant(ZoneOffset.UTC)
246244
.also { tidspunkt -> assertEquals(instant.truncatedTo(MILLIS), tidspunkt.truncatedTo(MILLIS)) }
247245
}
@@ -256,7 +254,7 @@ class QueryTest {
256254
}
257255

258256
private fun Connection.names(): List<String?> {
259-
val mapName = { rs: ResultSet -> rs.getString("name") }
257+
val mapName = { rs: ResultSet -> rs.string("name") }
260258
return prepareStatement("select name from name").use { it.executeQuery().map(mapName) }
261259
}
262260

0 commit comments

Comments
 (0)