Skip to content

Prepare next version of dataframe-compiler-plugin-core #1182

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

Merged
merged 4 commits into from
May 12, 2025
Merged
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
22 changes: 14 additions & 8 deletions core/api/core.api
Original file line number Diff line number Diff line change
Expand Up @@ -2359,11 +2359,13 @@ public final class org/jetbrains/kotlinx/dataframe/api/Gather {
public fun <init> (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/reflect/KType;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Z)V
public synthetic fun <init> (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/reflect/KType;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun cast ()Lorg/jetbrains/kotlinx/dataframe/api/Gather;
public final fun copy (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/reflect/KType;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Z)Lorg/jetbrains/kotlinx/dataframe/api/Gather;
public static synthetic fun copy$default (Lorg/jetbrains/kotlinx/dataframe/api/Gather;Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/reflect/KType;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ZILjava/lang/Object;)Lorg/jetbrains/kotlinx/dataframe/api/Gather;
public fun equals (Ljava/lang/Object;)Z
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
public final fun getColumns ()Lkotlin/jvm/functions/Function2;
public final fun getDf ()Lorg/jetbrains/kotlinx/dataframe/DataFrame;
public final fun getExplode ()Z
public final fun getFilter ()Lkotlin/jvm/functions/Function2;
public final fun getKeyTransform ()Lkotlin/jvm/functions/Function1;
public final fun getKeyType ()Lkotlin/reflect/KType;
public final fun getValueTransform ()Lkotlin/jvm/functions/Function1;
}

public final class org/jetbrains/kotlinx/dataframe/api/GatherKt {
Expand Down Expand Up @@ -5463,7 +5465,7 @@ public final class org/jetbrains/kotlinx/dataframe/exceptions/CellConversionExce
public final fun getRow ()Ljava/lang/Integer;
}

public final class org/jetbrains/kotlinx/dataframe/exceptions/ColumnNotFoundException : java/lang/RuntimeException, org/jetbrains/kotlinx/dataframe/exceptions/DataFrameException {
public final class org/jetbrains/kotlinx/dataframe/exceptions/ColumnNotFoundException : java/lang/RuntimeException, org/jetbrains/kotlinx/dataframe/exceptions/DataFrameError {
public fun <init> (Ljava/lang/String;Ljava/lang/String;)V
public final fun getColumnName ()Ljava/lang/String;
public fun getMessage ()Ljava/lang/String;
Expand All @@ -5474,11 +5476,11 @@ public final class org/jetbrains/kotlinx/dataframe/exceptions/ColumnTypeMismatch
public final fun getColumn ()Lorg/jetbrains/kotlinx/dataframe/DataColumn;
}

public abstract interface class org/jetbrains/kotlinx/dataframe/exceptions/DataFrameException {
public abstract interface class org/jetbrains/kotlinx/dataframe/exceptions/DataFrameError {
public abstract fun getMessage ()Ljava/lang/String;
}

public final class org/jetbrains/kotlinx/dataframe/exceptions/DuplicateColumnNamesException : java/lang/IllegalArgumentException, org/jetbrains/kotlinx/dataframe/exceptions/DataFrameException {
public final class org/jetbrains/kotlinx/dataframe/exceptions/DuplicateColumnNamesException : java/lang/IllegalArgumentException, org/jetbrains/kotlinx/dataframe/exceptions/DataFrameError {
public fun <init> (Ljava/util/List;)V
public final fun getAllColumnNames ()Ljava/util/List;
public final fun getDuplicatedNames ()Ljava/util/List;
Expand Down Expand Up @@ -5755,6 +5757,10 @@ public final class org/jetbrains/kotlinx/dataframe/impl/aggregation/receivers/Ag
public static final fun internal (Lorg/jetbrains/kotlinx/dataframe/aggregation/AggregateDsl;)Lorg/jetbrains/kotlinx/dataframe/impl/aggregation/receivers/AggregateInternalDsl;
}

public final class org/jetbrains/kotlinx/dataframe/impl/api/ConstructorsKt {
public static final fun withValuesImpl (Lkotlin/Pair;)Ljava/util/List;
}

public final class org/jetbrains/kotlinx/dataframe/impl/api/ConvertKt {
public static final fun convertRowColumnImpl (Lorg/jetbrains/kotlinx/dataframe/api/Convert;Lkotlin/reflect/KType;Lorg/jetbrains/kotlinx/dataframe/api/Infer;Lkotlin/jvm/functions/Function2;)Lorg/jetbrains/kotlinx/dataframe/DataFrame;
public static final fun withRowCellImpl (Lorg/jetbrains/kotlinx/dataframe/api/Convert;Lkotlin/reflect/KType;Lorg/jetbrains/kotlinx/dataframe/api/Infer;Lkotlin/jvm/functions/Function2;)Lorg/jetbrains/kotlinx/dataframe/DataFrame;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ public class DataFrameBuilder(private val header: List<String>) {

@JvmName("invoke1")
internal fun withValues(values: Iterable<Any?>): DataFrame<*> =
withValuesImpl(header, values.asList()).map { (name, values) ->
(header to values.asList()).withValuesImpl().map { (name, values) ->
DataColumn.createByInference(name, values)
}.toDataFrame()

Expand Down
65 changes: 60 additions & 5 deletions core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/gather.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import org.jetbrains.kotlinx.dataframe.ColumnsSelector
import org.jetbrains.kotlinx.dataframe.DataFrame
import org.jetbrains.kotlinx.dataframe.RowValueFilter
import org.jetbrains.kotlinx.dataframe.annotations.AccessApiOverload
import org.jetbrains.kotlinx.dataframe.annotations.Interpretable
import org.jetbrains.kotlinx.dataframe.annotations.Refine
import org.jetbrains.kotlinx.dataframe.columns.ColumnAccessor
import org.jetbrains.kotlinx.dataframe.columns.ColumnReference
import org.jetbrains.kotlinx.dataframe.columns.toColumnSet
Expand All @@ -15,6 +17,7 @@ import kotlin.reflect.typeOf

// region gather

@Interpretable("Gather0")
public fun <T, C> DataFrame<T>.gather(selector: ColumnsSelector<T, C>): Gather<T, C, String, C> =
Gather(
df = this,
Expand Down Expand Up @@ -44,30 +47,76 @@ public fun <T, C> DataFrame<T>.gather(vararg columns: KProperty<C>): Gather<T, C

// endregion

@Interpretable("GatherWhere")
public fun <T, C, K, R> Gather<T, C, K, R>.where(filter: RowValueFilter<T, C>): Gather<T, C, K, R> =
copy(filter = this.filter and filter)
Gather(
df = df,
columns = columns,
filter = this.filter and filter,
keyType = keyType,
keyTransform = keyTransform,
valueTransform = valueTransform,
explode = explode,
)

@Interpretable("GatherChangeType")
public fun <T, C, K, R> Gather<T, C?, K, R>.notNull(): Gather<T, C, K, R> = where { it != null } as Gather<T, C, K, R>

public fun <T, C, K, R> Gather<T, C, K, R>.explodeLists(): Gather<T, C, K, R> = copy(explode = true)
@Interpretable("GatherExplodeLists")
public fun <T, C, K, R> Gather<T, C, K, R>.explodeLists(): Gather<T, C, K, R> =
Gather(
df = df,
columns = columns,
filter = filter,
keyType = keyType,
keyTransform = keyTransform,
valueTransform = valueTransform,
explode = true,
)

@Interpretable("GatherMap")
public inline fun <T, C, reified K, R> Gather<T, C, *, R>.mapKeys(
noinline transform: (String) -> K,
): Gather<T, C, K, R> =
copy(keyTransform = transform as ((String) -> Nothing), keyType = typeOf<K>()) as Gather<T, C, K, R>
Gather(
df = df,
columns = columns,
filter = filter,
keyType = typeOf<K>(),
keyTransform = transform,
valueTransform = valueTransform,
explode = explode,
)

@Interpretable("GatherMap")
public fun <T, C, K, R> Gather<T, C, K, *>.mapValues(transform: (C) -> R): Gather<T, C, K, R> =
copy(valueTransform = transform as ((C) -> Nothing)) as Gather<T, C, K, R>
Gather(
df = df,
columns = columns,
filter = filter,
keyType = keyType,
keyTransform = keyTransform,
valueTransform = transform,
explode = explode,
)

public data class Gather<T, C, K, R>(
public class Gather<T, C, K, R>(
@PublishedApi
internal val df: DataFrame<T>,
@PublishedApi
internal val columns: ColumnsSelector<T, C>,
@PublishedApi
internal val filter: RowValueFilter<T, C>? = null,
@PublishedApi
internal val keyType: KType? = null,
@PublishedApi
internal val keyTransform: ((String) -> K),
@PublishedApi
internal val valueTransform: ((C) -> R)? = null,
@PublishedApi
internal val explode: Boolean = false,
) {
@Interpretable("GatherChangeType")
public fun <P> cast(): Gather<T, P, K, P> {
// TODO: introduce GatherWithTransform to avoid this error
require(valueTransform == null) { "Cast is not allowed to be called after `mapValues`" }
Expand All @@ -77,6 +126,8 @@ public data class Gather<T, C, K, R>(

// region into

@Refine
@Interpretable("GatherInto")
public fun <T, C, K, R> Gather<T, C, K, R>.into(keyColumn: String, valueColumn: String): DataFrame<T> =
gatherImpl(keyColumn, valueColumn)

Expand All @@ -100,6 +151,8 @@ public fun <T, C, K, R> Gather<T, C, K, R>.into(keyColumn: KProperty<K>, valueCo

// region keysInto

@Refine
@Interpretable("GatherKeysInto")
public fun <T, C, K, R> Gather<T, C, K, R>.keysInto(keyColumn: String): DataFrame<T> = gatherImpl(keyColumn, null)

@Deprecated(
Expand All @@ -120,6 +173,8 @@ public fun <T, C, K, R> Gather<T, C, K, R>.keysInto(keyColumn: KProperty<K>): Da

// region valuesInto

@Refine
@Interpretable("GatherValuesInto")
public fun <T, C, K, R> Gather<T, C, K, R>.valuesInto(valueColumn: String): DataFrame<T> = gatherImpl(null, valueColumn)

@Deprecated(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ package org.jetbrains.kotlinx.dataframe.exceptions

public class ColumnNotFoundException(public val columnName: String, public override val message: String) :
RuntimeException(),
DataFrameException
DataFrameError
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package org.jetbrains.kotlinx.dataframe.exceptions

/**
* If DataFrame function used by compiler plugin as implementation detail throws this exception, [message] will be reported as warning
* If DataFrame function used by compiler plugin as implementation detail throws exception
* that implements this interface, [message] will be reported as warning
*/
public interface DataFrameException {
public interface DataFrameError {
public val message: String
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package org.jetbrains.kotlinx.dataframe.exceptions

public class DuplicateColumnNamesException(public val allColumnNames: List<String>) :
IllegalArgumentException(),
DataFrameException {
DataFrameError {

public val duplicatedNames: List<String> = allColumnNames
.groupBy { it }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
package org.jetbrains.kotlinx.dataframe.impl.api

internal fun <T> withValuesImpl(header: List<String>, values: List<T>): List<Pair<String, List<T>>> {
import org.jetbrains.kotlinx.dataframe.exceptions.DataFrameError

/**
* Public API to be re-used in compiler plugin implementation
*/
public fun <T> Pair<List<String>, List<T>>.withValuesImpl(): List<Pair<String, List<T>>> {
val (header, values) = this
val ncol = header.size

require(header.isNotEmpty() && values.size.rem(ncol) == 0) {
"Number of values ${values.size} is not divisible by number of columns $ncol"
if (!(header.isNotEmpty() && values.size.rem(ncol) == 0)) {
throw WrongNumberOfValuesException(values.size, ncol)
}

val nrow = values.size / ncol
Expand All @@ -16,3 +22,9 @@ internal fun <T> withValuesImpl(header: List<String>, values: List<T>): List<Pai
header[col] to colValues
}
}

internal class WrongNumberOfValuesException(size: Int, ncol: Int) :
IllegalArgumentException(),
DataFrameError {
override val message = "Number of values $size is not divisible by number of columns $ncol"
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
package org.jetbrains.kotlinx.dataframe.plugin.impl.api

import org.jetbrains.kotlin.fir.expressions.FirExpression
Expand Down Expand Up @@ -35,7 +34,7 @@ class DataFrameBuilderInvoke0 : AbstractSchemaModificationInterpreter() {
val Arguments.values: FirVarargArgumentsExpression by arg(lens = Interpreter.Id)

override fun Arguments.interpret(): PluginDataFrameSchema {
val columns = withValuesImpl(receiver.header, values.arguments).map { (name, values) ->
val columns = (receiver.header to values.arguments).withValuesImpl().map { (name, values) ->
val type = session.typeContext.commonSuperTypeOrNull(values.map { it.resolvedType }) ?: error("$name $values")
simpleColumnOf(name, type)
}
Expand Down
Loading