Skip to content

Commit

Permalink
Merge pull request #62 from driessamyn/coroutines-docs
Browse files Browse the repository at this point in the history
Doc updates and small refactoring
  • Loading branch information
driessamyn authored Jan 29, 2025
2 parents ee3347b + 93b692f commit ccd84f0
Show file tree
Hide file tree
Showing 8 changed files with 321 additions and 186 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
# Kapper ORM

![build](https://github.com/driessamyn/kapper/actions/workflows/build-and-test.yml/badge.svg)
[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![Maven Central](https://img.shields.io/maven-central/v/net.samyn/kapper.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22net.samyn%22%20AND%20a:%22kapper%22)
![build](https://github.com/driessamyn/kapper/actions/workflows/build-and-test.yml/badge.svg)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=driessamyn_kapper&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=driessamyn_kapper)
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=driessamyn_kapper&metric=coverage)](https://sonarcloud.io/summary/new_code?id=driessamyn_kapper)

<img alt="logo" src="./img/kapper-logo-small.png" align="left" style="margin-right: 7px;"/>

Expand Down
1 change: 0 additions & 1 deletion core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,4 @@ dependencies {
integrationTestImplementation(libs.bundles.test.dbs)

testRuntimeOnly("org.junit.platform:junit-platform-launcher")
testImplementation(kotlin("test"))
}
91 changes: 17 additions & 74 deletions core/src/main/kotlin/net/samyn/kapper/internal/AutoConverter.kt
Original file line number Diff line number Diff line change
@@ -1,88 +1,31 @@
package net.samyn.kapper.internal

import net.samyn.kapper.KapperParseException
import net.samyn.kapper.KapperUnsupportedOperationException
import java.nio.ByteBuffer
import java.time.Instant
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.util.Calendar
import java.util.Date
import java.util.UUID
import kotlin.reflect.KClass

internal object AutoConverter {
internal class AutoConverter(
// register converters
// we can/should extend this to allow users to register custom converters.
private val converters: Map<KClass<*>, (Any) -> Any> =
mapOf(
UUID::class to ::convertUUID,
LocalDate::class to ::convertLocalDate,
LocalDateTime::class to ::convertLocalDateTime,
LocalTime::class to ::convertLocalTime,
Instant::class to ::convertInstant,
),
) {
fun convert(
value: Any,
target: KClass<*>,
): Any {
val converted =
when (target) {
UUID::class -> {
if (value is String) {
try {
UUID.fromString(value)
} catch (e: Exception) {
throw KapperParseException(
"Cannot parse $value to UUID",
e,
)
}
} else if (value is ByteArray) {
value.asUUID()
} else {
throw KapperUnsupportedOperationException(
"Cannot auto-convert from ${value.javaClass} to ${target.qualifiedName}",
)
}
}
LocalDate::class ->
if (value is Date) {
val cal = Calendar.getInstance()
cal.time = value
LocalDate.of(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH))
} else {
throw KapperUnsupportedOperationException(
"Cannot auto-convert from ${value.javaClass} to ${target.qualifiedName}",
)
}
LocalDateTime::class ->
if (value is Instant) {
LocalDateTime.ofInstant(value, java.time.ZoneOffset.UTC)
} else {
throw KapperUnsupportedOperationException(
"Cannot auto-convert from ${value.javaClass} to ${target.qualifiedName}",
)
}
LocalTime::class ->
if (value is Instant) {
LocalTime.ofInstant(value, java.time.ZoneOffset.UTC)
} else {
throw KapperUnsupportedOperationException(
"Cannot auto-convert from ${value.javaClass} to ${target.qualifiedName}",
)
}
Instant::class ->
if (value is LocalTime) {
value.atDate(LocalDate.now()).toInstant(java.time.ZoneOffset.UTC)
} else if (value is LocalDateTime) {
value.atZone(java.time.ZoneOffset.UTC).toInstant()
} else {
throw KapperUnsupportedOperationException(
"Cannot auto-convert from ${value.javaClass} to ${target.qualifiedName}",
)
}
else ->
throw KapperUnsupportedOperationException(
"Cannot auto-convert from ${value.javaClass} to ${target.qualifiedName}",
)
}
return converted
}

private fun ByteArray.asUUID(): UUID {
val b = ByteBuffer.wrap(this)
return UUID(b.getLong(), b.getLong())
}
): Any =
// Kover considers this not covered, which I think is a bug. Will reproduce in separate project and raise issue.
converters[target]?.invoke(value) ?: throw KapperUnsupportedOperationException(
"Cannot auto-convert from ${value.javaClass} to ${target.qualifiedName}",
)
}
87 changes: 87 additions & 0 deletions core/src/main/kotlin/net/samyn/kapper/internal/Converters.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package net.samyn.kapper.internal

import net.samyn.kapper.KapperParseException
import net.samyn.kapper.KapperUnsupportedOperationException
import java.nio.ByteBuffer
import java.time.Instant
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.util.Calendar
import java.util.Date
import java.util.UUID

internal fun convertInstant(value: Any): Instant =
when (value) {
is LocalTime -> {
value.atDate(LocalDate.now()).toInstant(java.time.ZoneOffset.UTC)
}

is LocalDateTime -> {
value.atZone(java.time.ZoneOffset.UTC).toInstant()
}

else -> {
throw KapperUnsupportedOperationException(
"Cannot auto-convert from ${value.javaClass} to Instant",
)
}
}

internal fun convertLocalTime(value: Any): LocalTime =
if (value is Instant) {
LocalTime.ofInstant(value, java.time.ZoneOffset.UTC)
} else {
throw KapperUnsupportedOperationException(
"Cannot auto-convert from ${value.javaClass} to LocalTime",
)
}

internal fun convertLocalDateTime(value: Any): LocalDateTime =
if (value is Instant) {
LocalDateTime.ofInstant(value, java.time.ZoneOffset.UTC)
} else {
throw KapperUnsupportedOperationException(
"Cannot auto-convert from ${value.javaClass} to LocalDateTime",
)
}

internal fun convertLocalDate(value: Any): LocalDate =
if (value is Date) {
val cal = Calendar.getInstance()
cal.time = value
LocalDate.of(cal[Calendar.YEAR], cal[Calendar.MONTH] + 1, cal[Calendar.DAY_OF_MONTH])
} else {
throw KapperUnsupportedOperationException(
"Cannot auto-convert from ${value.javaClass} to LocalDate",
)
}

internal fun convertUUID(value: Any): UUID =
when (value) {
is String -> {
try {
UUID.fromString(value)
} catch (e: Exception) {
throw KapperParseException(
"Cannot parse $value to UUID",
e,
)
}
}

is ByteArray -> {
value.asUUID()
}

else -> {
throw KapperUnsupportedOperationException(
"Cannot auto-convert from ${value.javaClass} to UUID",
)
}
}

fun ByteArray.asUUID(): UUID {
val b = ByteBuffer.wrap(this)
return UUID(b.getLong(), b.getLong())
}
2 changes: 1 addition & 1 deletion core/src/main/kotlin/net/samyn/kapper/internal/Mapper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import kotlin.reflect.full.primaryConstructor

internal class Mapper<T : Any>(
private val clazz: Class<T>,
val autoConverter: (Any, KClass<*>) -> Any = AutoConverter::convert,
val autoConverter: (Any, KClass<*>) -> Any = AutoConverter()::convert,
val sqlTypesConverter: (JDBCType, String, ResultSet, Int) -> Any? = SQLTypesConverter::convertSQLType,
) {
private val constructor: KFunction<T> =
Expand Down
14 changes: 7 additions & 7 deletions core/src/test/java/net/samyn/kapper/KapperJavaApiTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

// this is the Java equivalent of the Kotlin KapperApiTest
// its purpose is to test kapper is usable from Java
public class KapperJavaApiTest {
class KapperJavaApiTest {
private final Kapper kapper = Kapper.getInstance();

@Mock
Expand All @@ -32,9 +32,9 @@ public class KapperJavaApiTest {
private Connection mockConnection;

// TODO: support auto-mapping for record classes
public record TestEntity(int id, String name) { }
record TestEntity(int id, String name) { }

public KapperJavaApiTest() {
KapperJavaApiTest() {
MockitoAnnotations.openMocks(this);
setupMocks();
}
Expand Down Expand Up @@ -69,7 +69,7 @@ private void setupMocks() {
}

@Test
public void testGetInstance() {
void testGetInstance() {
assertNotNull(kapper.getClass());
}

Expand All @@ -79,7 +79,7 @@ class QueryTests {
// this can be added later.

@Test
public void testQueryWithCustomMapper() throws Exception {
void testQueryWithCustomMapper() throws Exception {
// Setup result set behavior
when(mockResultSet.next()).thenReturn(true, true, false);
when(mockResultSet.getInt("id")).thenReturn(1, 2);
Expand Down Expand Up @@ -119,7 +119,7 @@ public void testQueryWithCustomMapper() throws Exception {
@Nested
class QuerySingleTests {
@Test
public void testQuerySingleWithCustomMapper() throws Exception {
void testQuerySingleWithCustomMapper() throws Exception {
// Setup result set behavior
when(mockResultSet.next()).thenReturn(true, false);
when(mockResultSet.getInt("id")).thenReturn(1);
Expand Down Expand Up @@ -157,7 +157,7 @@ public void testQuerySingleWithCustomMapper() throws Exception {
@Nested
class ExecuteTests {
@Test
public void testExecuteWithMap() throws Exception {
void testExecuteWithMap() throws Exception {
// Setup statement behavior
when(mockStatement.executeUpdate()).thenReturn(1);

Expand Down
Loading

0 comments on commit ccd84f0

Please sign in to comment.