Skip to content

Commit

Permalink
Merge pull request #19 from IngotGG/feat/auto-deserialize-bool-from-int
Browse files Browse the repository at this point in the history
Automatically Convert Int to Boolean Where Applicable
  • Loading branch information
DebitCardz authored Jul 27, 2024
2 parents 858eb86 + 73cd9b2 commit 007d225
Show file tree
Hide file tree
Showing 7 changed files with 51 additions and 10 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ plugins {
}

group = "gg.ingot"
version = "1.3.3"
version = "1.3.4"

repositories {
mavenCentral()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ data class EntityField(
val columnName: String,
val nullable: Boolean,
val isJson: Boolean,
val isBoolean: Boolean,
val serializer: ColumnSerializer<*, *>?,
val deserializer: ColumnDeserializer<*, *>?,
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ internal class ModelTransformer(
columnName = retrieveName(field, annotation),
nullable = field.returnType.isMarkedNullable,
isJson = annotation?.json ?: false,
isBoolean = field.returnType.classifier == Boolean::class,
serializer = retrieveSerializer(field, annotation),
deserializer = retrieveDeserializer(field, annotation)
))
Expand Down
19 changes: 13 additions & 6 deletions src/main/kotlin/gg/ingot/iron/transformer/ResultTransformer.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
package gg.ingot.iron.transformer

import gg.ingot.iron.Iron
import gg.ingot.iron.IronSettings
import gg.ingot.iron.annotations.Model
import gg.ingot.iron.representation.EntityField
import gg.ingot.iron.strategies.NamingStrategy
import org.slf4j.LoggerFactory
import java.sql.ResultSet
import kotlin.reflect.KClass
import kotlin.reflect.full.declaredMemberProperties
import kotlin.reflect.full.primaryConstructor
import kotlin.reflect.jvm.isAccessible

Expand Down Expand Up @@ -114,8 +109,20 @@ internal class ResultTransformer(
}

try {
return if(columnLabel != null) result.getObject(columnLabel) as? T
val obj = if(columnLabel != null) result.getObject(columnLabel) as? T
else result.getObject(1) as? T

// Automatically convert Ints to Booleans for DBMS
// that don't give us back a boolean type.
@Suppress("KotlinConstantConditions")
if(obj != null && clazz == Boolean::class && obj is Int) {
if(obj != 0 && obj != 1) {
error("Could not convert the column to a boolean, the value was not 0 or 1.")
}
return (obj == 1) as? T
}

return obj
} catch(ex: ClassCastException) {
error("Could not cast the column to the desired type, if you're attempted to map to a model try annotating with @Model, if not try passing a custom deserializer.")
}
Expand Down
10 changes: 10 additions & 0 deletions src/main/kotlin/gg/ingot/iron/transformer/ValueTransformer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package gg.ingot.iron.transformer
import gg.ingot.iron.representation.EntityField
import gg.ingot.iron.serialization.*
import gg.ingot.iron.strategies.NamingStrategy
import org.slf4j.LoggerFactory
import java.sql.ResultSet
import kotlin.reflect.KClass

Expand Down Expand Up @@ -93,6 +94,15 @@ internal class ValueTransformer(
return java.lang.Enum.valueOf(field.javaField.type as Class<out Enum<*>>, value as String)
}

// Automatically convert Ints to Booleans for DBMS
// that don't give us back a boolean type.
if(value != null && value is Int && field.isBoolean) {
if(value != 0 && value != 1) {
error("Expected a boolean value, but found an integer value of $value for field: ${field.field.name}")
}
return value == 1
}

return value
}

Expand Down
6 changes: 3 additions & 3 deletions src/test/kotlin/DatabaseTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -381,9 +381,9 @@ class DatabaseTest {
fun `test transformer`() = runTest {
val value = connection.transaction {
execute("CREATE TABLE uuids(uuid TEXT PRIMARY KEY)")
prepare("INSERT INTO uuids VALUES (?)", UUID.randomUUID())
prepare("INSERT INTO uuids VALUES (?)", UUID.randomUUID())
prepare("INSERT INTO uuids VALUES (?)", UUID.randomUUID())
repeat(3) {
prepare("INSERT INTO uuids VALUES (?)", UUID.randomUUID())
}
prepare("INSERT INTO uuids VALUES (?) RETURNING *", UUID.randomUUID())
.single<UUID>(UUIDTransformer)
}
Expand Down
22 changes: 22 additions & 0 deletions src/test/kotlin/DeserializationTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -179,4 +179,26 @@ class DeserializationTest {
assertEquals("hello", mapped.json.example)
}

@Test
fun `deserialize ints as bools`() = runTest {
@Model
data class TestMapping(val bool: Boolean)

val connection = Iron("jdbc:sqlite::memory:")
.connect()

connection.execute("CREATE TABLE test(id INTEGER PRIMARY KEY, bool BOOLEAN NOT NULL)")
connection.execute("INSERT INTO test(bool) VALUES (true)")
connection.execute("INSERT INTO test(bool) VALUES (false)")

val booleans = connection.query("SELECT bool FROM test")
.all<Boolean>()

val modeledBooleans = connection.query("SELECT bool FROM test")
.all<TestMapping>()
.map { it.bool }

assertEquals(listOf(true, false), booleans)
assertEquals(listOf(true, false), modeledBooleans)
}
}

0 comments on commit 007d225

Please sign in to comment.