-
Notifications
You must be signed in to change notification settings - Fork 0
Typeful API in kotools.csv
#14
Comments
Here is an idea for the new reader API: internal data class Record(val values: NotEmptyList<NotBlankString?>)
internal sealed interface CsvReaderResult {
class Success(val records: NotEmptyList<Record>) : CsvReaderResult
sealed class Error(message: NotBlankString) : CsvReaderResult,
IllegalStateException(message.value) {
object BlankFileName : Error(
"Given file name is blank.".toNotBlankString()
)
class FileNotFound(file: NotBlankString) : Error(
"Given file $file doesn't exist.".toNotBlankString()
)
class RecordsNotFoundInFile(file: NotBlankString) : Error(
"The file $file doesn't have records.".toNotBlankString()
)
}
}
/**
* Reads a CSV [file] according to the [configuration] and returns the records
* wrapped in a [CsvReaderResult.Success] object, or returns a
* [CsvReaderResult.Error] if the process failed.
*/
internal fun readCsv(file: String, configuration: () -> Unit): CsvReaderResult {
println("> Call readCsv(file = $file, configuration = $configuration)")
val fileName: NotBlankString = file.toNotBlankStringOrNull()
?: return CsvReaderResult.Error.BlankFileName
val records: NotEmptyList<Record> = notEmptyListOf(
Record(notEmptyListOf(null, NotBlankString("a"), NotBlankString("b"))),
Record(notEmptyListOf(NotBlankString("c"), null, NotBlankString("d"))),
Record(notEmptyListOf(NotBlankString("e"), NotBlankString("f"), null))
)
return CsvReaderResult.Success(records)
}
internal fun main(): Unit =
when (val result: CsvReaderResult = readCsv(" ") {}) {
is CsvReaderResult.Success -> println(result.records)
is CsvReaderResult.Error -> throw result
} |
The issue of the last example is that unwrapping the Also, the API should use explicit types only for reducing the amount of runtime checks: the |
We will not use the |
Reading a CSV file is an IO operation that should run inside a coroutine. import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotools.types.string.NotBlankString
import kotools.types.string.notBlankStringOrThrow
/**
* Returns the [records][CsvReaderResult.Success.records] in the CSV file
* matching this path, or returns a [CsvReaderResult.Exception.FileNotFound] if
* no file matches this path, or returns a [CsvReaderResult.Exception.EmptyFile]
* if the file matching this path is empty.
*/
internal suspend fun CsvPathResult.Success.read(): CsvReaderResult =
withContext(CoroutineName("CsvReader") + Dispatchers.IO) { TODO() }
internal sealed interface CsvReaderResult {
class Success(val records: List<Map<String, String>>) : CsvReaderResult
sealed class Exception(reason: NotBlankString) :
IllegalStateException("The file ${reason.value}."),
CsvReaderResult {
class EmptyFile(file: NotBlankString) : Exception(
notBlankStringOrThrow("$file is empty")
)
class FileNotFound(file: NotBlankString) : Exception(
notBlankStringOrThrow("$file doesn't exist")
)
}
} |
Description
Create a package
kotools.csv
containing all declarations of the packageio.github.kotools.csv
.Then, deprecate all declarations of the old package.
Also, the
file
property should be required in this new API for avoiding runtime checks in favor of compile-time checks.Here is an exemple using the old API:
Checklist
Work in progress
section in changelog.The text was updated successfully, but these errors were encountered: