diff --git a/data4k/src/main/kotlin/dev/forkhandles/data/DataContainer.kt b/data4k/src/main/kotlin/dev/forkhandles/data/DataContainer.kt index 23716c0..06d72c5 100644 --- a/data4k/src/main/kotlin/dev/forkhandles/data/DataContainer.kt +++ b/data4k/src/main/kotlin/dev/forkhandles/data/DataContainer.kt @@ -14,15 +14,34 @@ abstract class DataContainer( private val getFn: (CONTENT, String) -> Any?, private val setFn: (CONTENT, String, Any?) -> Unit ) { + /** Required **/ - // - // CORE FUNCTIONS - these are the only ones that should call the defined mappings - // - - fun field(mapInFn: (OUT) -> NEXT, mapOutFn: (NEXT) -> OUT?) = + fun required(mapInFn: (OUT) -> NEXT, mapOutFn: (NEXT) -> OUT?) = property(mapInFn, mapOutFn) - fun ?> obj(mapInFn: (CONTENT) -> OUT, mapOutFn: (OUT) -> CONTENT?) = + fun required() = required({ it }, { it }) + + fun required(mapInFn: (OUT) -> NEXT) = required(mapInFn) { error("no outbound mapping defined") } + + fun > required(factory: ValueFactory) = + required(factory::of) { it.value } + + /** Optional **/ + + fun optional(mapInFn: (OUT) -> NEXT) = + required(mapInFn) { error("no outbound mapping defined") } + + fun optional(mapInFn: (OUT) -> NEXT, mapOutFn: (NEXT) -> OUT?) = + required(mapInFn) { it?.let(mapOutFn) } + + fun optional() = required({ it }, { it }) + + fun > optional(factory: ValueFactory): DataProperty, OUT?> = + required(factory::of) { it?.value } + + /** Other **/ + + fun > obj(mapInFn: (CONTENT) -> OUT, mapOutFn: (OUT) -> CONTENT?) = property(mapInFn, mapOutFn) fun list(mapInFn: (IN) -> OUT, mapOutFn: (OUT) -> IN?) = @@ -32,12 +51,8 @@ abstract class DataContainer( // "PRE MAPPED" FUNCTIONS // - fun field() = field({ it }, { it }) - fun list() = list({ it }, { it }) - fun field(mapInFn: (OUT) -> NEXT) = field(mapInFn) { error("no outbound mapping defined") } - fun list(mapInFn: (IN) -> OUT) = list(mapInFn) { error("no outbound mapping defined") } @@ -45,23 +60,15 @@ abstract class DataContainer( fun ?> list(mapInFn: (CONTENT) -> OUT) = list(mapInFn) { it?.data } - fun ?> obj(mapInFn: (CONTENT) -> OUT) = - obj(mapInFn) { it?.data } - - // - // VALUES4K functions - // + fun > obj(mapInFn: (CONTENT) -> OUT) = + obj(mapInFn) { it.data } - fun > field(factory: ValueFactory) = - field(factory::of) { it.value } + fun > optionalObj(mapInFn: (CONTENT) -> OUT): DataProperty, OUT?> = + property(mapInFn) { it?.data } fun > list(factory: ValueFactory) = list(factory::of) { it.value } - // - // UTILITY FUNCTIONS - for comparisons etc - // - override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false diff --git a/data4k/src/test/kotlin/dev/forkhandles/lens/DataContainerContract.kt b/data4k/src/test/kotlin/dev/forkhandles/lens/DataContainerContract.kt index faeef21..6b9d310 100644 --- a/data4k/src/test/kotlin/dev/forkhandles/lens/DataContainerContract.kt +++ b/data4k/src/test/kotlin/dev/forkhandles/lens/DataContainerContract.kt @@ -33,6 +33,7 @@ interface MainClassFields { var valueField: MyType var optionalField: String? + var optionalMappedField: Int? val optionalValueField: MyType? var optionalObjectField: T? val optionalListField: List? diff --git a/data4k/src/test/kotlin/dev/forkhandles/lens/JacksonDataContainerTest.kt b/data4k/src/test/kotlin/dev/forkhandles/lens/JacksonDataContainerTest.kt index 1e72c73..259e328 100644 --- a/data4k/src/test/kotlin/dev/forkhandles/lens/JacksonDataContainerTest.kt +++ b/data4k/src/test/kotlin/dev/forkhandles/lens/JacksonDataContainerTest.kt @@ -8,31 +8,32 @@ import java.math.BigDecimal class JacksonDataContainerTest : DataContainerContract() { class SubNodeBacked(node: JsonNode) : JacksonDataContainer(node), SubClassFields { - override var stringField by field() - override var noSuchField by field() + override var stringField by required() + override var noSuchField by required() } class NodeBacked(node: JsonNode) : JacksonDataContainer(node), MainClassFields { - override var stringField by field() - override var optionalField by field() - override var booleanField by field() - override var intField by field() - override var longField by field() - override var doubleField by field() - override var decimalField by field() - override var notAStringField by field() + override var stringField by required() + override var optionalField by optional() + override var optionalMappedField by optional(String::toInt, Int::toString) + override var booleanField by required() + override var intField by required() + override var longField by required() + override var doubleField by required() + override var decimalField by required() + override var notAStringField by required() override var listSubClassField by list(::SubNodeBacked) override var listField by list() override var listIntsField by list() override var listValueField by list(MyType) override val listMapped by list(Int::toString) override var objectField by obj(::SubNodeBacked) - override var valueField by field(MyType) - override var mappedField by field(String::toInt, Int::toString) + override var valueField by required(MyType) + override var mappedField by required(String::toInt, Int::toString) override val optionalListField: List? by list() - override var optionalObjectField by obj(::SubNodeBacked) - override val optionalValueField: MyType? by field(MyType) + override var optionalObjectField by optionalObj(::SubNodeBacked) + override var optionalValueField by optional(MyType) } override fun container(input: Map) = NodeBacked(ObjectMapper().valueToTree(input)) diff --git a/data4k/src/test/kotlin/dev/forkhandles/lens/MapDataContainerTest.kt b/data4k/src/test/kotlin/dev/forkhandles/lens/MapDataContainerTest.kt index 2f7a511..497c718 100644 --- a/data4k/src/test/kotlin/dev/forkhandles/lens/MapDataContainerTest.kt +++ b/data4k/src/test/kotlin/dev/forkhandles/lens/MapDataContainerTest.kt @@ -6,20 +6,21 @@ import java.math.BigDecimal class MapDataContainerTest : DataContainerContract() { class SubMap(propertySet: Map) : MapDataContainer(propertySet), SubClassFields { - override var stringField by field() - override var noSuchField by field() + override var stringField by required() + override var noSuchField by required() } class MapBacked(map: Map) : MapDataContainer(map), MainClassFields { - override var stringField by field() - override var booleanField by field() - override var intField by field() - override var longField by field() - override var doubleField by field() - override var decimalField by field() - override var notAStringField by field() + override var stringField by required() + override var booleanField by required() + override var intField by required() + override var longField by required() + override var doubleField by required() + override var decimalField by required() + override var notAStringField by required() - override var mappedField by field(String::toInt, Int::toString) + override var mappedField by required(String::toInt, Int::toString) + override var optionalMappedField by optional(String::toInt, Int::toString) override var listField by list() override var listValueField by list(MyType) @@ -29,12 +30,12 @@ class MapDataContainerTest : DataContainerContract( override var objectField by obj(::SubMap) - override var valueField by field(MyType) + override var valueField by required(MyType) - override var optionalField by field() + override var optionalField by optional() override val optionalListField: List? by list() - override var optionalObjectField by obj(::SubMap) - override val optionalValueField: MyType? by field(MyType) + override var optionalObjectField by optionalObj(::SubMap) + override var optionalValueField by optional(MyType) } override fun container(input: Map) = MapBacked(input)