Skip to content

Commit 01d99f6

Browse files
committed
[Compiler plugin] Support flatten via adapter for structure-related, data-agnostic operations
1 parent 2d31cd6 commit 01d99f6

File tree

6 files changed

+115
-0
lines changed

6 files changed

+115
-0
lines changed

core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/flatten.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,22 @@ package org.jetbrains.kotlinx.dataframe.api
22

33
import org.jetbrains.kotlinx.dataframe.ColumnsSelector
44
import org.jetbrains.kotlinx.dataframe.DataFrame
5+
import org.jetbrains.kotlinx.dataframe.annotations.Interpretable
6+
import org.jetbrains.kotlinx.dataframe.annotations.Refine
57
import org.jetbrains.kotlinx.dataframe.columns.ColumnReference
68
import org.jetbrains.kotlinx.dataframe.columns.toColumnSet
79
import org.jetbrains.kotlinx.dataframe.impl.api.flattenImpl
810
import kotlin.reflect.KProperty
911

1012
// region DataFrame
1113

14+
@Refine
15+
@Interpretable("FlattenDefault")
1216
public fun <T> DataFrame<T>.flatten(keepParentNameForColumns: Boolean = false, separator: String = "."): DataFrame<T> =
1317
flatten(keepParentNameForColumns, separator) { all() }
1418

19+
@Refine
20+
@Interpretable("Flatten0")
1521
public fun <T, C> DataFrame<T>.flatten(
1622
keepParentNameForColumns: Boolean = false,
1723
separator: String = ".",
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package org.jetbrains.kotlinx.dataframe.plugin.impl
2+
3+
import org.jetbrains.kotlinx.dataframe.AnyCol
4+
import org.jetbrains.kotlinx.dataframe.DataColumn
5+
import org.jetbrains.kotlinx.dataframe.DataFrame
6+
import org.jetbrains.kotlinx.dataframe.api.cast
7+
import org.jetbrains.kotlinx.dataframe.api.dataFrameOf
8+
import org.jetbrains.kotlinx.dataframe.columns.ColumnGroup
9+
import org.jetbrains.kotlinx.dataframe.columns.FrameColumn
10+
import org.jetbrains.kotlinx.dataframe.plugin.impl.api.TypeApproximation
11+
12+
fun PluginDataFrameSchema.asDataFrame(): DataFrame<ConeTypesAdapter> = columns().map()
13+
14+
fun DataFrame<ConeTypesAdapter>.toPluginDataFrameSchema() = PluginDataFrameSchema(columns().mapBack())
15+
16+
interface ConeTypesAdapter
17+
18+
private fun List<SimpleCol>.map(): DataFrame<ConeTypesAdapter> = map {
19+
when (it) {
20+
is SimpleDataColumn -> DataColumn.create(it.name, listOf(it.type))
21+
is SimpleColumnGroup -> DataColumn.createColumnGroup(it.name, it.columns().map())
22+
is SimpleFrameColumn -> DataColumn.createFrameColumn(it.name, listOf(it.columns().map()))
23+
}
24+
}.let { dataFrameOf(it).cast() }
25+
26+
private fun List<AnyCol>.mapBack(): List<SimpleCol> = map {
27+
when (it) {
28+
is ColumnGroup<*> -> {
29+
SimpleColumnGroup(it.name(), it.columns().mapBack())
30+
}
31+
is FrameColumn<*> -> {
32+
SimpleFrameColumn(it.name(), it[0].columns().mapBack())
33+
}
34+
else -> {
35+
SimpleDataColumn(it.name(), it[0] as TypeApproximation)
36+
}
37+
}
38+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package org.jetbrains.kotlinx.dataframe.plugin.impl.api
2+
3+
import org.jetbrains.kotlinx.dataframe.api.flatten
4+
import org.jetbrains.kotlinx.dataframe.api.pathOf
5+
import org.jetbrains.kotlinx.dataframe.columns.toColumnSet
6+
import org.jetbrains.kotlinx.dataframe.plugin.impl.AbstractSchemaModificationInterpreter
7+
import org.jetbrains.kotlinx.dataframe.plugin.impl.Arguments
8+
import org.jetbrains.kotlinx.dataframe.plugin.impl.PluginDataFrameSchema
9+
import org.jetbrains.kotlinx.dataframe.plugin.impl.Present
10+
import org.jetbrains.kotlinx.dataframe.plugin.impl.asDataFrame
11+
import org.jetbrains.kotlinx.dataframe.plugin.impl.dataFrame
12+
import org.jetbrains.kotlinx.dataframe.plugin.impl.toPluginDataFrameSchema
13+
14+
class FlattenDefault : AbstractSchemaModificationInterpreter() {
15+
val Arguments.receiver by dataFrame()
16+
val Arguments.keepParentNameForColumns: Boolean by arg(defaultValue = Present(false))
17+
val Arguments.separator: String by arg(defaultValue = Present("."))
18+
19+
override fun Arguments.interpret(): PluginDataFrameSchema {
20+
return receiver.asDataFrame().flatten(keepParentNameForColumns, separator).toPluginDataFrameSchema()
21+
}
22+
}
23+
24+
class Flatten0 : AbstractSchemaModificationInterpreter() {
25+
val Arguments.receiver by dataFrame()
26+
val Arguments.keepParentNameForColumns: Boolean by arg(defaultValue = Present(false))
27+
val Arguments.separator: String by arg(defaultValue = Present("."))
28+
val Arguments.columns: ColumnsResolver by arg()
29+
30+
override fun Arguments.interpret(): PluginDataFrameSchema {
31+
val columns = columns.resolve(receiver).map { pathOf(*it.path.path.toTypedArray()) }
32+
return receiver
33+
.asDataFrame()
34+
.flatten(keepParentNameForColumns, separator) { columns.toColumnSet() }
35+
.toPluginDataFrameSchema()
36+
}
37+
}
38+

plugins/kotlin-dataframe/src/org/jetbrains/kotlinx/dataframe/plugin/loadInterpreter.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ import org.jetbrains.kotlinx.dataframe.plugin.impl.api.ColsOf1
7474
import org.jetbrains.kotlinx.dataframe.plugin.impl.api.DataFrameBuilderInvoke0
7575
import org.jetbrains.kotlinx.dataframe.plugin.impl.api.DataFrameOf0
7676
import org.jetbrains.kotlinx.dataframe.plugin.impl.api.FillNulls0
77+
import org.jetbrains.kotlinx.dataframe.plugin.impl.api.Flatten0
78+
import org.jetbrains.kotlinx.dataframe.plugin.impl.api.FlattenDefault
7779
import org.jetbrains.kotlinx.dataframe.plugin.impl.api.FrameCols0
7880
import org.jetbrains.kotlinx.dataframe.plugin.impl.api.ReadExcel
7981
import org.jetbrains.kotlinx.dataframe.plugin.impl.api.ToDataFrame
@@ -190,6 +192,8 @@ internal inline fun <reified T> String.load(): T {
190192
"ReadExcel" -> ReadExcel()
191193
"FillNulls0" -> FillNulls0()
192194
"UpdateWith0" -> UpdateWith0()
195+
"Flatten0" -> Flatten0()
196+
"FlattenDefault" -> FlattenDefault()
193197
else -> error("$this")
194198
} as T
195199
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import org.jetbrains.kotlinx.dataframe.*
2+
import org.jetbrains.kotlinx.dataframe.annotations.*
3+
import org.jetbrains.kotlinx.dataframe.api.*
4+
import org.jetbrains.kotlinx.dataframe.io.*
5+
6+
fun box(): String {
7+
val df = dataFrameOf("a", "b", "c", "d")(1, 2, 3, 4)
8+
val grouped = df
9+
.group { a and b }.into("e")
10+
.group { e and c }.into("f")
11+
12+
grouped.flatten().compareSchemas(strict = true)
13+
val flattened = grouped.flatten { f.e }
14+
flattened.compareSchemas(strict = true)
15+
flattened.ungroup { f }.compareSchemas(strict = true)
16+
17+
grouped.flatten { f.e and f }.compareSchemas(strict = true)
18+
return "OK"
19+
}
20+
21+
22+
23+

plugins/kotlin-dataframe/tests-gen/org/jetbrains/kotlin/fir/dataframe/DataFrameBlackBoxCodegenTestGenerated.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,12 @@ public void testFillNulls() {
142142
runTest("testData/box/fillNulls.kt");
143143
}
144144

145+
@Test
146+
@TestMetadata("flatten.kt")
147+
public void testFlatten() {
148+
runTest("testData/box/flatten.kt");
149+
}
150+
145151
@Test
146152
@TestMetadata("flexibleReturnType.kt")
147153
public void testFlexibleReturnType() {

0 commit comments

Comments
 (0)