Skip to content
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

POJO toDataFrame support (and array improvements) #650

Merged
merged 14 commits into from
May 1, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import org.jetbrains.kotlinx.dataframe.impl.asList
import org.jetbrains.kotlinx.dataframe.impl.columnName
import org.jetbrains.kotlinx.dataframe.impl.columns.guessColumnType
import org.jetbrains.kotlinx.dataframe.index
import kotlin.reflect.KCallable
import kotlin.reflect.KClass
import kotlin.reflect.KProperty

Expand Down Expand Up @@ -115,24 +116,26 @@ public fun Iterable<Pair<String, Iterable<Any?>>>.toDataFrameFromPairs(): AnyFra
public interface TraversePropertiesDsl {

/**
* Skip given [classes] during recursive (dfs) traversal
* Skip given [classes] during recursive (dfs) traversal.
*/
public fun exclude(vararg classes: KClass<*>)

/**
* Skip given [properties] during recursive (dfs) traversal
* Skip given [properties] during recursive (dfs) traversal.
* These can also be getter-like functions (like `getX()` or `isX()`).
*/
public fun exclude(vararg properties: KProperty<*>)
public fun exclude(vararg properties: KCallable<*>)

/**
* Store given [classes] in ValueColumns without transformation into ColumnGroups or FrameColumns
* Store given [classes] in ValueColumns without transformation into ColumnGroups or FrameColumns.
*/
public fun preserve(vararg classes: KClass<*>)

/**
* Store given [properties] in ValueColumns without transformation into ColumnGroups or FrameColumns
* Store given [properties] in ValueColumns without transformation into ColumnGroups or FrameColumns.
* These can also be getter-like functions (like `getX()` or `isX()`).
*/
public fun preserve(vararg properties: KProperty<*>)
public fun preserve(vararg properties: KCallable<*>)
}

public inline fun <reified T> TraversePropertiesDsl.preserve(): Unit = preserve(T::class)
Expand All @@ -148,7 +151,7 @@ public abstract class CreateDataFrameDsl<T> : TraversePropertiesDsl {
public infix fun AnyBaseCol.into(path: ColumnPath): Unit = add(this, path)

public abstract fun properties(
vararg roots: KProperty<*>,
vararg roots: KCallable<*>,
maxDepth: Int = 0,
body: (TraversePropertiesDsl.() -> Unit)? = null,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import org.jetbrains.kotlinx.dataframe.DataFrame
import org.jetbrains.kotlinx.dataframe.DataRow
import org.jetbrains.kotlinx.dataframe.annotations.ColumnName
import org.jetbrains.kotlinx.dataframe.annotations.DataSchema
import org.jetbrains.kotlinx.dataframe.impl.schema.getPropertiesOrder
import org.jetbrains.kotlinx.dataframe.impl.schema.getPropertyOrderFromPrimaryConstructor
import org.jetbrains.kotlinx.dataframe.schema.ColumnSchema
import kotlin.reflect.KClass
import kotlin.reflect.KType
Expand Down Expand Up @@ -53,7 +53,7 @@ internal object MarkersExtractor {
}

private fun getFields(markerClass: KClass<*>, nullableProperties: Boolean): List<GeneratedField> {
val order = getPropertiesOrder(markerClass)
val order = getPropertyOrderFromPrimaryConstructor(markerClass) ?: emptyMap()
return markerClass.memberProperties.sortedBy { order[it.name] ?: Int.MAX_VALUE }.mapIndexed { _, it ->
val fieldName = ValidFieldName.of(it.name)
val columnName = it.findAnnotation<ColumnName>()?.name ?: fieldName.unquoted
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ import org.jetbrains.kotlinx.dataframe.impl.columns.toColumnSet
import org.jetbrains.kotlinx.dataframe.nrow
import java.math.BigDecimal
import java.math.BigInteger
import kotlin.reflect.KCallable
import kotlin.reflect.KClass
import kotlin.reflect.KFunction
import kotlin.reflect.KProperty
import kotlin.reflect.KType
import kotlin.reflect.KTypeProjection
Expand All @@ -23,6 +25,7 @@ import kotlin.reflect.full.createType
import kotlin.reflect.full.findAnnotation
import kotlin.reflect.full.isSubtypeOf
import kotlin.reflect.full.starProjectedType
import kotlin.reflect.full.valueParameters
import kotlin.reflect.full.withNullability
import kotlin.reflect.jvm.jvmErasure
import kotlin.reflect.typeOf
Expand Down Expand Up @@ -337,5 +340,32 @@ internal fun List<String>.joinToCamelCaseString(): String {
.replaceFirstChar { it.lowercaseChar() }
}

internal fun KFunction<*>.isGetterLike(): Boolean =
(name.startsWith("get") || name.startsWith("is")) && valueParameters.isEmpty()

internal fun KCallable<*>.isGetterLike(): Boolean =
when (this) {
is KProperty<*> -> true
is KFunction<*> -> isGetterLike()
else -> false
}

@PublishedApi
internal val <T> KProperty<T>.columnName: String get() = findAnnotation<ColumnName>()?.name ?: name
internal val KProperty<*>.columnName: String
get() = findAnnotation<ColumnName>()?.name ?: name

@PublishedApi
internal val KCallable<*>.columnName: String
get() = findAnnotation<ColumnName>()?.name
?: when (this) {
// for defining the column names based on a getter-function, we use the function name minus the get/is prefix
is KFunction<*> ->
name
.removePrefix("get")
.removePrefix("is")
.replaceFirstChar { it.lowercase() }

is KProperty<*> -> this.columnName

else -> name
}
Loading