Skip to content

Commit

Permalink
add toDataFrame pojo-like class check
Browse files Browse the repository at this point in the history
  • Loading branch information
AndreiKingsley committed Mar 5, 2025
1 parent c29d8bb commit de710b0
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,13 @@ internal val KClass<*>.isValueType: Boolean
this.isArray

/**
* Checks if `KClass` has properties.
* Checks if `KClass` has public properties / getter functions (for pojo-like classes).
*/
@PublishedApi
internal val KClass<*>.hasProperties: Boolean
get() = this.memberProperties.isNotEmpty()
get() = this.memberProperties.any { it.visibility == KVisibility.PUBLIC } ||
// check pojo-like classes
this.memberFunctions.any { it.visibility == KVisibility.PUBLIC && it.isGetterLike() }

internal class CreateDataFrameDslImpl<T>(
override val source: Iterable<T>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,14 @@ class CreateDataFrameTests {
enums.toDataFrame() shouldBe dataFrameOf("value")(*enums.toTypedArray())
}

class NoPublicPropsClass(private val a: Int, private val b: String)

@Test
fun `should convert class with no public properties to DataFrame with value column`() {
val objs: List<NoPublicPropsClass> = listOf(NoPublicPropsClass(1, "a"), NoPublicPropsClass(2, "b"))
objs.toDataFrame() shouldBe dataFrameOf("value")(*objs.toTypedArray())
}

interface Animal {
fun say(): String
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,13 @@ internal val KClass<*>.isValueType: Boolean
this.isArray

/**
* Checks if `KClass` has properties.
* Checks if `KClass` has public properties / getter functions (for pojo-like classes).
*/
@PublishedApi
internal val KClass<*>.hasProperties: Boolean
get() = this.memberProperties.isNotEmpty()
get() = this.memberProperties.any { it.visibility == KVisibility.PUBLIC } ||
// check pojo-like classes
this.memberFunctions.any { it.visibility == KVisibility.PUBLIC && it.isGetterLike() }

internal class CreateDataFrameDslImpl<T>(
override val source: Iterable<T>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,14 @@ class CreateDataFrameTests {
enums.toDataFrame() shouldBe dataFrameOf("value")(*enums.toTypedArray())
}

class NoPublicPropsClass(private val a: Int, private val b: String)

@Test
fun `should convert class with no public properties to DataFrame with value column`() {
val objs: List<NoPublicPropsClass> = listOf(NoPublicPropsClass(1, "a"), NoPublicPropsClass(2, "b"))
objs.toDataFrame() shouldBe dataFrameOf("value")(*objs.toTypedArray())
}

interface Animal {
fun say(): String
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.fir.scopes.collectAllProperties
import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.ConeFlexibleType
Expand Down Expand Up @@ -224,12 +225,27 @@ internal fun KotlinTypeFacade.toDataFrame(
Names.TEMPORAL_AMOUNT_CLASS_ID.constructClassLikeType(emptyArray(), isNullable = true), session
)

fun FirNamedFunctionSymbol.isGetterLike(): Boolean {
val functionName = this.name.asString()
return (functionName.startsWith("get") || functionName.startsWith("is")) &&
this.valueParameterSymbols.isEmpty() &&
this.typeParameterSymbols.isEmpty()
}

fun ConeKotlinType.hasProperties(): Boolean {
val symbol = this.toRegularClassSymbol(session) as? FirClassSymbol<*> ?: return false
val scope = symbol.unsubstitutedScope(session, ScopeSession(), withForcedTypeCalculator = false, memberRequiredPhase = null)
return scope.collectAllProperties().isNotEmpty()
val scope = symbol.unsubstitutedScope(
session,
ScopeSession(),
withForcedTypeCalculator = false,
memberRequiredPhase = null
)

return scope.collectAllProperties().any { it.visibility == Visibilities.Public } ||
scope.collectAllFunctions().any { it.visibility == Visibilities.Public && it.isGetterLike() }
}


val excludes =
traverseConfiguration.excludeProperties.mapNotNullTo(mutableSetOf()) { it.calleeReference.toResolvedPropertySymbol() }
val excludedClasses = traverseConfiguration.excludeClasses.mapTo(mutableSetOf()) { it.argument.resolvedType }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import org.jetbrains.kotlinx.dataframe.*
import org.jetbrains.kotlinx.dataframe.api.*

class NoPublicPropsClass(private val a: Int, private val b: String)

fun box(): String {
val objs: List<NoPublicPropsClass> = listOf(NoPublicPropsClass(1, "a"), NoPublicPropsClass(2, "b"))
val df = objs.toDataFrame()

val objsCol: DataColumn<NoPublicPropsClass> = df.value

return "OK"
}
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,12 @@ public void testToDataFrameNoPropertiesType() {
runTest("testData/box/toDataFrameNoPropertiesType.kt");
}

@Test
@TestMetadata("toDataFrameNoPublicPropertiesType.kt")
public void testToDataFrameNoPublicPropertiesType() {
runTest("testData/box/toDataFrameNoPublicPropertiesType.kt");
}

@Test
@TestMetadata("toDataFrameValueTypes.kt")
public void testToDataFrameValueTypes() {
Expand Down

0 comments on commit de710b0

Please sign in to comment.