Skip to content

Commit b555ed3

Browse files
authored
Merge pull request #21 from blackmo18/feature/not-case-sensitive
Feature/not case sensitive
2 parents 6382ec5 + 5512855 commit b555ed3

File tree

12 files changed

+108
-28
lines changed

12 files changed

+108
-28
lines changed

docs/ChangeLog.MD

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
# 0.7.1
2+
Remove unused lines in JVM Date Parser
3+
4+
# 0.7.0
5+
Added Feature
6+
- case sensitive flag #11
7+
18
# 0.6.0
29
Added Feature and Enhancement
310
- ignore unknown/unmapped fields

docs/README.MD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ If a variable in your data class is a nullable, all you have to do is mark it wi
121121
| dateTimeSeparator | `(space)` | date time separator |
122122
| trimWhiteSpace | `true` | trims white spaces on csv entries |
123123
| ignoreUnknownFields | `false` | ignore unknown / unmapped fields in input |
124+
| caseSensitive | `true` | case sensitive header matching |
124125
| customKeyMap | `null` |`Map<String,String>` custom key mapping, priority if not empty or null |
125126
| customKeyMapDataProperty | `null` |`Map<String, KProperty<*>>` custom key mapping |
126127

src/commonMain/kotlin/io/github/blackmo18/grass/context/GrassParserContext.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,18 @@ class GrassParserContext : GrassParserCtx {
4040
*/
4141
override var ignoreUnknownFields: Boolean = false
4242

43+
/**
44+
* header case sensitive
45+
*/
46+
override var caseSensitve: Boolean = true
47+
4348
/**
4449
* custom key mapping from csv header to **data class** field name
4550
*/
4651
override var customKeyMap: Map<String, String>? = null
4752

53+
/**
54+
* custom key mapping from csv header to **data class** property name
55+
*/
4856
override var customKeyMapDataProperty: Map<String, KProperty<*>>? = null
4957
}

src/commonMain/kotlin/io/github/blackmo18/grass/context/GrassParserCtx.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,18 @@ import kotlin.reflect.KProperty
88
* * time formatting
99
* * date-time separator
1010
* * trim white space
11+
* * ignore unknown fields
12+
* * case sensitive
1113
* * custom key mapping
14+
* * custom key mapping class property
1215
*/
1316
interface GrassParserCtx {
1417
val dateFormat: String
1518
val timeFormat: String
1619
val dateTimeSeparator: String
1720
val trimWhiteSpace: Boolean
1821
var ignoreUnknownFields: Boolean
22+
var caseSensitve: Boolean
1923
val customKeyMap: Map<String, String>?
2024
val customKeyMapDataProperty: Map<String, KProperty<*>>?
2125
}

src/commonMain/kotlin/io/github/blackmo18/grass/pot/Root.kt

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ import kotlin.reflect.*
1010
* @param type data **class** definition
1111
* @param trim removes white spaces defined within csv column entry
1212
* @param ignoreUnknownFields ignores unknown fields
13+
* @param caseSensitive case sensitive header matching
1314
* @author blackmo18
1415
*/
1516
@ExperimentalStdlibApi
1617
open class Root<out T>(
1718
val type: KClass<*>,
1819
private val trim: Boolean,
19-
private val ignoreUnknownFields: Boolean
20+
private val ignoreUnknownFields: Boolean,
21+
private val caseSensitive: Boolean
2022
) {
2123
/**
2224
* Key-value pair containing the expression on converting from data class property name
@@ -47,7 +49,7 @@ open class Root<out T>(
4749
}
4850

4951
row.forEach { mapRow ->
50-
val key = mapRow.key.trim()
52+
val key = mapRow.key.caseSensitive(caseSensitive).trim()
5153
val value = mapRow.value.trimOrNot(trim)
5254
val hasKey = paramNTypes.containsKey(key)
5355
when {
@@ -60,7 +62,7 @@ open class Root<out T>(
6062
actualParams[index] = null
6163
}
6264
else -> {
63-
if (customKeyMap.isNotEmpty() && customKeyMap.containsKey(key)) {
65+
if (customKeyMap.containsKey(key)) {
6466
val mappedKey = customKeyMap[key]?.trim()
6567
if(paramNTypes.containsKey(mappedKey)) {
6668
customKeyMap.remove(mappedKey)
@@ -78,6 +80,11 @@ open class Root<out T>(
7880
return actualParams
7981
}
8082

83+
private fun String.caseSensitive(boolean: Boolean) : String = when {
84+
!boolean -> this.toUpperCase()
85+
else -> this
86+
}
87+
8188
private fun String.trimOrNot(boolean: Boolean): String = when {
8289
boolean -> this.trim()
8390
else -> this

src/commonMain/kotlin/io/github/blackmo18/grass/pot/Stem.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ expect open class Stem<out T> actual constructor(
1717
type: KClass<*>,
1818
trim: Boolean,
1919
ignoreUnknownFields: Boolean,
20+
caseSensitive: Boolean,
2021
receivedKeyMap: Map<String, String>?,
2122
receivedKeyMapDataProperty: Map<String, KProperty<*>>?
2223
): Root<T> {

src/jvmMain/kotlin/io/github/blackmo18/grass/pot/Plant.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import kotlin.reflect.KType
1414
*/
1515
@ExperimentalStdlibApi
1616
actual class Plant<T> actual constructor(val ctx: GrassParserContext, type: KClass<*>)
17-
: Stem<T>(type, ctx.trimWhiteSpace, ctx.ignoreUnknownFields, ctx.customKeyMap, ctx.customKeyMapDataProperty) {
17+
: Stem<T>(type, ctx.trimWhiteSpace, ctx.ignoreUnknownFields, ctx.caseSensitve, ctx.customKeyMap, ctx.customKeyMapDataProperty) {
1818

1919
actual val dateTimeTypes = DateTimeTypes(ctx.dateFormat, ctx.timeFormat, ctx.dateTimeSeparator)
2020

src/jvmMain/kotlin/io/github/blackmo18/grass/pot/Stem.kt

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import kotlin.reflect.KProperty
99
* Implementation **class** of [Root] Conversion Engine from csv contents to **data class** definition
1010
* @param type data **class** definition
1111
* @param trim removes white spaces defined within csv column entry
12+
* @param caseSensitive case sensitive header matching
1213
* @param ignoreUnknownFields ignores unknown fields
1314
* @param receivedKeyMap custom user defined key mapping values
1415
* @author blackmo18
@@ -19,9 +20,10 @@ actual open class Stem<out T> actual constructor(
1920
type: KClass<*>,
2021
trim: Boolean,
2122
ignoreUnknownFields: Boolean,
23+
private val caseSensitive: Boolean,
2224
private val receivedKeyMap: Map<String, String>?,
2325
private val receivedKeyMapDataProperty: Map<String, KProperty<*>>?
24-
): Root<T>(type, trim, ignoreUnknownFields) {
26+
): Root<T>(type, trim, ignoreUnknownFields, caseSensitive) {
2527
/**
2628
* @return converted sequence of data [T]
2729
*/
@@ -58,16 +60,44 @@ actual open class Stem<out T> actual constructor(
5860
}
5961

6062
private fun initOnMethod() {
63+
if (caseSensitive) {
64+
onCaseSensitive()
65+
} else {
66+
onNotCaseSensitive()
67+
}
68+
}
69+
70+
private fun onCaseSensitive() {
6171
type.constructors.first().parameters.forEach { kParam ->
6272
paramNTypes[kParam.name] = getType(kParam.type) as ((String) -> Any)?
6373
paramNIndex[kParam.name] = kParam.index
6474
if (!receivedKeyMap.isNullOrEmpty()) {
65-
receivedKeyMap.let { customKeyMap.putAll(it) }
75+
receivedKeyMap.let { pair ->
76+
customKeyMap.putAll(pair)
77+
}
6678
} else {
6779
receivedKeyMapDataProperty?.forEach {
6880
customKeyMap[it.key] = it.value.name
6981
}
7082
}
7183
}
7284
}
85+
86+
private fun onNotCaseSensitive() {
87+
type.constructors.first().parameters.forEach { kParam ->
88+
paramNTypes[kParam.name?.toUpperCase()] = getType(kParam.type) as ((String) -> Any)?
89+
paramNIndex[kParam.name?.toUpperCase()] = kParam.index
90+
if (!receivedKeyMap.isNullOrEmpty()) {
91+
receivedKeyMap.let { pair ->
92+
pair.forEach { (key, value) ->
93+
customKeyMap[key.toUpperCase()] = value.toUpperCase()
94+
}
95+
}
96+
} else {
97+
receivedKeyMapDataProperty?.forEach {
98+
customKeyMap[it.key.toUpperCase()] = it.value.name.toUpperCase()
99+
}
100+
}
101+
}
102+
}
73103
}

src/jvmMain/kotlin/io/github/blackmo18/grass/vein/DateTimeTypes.kt

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,11 @@ actual class DateTimeTypes actual constructor(dateFormat: String, timeFormat: St
1818
private val dateTimeFormatter = DateTimeFormatter.ofPattern("${dateFormat}${dateTimeSeparator}${timeFormat}")
1919
private val timeFormatter = DateTimeFormatter.ofPattern(timeFormat)
2020

21-
actual val formatDate = fun (value: String): Any? = when {
22-
value.isNotBlank() -> LocalDate.parse(value, dateFormatter)
23-
else -> null
24-
}
21+
actual val formatDate = fun (value: String): Any? = LocalDate.parse(value, dateFormatter)
2522

26-
actual val formatDateTime = fun (value: String): Any? = when {
27-
value.isNotBlank() -> LocalDateTime.parse(value, dateTimeFormatter)
28-
else -> null
29-
}
23+
actual val formatDateTime = fun (value: String): Any? = LocalDateTime.parse(value, dateTimeFormatter)
3024

31-
actual val formatTime = fun(value: String): Any? = when {
32-
value.isNotBlank() -> LocalTime.parse(value, timeFormatter)
33-
else -> null
34-
}
25+
actual val formatTime = fun(value: String): Any? = LocalTime.parse(value, timeFormatter)
3526

3627
actual val mapTypes = mapOf(
3728
typeOf<LocalDate>() to formatDate,

src/jvmTest/kotlin/io/github/blackmo18/grass/DataParserTest.kt

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ package io.github.blackmo18.grass
33
import com.github.doyaaaaaken.kotlincsv.dsl.csvReader
44
import io.github.blackmo18.grass.data.*
55
import io.github.blackmo18.grass.dsl.grass
6-
import io.kotlintest.TestCase
7-
import io.kotlintest.TestResult
86
import io.kotlintest.shouldBe
97
import io.kotlintest.specs.WordSpec
108
import kotlinx.coroutines.flow.asFlow
@@ -20,9 +18,6 @@ import kotlin.test.assertTrue
2018
*/
2119
@ExperimentalStdlibApi
2220
class DataParserTest: WordSpec() {
23-
override fun afterTest(testCase: TestCase, result: TestResult) {
24-
super.afterTest(testCase, result)
25-
}
2621
init {
2722
"Parse into Data Class" should {
2823
"parse to primitive data type" {
@@ -134,8 +129,7 @@ class DataParserTest: WordSpec() {
134129
assertTrue { expected0 == parsed.first() }
135130
}
136131
"parse null values with custom names using data class property" {
137-
138-
val expected0 = NullableDataTypesCustomNames(null, null, null, null, null, null, null)
132+
val expected = NullableDataTypesCustomNames(null, null, null, null, null, null, null)
139133
val contents = readTestFile("/primitive-empty.csv")
140134
val parser = grass<NullableDataTypesCustomNames> {
141135
customKeyMapDataProperty = mapOf(
@@ -146,11 +140,10 @@ class DataParserTest: WordSpec() {
146140
}
147141
val parsed = parser.harvest(contents)
148142

149-
assertTrue { expected0 == parsed.first() }
143+
assertTrue { expected == parsed.first() }
150144
}
151145
}
152146

153-
154147
"parse java date and time" should {
155148
"parse default time and date format" {
156149
val date = LocalDate.of(2020, 12, 1)
@@ -193,9 +186,42 @@ class DataParserTest: WordSpec() {
193186
customKeyMap = mapOf("longX" to "long", "floatX" to "float")
194187
}.harvest(contents)
195188
val actual = parsed.first()
196-
197189
assertTrue { actual == expected }
198190
}
191+
"parse not case sensitive keys" {
192+
val expected = PrimitiveTypes(0, 1, 2, 3.0f, 4.0, true, "hello")
193+
val contents = readTestFile("/primitive-uppercase.csv").asSequence()
194+
val parsed = grass<PrimitiveTypes>{
195+
caseSensitve = false
196+
}.harvest(contents)
197+
val actual = parsed.first()
198+
assertTrue { actual == expected }
199+
}
200+
"parse not case sensitive with custom key mapping default" {
201+
val expected = PrimitiveTypes(0, 1, 2, 3.0f, 4.0, true, "hello")
202+
val contents = readTestFile("/primitive-missmatched.csv").asSequence()
203+
val parsed = grass<PrimitiveTypes>{
204+
customKeyMap = mapOf("LONGX" to "LONG", "floatX" to "float")
205+
caseSensitve = false
206+
}.harvest(contents)
207+
val actual = parsed.first()
208+
assertTrue { actual == expected }
209+
}
210+
"parse not case sensitive with custom key map data class property" {
211+
val expected = NullableDataTypesCustomNames(null, null, null, null, null, null, null)
212+
val contents = readTestFile("/primitive-empty.csv")
213+
val parser = grass<NullableDataTypesCustomNames> {
214+
customKeyMapDataProperty = mapOf(
215+
"SHORT" to NullableDataTypesCustomNames::shortCustom, "int" to NullableDataTypesCustomNames::intCustom, "LONG" to NullableDataTypesCustomNames::longCustom,
216+
"float" to NullableDataTypesCustomNames::floatCustom, "double" to NullableDataTypesCustomNames::doubleCustom, "BOOLEAN" to NullableDataTypesCustomNames::booleanCustom,
217+
"STRING" to NullableDataTypesCustomNames::stringCustom
218+
)
219+
caseSensitve = false
220+
}
221+
val parsed = parser.harvest(contents)
222+
223+
assertTrue { expected == parsed.first() }
224+
}
199225
}
200226
}
201227
}

0 commit comments

Comments
 (0)