Skip to content

Port to use kotlinx-io #159

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: version_2_0_0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ plugins {
alias(libs.plugins.dokka)
alias(libs.plugins.kover)
alias(libs.plugins.mavenPublish)
alias(libs.plugins.kotest)
}

group = "com.jsoizo"
version = "1.10.0"
version = "2.0.0-dev1"
val projectName = "kotlin-csv"

buildscript {
Expand All @@ -36,12 +37,30 @@ kotlin {
nodejs {
}
}
@OptIn(org.jetbrains.kotlin.gradle.ExperimentalWasmDsl::class)
wasmJs {
browser()
nodejs()
}
sourceSets {
commonMain {}
commonMain {
dependencies {
implementation(libs.kotlinx.coroutines.core)
api(libs.kotlinx.io)
}
}
commonTest {
dependencies {
implementation(kotlin("test-common"))
implementation(kotlin("test-annotations-common"))
implementation(libs.kotest.framework.engine)
implementation(libs.kotlinx.datetime)
}
}

wasmJsTest {
dependencies {
implementation(kotlin("test-wasm-js"))
}
}

Expand Down Expand Up @@ -118,4 +137,4 @@ mavenPublishing {
}
}
}
}
}
3 changes: 2 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
kotlin.code.style=official
kotlin.code.style=official
org.gradle.jvmargs=-Xmx4096m
5 changes: 5 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[versions]
kotlin = "2.1.0"
kotlinx-io = "0.6.0"
coroutines = "1.10.1"
maven-publish = "0.30.0"
kover = "0.8.2"
Expand All @@ -9,8 +10,11 @@ kotest = "5.9.1"
[libraries]
#kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" }
kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version = "0.6.1" }
kotlinx-io = { module = "org.jetbrains.kotlinx:kotlinx-io-core", version.ref = "kotlinx-io" }
kotest-runner-junit5 = { module = "io.kotest:kotest-runner-junit5", version.ref = "kotest" }
kotest-assertions-core = { module = "io.kotest:kotest-assertions-core", version.ref = "kotest" }
kotest-framework-engine = { module = "io.kotest:kotest-framework-engine", version.ref = "kotest" }

[bundles]
kotest = ["kotest-runner-junit5", "kotest-assertions-core"]
Expand All @@ -20,3 +24,4 @@ kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref =
kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" }
dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" }
mavenPublish = { id = "com.vanniktech.maven.publish", version.ref = "maven-publish" }
kotest = { id = "io.kotest.multiplatform", version.ref = "kotest" }
106 changes: 97 additions & 9 deletions src/commonMain/kotlin/com/jsoizo/kotlincsv/client/CsvReader.kt
Original file line number Diff line number Diff line change
@@ -1,22 +1,110 @@
package com.jsoizo.kotlincsv.client

import com.jsoizo.kotlincsv.dsl.context.CsvReaderContext
import com.jsoizo.kotlincsv.dsl.CsvReaderScope
import com.jsoizo.kotlincsv.dsl.context.ICsvReaderContext
import kotlinx.io.Source
import kotlinx.io.files.Path

/**
* CSV Reader class
*
* @author doyaaaaaken
*/
expect class CsvReader(
ctx: CsvReaderContext = CsvReaderContext()
) {
interface CsvReader : ICsvReaderContext {
/**
* read csv data as String, and convert into List<List<String>>
*/
fun readAll(data: String): List<List<String>>

/**
* read csv data from a Source, and convert into List<List<String>>.
*/
fun readAll(data: Source): List<List<String>>

/**
* read csv data from a Path, and convert into List<List<String>>
*
* No need to close the [path] when calling this method.
*/
fun readAll(path: Path): List<List<String>>

/**
* read csv data with header, and convert into List<Map<String, String>>
*/
fun readAllWithHeader(data: String): List<Map<String, String>>

/**
* read csv data with a header from a Source, and convert into List<List<String>>.
*/
fun readAllWithHeader(data: Source): List<Map<String, String>>

/**
* read csv data with header, and convert into List<Map<String, String>>
*
* No need to close [path] when calling this method.
*/
fun readAllWithHeader(path: Path): List<Map<String, String>>

/**
* open [source] and execute reading process.
*
* If you want to control read flow precisely, use this method.
* Otherwise, use utility method (e.g. CsvReader.readAll ).
*
* Usage example:
* <pre>
* val data: Sequence<List<String?>> = csvReader().open(source) {
* readAllAsSequence()
* .map { fields -> fields.map { it.trim() } }
* .map { fields -> fields.map { if(it.isBlank()) null else it } }
* }
* </pre>
*/
fun <T> open(source: Source, read: CsvReaderScope.() -> T): T

/**
* open [path] and execute reading process.
*
* If you want to control read flow precisely, use this method.
* Otherwise, use utility method (e.g. CsvReader.readAll ).
*
* Usage example:
* <pre>
* val data: Sequence<List<String?>> = csvReader().open("test.csv") {
* readAllAsSequence()
* .map { fields -> fields.map { it.trim() } }
* .map { fields -> fields.map { if(it.isBlank()) null else it } }
* }
* </pre>
*/
fun <T> open(path: Path, read: CsvReaderScope.() -> T): T

/**
* open [source] and execute reading process on a **suspending** function.
*
* If you want to control read flow precisely, use this method.
* Otherwise, use utility method (e.g. CsvReader.readAll ).
*
* Usage example:
* <pre>
* val data: Sequence<List<String?>> = csvReader().open(source) {
* readAllAsSequence()
* .map { fields -> fields.map { it.trim() } }
* .map { fields -> fields.map { if(it.isBlank()) null else it } }
* }
* </pre>
*/
suspend fun <T> openAsync(source: Source, read: suspend CsvReaderScope.() -> T): T

/**
* open [path] and execute reading process on a **suspending** function.
*
* If you want to control read flow precisely, use this method.
* Otherwise, use utility method (e.g. CsvReader.readAll ).
*
* Usage example:
* <pre>
* val data: Sequence<List<String?>> = csvReader().openAsync("test.csv") {
* readAllAsSequence()
* .map { fields -> fields.map { it.trim() } }
* .map { fields -> fields.map { if(it.isBlank()) null else it } }
* }
* </pre>
*/
suspend fun <T> openAsync(path: Path, read: suspend CsvReaderScope.() -> T): T
}
108 changes: 108 additions & 0 deletions src/commonMain/kotlin/com/jsoizo/kotlincsv/client/CsvReaderImpl.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package com.jsoizo.kotlincsv.client

import com.jsoizo.kotlincsv.dsl.CsvReaderScope
import com.jsoizo.kotlincsv.dsl.context.CsvReaderContext
import com.jsoizo.kotlincsv.dsl.context.ICsvReaderContext
import kotlinx.io.Buffer
import kotlinx.io.Source
import kotlinx.io.buffered
import kotlinx.io.files.Path
import kotlinx.io.files.SystemFileSystem

/**
* CSVReader implementation.
*
* @author gsteckman
*/
internal class CsvReaderImpl(
private val ctx: CsvReaderContext = CsvReaderContext()
) : CsvReader, ICsvReaderContext by ctx {
override fun readAll(data: String): List<List<String>> = data.csvReadAll(ctx)

override fun readAll(data: Source): List<List<String>> = data.csvReadAll(ctx)

override fun readAll(path: Path): List<List<String>> = path.csvReadAll(ctx)

override fun readAllWithHeader(data: String): List<Map<String, String>> =
data.csvReadAllWithHeader(ctx)

override fun readAllWithHeader(data: Source): List<Map<String, String>> = data.csvReadAllWithHeader(ctx)

override fun readAllWithHeader(path: Path): List<Map<String, String>> = path.csvReadAllWithHeader(ctx)

override fun <T> open(source: Source, read: CsvReaderScope.() -> T): T =
SourceCsvReaderScope(ctx, source, ctx.logger).read()

override fun <T> open(path: Path, read: CsvReaderScope.() -> T): T =
SystemFileSystem.source(path).buffered().use {
return open(it, read)
}

override suspend fun <T> openAsync(source: Source, read: suspend CsvReaderScope.() -> T): T =
SourceCsvReaderScope(ctx, source, ctx.logger).read()

override suspend fun <T> openAsync(path: Path, read: suspend CsvReaderScope.() -> T): T =
SystemFileSystem.source(path).buffered().use {
return openAsync(it, read)
}
}

/**
* read csv data as String, and convert into List<List<String>>
*/
fun String.csvReadAll(ctx: CsvReaderContext = CsvReaderContext()): List<List<String>> =
Buffer().apply{ write(encodeToByteArray()) }.use {
it.csvReadAll(ctx)
}

/**
* read csv data with header, and convert into List<Map<String, String>>
*/
fun String.csvReadAllWithHeader(ctx: CsvReaderContext = CsvReaderContext()): List<Map<String, String>> =
Buffer().apply{ write(encodeToByteArray()) }.use {
it.csvReadAllWithHeader(ctx)
}

/**
* read csv data from a Source, and convert into List<List<String>>.
*/
fun Source.csvReadAll(ctx: CsvReaderContext = CsvReaderContext()): List<List<String>> =
SourceCsvReaderScope(ctx, this, ctx.logger).readAllAsSequence().toList()

/**
* read csv data from a Path, and convert into List<List<String>>.
*
* No need to close the Path when calling this method.
*/
fun Path.csvReadAll(ctx: CsvReaderContext = CsvReaderContext()): List<List<String>> =
SystemFileSystem.source(this).buffered().use {
return it.csvReadAll(ctx)
}

/**
* read csv data with a header from a Source, and convert into List<List<String>>.
*/
fun Source.csvReadAllWithHeader(ctx: CsvReaderContext = CsvReaderContext()): List<Map<String, String>> =
SourceCsvReaderScope(ctx, this, ctx.logger).readAllWithHeaderAsSequence().toList()

/**
* read csv data with header, and convert into List<Map<String, String>>
*
* No need to close Path when calling this method.
*/
fun Path.csvReadAllWithHeader(ctx: CsvReaderContext = CsvReaderContext()): List<Map<String, String>> =
SystemFileSystem.source(this).buffered().use {
return it.csvReadAllWithHeader(ctx)
}

/**
* read all csv rows as Sequence
*/
fun Source.csvReadAllAsSequence(fieldsNum: Int? = null, ctx: CsvReaderContext = CsvReaderContext())
: Sequence<List<String>> = SourceCsvReaderScope(ctx, this, ctx.logger).readAllAsSequence(fieldsNum)

/**
* read all csv rows as Sequence with header information
*/
fun Source.csvReadAllWithHeaderAsSequence(ctx: CsvReaderContext = CsvReaderContext())
: Sequence<Map<String, String>> = SourceCsvReaderScope(ctx, this, ctx.logger).readAllWithHeaderAsSequence()
27 changes: 16 additions & 11 deletions src/commonMain/kotlin/com/jsoizo/kotlincsv/client/CsvWriter.kt
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
package com.jsoizo.kotlincsv.client

import com.jsoizo.kotlincsv.dsl.context.CsvWriterContext
import com.jsoizo.kotlincsv.dsl.CsvWriterScope
import com.jsoizo.kotlincsv.dsl.context.ICsvWriterContext
import kotlinx.io.Sink
import kotlinx.io.files.Path

/**
* CSV Writer class
*
* @author doyaaaaaken
*/
expect class CsvWriter(ctx: CsvWriterContext = CsvWriterContext()) {
interface CsvWriter : ICsvWriterContext {
fun writeAll(rows: List<List<Any?>>, sink: Sink, append: Boolean = false)

fun open(targetFileName: String, append: Boolean = false, write: ICsvFileWriter.() -> Unit)
fun writeAll(rows: List<List<Any?>>, path: Path, append: Boolean = false)

fun writeAll(rows: List<List<Any?>>, targetFileName: String, append: Boolean = false)
suspend fun writeAllAsync(rows: List<List<Any?>>, sink: Sink, append: Boolean = false)

suspend fun writeAllAsync(rows: List<List<Any?>>, targetFileName: String, append: Boolean = false)
suspend fun writeAllAsync(rows: List<List<Any?>>, path: Path, append: Boolean = false)

suspend fun openAsync(targetFileName: String, append: Boolean = false, write: suspend ICsvFileWriter.() -> Unit)
fun open(sink: Sink, append: Boolean = false, write: CsvWriterScope.() -> Unit)

fun open(path: Path, append: Boolean = false, write: CsvWriterScope.() -> Unit)

suspend fun openAsync(sink: Sink, append: Boolean = false, write: suspend CsvWriterScope.() -> Unit)

suspend fun openAsync(path: Path, append: Boolean = false, write: suspend CsvWriterScope.() -> Unit)
}
Loading
Loading