From fb7342654c099233bab458b1731d34d4f72da5d3 Mon Sep 17 00:00:00 2001 From: "andrei.kislitsyn" Date: Tue, 18 Nov 2025 15:53:34 +0400 Subject: [PATCH 01/14] join kdocs --- .../jetbrains/kotlinx/dataframe/api/join.kt | 478 +++++++++++++++++- .../documentation/DocumentationUrls.kt | 3 + 2 files changed, 473 insertions(+), 8 deletions(-) diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt index 99cecc1baf..b0e1abefaf 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt @@ -1,6 +1,7 @@ package org.jetbrains.kotlinx.dataframe.api import org.jetbrains.kotlinx.dataframe.ColumnsContainer +import org.jetbrains.kotlinx.dataframe.ColumnsSelector import org.jetbrains.kotlinx.dataframe.DataFrame import org.jetbrains.kotlinx.dataframe.annotations.AccessApiOverload import org.jetbrains.kotlinx.dataframe.annotations.Interpretable @@ -12,6 +13,9 @@ import org.jetbrains.kotlinx.dataframe.columns.ColumnWithPath import org.jetbrains.kotlinx.dataframe.columns.ColumnsResolver import org.jetbrains.kotlinx.dataframe.columns.UnresolvedColumnsPolicy import org.jetbrains.kotlinx.dataframe.columns.toColumnSet +import org.jetbrains.kotlinx.dataframe.documentation.DocumentationUrls +import org.jetbrains.kotlinx.dataframe.documentation.ExcludeFromSources +import org.jetbrains.kotlinx.dataframe.documentation.SelectingColumns import org.jetbrains.kotlinx.dataframe.impl.DataFrameReceiver import org.jetbrains.kotlinx.dataframe.impl.api.extractJoinColumns import org.jetbrains.kotlinx.dataframe.impl.api.joinImpl @@ -19,6 +23,83 @@ import org.jetbrains.kotlinx.dataframe.impl.columns.ColumnListImpl import org.jetbrains.kotlinx.dataframe.util.DEPRECATED_ACCESS_API import kotlin.reflect.KProperty +/** + * If no join columns are specified, all columns with matching names in both [DataFrame]s are used. + * + * If both [DataFrame]s contain columns with the same name that are *not* part of the join keys, + * such columns are treated as distinct. Such a column from the right [DataFrame] will be automatically + * renamed in the resulting [DataFrame]. + */ +private interface JoinBehavior + +/** + * Joins this [DataFrame] with [other][\other] [DataFrame] using selected key columns. + * + * Creates a new [DataFrame] by combining [rows][org.jetbrains.kotlinx.dataframe.DataRow] + * from two input dataframes according to one or more matching key columns. + * + * {@include [JoinTypeDescription]} + * + * @include [JoinBehavior] + * + * See also shortcuts with each of join types: + * [innerJoin], [leftJoin], [rightJoin], [fullJoin], [filterJoin], [excludeJoin]. + * + * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention] + * + * See [Selecting Columns][SelectingColumns]. + * + * For more information, {@include [DocumentationUrls.Join]}. + * + * ### This `join` overload + */ +private interface JoinDocs + +// `join` method used in the example +private interface JoinMethod + +/** + * [JoinDsl] defines the columns used for joining [DataFrame]s + * and provides methods to match columns with different names + * between the left and right sides. + * + * Provides the left [DataFrame] both as the receiver (`this`) and as the argument (`it`), + * allowing you to reference its columns directly. + * Use [right][JoinDsl.right] to access columns from the right [DataFrame], + * and [match][JoinDsl.match] to explicitly pair columns with different names. + * + * See also [Columns selection via DSL][SelectingColumns.Dsl]. + * + * ### Examples + * ```kotlin + * // Join by two columns with the same names in both dataframes + * dfLeft.{@get [JoinMethod] join}(dfRight) { name and city } + * + * // Join by one column with different names — + * // "firstName" in the left dataframe and "name" in the right one + * dfLeft.{@get [JoinMethod] join}(dfRight) { left -> left.firstName match right.name } + * ``` + */ +@ExcludeFromSources +internal interface JoinDslDescription + +/** + * Select join columns (incl. with different names in this and [other][other] [DataFrame]s) + * using [JoinDsl]. + * + * @include [JoinDslDescription] + */ +private interface SelectingColumnsJoinDsl + +/** + * @include [JoinDocs] + * @include [SelectingColumnsJoinDsl] + * @param other [DataFrame] to join with. + * @param type [JoinType] defining how rows are matched and combined. + * @param selector [JoinColumnsSelector] specifying join columns; + * if `null`, same-name columns are used. + * @return joined [DataFrame]. + */ @Refine @Interpretable("Join0") public fun DataFrame.join( @@ -27,12 +108,61 @@ public fun DataFrame.join( selector: JoinColumnsSelector? = null, ): DataFrame = joinImpl(other, type, addNewColumns = type.addNewColumns, selector) +/** + * ### Example + * ```kotlin + * // Join by two columns with the same names in both dataframes + * dfLeft.{@get [JoinMethod] join}(dfRight, "name", "city") + * ``` + */ +private interface JoinStringApiExample + +/** + * @include [JoinDocs] + * @include [SelectingColumns.ColumnNames] + * @include [JoinStringApiExample] + * @param other [DataFrame] to join with. + * @param columns [Column Names][String] specifying join columns. + * @param type [JoinType] defining how rows are matched and combined. + * @return joined [DataFrame]. + */ public fun DataFrame.join( other: DataFrame, vararg columns: String, type: JoinType = JoinType.Inner, ): DataFrame = join(other, type) { columns.toColumnSet() } +/** + * Performs [inner join][JoinType.Inner] of this [DataFrame] with [other][\other] [DataFrame] + * using selected key columns. + * @include [JoinType.Inner] + * + * This is a shortcut for [join] with [JoinType.Inner]. + * + * @include [JoinBehavior] + * + * See also general [join] as well as other shortcuts with each of join types: + * [leftJoin], [rightJoin], [fullJoin], [filterJoin], [excludeJoin]. + * + * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention] + * + * See [Selecting Columns][SelectingColumns]. + * + * For more information, {@include [DocumentationUrls.Join]}. + * + * ### This `innerJoin` overload + */ +@ExcludeFromSources +private interface InnerJoinDocs + +/** + * @include [InnerJoinDocs] + * @include [SelectingColumnsJoinDsl] {@set [JoinMethod] innerJoin} + * @param other [DataFrame] to join with. + * @param selector [JoinColumnsSelector] specifying join columns; + * if `null`, same-name columns are used. + * @return joined [DataFrame]. + */ @Refine @Interpretable("InnerJoin") public fun DataFrame.innerJoin( @@ -40,9 +170,48 @@ public fun DataFrame.innerJoin( selector: JoinColumnsSelector? = null, ): DataFrame = join(other, JoinType.Inner, selector = selector) +/** + * @include [InnerJoinDocs] + * @include [SelectingColumns.ColumnNames] + * @include [JoinStringApiExample] {@set [JoinMethod] innerJoin} + * @param other [DataFrame] to join with. + * @param columns [Column Names][String] specifying join columns. + * @return joined [DataFrame]. + */ public fun DataFrame.innerJoin(other: DataFrame, vararg columns: String): DataFrame = innerJoin(other) { columns.toColumnSet() } +/** + * Performs [left join][JoinType.Left] of this [DataFrame] with [other][\other] [DataFrame] + * using selected key columns. + * @include [JoinType.Left] + * + * This is a shortcut for [join] with [JoinType.Left]. + * + * @include [JoinBehavior] + * + * See also general [join] as well as other shortcuts with each of join types: + * [innerJoin], [rightJoin], [fullJoin], [filterJoin], [excludeJoin]. + * + * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention] + * + * See [Selecting Columns][SelectingColumns]. + * + * For more information, {@include [DocumentationUrls.Join]}. + * + * ### This `leftJoin` overload + */ +@ExcludeFromSources +private interface LeftJoinDocs + +/** + * @include [LeftJoinDocs] + * @include [SelectingColumnsJoinDsl] {@set [JoinMethod] leftJoin} + * @param other [DataFrame] to join with. + * @param selector [JoinColumnsSelector] specifying join columns; + * if `null`, same-name columns are used. + * @return joined [DataFrame]. + */ @Refine @Interpretable("LeftJoin") public fun DataFrame.leftJoin( @@ -50,9 +219,48 @@ public fun DataFrame.leftJoin( selector: JoinColumnsSelector? = null, ): DataFrame = join(other, JoinType.Left, selector = selector) +/** + * @include [LeftJoinDocs] + * @include [SelectingColumns.ColumnNames] + * @include [JoinStringApiExample] {@set [JoinMethod] leftJoin} + * @param other [DataFrame] to join with. + * @param columns [Column Names][String] specifying join columns. + * @return joined [DataFrame]. + */ public fun DataFrame.leftJoin(other: DataFrame, vararg columns: String): DataFrame = leftJoin(other) { columns.toColumnSet() } +/** + * Performs [right join][JoinType.Right] of this [DataFrame] with [other][\other] [DataFrame] + * using selected key columns. + * @include [JoinType.Right] + * + * This is a shortcut for [join] with [JoinType.Right]. + * + * @include [JoinBehavior] + * + * See also general [join] as well as other shortcuts with each of join types: + * [innerJoin], [leftJoin], [fullJoin], [filterJoin], [excludeJoin]. + * + * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention] + * + * See [Selecting Columns][SelectingColumns]. + * + * For more information, {@include [DocumentationUrls.Join]}. + * + * ### This `rightJoin` overload + */ +@ExcludeFromSources +private interface RightJoinDocs + +/** + * @include [RightJoinDocs] + * @include [SelectingColumnsJoinDsl] {@set [JoinMethod] rightJoin} + * @param other [DataFrame] to join with. + * @param selector [JoinColumnsSelector] specifying join columns; + * if `null`, same-name columns are used. + * @return joined [DataFrame]. + */ @Refine @Interpretable("RightJoin") public fun DataFrame.rightJoin( @@ -60,9 +268,48 @@ public fun DataFrame.rightJoin( selector: JoinColumnsSelector? = null, ): DataFrame = join(other, JoinType.Right, selector = selector) +/** + * @include [RightJoinDocs] + * @include [SelectingColumns.ColumnNames] + * @include [JoinStringApiExample] {@set [JoinMethod] rightJoin} + * @param other [DataFrame] to join with. + * @param columns [Column Names][String] specifying join columns. + * @return joined [DataFrame]. + */ public fun DataFrame.rightJoin(other: DataFrame, vararg columns: String): DataFrame = rightJoin(other) { columns.toColumnSet() } +/** + * Performs [full join][JoinType.Full] of this [DataFrame] with [other][\other] [DataFrame] + * using selected key columns. + * @include [JoinType.Full] + * + * This is a shortcut for [join] with [JoinType.Full]. + * + * @include [JoinBehavior] + * + * See also general [join] as well as other shortcuts with each of join types: + * [innerJoin], [leftJoin], [rightJoin], [filterJoin], [excludeJoin]. + * + * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention] + * + * See [Selecting Columns][SelectingColumns]. + * + * For more information, {@include [DocumentationUrls.Join]}. + * + * ### This `fullJoin` overload + */ +@ExcludeFromSources +private interface FullJoinDocs + +/** + * @include [FullJoinDocs] + * @include [SelectingColumnsJoinDsl] {@set [JoinMethod] fullJoin} + * @param other [DataFrame] to join with. + * @param selector [JoinColumnsSelector] specifying join columns; + * if `null`, same-name columns are used. + * @return joined [DataFrame]. + */ @Refine @Interpretable("FullJoin") public fun DataFrame.fullJoin( @@ -70,9 +317,48 @@ public fun DataFrame.fullJoin( selector: JoinColumnsSelector? = null, ): DataFrame = join(other, JoinType.Full, selector = selector) +/** + * @include [FullJoinDocs] + * @include [SelectingColumns.ColumnNames] + * @include [JoinStringApiExample] {@set [JoinMethod] fullJoin} + * @param other [DataFrame] to join with. + * @param columns [Column Names][String] specifying join columns. + * @return joined [DataFrame]. + */ public fun DataFrame.fullJoin(other: DataFrame, vararg columns: String): DataFrame = fullJoin(other) { columns.toColumnSet() } +/** + * Performs [filter join][JoinType.Filter] of this [DataFrame] with [other][\other] [DataFrame] + * using selected key columns. + * @include [JoinType.Filter] + * + * This is a shortcut for [join] with [JoinType.Filter]. + * + * @include [JoinBehavior] + * + * See also general [join] as well as other shortcuts with each of join types: + * [innerJoin], [leftJoin], [rightJoin], [fullJoin], [excludeJoin]. + * + * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention] + * + * See [Selecting Columns][SelectingColumns]. + * + * For more information, {@include [DocumentationUrls.Join]}. + * + * ### This `filterJoin` overload + */ +@ExcludeFromSources +private interface FilterJoinDocs + +/** + * @include [FilterJoinDocs] + * @include [SelectingColumnsJoinDsl] {@set [JoinMethod] filterJoin} + * @param other [DataFrame] to join with. + * @param selector [JoinColumnsSelector] specifying join columns; + * if `null`, same-name columns are used. + * @return joined [DataFrame]. + */ @Refine @Interpretable("FilterJoin") public fun DataFrame.filterJoin( @@ -80,9 +366,48 @@ public fun DataFrame.filterJoin( selector: JoinColumnsSelector? = null, ): DataFrame = joinImpl(other, JoinType.Inner, addNewColumns = false, selector = selector) +/** + * @include [FilterJoinDocs] + * @include [SelectingColumns.ColumnNames] + * @include [JoinStringApiExample] {@set [JoinMethod] filterJoin} + * @param other [DataFrame] to join with. + * @param columns [Column Names][String] specifying join columns. + * @return joined [DataFrame]. + */ public fun DataFrame.filterJoin(other: DataFrame, vararg columns: String): DataFrame = filterJoin(other) { columns.toColumnSet() } +/** + * Performs [exclude join][JoinType.Exclude] of this [DataFrame] with [other][\other] [DataFrame] + * using selected key columns. + * @include [JoinType.Exclude] + * + * This is a shortcut for [join] with [JoinType.Exclude]. + * + * @include [JoinBehavior] + * + * See also general [join] as well as other shortcuts with each of join types: + * [innerJoin], [leftJoin], [rightJoin], [filterJoin], [fullJoin]. + * + * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention] + * + * See [Selecting Columns][SelectingColumns]. + * + * For more information, {@include [DocumentationUrls.Join]}. + * + * ### This `excludeJoin` overload + */ +@ExcludeFromSources +private interface ExcludeJoinDocs + +/** + * @include [ExcludeJoinDocs] + * @include [SelectingColumnsJoinDsl] {@set [JoinMethod] excludeJoin} + * @param other [DataFrame] to join with. + * @param selector [JoinColumnsSelector] specifying join columns; + * if `null`, same-name columns are used. + * @return joined [DataFrame]. + */ @Refine @Interpretable("ExcludeJoin") public fun DataFrame.excludeJoin( @@ -90,26 +415,79 @@ public fun DataFrame.excludeJoin( selector: JoinColumnsSelector? = null, ): DataFrame = joinImpl(other, JoinType.Exclude, addNewColumns = false, selector = selector) +/** + * @include [ExcludeJoinDocs] + * @include [SelectingColumns.ColumnNames] + * @include [JoinStringApiExample] {@set [JoinMethod] excludeJoin} + * @param other [DataFrame] to join with. + * @param columns [Column Names][String] specifying join columns. + * @return joined [DataFrame]. + */ public fun DataFrame.excludeJoin(other: DataFrame, vararg columns: String): DataFrame = excludeJoin(other) { columns.toColumnSet() } +/** + * Joins all [DataFrame]s in this iterable into a single [DataFrame]. + * + * Sequentially applies the [join] operation to each [DataFrame] in order. + * Returns `null` if the iterable is empty. + * + * @param [joinType] [JoinType] defining how rows are matched and combined. + * @param [selector] optional [JoinColumnsSelector] specifying key columns. + * @return resulting [DataFrame], or `null` if the iterable is empty. + */ public fun Iterable>.joinOrNull( joinType: JoinType = JoinType.Inner, selector: JoinColumnsSelector? = null, ): DataFrame? = fold, DataFrame?>(null) { joined, new -> joined?.join(new, joinType, selector = selector) ?: new } +/** + * A specialized [ColumnsSelectionDsl] that allows specifying [join] matching columns + * with different names in left and right [DataFrame]s. + * + * @include [JoinDslDescription] + */ public interface JoinDsl : ColumnsSelectionDsl { + /** + * Provides access to columns of the right [DataFrame] + * for further matching with left columns [match]. + */ public val right: DataFrame + /** + * Matches columns from the left and right [DataFrame]s for [joining][join]. + * + * The receiver column must belong to the left [DataFrame], + * and the argument ([\other]) column must belong to the right [DataFrame]. + * + * @receiver column from the left [DataFrame]. + * @param [other] column from the right [DataFrame]. + * @return [ColumnMatch] representing the column pair used for joining. + */ + @ExcludeFromSources + private interface MatchDocs + + /** + * @include [MatchDocs] + */ @Interpretable("Match0") public infix fun ColumnReference.match(other: ColumnReference): ColumnMatch = ColumnMatch(this, other) + /** + * @include [MatchDocs] + */ public infix fun String.match(other: ColumnReference): ColumnMatch = ColumnMatch(toColumnOf(), other) + /** + * @include [MatchDocs] + */ public infix fun ColumnReference.match(other: String): ColumnMatch = ColumnMatch(this, other.toColumnOf()) + /** + * @include [MatchDocs] + */ public infix fun String.match(other: String): ColumnMatch = ColumnMatch(toColumnAccessor(), other.toColumnAccessor()) @@ -129,6 +507,12 @@ public interface JoinDsl : ColumnsSelectionDsl { ColumnMatch(toColumnAccessor(), other) public companion object { + /** + * **For internal use only.** + * Not intended for public API consumption. + * + * Used in Compiler Plugin. + */ public fun defaultJoinColumns(left: DataFrame, right: DataFrame): JoinColumnsSelector = { left.columnNames().intersect(right.columnNames().toSet()) @@ -136,6 +520,12 @@ public interface JoinDsl : ColumnsSelectionDsl { .let { ColumnListImpl(it) } } + /** + * **For internal use only.** + * Not intended for public API consumption. + * + * Used in Compiler Plugin. + */ public fun getColumns( left: DataFrame, other: DataFrame, @@ -150,6 +540,9 @@ public interface JoinDsl : ColumnsSelectionDsl { } } +/** + * A special [ColumnSet] that specifies [column match][JoinDsl.match] for [join] operation. + */ public interface ColumnMatch : ColumnSet { public val left: ColumnReference public val right: ColumnReference @@ -162,30 +555,99 @@ internal class ColumnMatchImpl(override val left: ColumnReference, overrid throw UnsupportedOperationException() } +/** + * Creates a [ColumnMatch]. + * + * Not intended for public API consumption. Please, use [match][JoinDsl.match] instead. + */ public fun ColumnMatch(left: ColumnReference, right: ColumnReference): ColumnMatch = ColumnMatchImpl(left, right) +/** + * A specialized [ColumnsSelector] used for matching columns in a [join] operation. + * + * Provides [JoinDsl] both as the receiver and the lambda parameter, and expects + * a [ColumnsResolver] as the return value. + * + * Enables defining matching columns from left and right [DataFrame]s + * using [right][JoinDsl.right] and [match][JoinDsl.match]. + */ public typealias JoinColumnsSelector = JoinDsl.(ColumnsContainer) -> ColumnsResolver<*> +/** + * Represents the type of [join] operation. + * + * {@include [JoinTypeDescription]} + */ public enum class JoinType { - Left, // all data from left dataframe, nulls for mismatches in right dataframe - Right, // all data from right dataframe, nulls for mismatches in left dataframe - Inner, // only matched data from right and left dataframe - Filter, // only matched data from left dataframe - Full, // all data from left and from right dataframe, nulls for any mismatches - Exclude, // mismatched rows from left dataframe + + /** + * Includes all rows from the left [DataFrame]; rows with matching keys are merged, + * unmatched right-side values are filled with `null`. + */ + Left, + + /** + * Includes all rows from the right [DataFrame]; rows with matching keys are merged, + * unmatched left-side values are filled with `null`. + */ + Right, + + /** + * Includes only rows with matching keys from both [DataFrame]s; + * rows are merged. + */ + Inner, + + /** + * Includes only rows from the left [DataFrame] that have a match in the right one; + * right-side columns are not merged. + */ + Filter, + + /** + * Includes all rows from both [DataFrame]s; matching rows are merged, + * all mismatches are filled with `null`. + */ + Full, + + /** + * Includes only rows from the left [DataFrame] that do *not* have a match in the right one; + * right-side columns are not merged. + */ + Exclude, } +/** + * There are two categories of joins: + * * **Merging joins** — merge matching rows from both [DataFrame]s into a single row. + * * **Non-merging joins** — select rows from the left [DataFrame] based on whether + * a match exists in the right one, without merging columns. + * + * The exact behavior depends on the specified [join type][\type]: + * + * **Merging joins:** + * * [JoinType.Inner] (default) — {@include [JoinType.Inner]} + * * [JoinType.Left] — {@include [JoinType.Left]} + * * [JoinType.Right] — {@include [JoinType.Right]} + * * [JoinType.Full] — {@include [JoinType.Full]} + * + * **Non-merging joins:** + * * [JoinType.Filter] — {@include [JoinType.Filter]} + * * [JoinType.Exclude] — {@include [JoinType.Exclude]} + */ +internal interface JoinTypeDescription + internal val JoinType.addNewColumns: Boolean get() = when (this) { JoinType.Filter, JoinType.Exclude -> false JoinType.Left, JoinType.Right, JoinType.Inner, JoinType.Full -> true } -public val JoinType.allowLeftNulls: Boolean +internal val JoinType.allowLeftNulls: Boolean get() = this == JoinType.Right || this == JoinType.Full -public val JoinType.allowRightNulls: Boolean +internal val JoinType.allowRightNulls: Boolean get() = this == JoinType.Left || this == JoinType.Full || this == JoinType.Exclude diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/documentation/DocumentationUrls.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/documentation/DocumentationUrls.kt index 959cda40b3..2971a17b40 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/documentation/DocumentationUrls.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/documentation/DocumentationUrls.kt @@ -179,4 +179,7 @@ internal interface DocumentationUrls { /** [See "`pivot` inside aggregation" on the documentation website.]({@include [Url]}/pivot.html#pivot-inside-aggregate) */ interface PivotInsideAggregationStatistics + + /** [See `join` on the documentation website.]({@include [Url]}/join.html) */ + interface Join } From abd2e9b103c1e0deda00b81807e4b4f295be1b06 Mon Sep 17 00:00:00 2001 From: "andrei.kislitsyn" Date: Tue, 18 Nov 2025 17:52:34 +0400 Subject: [PATCH 02/14] joinWith kdocs --- .../jetbrains/kotlinx/dataframe/api/join.kt | 16 +- .../kotlinx/dataframe/api/joinWith.kt | 216 +++++++++++++++++- .../documentation/DocumentationUrls.kt | 3 + 3 files changed, 227 insertions(+), 8 deletions(-) diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt index b0e1abefaf..775faa4dfe 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt @@ -42,8 +42,10 @@ private interface JoinBehavior * * @include [JoinBehavior] * - * See also shortcuts with each of join types: - * [innerJoin], [leftJoin], [rightJoin], [fullJoin], [filterJoin], [excludeJoin]. + * Each join type has a corresponding shortcut function: + * [innerJoin], [leftJoin], [rightJoin], [fullJoin], [filterJoin], and [excludeJoin]. + * + * See also [joinWith], which performs a join by matching row values condition. * * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention] * @@ -95,7 +97,7 @@ private interface SelectingColumnsJoinDsl * @include [JoinDocs] * @include [SelectingColumnsJoinDsl] * @param other [DataFrame] to join with. - * @param type [JoinType] defining how rows are matched and combined. + * @param type [JoinType] defining how the resulting rows are constructed. * @param selector [JoinColumnsSelector] specifying join columns; * if `null`, same-name columns are used. * @return joined [DataFrame]. @@ -123,7 +125,7 @@ private interface JoinStringApiExample * @include [JoinStringApiExample] * @param other [DataFrame] to join with. * @param columns [Column Names][String] specifying join columns. - * @param type [JoinType] defining how rows are matched and combined. + * @param type [JoinType] defining how the resulting rows are constructed. * @return joined [DataFrame]. */ public fun DataFrame.join( @@ -582,19 +584,19 @@ public typealias JoinColumnsSelector = JoinDsl.(ColumnsContainer) public enum class JoinType { /** - * Includes all rows from the left [DataFrame]; rows with matching keys are merged, + * Includes all rows from the left [DataFrame]; matching rows are merged, * unmatched right-side values are filled with `null`. */ Left, /** - * Includes all rows from the right [DataFrame]; rows with matching keys are merged, + * Includes all rows from the right [DataFrame]; matching rows are merged, * unmatched left-side values are filled with `null`. */ Right, /** - * Includes only rows with matching keys from both [DataFrame]s; + * Includes only matching rows from both [DataFrame]s; * rows are merged. */ Inner, diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/joinWith.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/joinWith.kt index b0a17ae44f..8fd8d32917 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/joinWith.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/joinWith.kt @@ -5,14 +5,96 @@ import org.jetbrains.kotlinx.dataframe.DataRow import org.jetbrains.kotlinx.dataframe.Selector import org.jetbrains.kotlinx.dataframe.annotations.Interpretable import org.jetbrains.kotlinx.dataframe.annotations.Refine +import org.jetbrains.kotlinx.dataframe.documentation.DocumentationUrls +import org.jetbrains.kotlinx.dataframe.documentation.DocumentationUrls.Join +import org.jetbrains.kotlinx.dataframe.documentation.ExcludeFromSources +import org.jetbrains.kotlinx.dataframe.documentation.SelectingColumns +import org.jetbrains.kotlinx.dataframe.documentation.SelectingColumns.ColumnGroupsAndNestedColumnsMention import org.jetbrains.kotlinx.dataframe.impl.api.joinWithImpl +/** + * A [JoinExpression] defines the matching condition between [rows][DataRow] of the two [DataFrame]s. + * It provides access to row values from both the left and right [DataFrame]s + * and expects a [Boolean] result indicating whether the rows match. + * All combinations of rows from the left and right [DataFrame]s that satisfies + * this condition are matched. + * + * This method is useful when the data was not originally designed relationally, or when + * rows should be matched based on custom logic rather than simple equality. + * + * Creates a new [DataFrame] by combining [rows][DataRow] + * from both inputs according to the [\joinExpression] matching rule. + */ +@ExcludeFromSources +private interface JoinWithCommonDescription + +// `joinWith` method used in the example +private interface JoinWithMethod + +/** + * ### Examples + * ```kotlin + * // Join rows where the `fullName` value in the left DataFrame + * // contains the `firstName` value in the right DataFrame. + * dfLeft.{@get [JoinWithMethod] joinWith}(dfRight) { left -> left.fullName.contains(right.firstName) } + * + * // Join rows where the `date` value in the right DataFrame + * // falls within the interval defined by the `startDate` and `endDate` + * // values in the left DataFrame. + * dfLeft.{@get [JoinWithMethod] joinWith}(dfRight) { right.date in startDate..endDate } + * ``` + */ +private interface JoinWithExample + +/** + * A specialized [DataRow] used in a [JoinExpression]. + * + * Represents a row from the left [DataFrame] (as the receiver) + * and provides access to the row from the right [DataFrame] via [right]. + */ public interface JoinedDataRow : DataRow { public val right: DataRow } +/** + * A special [row][DataRow] expression used to define + * the row-matching condition in a [joinWith] operation. + * + * Provides the [row][DataRow] of the left [DataFrame] both + * as the receiver (`this`) and as the argument (`it`), + * allowing you to reference its values directly. + * + * The [row][DataRow] of the right [DataFrame] is available + * via [right][JoinedDataRow.right]. + * + * The expression must return a [Boolean] indicating whether + * the rows from the left and right [DataFrame]s match. + */ public typealias JoinExpression = Selector, Boolean> +/** + * Joins this [DataFrame] with the [right][\right] [DataFrame] + * using the provided [\joinExpression]. + * + * @include [JoinWithCommonDescription] + * + * {@include [JoinTypeDescription]} + * + * Each join type has a corresponding shortcut function: + * [innerJoinWith], [leftJoinWith], [rightJoinWith], [fullJoinWith], [filterJoinWith], and [excludeJoinWith]. + * + * See also [join], which performs a join by simply matching columns. + * + * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention] + * + * For more information, {@include [DocumentationUrls.JoinWith]}. + * + * @include [JoinWithExample] + * @param [right] [DataFrame] to join with. + * @param [type] [JoinType] defining how rows are matched and combined. + * @param [joinExpression] [JoinExpression] specifying rows join condition. + * @return joined [DataFrame]. + */ @Refine @Interpretable("JoinWith") public fun DataFrame.joinWith( @@ -21,31 +103,163 @@ public fun DataFrame.joinWith( joinExpression: JoinExpression, ): DataFrame = joinWithImpl(right, type, addNewColumns = type.addNewColumns, joinExpression) +/** + * Performs [inner join][JoinType.Inner] of this [DataFrame] with the [right][\right] [DataFrame] + * using the provided [\joinExpression]. {@include [JoinType.Inner]} + * + * This is a shortcut for [joinWith] with [JoinType.Inner]. + * + * @include [JoinWithCommonDescription] + * + * See also general [joinWith] as well as other shortcuts with each of join types: + * [leftJoinWith], [rightJoinWith], [fullJoinWith], [filterJoinWith], [excludeJoinWith]. + * + * See also [join], which performs a join by simply matching columns. + * + * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention] + * + * For more information, {@include [DocumentationUrls.JoinWith]}. + * + * @include [JoinWithExample] {@set [JoinWithMethod] innerJoinWith} + * @param [right] [DataFrame] to join with. + * @param [joinExpression] [JoinExpression] specifying rows join condition. + * @return joined [DataFrame]. + */ @Refine @Interpretable("InnerJoinWith") public fun DataFrame.innerJoinWith(right: DataFrame, joinExpression: JoinExpression): DataFrame = joinWith(right, JoinType.Inner, joinExpression) +/** + * Performs [left join][JoinType.Left] of this [DataFrame] with the [right][\right] [DataFrame] + * using the provided [\joinExpression]. {@include [JoinType.Left]} + * + * This is a shortcut for [joinWith] with [JoinType.Left]. + * + * @include [JoinWithCommonDescription] + * + * See also general [joinWith] as well as other shortcuts with each of join types: + * [innerJoinWith], [rightJoinWith], [fullJoinWith], [filterJoinWith], [excludeJoinWith]. + * + * See also [join], which performs a join by simply matching columns. + * + * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention] + * + * For more information, {@include [DocumentationUrls.JoinWith]}. + * + * @include [JoinWithExample] {@set [JoinWithMethod] leftJoinWith} + * @param [right] [DataFrame] to join with. + * @param [joinExpression] [JoinExpression] specifying rows join condition. + * @return joined [DataFrame]. + */ @Refine @Interpretable("LeftJoinWith") public fun DataFrame.leftJoinWith(right: DataFrame, joinExpression: JoinExpression): DataFrame = joinWith(right, JoinType.Left, joinExpression) +/** + * Performs [right join][JoinType.Right] of this [DataFrame] with the [right][\right] [DataFrame] + * using the provided [\joinExpression]. {@include [JoinType.Right]} + * + * This is a shortcut for [joinWith] with [JoinType.Right]. + * + * @include [JoinWithCommonDescription] + * + * See also general [joinWith] as well as other shortcuts with each of join types: + * [innerJoinWith], [leftJoinWith], [fullJoinWith], [filterJoinWith], [excludeJoinWith]. + * + * See also [join], which performs a join by simply matching columns. + * + * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention] + * + * For more information, {@include [DocumentationUrls.JoinWith]}. + * + * @include [JoinWithExample] {@set [JoinWithMethod] rightJoinWith} + * @param [right] [DataFrame] to join with. + * @param [joinExpression] [JoinExpression] specifying rows join condition. + * @return joined [DataFrame]. + */ @Refine @Interpretable("RightJoinWith") public fun DataFrame.rightJoinWith(right: DataFrame, joinExpression: JoinExpression): DataFrame = joinWith(right, JoinType.Right, joinExpression) +/** + * Performs [full join][JoinType.Full] of this [DataFrame] with the [right][\right] [DataFrame] + * using the provided [\joinExpression]. {@include [JoinType.Full]} + * + * This is a shortcut for [joinWith] with [JoinType.Full]. + * + * @include [JoinWithCommonDescription] + * + * See also general [joinWith] as well as other shortcuts with each of join types: + * [leftJoinWith], [rightJoinWith], [innerJoinWith], [filterJoinWith], [excludeJoinWith]. + * + * See also [join], which performs a join by simply matching columns. + * + * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention] + * + * For more information, {@include [DocumentationUrls.JoinWith]}. + * + * @include [JoinWithExample] {@set [JoinWithMethod] fullJoinWith} + * @param [right] [DataFrame] to join with. + * @param [joinExpression] [JoinExpression] specifying rows join condition. + * @return joined [DataFrame]. + */ @Refine @Interpretable("FullJoinWith") public fun DataFrame.fullJoinWith(right: DataFrame, joinExpression: JoinExpression): DataFrame = joinWith(right, JoinType.Full, joinExpression) +/** + * Performs [filter join][JoinType.Filter] of this [DataFrame] with the [right][\right] [DataFrame] + * using the provided [\joinExpression]. {@include [JoinType.Filter]} + * + * This is a shortcut for [joinWith] with [JoinType.Filter]. + * + * @include [JoinWithCommonDescription] + * + * See also general [joinWith] as well as other shortcuts with each of join types: + * [leftJoinWith], [rightJoinWith], [fullJoinWith], [innerJoinWith], [excludeJoinWith]. + * + * See also [join], which performs a join by simply matching columns. + * + * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention] + * + * For more information, {@include [DocumentationUrls.JoinWith]}. + * + * @include [JoinWithExample] {@set [JoinWithMethod] filterJoinWith} + * @param [right] [DataFrame] to join with. + * @param [joinExpression] [JoinExpression] specifying rows join condition. + * @return joined [DataFrame]. + */ @Refine @Interpretable("FilterJoinWith") public fun DataFrame.filterJoinWith(right: DataFrame, joinExpression: JoinExpression): DataFrame = - joinWithImpl(right, JoinType.Inner, addNewColumns = false, joinExpression) + joinWithImpl(right, JoinType.Filter, addNewColumns = false, joinExpression) +/** + * Performs [exclude join][JoinType.Exclude] of this [DataFrame] with the [right][\right] [DataFrame] + * using the provided [\joinExpression]. {@include [JoinType.Exclude]} + * + * This is a shortcut for [joinWith] with [JoinType.Exclude]. + * + * @include [JoinWithCommonDescription] + * + * See also general [joinWith] as well as other shortcuts with each of join types: + * [leftJoinWith], [rightJoinWith], [fullJoinWith], [filterJoinWith], [innerJoinWith]. + * + * See also [join], which performs a join by simply matching columns. + * + * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention] + * + * For more information, {@include [DocumentationUrls.JoinWith]}. + * + * @include [JoinWithExample] {@set [JoinWithMethod] excludeJoinWith} + * @param [right] [DataFrame] to join with. + * @param [joinExpression] [JoinExpression] specifying rows join condition. + * @return joined [DataFrame]. + */ @Refine @Interpretable("ExcludeJoinWith") public fun DataFrame.excludeJoinWith( diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/documentation/DocumentationUrls.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/documentation/DocumentationUrls.kt index 2971a17b40..006c494270 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/documentation/DocumentationUrls.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/documentation/DocumentationUrls.kt @@ -182,4 +182,7 @@ internal interface DocumentationUrls { /** [See `join` on the documentation website.]({@include [Url]}/join.html) */ interface Join + + /** [See `joinWith` on the documentation website.]({@include [Url]}/joinWith.html) */ + interface JoinWith } From 3e1351e2461e02df9c5f7f2d5df289df85d52210 Mon Sep 17 00:00:00 2001 From: "andrei.kislitsyn" Date: Thu, 20 Nov 2025 15:53:55 +0400 Subject: [PATCH 03/14] join kdocs fixes --- .../dataframe/documentation/AutoRenaming.kt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/documentation/AutoRenaming.kt diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/documentation/AutoRenaming.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/documentation/AutoRenaming.kt new file mode 100644 index 0000000000..d4ba3cefcf --- /dev/null +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/documentation/AutoRenaming.kt @@ -0,0 +1,18 @@ +package org.jetbrains.kotlinx.dataframe.documentation + +import org.jetbrains.kotlinx.dataframe.DataFrame + +/** + * ## Auto-renaming in [DataFrame] + * + * In some operations, multiple columns with the same name may appear + * in the resulting [DataFrame]. + * + * In such cases, columns with duplicate names are automatically renamed + * using the pattern `"\$name\$n"`, where `name` is the original column name + * and `n` is a unique index (1, 2, 3, and so on); the first name column goes without a number. + * + * It is recommended to [rename][org.jetbrains.kotlinx.dataframe.api.rename] them + * to maintain clarity and improve code readability. + */ +internal interface AutoRenaming From e070b97b537bc8a3b852d0629f31860676c5ae8c Mon Sep 17 00:00:00 2001 From: "andrei.kislitsyn" Date: Thu, 20 Nov 2025 15:53:59 +0400 Subject: [PATCH 04/14] join kdocs fixes --- .../jetbrains/kotlinx/dataframe/api/join.kt | 87 +++++++++---------- .../kotlinx/dataframe/api/joinWith.kt | 64 +++++++------- 2 files changed, 76 insertions(+), 75 deletions(-) diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt index 775faa4dfe..382380dee6 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt @@ -27,13 +27,15 @@ import kotlin.reflect.KProperty * If no join columns are specified, all columns with matching names in both [DataFrame]s are used. * * If both [DataFrame]s contain columns with the same name that are *not* part of the join keys, - * such columns are treated as distinct. Such a column from the right [DataFrame] will be automatically - * renamed in the resulting [DataFrame]. + * such columns are treated as distinct. Such a column from the right [DataFrame] will be + * [automatically renamed][org.jetbrains.kotlinx.dataframe.documentation.AutoRenaming] + * in the resulting [DataFrame]. */ +@ExcludeFromSources private interface JoinBehavior /** - * Joins this [DataFrame] with [other][\other] [DataFrame] using selected key columns. + * Joins this [DataFrame] with the [other][\other] [DataFrame] using the selected key columns. * * Creates a new [DataFrame] by combining [rows][org.jetbrains.kotlinx.dataframe.DataRow] * from two input dataframes according to one or more matching key columns. @@ -55,10 +57,12 @@ private interface JoinBehavior * * ### This `join` overload */ +@ExcludeFromSources private interface JoinDocs // `join` method used in the example -private interface JoinMethod +@ExcludeFromSources +private interface JOIN_METHOD /** * [JoinDsl] defines the columns used for joining [DataFrame]s @@ -86,11 +90,12 @@ private interface JoinMethod internal interface JoinDslDescription /** - * Select join columns (incl. with different names in this and [other][other] [DataFrame]s) + * Select join columns (incl. with different names in `this` and [other][other] [DataFrame]s) * using [JoinDsl]. * * @include [JoinDslDescription] */ +@ExcludeFromSources private interface SelectingColumnsJoinDsl /** @@ -135,15 +140,15 @@ public fun DataFrame.join( ): DataFrame = join(other, type) { columns.toColumnSet() } /** - * Performs [inner join][JoinType.Inner] of this [DataFrame] with [other][\other] [DataFrame] - * using selected key columns. + * Performs a [inner join][JoinType.Inner] of this [DataFrame] with the [other][\other] [DataFrame] + * using the selected key columns. * @include [JoinType.Inner] * * This is a shortcut for [join] with [JoinType.Inner]. * * @include [JoinBehavior] * - * See also general [join] as well as other shortcuts with each of join types: + * See also general [join], as well as other shortcuts with each of join types: * [leftJoin], [rightJoin], [fullJoin], [filterJoin], [excludeJoin]. * * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention] @@ -159,7 +164,7 @@ private interface InnerJoinDocs /** * @include [InnerJoinDocs] - * @include [SelectingColumnsJoinDsl] {@set [JoinMethod] innerJoin} + * @include [SelectingColumnsJoinDsl] {@set [JOIN_METHOD] innerJoin} * @param other [DataFrame] to join with. * @param selector [JoinColumnsSelector] specifying join columns; * if `null`, same-name columns are used. @@ -175,7 +180,7 @@ public fun DataFrame.innerJoin( /** * @include [InnerJoinDocs] * @include [SelectingColumns.ColumnNames] - * @include [JoinStringApiExample] {@set [JoinMethod] innerJoin} + * @include [JoinStringApiExample] {@set [JOIN_METHOD] innerJoin} * @param other [DataFrame] to join with. * @param columns [Column Names][String] specifying join columns. * @return joined [DataFrame]. @@ -184,15 +189,15 @@ public fun DataFrame.innerJoin(other: DataFrame, vararg columns: St innerJoin(other) { columns.toColumnSet() } /** - * Performs [left join][JoinType.Left] of this [DataFrame] with [other][\other] [DataFrame] - * using selected key columns. + * Performs a [left join][JoinType.Left] of this [DataFrame] with the [other][\other] [DataFrame] + * using the selected key columns. * @include [JoinType.Left] * * This is a shortcut for [join] with [JoinType.Left]. * * @include [JoinBehavior] * - * See also general [join] as well as other shortcuts with each of join types: + * See also general [join], as well as other shortcuts with each of join types: * [innerJoin], [rightJoin], [fullJoin], [filterJoin], [excludeJoin]. * * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention] @@ -208,7 +213,7 @@ private interface LeftJoinDocs /** * @include [LeftJoinDocs] - * @include [SelectingColumnsJoinDsl] {@set [JoinMethod] leftJoin} + * @include [SelectingColumnsJoinDsl] {@set [JOIN_METHOD] leftJoin} * @param other [DataFrame] to join with. * @param selector [JoinColumnsSelector] specifying join columns; * if `null`, same-name columns are used. @@ -224,7 +229,7 @@ public fun DataFrame.leftJoin( /** * @include [LeftJoinDocs] * @include [SelectingColumns.ColumnNames] - * @include [JoinStringApiExample] {@set [JoinMethod] leftJoin} + * @include [JoinStringApiExample] {@set [JOIN_METHOD] leftJoin} * @param other [DataFrame] to join with. * @param columns [Column Names][String] specifying join columns. * @return joined [DataFrame]. @@ -233,7 +238,7 @@ public fun DataFrame.leftJoin(other: DataFrame, vararg columns: Str leftJoin(other) { columns.toColumnSet() } /** - * Performs [right join][JoinType.Right] of this [DataFrame] with [other][\other] [DataFrame] + * Performs a [right join][JoinType.Right] of this [DataFrame] with [other][\other] [DataFrame] * using selected key columns. * @include [JoinType.Right] * @@ -241,7 +246,7 @@ public fun DataFrame.leftJoin(other: DataFrame, vararg columns: Str * * @include [JoinBehavior] * - * See also general [join] as well as other shortcuts with each of join types: + * See also general [join], as well as other shortcuts with each of join types: * [innerJoin], [leftJoin], [fullJoin], [filterJoin], [excludeJoin]. * * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention] @@ -257,7 +262,7 @@ private interface RightJoinDocs /** * @include [RightJoinDocs] - * @include [SelectingColumnsJoinDsl] {@set [JoinMethod] rightJoin} + * @include [SelectingColumnsJoinDsl] {@set [JOIN_METHOD] rightJoin} * @param other [DataFrame] to join with. * @param selector [JoinColumnsSelector] specifying join columns; * if `null`, same-name columns are used. @@ -273,7 +278,7 @@ public fun DataFrame.rightJoin( /** * @include [RightJoinDocs] * @include [SelectingColumns.ColumnNames] - * @include [JoinStringApiExample] {@set [JoinMethod] rightJoin} + * @include [JoinStringApiExample] {@set [JOIN_METHOD] rightJoin} * @param other [DataFrame] to join with. * @param columns [Column Names][String] specifying join columns. * @return joined [DataFrame]. @@ -282,7 +287,7 @@ public fun DataFrame.rightJoin(other: DataFrame, vararg columns: St rightJoin(other) { columns.toColumnSet() } /** - * Performs [full join][JoinType.Full] of this [DataFrame] with [other][\other] [DataFrame] + * Performs a [full join][JoinType.Full] of this [DataFrame] with [other][\other] [DataFrame] * using selected key columns. * @include [JoinType.Full] * @@ -290,7 +295,7 @@ public fun DataFrame.rightJoin(other: DataFrame, vararg columns: St * * @include [JoinBehavior] * - * See also general [join] as well as other shortcuts with each of join types: + * See also general [join], as well as other shortcuts with each of join types: * [innerJoin], [leftJoin], [rightJoin], [filterJoin], [excludeJoin]. * * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention] @@ -306,7 +311,7 @@ private interface FullJoinDocs /** * @include [FullJoinDocs] - * @include [SelectingColumnsJoinDsl] {@set [JoinMethod] fullJoin} + * @include [SelectingColumnsJoinDsl] {@set [JOIN_METHOD] fullJoin} * @param other [DataFrame] to join with. * @param selector [JoinColumnsSelector] specifying join columns; * if `null`, same-name columns are used. @@ -322,7 +327,7 @@ public fun DataFrame.fullJoin( /** * @include [FullJoinDocs] * @include [SelectingColumns.ColumnNames] - * @include [JoinStringApiExample] {@set [JoinMethod] fullJoin} + * @include [JoinStringApiExample] {@set [JOIN_METHOD] fullJoin} * @param other [DataFrame] to join with. * @param columns [Column Names][String] specifying join columns. * @return joined [DataFrame]. @@ -331,7 +336,7 @@ public fun DataFrame.fullJoin(other: DataFrame, vararg columns: Str fullJoin(other) { columns.toColumnSet() } /** - * Performs [filter join][JoinType.Filter] of this [DataFrame] with [other][\other] [DataFrame] + * Performs a [filter join][JoinType.Filter] of this [DataFrame] with [other][\other] [DataFrame] * using selected key columns. * @include [JoinType.Filter] * @@ -339,7 +344,7 @@ public fun DataFrame.fullJoin(other: DataFrame, vararg columns: Str * * @include [JoinBehavior] * - * See also general [join] as well as other shortcuts with each of join types: + * See also general [join], as well as other shortcuts with each of join types: * [innerJoin], [leftJoin], [rightJoin], [fullJoin], [excludeJoin]. * * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention] @@ -355,7 +360,7 @@ private interface FilterJoinDocs /** * @include [FilterJoinDocs] - * @include [SelectingColumnsJoinDsl] {@set [JoinMethod] filterJoin} + * @include [SelectingColumnsJoinDsl] {@set [JOIN_METHOD] filterJoin} * @param other [DataFrame] to join with. * @param selector [JoinColumnsSelector] specifying join columns; * if `null`, same-name columns are used. @@ -371,7 +376,7 @@ public fun DataFrame.filterJoin( /** * @include [FilterJoinDocs] * @include [SelectingColumns.ColumnNames] - * @include [JoinStringApiExample] {@set [JoinMethod] filterJoin} + * @include [JoinStringApiExample] {@set [JOIN_METHOD] filterJoin} * @param other [DataFrame] to join with. * @param columns [Column Names][String] specifying join columns. * @return joined [DataFrame]. @@ -380,7 +385,7 @@ public fun DataFrame.filterJoin(other: DataFrame, vararg columns: S filterJoin(other) { columns.toColumnSet() } /** - * Performs [exclude join][JoinType.Exclude] of this [DataFrame] with [other][\other] [DataFrame] + * Performs a [exclude join][JoinType.Exclude] of this [DataFrame] with [other][\other] [DataFrame] * using selected key columns. * @include [JoinType.Exclude] * @@ -388,7 +393,7 @@ public fun DataFrame.filterJoin(other: DataFrame, vararg columns: S * * @include [JoinBehavior] * - * See also general [join] as well as other shortcuts with each of join types: + * See also general [join], as well as other shortcuts with each of join types: * [innerJoin], [leftJoin], [rightJoin], [filterJoin], [fullJoin]. * * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention] @@ -404,7 +409,7 @@ private interface ExcludeJoinDocs /** * @include [ExcludeJoinDocs] - * @include [SelectingColumnsJoinDsl] {@set [JoinMethod] excludeJoin} + * @include [SelectingColumnsJoinDsl] {@set [JOIN_METHOD] excludeJoin} * @param other [DataFrame] to join with. * @param selector [JoinColumnsSelector] specifying join columns; * if `null`, same-name columns are used. @@ -420,7 +425,7 @@ public fun DataFrame.excludeJoin( /** * @include [ExcludeJoinDocs] * @include [SelectingColumns.ColumnNames] - * @include [JoinStringApiExample] {@set [JoinMethod] excludeJoin} + * @include [JoinStringApiExample] {@set [JOIN_METHOD] excludeJoin} * @param other [DataFrame] to join with. * @param columns [Column Names][String] specifying join columns. * @return joined [DataFrame]. @@ -471,25 +476,17 @@ public interface JoinDsl : ColumnsSelectionDsl { @ExcludeFromSources private interface MatchDocs - /** - * @include [MatchDocs] - */ + /** @include [MatchDocs] */ @Interpretable("Match0") public infix fun ColumnReference.match(other: ColumnReference): ColumnMatch = ColumnMatch(this, other) - /** - * @include [MatchDocs] - */ + /** @include [MatchDocs] */ public infix fun String.match(other: ColumnReference): ColumnMatch = ColumnMatch(toColumnOf(), other) - /** - * @include [MatchDocs] - */ + /** @include [MatchDocs] */ public infix fun ColumnReference.match(other: String): ColumnMatch = ColumnMatch(this, other.toColumnOf()) - /** - * @include [MatchDocs] - */ + /** @include [MatchDocs] */ public infix fun String.match(other: String): ColumnMatch = ColumnMatch(toColumnAccessor(), other.toColumnAccessor()) @@ -543,7 +540,7 @@ public interface JoinDsl : ColumnsSelectionDsl { } /** - * A special [ColumnSet] that specifies [column match][JoinDsl.match] for [join] operation. + * A special [ColumnSet] that specifies a [column match][JoinDsl.match] for the [join] operation. */ public interface ColumnMatch : ColumnSet { public val left: ColumnReference @@ -560,7 +557,7 @@ internal class ColumnMatchImpl(override val left: ColumnReference, overrid /** * Creates a [ColumnMatch]. * - * Not intended for public API consumption. Please, use [match][JoinDsl.match] instead. + * Not intended for public API consumption. Please use [match][JoinDsl.match] instead. */ public fun ColumnMatch(left: ColumnReference, right: ColumnReference): ColumnMatch = ColumnMatchImpl(left, right) diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/joinWith.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/joinWith.kt index 8fd8d32917..118e31ae74 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/joinWith.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/joinWith.kt @@ -6,21 +6,19 @@ import org.jetbrains.kotlinx.dataframe.Selector import org.jetbrains.kotlinx.dataframe.annotations.Interpretable import org.jetbrains.kotlinx.dataframe.annotations.Refine import org.jetbrains.kotlinx.dataframe.documentation.DocumentationUrls -import org.jetbrains.kotlinx.dataframe.documentation.DocumentationUrls.Join import org.jetbrains.kotlinx.dataframe.documentation.ExcludeFromSources import org.jetbrains.kotlinx.dataframe.documentation.SelectingColumns -import org.jetbrains.kotlinx.dataframe.documentation.SelectingColumns.ColumnGroupsAndNestedColumnsMention import org.jetbrains.kotlinx.dataframe.impl.api.joinWithImpl /** * A [JoinExpression] defines the matching condition between [rows][DataRow] of the two [DataFrame]s. * It provides access to row values from both the left and right [DataFrame]s * and expects a [Boolean] result indicating whether the rows match. - * All combinations of rows from the left and right [DataFrame]s that satisfies + * All combinations of rows from the left- and right [DataFrame] that satisfies * this condition are matched. * - * This method is useful when the data was not originally designed relationally, or when - * rows should be matched based on custom logic rather than simple equality. + * This method is useful when rows should be matched based on custom logic + * rather than simple values equality. * * Creates a new [DataFrame] by combining [rows][DataRow] * from both inputs according to the [\joinExpression] matching rule. @@ -29,21 +27,27 @@ import org.jetbrains.kotlinx.dataframe.impl.api.joinWithImpl private interface JoinWithCommonDescription // `joinWith` method used in the example -private interface JoinWithMethod +@ExcludeFromSources +private interface JOIN_WITH_METHOD /** * ### Examples * ```kotlin - * // Join rows where the `fullName` value in the left DataFrame - * // contains the `firstName` value in the right DataFrame. + * // Join rows where the `fullName` value in the left `DataFrame` + * // contains the `firstName` value in the right `DataFrame`. * dfLeft.{@get [JoinWithMethod] joinWith}(dfRight) { left -> left.fullName.contains(right.firstName) } * - * // Join rows where the `date` value in the right DataFrame + * // Join rows where the `date` value in the right `DataFrame` * // falls within the interval defined by the `startDate` and `endDate` - * // values in the left DataFrame. + * // values in the left `DataFrame`. * dfLeft.{@get [JoinWithMethod] joinWith}(dfRight) { right.date in startDate..endDate } + * + * // String API; join rows where `score` value in the left `DataFrame` is higher than 3.4 + * // and the `passed` value in the right `DataFrame` is `true`. + * dfLeft.{@get [JoinWithMethod] joinWith}(dfRight) { "score"() > 3.4 && right["passed"] as Boolean } * ``` */ +@ExcludeFromSources private interface JoinWithExample /** @@ -83,7 +87,7 @@ public typealias JoinExpression = Selector, Boolean> * Each join type has a corresponding shortcut function: * [innerJoinWith], [leftJoinWith], [rightJoinWith], [fullJoinWith], [filterJoinWith], and [excludeJoinWith]. * - * See also [join], which performs a join by simply matching columns. + * See also [join], which performs a join by exact values equality in the selected columns. * * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention] * @@ -92,7 +96,7 @@ public typealias JoinExpression = Selector, Boolean> * @include [JoinWithExample] * @param [right] [DataFrame] to join with. * @param [type] [JoinType] defining how rows are matched and combined. - * @param [joinExpression] [JoinExpression] specifying rows join condition. + * @param [joinExpression] [JoinExpression] specifying the rows join condition. * @return joined [DataFrame]. */ @Refine @@ -104,7 +108,7 @@ public fun DataFrame.joinWith( ): DataFrame = joinWithImpl(right, type, addNewColumns = type.addNewColumns, joinExpression) /** - * Performs [inner join][JoinType.Inner] of this [DataFrame] with the [right][\right] [DataFrame] + * Performs a [inner join][JoinType.Inner] of this [DataFrame] with the [right][\right] [DataFrame] * using the provided [\joinExpression]. {@include [JoinType.Inner]} * * This is a shortcut for [joinWith] with [JoinType.Inner]. @@ -120,9 +124,9 @@ public fun DataFrame.joinWith( * * For more information, {@include [DocumentationUrls.JoinWith]}. * - * @include [JoinWithExample] {@set [JoinWithMethod] innerJoinWith} + * @include [JoinWithExample] {@set [JOIN_WITH_METHOD] innerJoinWith} * @param [right] [DataFrame] to join with. - * @param [joinExpression] [JoinExpression] specifying rows join condition. + * @param [joinExpression] [JoinExpression] specifying the rows join condition. * @return joined [DataFrame]. */ @Refine @@ -131,7 +135,7 @@ public fun DataFrame.innerJoinWith(right: DataFrame, joinExpression joinWith(right, JoinType.Inner, joinExpression) /** - * Performs [left join][JoinType.Left] of this [DataFrame] with the [right][\right] [DataFrame] + * Performs a [left join][JoinType.Left] of this [DataFrame] with the [right][\right] [DataFrame] * using the provided [\joinExpression]. {@include [JoinType.Left]} * * This is a shortcut for [joinWith] with [JoinType.Left]. @@ -147,9 +151,9 @@ public fun DataFrame.innerJoinWith(right: DataFrame, joinExpression * * For more information, {@include [DocumentationUrls.JoinWith]}. * - * @include [JoinWithExample] {@set [JoinWithMethod] leftJoinWith} + * @include [JoinWithExample] {@set [JOIN_WITH_METHOD] leftJoinWith} * @param [right] [DataFrame] to join with. - * @param [joinExpression] [JoinExpression] specifying rows join condition. + * @param [joinExpression] [JoinExpression] specifying the rows join condition. * @return joined [DataFrame]. */ @Refine @@ -158,7 +162,7 @@ public fun DataFrame.leftJoinWith(right: DataFrame, joinExpression: joinWith(right, JoinType.Left, joinExpression) /** - * Performs [right join][JoinType.Right] of this [DataFrame] with the [right][\right] [DataFrame] + * Performs a [right join][JoinType.Right] of this [DataFrame] with the [right][\right] [DataFrame] * using the provided [\joinExpression]. {@include [JoinType.Right]} * * This is a shortcut for [joinWith] with [JoinType.Right]. @@ -174,9 +178,9 @@ public fun DataFrame.leftJoinWith(right: DataFrame, joinExpression: * * For more information, {@include [DocumentationUrls.JoinWith]}. * - * @include [JoinWithExample] {@set [JoinWithMethod] rightJoinWith} + * @include [JoinWithExample] {@set [JOIN_WITH_METHOD] rightJoinWith} * @param [right] [DataFrame] to join with. - * @param [joinExpression] [JoinExpression] specifying rows join condition. + * @param [joinExpression] [JoinExpression] specifying the rows join condition. * @return joined [DataFrame]. */ @Refine @@ -185,7 +189,7 @@ public fun DataFrame.rightJoinWith(right: DataFrame, joinExpression joinWith(right, JoinType.Right, joinExpression) /** - * Performs [full join][JoinType.Full] of this [DataFrame] with the [right][\right] [DataFrame] + * Performs a [full join][JoinType.Full] of this [DataFrame] with the [right][\right] [DataFrame] * using the provided [\joinExpression]. {@include [JoinType.Full]} * * This is a shortcut for [joinWith] with [JoinType.Full]. @@ -201,9 +205,9 @@ public fun DataFrame.rightJoinWith(right: DataFrame, joinExpression * * For more information, {@include [DocumentationUrls.JoinWith]}. * - * @include [JoinWithExample] {@set [JoinWithMethod] fullJoinWith} + * @include [JoinWithExample] {@set [JOIN_WITH_METHOD] fullJoinWith} * @param [right] [DataFrame] to join with. - * @param [joinExpression] [JoinExpression] specifying rows join condition. + * @param [joinExpression] [JoinExpression] specifying the rows join condition. * @return joined [DataFrame]. */ @Refine @@ -212,7 +216,7 @@ public fun DataFrame.fullJoinWith(right: DataFrame, joinExpression: joinWith(right, JoinType.Full, joinExpression) /** - * Performs [filter join][JoinType.Filter] of this [DataFrame] with the [right][\right] [DataFrame] + * Performs a [filter join][JoinType.Filter] of this [DataFrame] with the [right][\right] [DataFrame] * using the provided [\joinExpression]. {@include [JoinType.Filter]} * * This is a shortcut for [joinWith] with [JoinType.Filter]. @@ -228,9 +232,9 @@ public fun DataFrame.fullJoinWith(right: DataFrame, joinExpression: * * For more information, {@include [DocumentationUrls.JoinWith]}. * - * @include [JoinWithExample] {@set [JoinWithMethod] filterJoinWith} + * @include [JoinWithExample] {@set [JOIN_WITH_METHOD] filterJoinWith} * @param [right] [DataFrame] to join with. - * @param [joinExpression] [JoinExpression] specifying rows join condition. + * @param [joinExpression] [JoinExpression] specifying the rows join condition. * @return joined [DataFrame]. */ @Refine @@ -239,7 +243,7 @@ public fun DataFrame.filterJoinWith(right: DataFrame, joinExpressio joinWithImpl(right, JoinType.Filter, addNewColumns = false, joinExpression) /** - * Performs [exclude join][JoinType.Exclude] of this [DataFrame] with the [right][\right] [DataFrame] + * Performs a [exclude join][JoinType.Exclude] of this [DataFrame] with the [right][\right] [DataFrame] * using the provided [\joinExpression]. {@include [JoinType.Exclude]} * * This is a shortcut for [joinWith] with [JoinType.Exclude]. @@ -255,9 +259,9 @@ public fun DataFrame.filterJoinWith(right: DataFrame, joinExpressio * * For more information, {@include [DocumentationUrls.JoinWith]}. * - * @include [JoinWithExample] {@set [JoinWithMethod] excludeJoinWith} + * @include [JoinWithExample] {@set [JOIN_WITH_METHOD] excludeJoinWith} * @param [right] [DataFrame] to join with. - * @param [joinExpression] [JoinExpression] specifying rows join condition. + * @param [joinExpression] [JoinExpression] specifying the rows join condition. * @return joined [DataFrame]. */ @Refine From d228cbc80253b858719b1bc17eac353e365ad6bc Mon Sep 17 00:00:00 2001 From: "andrei.kislitsyn" Date: Thu, 20 Nov 2025 17:32:55 +0400 Subject: [PATCH 05/14] ktlint format --- core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt | 1 + .../main/kotlin/org/jetbrains/kotlinx/dataframe/api/joinWith.kt | 1 + 2 files changed, 2 insertions(+) diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt index 382380dee6..9484b0a8ad 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt @@ -61,6 +61,7 @@ private interface JoinBehavior private interface JoinDocs // `join` method used in the example +@Suppress("ktlint:standard:class-naming") @ExcludeFromSources private interface JOIN_METHOD diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/joinWith.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/joinWith.kt index 118e31ae74..99ae4ac085 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/joinWith.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/joinWith.kt @@ -27,6 +27,7 @@ import org.jetbrains.kotlinx.dataframe.impl.api.joinWithImpl private interface JoinWithCommonDescription // `joinWith` method used in the example +@Suppress("ktlint:standard:class-naming") @ExcludeFromSources private interface JOIN_WITH_METHOD From 6337ea4d5bc596ccc74f7899e80bf28d6c96c99d Mon Sep 17 00:00:00 2001 From: "andrei.kislitsyn" Date: Thu, 20 Nov 2025 17:35:43 +0400 Subject: [PATCH 06/14] kodex exclude fix --- core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt index 9484b0a8ad..1694bae5b3 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt @@ -636,6 +636,7 @@ public enum class JoinType { * * [JoinType.Filter] — {@include [JoinType.Filter]} * * [JoinType.Exclude] — {@include [JoinType.Exclude]} */ +@ExcludeFromSources internal interface JoinTypeDescription internal val JoinType.addNewColumns: Boolean From 04aeb78e2fbd3ff8b1874f48f6b48fa0b8d09c51 Mon Sep 17 00:00:00 2001 From: "andrei.kislitsyn" Date: Thu, 20 Nov 2025 17:37:55 +0400 Subject: [PATCH 07/14] apiDump --- core/api/core.api | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/api/core.api b/core/api/core.api index e76e11eaba..4f5c393e97 100644 --- a/core/api/core.api +++ b/core/api/core.api @@ -2662,8 +2662,6 @@ public final class org/jetbrains/kotlinx/dataframe/api/JoinKt { public static final fun fullJoin (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lkotlin/jvm/functions/Function2;)Lorg/jetbrains/kotlinx/dataframe/DataFrame; public static final fun fullJoin (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lorg/jetbrains/kotlinx/dataframe/DataFrame;[Ljava/lang/String;)Lorg/jetbrains/kotlinx/dataframe/DataFrame; public static synthetic fun fullJoin$default (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lorg/jetbrains/kotlinx/dataframe/DataFrame; - public static final fun getAllowLeftNulls (Lorg/jetbrains/kotlinx/dataframe/api/JoinType;)Z - public static final fun getAllowRightNulls (Lorg/jetbrains/kotlinx/dataframe/api/JoinType;)Z public static final fun innerJoin (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lkotlin/jvm/functions/Function2;)Lorg/jetbrains/kotlinx/dataframe/DataFrame; public static final fun innerJoin (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lorg/jetbrains/kotlinx/dataframe/DataFrame;[Ljava/lang/String;)Lorg/jetbrains/kotlinx/dataframe/DataFrame; public static synthetic fun innerJoin$default (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lorg/jetbrains/kotlinx/dataframe/DataFrame; From fd87cdfde38cb9b3c8cbccfe67298fdaa677df3e Mon Sep 17 00:00:00 2001 From: "andrei.kislitsyn" Date: Thu, 20 Nov 2025 22:15:58 +0400 Subject: [PATCH 08/14] fix join type enum kdocs --- .../jetbrains/kotlinx/dataframe/api/join.kt | 84 +++++++++++++------ .../kotlinx/dataframe/api/joinWith.kt | 12 +-- 2 files changed, 66 insertions(+), 30 deletions(-) diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt index 1694bae5b3..c94e530528 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt @@ -143,7 +143,7 @@ public fun DataFrame.join( /** * Performs a [inner join][JoinType.Inner] of this [DataFrame] with the [other][\other] [DataFrame] * using the selected key columns. - * @include [JoinType.Inner] + * @include [InnerJoinTypeDocs] * * This is a shortcut for [join] with [JoinType.Inner]. * @@ -192,7 +192,7 @@ public fun DataFrame.innerJoin(other: DataFrame, vararg columns: St /** * Performs a [left join][JoinType.Left] of this [DataFrame] with the [other][\other] [DataFrame] * using the selected key columns. - * @include [JoinType.Left] + * @include [LeftJoinTypeDocs] * * This is a shortcut for [join] with [JoinType.Left]. * @@ -241,7 +241,7 @@ public fun DataFrame.leftJoin(other: DataFrame, vararg columns: Str /** * Performs a [right join][JoinType.Right] of this [DataFrame] with [other][\other] [DataFrame] * using selected key columns. - * @include [JoinType.Right] + * @include [RightJoinTypeDocs] * * This is a shortcut for [join] with [JoinType.Right]. * @@ -290,7 +290,7 @@ public fun DataFrame.rightJoin(other: DataFrame, vararg columns: St /** * Performs a [full join][JoinType.Full] of this [DataFrame] with [other][\other] [DataFrame] * using selected key columns. - * @include [JoinType.Full] + * @include [FullJoinTypeDocs] * * This is a shortcut for [join] with [JoinType.Full]. * @@ -339,7 +339,7 @@ public fun DataFrame.fullJoin(other: DataFrame, vararg columns: Str /** * Performs a [filter join][JoinType.Filter] of this [DataFrame] with [other][\other] [DataFrame] * using selected key columns. - * @include [JoinType.Filter] + * @include [FilterJoinTypeDocs] * * This is a shortcut for [join] with [JoinType.Filter]. * @@ -388,7 +388,7 @@ public fun DataFrame.filterJoin(other: DataFrame, vararg columns: S /** * Performs a [exclude join][JoinType.Exclude] of this [DataFrame] with [other][\other] [DataFrame] * using selected key columns. - * @include [JoinType.Exclude] + * @include [ExcludeJoinTypeDocs] * * This is a shortcut for [join] with [JoinType.Exclude]. * @@ -574,6 +574,48 @@ public fun ColumnMatch(left: ColumnReference, right: ColumnReference): */ public typealias JoinColumnsSelector = JoinDsl.(ColumnsContainer) -> ColumnsResolver<*> +/** + * Includes only matching rows from both [DataFrame]s; + * rows are merged. + */ +@ExcludeFromSources +internal interface InnerJoinTypeDocs + +/** + * Includes all rows from the left [DataFrame]; matching rows are merged, + * unmatched right-side values are filled with `null`. + */ +@ExcludeFromSources +internal interface LeftJoinTypeDocs + +/** + * Includes all rows from the right [DataFrame]; matching rows are merged, + * unmatched left-side values are filled with `null`. + */ +@ExcludeFromSources +internal interface RightJoinTypeDocs + +/** + * Includes only rows from the left [DataFrame] that have a match in the right one; + * right-side columns are not merged. + */ +@ExcludeFromSources +internal interface FilterJoinTypeDocs + +/** + * Includes all rows from both [DataFrame]s; matching rows are merged, + * all mismatches are filled with `null`. + */ +@ExcludeFromSources +internal interface FullJoinTypeDocs + +/** + * Includes only rows from the left [DataFrame] that do *not* have a match in the right one; + * right-side columns are not merged. + */ +@ExcludeFromSources +internal interface ExcludeJoinTypeDocs + /** * Represents the type of [join] operation. * @@ -582,38 +624,32 @@ public typealias JoinColumnsSelector = JoinDsl.(ColumnsContainer) public enum class JoinType { /** - * Includes all rows from the left [DataFrame]; matching rows are merged, - * unmatched right-side values are filled with `null`. + * @include [LeftJoinTypeDocs] */ Left, /** - * Includes all rows from the right [DataFrame]; matching rows are merged, - * unmatched left-side values are filled with `null`. + * @include [RightJoinTypeDocs] */ Right, /** - * Includes only matching rows from both [DataFrame]s; - * rows are merged. + * @include [InnerJoinTypeDocs] */ Inner, /** - * Includes only rows from the left [DataFrame] that have a match in the right one; - * right-side columns are not merged. + * @include [FilterJoinTypeDocs] */ Filter, /** - * Includes all rows from both [DataFrame]s; matching rows are merged, - * all mismatches are filled with `null`. + * @include [FullJoinTypeDocs] */ Full, /** - * Includes only rows from the left [DataFrame] that do *not* have a match in the right one; - * right-side columns are not merged. + * @include [ExcludeJoinTypeDocs] */ Exclude, } @@ -627,14 +663,14 @@ public enum class JoinType { * The exact behavior depends on the specified [join type][\type]: * * **Merging joins:** - * * [JoinType.Inner] (default) — {@include [JoinType.Inner]} - * * [JoinType.Left] — {@include [JoinType.Left]} - * * [JoinType.Right] — {@include [JoinType.Right]} - * * [JoinType.Full] — {@include [JoinType.Full]} + * * [JoinType.Inner] (default) — {@include [InnerJoinTypeDocs]} + * * [JoinType.Left] — {@include [LeftJoinTypeDocs]} + * * [JoinType.Right] — {@include [RightJoinTypeDocs]} + * * [JoinType.Full] — {@include [FullJoinTypeDocs]} * * **Non-merging joins:** - * * [JoinType.Filter] — {@include [JoinType.Filter]} - * * [JoinType.Exclude] — {@include [JoinType.Exclude]} + * * [JoinType.Filter] — {@include [FilterJoinTypeDocs]} + * * [JoinType.Exclude] — {@include [ExcludeJoinTypeDocs]} */ @ExcludeFromSources internal interface JoinTypeDescription diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/joinWith.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/joinWith.kt index 99ae4ac085..8dcec07638 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/joinWith.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/joinWith.kt @@ -110,7 +110,7 @@ public fun DataFrame.joinWith( /** * Performs a [inner join][JoinType.Inner] of this [DataFrame] with the [right][\right] [DataFrame] - * using the provided [\joinExpression]. {@include [JoinType.Inner]} + * using the provided [\joinExpression]. {@include [InnerJoinTypeDocs]} * * This is a shortcut for [joinWith] with [JoinType.Inner]. * @@ -137,7 +137,7 @@ public fun DataFrame.innerJoinWith(right: DataFrame, joinExpression /** * Performs a [left join][JoinType.Left] of this [DataFrame] with the [right][\right] [DataFrame] - * using the provided [\joinExpression]. {@include [JoinType.Left]} + * using the provided [\joinExpression]. {@include [LeftJoinTypeDocs]} * * This is a shortcut for [joinWith] with [JoinType.Left]. * @@ -164,7 +164,7 @@ public fun DataFrame.leftJoinWith(right: DataFrame, joinExpression: /** * Performs a [right join][JoinType.Right] of this [DataFrame] with the [right][\right] [DataFrame] - * using the provided [\joinExpression]. {@include [JoinType.Right]} + * using the provided [\joinExpression]. {@include [RightJoinTypeDocs]} * * This is a shortcut for [joinWith] with [JoinType.Right]. * @@ -191,7 +191,7 @@ public fun DataFrame.rightJoinWith(right: DataFrame, joinExpression /** * Performs a [full join][JoinType.Full] of this [DataFrame] with the [right][\right] [DataFrame] - * using the provided [\joinExpression]. {@include [JoinType.Full]} + * using the provided [\joinExpression]. {@include [FullJoinTypeDocs]} * * This is a shortcut for [joinWith] with [JoinType.Full]. * @@ -218,7 +218,7 @@ public fun DataFrame.fullJoinWith(right: DataFrame, joinExpression: /** * Performs a [filter join][JoinType.Filter] of this [DataFrame] with the [right][\right] [DataFrame] - * using the provided [\joinExpression]. {@include [JoinType.Filter]} + * using the provided [\joinExpression]. {@include [FilterJoinTypeDocs]} * * This is a shortcut for [joinWith] with [JoinType.Filter]. * @@ -245,7 +245,7 @@ public fun DataFrame.filterJoinWith(right: DataFrame, joinExpressio /** * Performs a [exclude join][JoinType.Exclude] of this [DataFrame] with the [right][\right] [DataFrame] - * using the provided [\joinExpression]. {@include [JoinType.Exclude]} + * using the provided [\joinExpression]. {@include [ExcludeJoinTypeDocs]} * * This is a shortcut for [joinWith] with [JoinType.Exclude]. * From 9ccf88ec6fd7b11dcc3c4417f883e60a97301141 Mon Sep 17 00:00:00 2001 From: "andrei.kislitsyn" Date: Thu, 20 Nov 2025 22:27:19 +0400 Subject: [PATCH 09/14] join kdocs fixes --- .../src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt | 2 +- .../main/kotlin/org/jetbrains/kotlinx/dataframe/api/joinWith.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt index c94e530528..544896d4bc 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt @@ -91,7 +91,7 @@ private interface JOIN_METHOD internal interface JoinDslDescription /** - * Select join columns (incl. with different names in `this` and [other][other] [DataFrame]s) + * Select join columns (including those that have different names in different [DataFrame]s) * using [JoinDsl]. * * @include [JoinDslDescription] diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/joinWith.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/joinWith.kt index 8dcec07638..980ddbacda 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/joinWith.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/joinWith.kt @@ -70,7 +70,7 @@ public interface JoinedDataRow : DataRow { * allowing you to reference its values directly. * * The [row][DataRow] of the right [DataFrame] is available - * via [right][JoinedDataRow.right]. + * as [right][JoinedDataRow.right]. * * The expression must return a [Boolean] indicating whether * the rows from the left and right [DataFrame]s match. From 5fa8398ec90784a5fa983ce83f63f3ad805d17fa Mon Sep 17 00:00:00 2001 From: "andrei.kislitsyn" Date: Thu, 20 Nov 2025 23:54:34 +0400 Subject: [PATCH 10/14] join types enum kdocs fixes --- .../jetbrains/kotlinx/dataframe/api/join.kt | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt index 544896d4bc..8eec9c8142 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt @@ -624,32 +624,38 @@ internal interface ExcludeJoinTypeDocs public enum class JoinType { /** - * @include [LeftJoinTypeDocs] + * Includes all rows from the left [DataFrame]; matching rows are merged, + * unmatched right-side values are filled with `null`. */ Left, /** - * @include [RightJoinTypeDocs] + * Includes all rows from the right [DataFrame]; matching rows are merged, + * unmatched left-side values are filled with `null`. */ Right, /** - * @include [InnerJoinTypeDocs] + * Includes only matching rows from both [DataFrame]s; + * rows are merged. */ Inner, /** - * @include [FilterJoinTypeDocs] + * Includes only rows from the left [DataFrame] that have a match in the right one; + * right-side columns are not merged. */ Filter, /** - * @include [FullJoinTypeDocs] + * Includes all rows from both [DataFrame]s; matching rows are merged, + * all mismatches are filled with `null`. */ Full, /** - * @include [ExcludeJoinTypeDocs] + * Includes only rows from the left [DataFrame] that do *not* have a match in the right one; + * right-side columns are not merged. */ Exclude, } From 6d17b982756d106eaacc39e97f221760f1a63c5d Mon Sep 17 00:00:00 2001 From: "andrei.kislitsyn" Date: Fri, 21 Nov 2025 14:57:16 +0400 Subject: [PATCH 11/14] join kdocs fixes --- .../main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt | 6 +++--- .../kotlin/org/jetbrains/kotlinx/dataframe/api/joinWith.kt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt index 8eec9c8142..89e5cbb7c1 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt @@ -61,7 +61,7 @@ private interface JoinBehavior private interface JoinDocs // `join` method used in the example -@Suppress("ktlint:standard:class-naming") +@Suppress("ClassName") @ExcludeFromSources private interface JOIN_METHOD @@ -141,7 +141,7 @@ public fun DataFrame.join( ): DataFrame = join(other, type) { columns.toColumnSet() } /** - * Performs a [inner join][JoinType.Inner] of this [DataFrame] with the [other][\other] [DataFrame] + * Performs an [inner join][JoinType.Inner] of this [DataFrame] with the [other][\other] [DataFrame] * using the selected key columns. * @include [InnerJoinTypeDocs] * @@ -386,7 +386,7 @@ public fun DataFrame.filterJoin(other: DataFrame, vararg columns: S filterJoin(other) { columns.toColumnSet() } /** - * Performs a [exclude join][JoinType.Exclude] of this [DataFrame] with [other][\other] [DataFrame] + * Performs an [exclude join][JoinType.Exclude] of this [DataFrame] with [other][\other] [DataFrame] * using selected key columns. * @include [ExcludeJoinTypeDocs] * diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/joinWith.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/joinWith.kt index 980ddbacda..48acd75a26 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/joinWith.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/joinWith.kt @@ -27,7 +27,7 @@ import org.jetbrains.kotlinx.dataframe.impl.api.joinWithImpl private interface JoinWithCommonDescription // `joinWith` method used in the example -@Suppress("ktlint:standard:class-naming") +@Suppress("ClassName") @ExcludeFromSources private interface JOIN_WITH_METHOD @@ -109,7 +109,7 @@ public fun DataFrame.joinWith( ): DataFrame = joinWithImpl(right, type, addNewColumns = type.addNewColumns, joinExpression) /** - * Performs a [inner join][JoinType.Inner] of this [DataFrame] with the [right][\right] [DataFrame] + * Performs an [inner join][JoinType.Inner] of this [DataFrame] with the [right][\right] [DataFrame] * using the provided [\joinExpression]. {@include [InnerJoinTypeDocs]} * * This is a shortcut for [joinWith] with [JoinType.Inner]. @@ -244,7 +244,7 @@ public fun DataFrame.filterJoinWith(right: DataFrame, joinExpressio joinWithImpl(right, JoinType.Filter, addNewColumns = false, joinExpression) /** - * Performs a [exclude join][JoinType.Exclude] of this [DataFrame] with the [right][\right] [DataFrame] + * Performs an [exclude join][JoinType.Exclude] of this [DataFrame] with the [right][\right] [DataFrame] * using the provided [\joinExpression]. {@include [ExcludeJoinTypeDocs]} * * This is a shortcut for [joinWith] with [JoinType.Exclude]. From 93b9d8c911569afe124eda221ae2f784492a47ac Mon Sep 17 00:00:00 2001 From: "andrei.kislitsyn" Date: Fri, 21 Nov 2025 15:00:33 +0400 Subject: [PATCH 12/14] join kdocs fixes --- .../org/jetbrains/kotlinx/dataframe/api/join.kt | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt index 89e5cbb7c1..5d658aab6e 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt @@ -123,6 +123,7 @@ public fun DataFrame.join( * dfLeft.{@get [JoinMethod] join}(dfRight, "name", "city") * ``` */ +@ExcludeFromSources private interface JoinStringApiExample /** @@ -239,8 +240,8 @@ public fun DataFrame.leftJoin(other: DataFrame, vararg columns: Str leftJoin(other) { columns.toColumnSet() } /** - * Performs a [right join][JoinType.Right] of this [DataFrame] with [other][\other] [DataFrame] - * using selected key columns. + * Performs a [right join][JoinType.Right] of this [DataFrame] with the [other][\other] [DataFrame] + * using the selected key columns. * @include [RightJoinTypeDocs] * * This is a shortcut for [join] with [JoinType.Right]. @@ -288,8 +289,8 @@ public fun DataFrame.rightJoin(other: DataFrame, vararg columns: St rightJoin(other) { columns.toColumnSet() } /** - * Performs a [full join][JoinType.Full] of this [DataFrame] with [other][\other] [DataFrame] - * using selected key columns. + * Performs a [full join][JoinType.Full] of this [DataFrame] with the [other][\other] [DataFrame] + * using the selected key columns. * @include [FullJoinTypeDocs] * * This is a shortcut for [join] with [JoinType.Full]. @@ -337,8 +338,8 @@ public fun DataFrame.fullJoin(other: DataFrame, vararg columns: Str fullJoin(other) { columns.toColumnSet() } /** - * Performs a [filter join][JoinType.Filter] of this [DataFrame] with [other][\other] [DataFrame] - * using selected key columns. + * Performs a [filter join][JoinType.Filter] of this [DataFrame] with the [other][\other] [DataFrame] + * using the selected key columns. * @include [FilterJoinTypeDocs] * * This is a shortcut for [join] with [JoinType.Filter]. @@ -386,8 +387,8 @@ public fun DataFrame.filterJoin(other: DataFrame, vararg columns: S filterJoin(other) { columns.toColumnSet() } /** - * Performs an [exclude join][JoinType.Exclude] of this [DataFrame] with [other][\other] [DataFrame] - * using selected key columns. + * Performs an [exclude join][JoinType.Exclude] of this [DataFrame] with the [other][\other] [DataFrame] + * using the selected key columns. * @include [ExcludeJoinTypeDocs] * * This is a shortcut for [join] with [JoinType.Exclude]. From 16744a814e37f423a20f3a751c0e380bdc7ec00f Mon Sep 17 00:00:00 2001 From: "andrei.kislitsyn" Date: Fri, 21 Nov 2025 15:01:22 +0400 Subject: [PATCH 13/14] AutoRenaming kdocs fixes --- .../jetbrains/kotlinx/dataframe/documentation/AutoRenaming.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/documentation/AutoRenaming.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/documentation/AutoRenaming.kt index d4ba3cefcf..1624f0a8c6 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/documentation/AutoRenaming.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/documentation/AutoRenaming.kt @@ -10,7 +10,8 @@ import org.jetbrains.kotlinx.dataframe.DataFrame * * In such cases, columns with duplicate names are automatically renamed * using the pattern `"\$name\$n"`, where `name` is the original column name - * and `n` is a unique index (1, 2, 3, and so on); the first name column goes without a number. + * and `n` is a unique index (1, 2, 3, and so on); + * the first time the name of the column is encountered, no number is appended. * * It is recommended to [rename][org.jetbrains.kotlinx.dataframe.api.rename] them * to maintain clarity and improve code readability. From 91181ebb8e5e7405b3345840eafd2e8ab2ca4f95 Mon Sep 17 00:00:00 2001 From: "andrei.kislitsyn" Date: Fri, 21 Nov 2025 15:55:25 +0400 Subject: [PATCH 14/14] join kdocs fixes --- .../org/jetbrains/kotlinx/dataframe/api/join.kt | 7 +++++-- .../jetbrains/kotlinx/dataframe/api/joinWith.kt | 14 +++++++------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt index 5d658aab6e..9d49458831 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/join.kt @@ -66,9 +66,9 @@ private interface JoinDocs private interface JOIN_METHOD /** - * [JoinDsl] defines the columns used for joining [DataFrame]s + * [JoinDsl] allows you to define the columns used for joining [DataFrame]s * and provides methods to match columns with different names - * between the left and right sides. + * between the left and right side. * * Provides the left [DataFrame] both as the receiver (`this`) and as the argument (`it`), * allowing you to reference its columns directly. @@ -85,6 +85,9 @@ private interface JOIN_METHOD * // Join by one column with different names — * // "firstName" in the left dataframe and "name" in the right one * dfLeft.{@get [JoinMethod] join}(dfRight) { left -> left.firstName match right.name } + * + * // Match columns using String API + * dfLeft.{@get [JoinMethod] join}(dfRight) { "symbol" match right.getValue("char") } * ``` */ @ExcludeFromSources diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/joinWith.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/joinWith.kt index 48acd75a26..87db6a0ba2 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/joinWith.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/joinWith.kt @@ -88,7 +88,7 @@ public typealias JoinExpression = Selector, Boolean> * Each join type has a corresponding shortcut function: * [innerJoinWith], [leftJoinWith], [rightJoinWith], [fullJoinWith], [filterJoinWith], and [excludeJoinWith]. * - * See also [join], which performs a join by exact values equality in the selected columns. + * See also [join], which performs a join by exact value equality in the selected columns. * * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention] * @@ -119,7 +119,7 @@ public fun DataFrame.joinWith( * See also general [joinWith] as well as other shortcuts with each of join types: * [leftJoinWith], [rightJoinWith], [fullJoinWith], [filterJoinWith], [excludeJoinWith]. * - * See also [join], which performs a join by simply matching columns. + * See also [join], which performs a join by exact value equality in the selected columns. * * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention] * @@ -146,7 +146,7 @@ public fun DataFrame.innerJoinWith(right: DataFrame, joinExpression * See also general [joinWith] as well as other shortcuts with each of join types: * [innerJoinWith], [rightJoinWith], [fullJoinWith], [filterJoinWith], [excludeJoinWith]. * - * See also [join], which performs a join by simply matching columns. + * See also [join], which performs a join by exact value equality in the selected columns. * * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention] * @@ -173,7 +173,7 @@ public fun DataFrame.leftJoinWith(right: DataFrame, joinExpression: * See also general [joinWith] as well as other shortcuts with each of join types: * [innerJoinWith], [leftJoinWith], [fullJoinWith], [filterJoinWith], [excludeJoinWith]. * - * See also [join], which performs a join by simply matching columns. + * See also [join], which performs a join by exact value equality in the selected columns. * * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention] * @@ -200,7 +200,7 @@ public fun DataFrame.rightJoinWith(right: DataFrame, joinExpression * See also general [joinWith] as well as other shortcuts with each of join types: * [leftJoinWith], [rightJoinWith], [innerJoinWith], [filterJoinWith], [excludeJoinWith]. * - * See also [join], which performs a join by simply matching columns. + * See also [join], which performs a join by exact value equality in the selected columns. * * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention] * @@ -227,7 +227,7 @@ public fun DataFrame.fullJoinWith(right: DataFrame, joinExpression: * See also general [joinWith] as well as other shortcuts with each of join types: * [leftJoinWith], [rightJoinWith], [fullJoinWith], [innerJoinWith], [excludeJoinWith]. * - * See also [join], which performs a join by simply matching columns. + * See also [join], which performs a join by exact value equality in the selected columns. * * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention] * @@ -254,7 +254,7 @@ public fun DataFrame.filterJoinWith(right: DataFrame, joinExpressio * See also general [joinWith] as well as other shortcuts with each of join types: * [leftJoinWith], [rightJoinWith], [fullJoinWith], [filterJoinWith], [innerJoinWith]. * - * See also [join], which performs a join by simply matching columns. + * See also [join], which performs a join by exact value equality in the selected columns. * * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention] *