-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7158fcc
commit 0e75eec
Showing
4 changed files
with
88 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
32 changes: 21 additions & 11 deletions
32
lens4k/src/main/kotlin/dev/forkhandles/lens/MapWrapper.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,27 @@ | ||
package dev.forkhandles.lens | ||
|
||
import com.fasterxml.jackson.databind.JsonNode | ||
|
||
@Suppress("UNCHECKED_CAST") | ||
abstract class MapWrapper(private val map: Map<String, Any?>) { | ||
class Field<OUT> : AbstractLensProp<MapWrapper, OUT>({ map.containsKey(it) }, { map[it] }) | ||
class ListField<IN : Any, OUT>(mapFn: (IN) -> OUT) : AbstractLensProp<MapWrapper, List<OUT>>( | ||
{ map.containsKey(it) }, | ||
{ (map[it] as List<IN>).map(mapFn) } | ||
) | ||
abstract class AbstractWrapper<CONTENT>( | ||
private val contents: CONTENT, | ||
existsFn: CONTENT.(String) -> Boolean, | ||
getFn: CONTENT.(String) -> Any? | ||
) { | ||
private val exists: AbstractWrapper<CONTENT>.(String) -> Boolean = { contents.existsFn(it) } | ||
private val get: AbstractWrapper<CONTENT>.(String) -> Any? = { contents.getFn(it) } | ||
|
||
inner class Field<OUT> : LensProp<AbstractWrapper<CONTENT>, OUT>(exists, get) | ||
|
||
class ObjectField<OUT : MapWrapper>(wrapper: (Map<String, Any?>) -> OUT) : | ||
AbstractLensProp<MapWrapper, OUT>( | ||
{ map.containsKey(it) }, | ||
{ wrapper(map[it] as Map<String, Any?>) } | ||
) | ||
inner class ListField<IN : Any, OUT>(mapFn: (IN) -> OUT) : | ||
LensProp<AbstractWrapper<CONTENT>, List<OUT>>(exists, { (get(it) as List<IN>).map(mapFn) }) | ||
|
||
inner class ObjectField<OUT : AbstractWrapper<CONTENT>>(mapFn: (CONTENT) -> OUT) : | ||
LensProp<AbstractWrapper<CONTENT>, OUT>(exists, { mapFn(get(it) as CONTENT) }) | ||
} | ||
|
||
abstract class MapWrapper(map: Map<String, Any?>) : | ||
AbstractWrapper<Map<String, Any?>>(map, { map.containsKey(it) }, { map[it] }) | ||
|
||
abstract class JacksonWrapper(node: JsonNode) : | ||
AbstractWrapper<JsonNode>(node, { node.has(it) }, { node[it] }) |
64 changes: 64 additions & 0 deletions
64
lens4k/src/test/kotlin/dev/forkhandles/lens/JacksonWrapperTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package dev.forkhandles.lens | ||
|
||
import com.fasterxml.jackson.databind.JsonNode | ||
import com.fasterxml.jackson.databind.ObjectMapper | ||
import org.junit.jupiter.api.Test | ||
import strikt.api.expectThat | ||
import strikt.api.expectThrows | ||
import strikt.assertions.isEqualTo | ||
import strikt.assertions.message | ||
|
||
class JacksonWrapperTest { | ||
|
||
class SubMap(node: JsonNode) : JacksonWrapper(node) { | ||
val stringField by Field<String>() | ||
} | ||
|
||
class NodeBacked(node: JsonNode) : JacksonWrapper(node) { | ||
val stringField by Field<String>() | ||
val booleanField by Field<Boolean>() | ||
val intField by Field<Int>() | ||
val longField by Field<Long>() | ||
val decimalField by Field<Double>() | ||
val notAStringField by Field<String>() | ||
val noSuchField by Field<String>() | ||
val listField by ListField(::SubMap) | ||
val listField2 by ListField(Any::toString) | ||
val objectField by ObjectField(::SubMap) | ||
} | ||
|
||
@Test | ||
fun `can get values from properties`() { | ||
val mapBacked = NodeBacked( | ||
ObjectMapper().valueToTree( | ||
mapOf( | ||
"stringField" to "string", | ||
"booleanField" to true, | ||
"intField" to 123, | ||
"longField" to Long.MAX_VALUE, | ||
"decimalField" to 1.1234, | ||
"notAStringField" to 123, | ||
"listField" to listOf( | ||
mapOf("stringField" to "string1"), | ||
mapOf("stringField" to "string2"), | ||
), | ||
"listField2" to listOf("string1", "string2"), | ||
"objectField" to mapOf( | ||
"stringField" to "string" | ||
) | ||
) | ||
) | ||
) | ||
|
||
expectThat(mapBacked.stringField).isEqualTo("string") | ||
expectThat(mapBacked.booleanField).isEqualTo(true) | ||
expectThat(mapBacked.intField).isEqualTo(123) | ||
expectThat(mapBacked.longField).isEqualTo(Long.MAX_VALUE) | ||
expectThat(mapBacked.decimalField).isEqualTo(1.1234) | ||
expectThat(mapBacked.listField.map { it.stringField }).isEqualTo(listOf("string1", "string2")) | ||
expectThat(mapBacked.listField2).isEqualTo(listOf("string1", "string2")) | ||
expectThat(mapBacked.objectField.stringField).isEqualTo("string") | ||
expectThrows<NoSuchElementException> { mapBacked.notAStringField }.message.isEqualTo("Value for field <notAStringField> is not a class kotlin.String but class kotlin.Int") | ||
expectThrows<NoSuchElementException> { mapBacked.noSuchField }.message.isEqualTo("Field <noSuchField> is missing") | ||
} | ||
} |