Kotlin / dataframe

Structured data processing in Kotlin
https://kotlin.github.io/dataframe/overview.html
Apache License 2.0
768 stars 48 forks source link

POJO toDataFrame support (and array improvements) #650

Closed Jolanrensen closed 2 months ago

Jolanrensen commented 3 months ago

Fixes https://github.com/Kotlin/dataframe/issues/380

This PR relaxes, the toDataFrame() properties() DSL to allow for getter functions too.

If no memberProperties are available, it'll fall back to getter-like memberFunctions. Also, it now tries to sort by any constructor if there are multiple (common in java with a no-arg constructor).

EDIT:

koperagen commented 2 months ago

Let's add a check in isValueType for different arrays. Maybe there's a simple check? If there's no, below code from compiler for reference. Also, functions in java class can in theory be static, we should filter them out. Please check how Kotlin reflection sees a List and Int, int, Number returned from Java bean: it could be that they're not converted automatically to their Kotlin counterparts and our isValue or isIterable checks won't work. Last thing that worth checking is type arguments. Map<String, Integer> from Java can become something like (Mutable)Map<String!, Int!> in Kotlin. Expected result here would be Map<String?, Int?>

private fun ConeKotlinType.isArrayType(isNullable: Boolean?): Boolean {
    return isBuiltinType(StandardClassIds.Array, isNullable) ||
            StandardClassIds.primitiveArrayTypeByElementType.values.any { isBuiltinType(it, isNullable) } ||
            StandardClassIds.unsignedArrayTypeByElementType.values.any { isBuiltinType(it, isNullable) }
}

val primitiveTypes = setOf(Boolean, Char, Byte, Short, Int, Long, Float, Double)

    val primitiveArrayTypeByElementType = primitiveTypes.associateWith { id -> id.shortClassName.primitiveArrayId() }

 val unsignedTypes = setOf(UByte, UShort, UInt, ULong)
    val unsignedArrayTypeByElementType = unsignedTypes.associateWith { id -> id.shortClassName.primitiveArrayId() }

private fun Name.primitiveArrayId() = ClassId(StandardClassIds.Array.packageFqName, Name.identifier(identifier + StandardClassIds.Array.shortClassName.identifier))
koperagen commented 2 months ago

Let's filter out functions that have type arguments too

class B {
    fun <T> getA(): T {
        return TODO()
    }

    fun <T> getAa(): List<T> {
        return TODO()
    }
}

fun t(b: B) {
    b.getAa<Int>()
}
Jolanrensen commented 2 months ago

Let's add a check in isValueType for different arrays. Maybe there's a simple check? If there's no, below code from compiler for reference. Also, functions in java class can in theory be static, we should filter them out. Please check how Kotlin reflection sees a List and Int, int, Number returned from Java bean: it could be that they're not converted automatically to their Kotlin counterparts and our isValue or isIterable checks won't work. Last thing that worth checking is type arguments. Map<String, Integer> from Java can become something like (Mutable)Map<String!, Int!> in Kotlin. Expected result here would be Map<String?, Int?>

private fun ConeKotlinType.isArrayType(isNullable: Boolean?): Boolean {
    return isBuiltinType(StandardClassIds.Array, isNullable) ||
            StandardClassIds.primitiveArrayTypeByElementType.values.any { isBuiltinType(it, isNullable) } ||
            StandardClassIds.unsignedArrayTypeByElementType.values.any { isBuiltinType(it, isNullable) }
}

val primitiveTypes = setOf(Boolean, Char, Byte, Short, Int, Long, Float, Double)

    val primitiveArrayTypeByElementType = primitiveTypes.associateWith { id -> id.shortClassName.primitiveArrayId() }

 val unsignedTypes = setOf(UByte, UShort, UInt, ULong)
    val unsignedArrayTypeByElementType = unsignedTypes.associateWith { id -> id.shortClassName.primitiveArrayId() }

private fun Name.primitiveArrayId() = ClassId(StandardClassIds.Array.packageFqName, Name.identifier(identifier + StandardClassIds.Array.shortClassName.identifier))

lucky for us, static functions aren't in memberFunctions so this works by default :) working on the rest...

Jolanrensen commented 2 months ago

I tried to add your requests to the PR and even added a little extra I needed for debugging/testing (see top comment).

I also spawned a couple of new related issues: