@@ -10,53 +10,231 @@ import org.jetbrains.kotlinx.dataframe.annotations.Interpretable
1010import org.jetbrains.kotlinx.dataframe.annotations.Refine
1111import org.jetbrains.kotlinx.dataframe.columns.ColumnAccessor
1212import org.jetbrains.kotlinx.dataframe.columns.ColumnPath
13+ import org.jetbrains.kotlinx.dataframe.documentation.DocumentationUrls
14+ import org.jetbrains.kotlinx.dataframe.documentation.DslGrammarLink
15+ import org.jetbrains.kotlinx.dataframe.documentation.ExcludeFromSources
16+ import org.jetbrains.kotlinx.dataframe.documentation.Indent
17+ import org.jetbrains.kotlinx.dataframe.documentation.LineBreak
18+ import org.jetbrains.kotlinx.dataframe.documentation.SelectingColumns
1319import org.jetbrains.kotlinx.dataframe.impl.api.insertImpl
1420import org.jetbrains.kotlinx.dataframe.impl.columnName
1521import org.jetbrains.kotlinx.dataframe.impl.removeAt
1622import org.jetbrains.kotlinx.dataframe.util.DEPRECATED_ACCESS_API
23+ import org.jetbrains.kotlinx.dataframe.util.INSERT_AFTER_COL_PATH
24+ import org.jetbrains.kotlinx.dataframe.util.INSERT_AFTER_COL_PATH_REPLACE
1725import kotlin.reflect.KProperty
1826
1927// region DataFrame
2028
2129// region insert
2230
31+ /* *
32+ * This function does not immediately insert the new column but instead specify a column to insert and
33+ * returns an [InsertClause],
34+ * which serves as an intermediate step.
35+ * The [InsertClause] object provides methods to insert a new column using:
36+ * - [under][InsertClause.under] - inserts a new column under the specified column group.
37+ * - [after][InsertClause.after] - inserts a new column after the specified column.
38+ * - [at][InsertClause.at]- inserts a new column at the specified position.
39+ *
40+ * Each method returns a new [DataFrame] with the inserted column.
41+ *
42+ * Check out [Grammar].
43+ *
44+ * @include [SelectingColumns.ColumnGroupsAndNestedColumnsMention]
45+ *
46+ * See [Selecting Columns][InsertSelectingOptions].
47+ *
48+ * For more information: {@include [DocumentationUrls.Insert]}
49+ *
50+ * See also:
51+ * - [move][DataFrame.move] - move columns to a new position within the [DataFrame].
52+ * - [add][DataFrame.add] - add new columns to the [DataFrame]
53+ * (without specifying a position, to the end of the [DataFrame]).
54+ */
55+ internal interface InsertDocs {
56+
57+ /* *
58+ * {@comment Version of [SelectingColumns] with correctly filled in examples}
59+ * @include [SelectingColumns] {@include [SetInsertOperationArg]}
60+ */
61+ interface InsertSelectingOptions
62+
63+
64+ /* *
65+ * ## Insert Operation Grammar
66+ * {@include [LineBreak]}
67+ * {@include [DslGrammarLink]}
68+ * {@include [LineBreak]}
69+ *
70+ * **[`insert`][insert]**`(column: `[`DataColumn`][DataColumn]`)`
71+ *
72+ * {@include [Indent]}
73+ * `| `[`insert`][insert]`(name: `[`String`][String]`, infer: `[`Infer`][Infer]`, rowExpression: `[`RowExpression`][RowExpression]` }`
74+ *
75+ * {@include [Indent]}
76+ * __`.`__[**`under`**][InsertClause.under]` { `**`column: `[`ColumnSelector`][ColumnSelector]**` }`
77+ *
78+ * {@include [Indent]}
79+ * `| `__`.`__[**`under`**][InsertClause.under]`(columnPath: `[`ColumnPath`][ColumnPath]`)`
80+ *
81+ * {@include [Indent]}
82+ * `| `__`.`__[**`after`**][InsertClause.after]` { `**`column: `[`ColumnSelector`][ColumnSelector]**` }`
83+ *
84+ * {@include [Indent]}
85+ * `| `__`.`__[**`at`**][InsertClause.at]`(position: `[`Int`][Int]`)`
86+ */
87+ interface Grammar
88+ }
89+
90+ /* * {@set [SelectingColumns.OPERATION] [insert][insert]} */
91+ @ExcludeFromSources
92+ private interface SetInsertOperationArg
93+
94+ /* *
95+ * Inserts the given [column] into this [DataFrame].
96+ *
97+ * {@include [InsertDocs]}
98+ *
99+ * ### Examples:
100+ * ```kotlin
101+ * // Insert a new column "age" under the column group with path ("info", "personal").
102+ * df.insert(age).under(pathOf("info", "personal"))
103+ *
104+ * // Insert a new column "count" after the column "url".
105+ * df.insert(count).after { url }
106+ * ```
107+ *
108+ * @param column A single [DataColumn] to insert into the [DataFrame].
109+ * @return An [InsertClause] for specifying the placement of the new column.
110+ */
23111public fun <T , C > DataFrame<T>.insert (column : DataColumn <C >): InsertClause <T > = InsertClause (this , column)
24112
113+ /* *
114+ * Creates a new column using the provided [expression][AddExpression] and inserts it into this [DataFrame].
115+ *
116+ * {@include [AddExpressionDocs]}
117+ *
118+ * {@include [InsertDocs]}
119+ *
120+ * ## Examples
121+ *
122+ * ```kotlin
123+ * // Insert a new column "sum" that contains the sum of values from the "firstValue"
124+ * // and "secondValue" columns for each row after the "firstValue" column.
125+ * val dfWithSum = df.insert("sum") { firstValue + secondValue }.after { firstValue }
126+ *
127+ * // Insert a new "fibonacci" column with the Fibonacci sequence under a "math" column group:
128+ * // for the first two rows, the value is 1;
129+ * // for subsequent rows, it's the sum of the two previous Fibonacci values.
130+ * val dfWithFibonacci = df.insert("fibonacci") {
131+ * if (index() < 2) 1
132+ * else prev()!!.newValue<Int>() + prev()!!.prev()!!.newValue<Int>()
133+ * }.under("math")
134+ * ```
135+ *
136+ * @param name The name of the new column to be created and inserted.
137+ * @param infer Controls how values are inferred when building the new column. Defaults to [Infer.Nulls].
138+ * @param expression An [AddExpression] that computes the value for each row of the new column.
139+ * @return An [InsertClause] for specifying the placement of the newly created column.
140+ */
25141@Interpretable(" Insert1" )
26142public inline fun <T , reified R > DataFrame<T>.insert (
27143 name : String ,
28144 infer : Infer = Infer .Nulls ,
29- noinline expression : RowExpression <T , R >,
145+ noinline expression : AddExpression <T , R >,
30146): InsertClause <T > = insert(mapToColumn(name, infer, expression))
31147
32148@Deprecated(DEPRECATED_ACCESS_API )
33149@AccessApiOverload
34150public inline fun <T , reified R > DataFrame<T>.insert (
35151 column : ColumnAccessor <R >,
36152 infer : Infer = Infer .Nulls ,
37- noinline expression : RowExpression <T , R >,
153+ noinline expression : AddExpression <T , R >,
38154): InsertClause <T > = insert(column.name(), infer, expression)
39155
40156@Deprecated(DEPRECATED_ACCESS_API )
41157@AccessApiOverload
42158public inline fun <T , reified R > DataFrame<T>.insert (
43159 column : KProperty <R >,
44160 infer : Infer = Infer .Nulls ,
45- noinline expression : RowExpression <T , R >,
161+ noinline expression : AddExpression <T , R >,
46162): InsertClause <T > = insert(column.columnName, infer, expression)
47163
48164// endregion
49165
166+ /* *
167+ * An intermediate class used in the [insert] operation.
168+ *
169+ * This class itself does not perform any insertions — it is a transitional step
170+ * before specifying how to insert the selected columns.
171+ * It must be followed by one of the inserting methods
172+ * to produce a new [DataFrame] with an inserted column.
173+ *
174+ * Use the following methods to perform the insertion:
175+ * - [under][InsertClause.under] - inserts a new column under the specified column group.
176+ * - [after][InsertClause.after] - inserts a new column after the specified column.
177+ * - [at][InsertClause.at]- inserts a new column at the specified position.
178+ *
179+ * See [Grammar][InsertDocs.Grammar] for more details.
180+ */
50181public class InsertClause <T >(internal val df : DataFrame <T >, internal val column : AnyCol ) {
51182 override fun toString (): String = " InsertClause(df=$df , column=$column )"
52183}
53184
54185// region under
55186
187+ /* *
188+ * Inserts the new column previously specified with [insert] under
189+ * the selected [column group][column].
190+ *
191+ * Works only with existing column groups.
192+ * To insert into a new column group, use the overloads:
193+ * `under(path: ColumnPath)` or `under(column: String)`.
194+ *
195+ * For more information: {@include [DocumentationUrls.Insert]}
196+ *
197+ * See [Grammar][InsertDocs.Grammar] for more details.
198+ *
199+ * See [SelectingColumns.Dsl].
200+ *
201+ * ### Examples
202+ * ```kotlin
203+ * // Insert a new column "age" under the column group with path ("info", "personal")
204+ * df.insert(age).under { info.personal }
205+ *
206+ * // Insert a new column "sum" under the only top-level column group
207+ * val dfWithSum = df.insert("sum") { a + b }.under { colGroups().single() }
208+ * ```
209+ *
210+ * @param column The [ColumnSelector] used to choose an existing column group in this [DataFrame]
211+ * under which the new column will be inserted.
212+ * @return A new [DataFrame] with the inserted column placed under the selected group.
213+ */
56214@Refine
57215@Interpretable(" Under0" )
58216public fun <T > InsertClause<T>.under (column : ColumnSelector <T , * >): DataFrame <T > = under(df.getColumnPath(column))
59217
218+ /* *
219+ * Inserts the new column previously specified with [insert] under
220+ * the column group defined by the given [columnPath].
221+ *
222+ * {@include [org.jetbrains.kotlinx.dataframe.documentation.ColumnPathCreation]}
223+ *
224+ * See [Grammar][InsertDocs.Grammar] for more details.
225+ *
226+ * For more information: {@include [DocumentationUrls.Insert]}
227+ *
228+ * ### Example
229+ * ```kotlin
230+ * // Insert a new column "age" under the column group with path ("info", "personal")
231+ * df.insert(age).under(pathOf("info", "personal"))
232+ * ```
233+ *
234+ * @param columnPath The [ColumnPath] specifying the path to a column group in this [DataFrame]
235+ * under which the new column will be inserted.
236+ * @return A new [DataFrame] with the inserted column placed under the specified column group.
237+ */
60238@Refine
61239@Interpretable(" Under1" )
62240public fun <T > InsertClause<T>.under (columnPath : ColumnPath ): DataFrame <T > =
@@ -70,6 +248,26 @@ public fun <T> InsertClause<T>.under(column: ColumnAccessor<*>): DataFrame<T> =
70248@AccessApiOverload
71249public fun <T > InsertClause<T>.under (column : KProperty <* >): DataFrame <T > = under(column.columnName)
72250
251+ /* *
252+ * Inserts the new column previously specified with [insert] under
253+ * the given column group by its [name][column].
254+ *
255+ * If the column group with the provided [name][column] does not exist, it will be created automatically.
256+ *
257+ * For more information: {@include [DocumentationUrls.Insert]}
258+ *
259+ * See [Grammar][InsertDocs.Grammar] for more details.
260+ *
261+ * ### Example
262+ * ```kotlin
263+ * // Insert a new column "age" under the "info" column group.
264+ * df.insert(age).under("info")
265+ * ```
266+ *
267+ * @param column The [name][String] of the column group in this [DataFrame].
268+ * If the group does not exist, it will be created.
269+ * @return A new [DataFrame] with the inserted column placed under the specified column group.
270+ */
73271@Refine
74272@Interpretable(" Under4" )
75273public fun <T > InsertClause<T>.under (column : String ): DataFrame <T > = under(pathOf(column))
@@ -78,29 +276,98 @@ public fun <T> InsertClause<T>.under(column: String): DataFrame<T> = under(pathO
78276
79277// region after
80278
279+ /* *
280+ * Inserts the new column previously specified with [insert]
281+ * at the position immediately after the selected [column] (on the same level).
282+ *
283+ * For more information: {@include [DocumentationUrls.Insert]}
284+ *
285+ * See [Grammar][InsertDocs.Grammar] for more details.
286+ *
287+ * See also: [SelectingColumns.Dsl].
288+ *
289+ * ### Examples:
290+ * ```kotlin
291+ * // Insert a new column "age" after the "name" column
292+ * df.insert(age).after { name }
293+ *
294+ * // Insert a new column "sum" after the nested "min" column (inside the "stats" column group)
295+ * val dfWithSum = df.insert("sum") { a + b }.after { stats.min }
296+ * ```
297+ *
298+ * @param column The [ColumnSelector] used to choose an existing column in this [DataFrame],
299+ * after which the new column will be inserted.
300+ * @return A new [DataFrame] with the inserted column placed after the selected column.
301+ */
81302@Refine
82303@Interpretable(" InsertAfter0" )
83- public fun <T > InsertClause<T>.after (column : ColumnSelector <T , * >): DataFrame <T > = after (df.getColumnPath(column))
304+ public fun <T > InsertClause<T>.after (column : ColumnSelector <T , * >): DataFrame <T > = afterImpl (df.getColumnPath(column))
84305
306+ /* *
307+ * Inserts the new column previously specified with [insert]
308+ * at the position immediately after the column with the given [name][column].
309+ *
310+ * For more information: {@include [DocumentationUrls.Insert]}
311+ *
312+ * See [Grammar][InsertDocs.Grammar] for more details.
313+ *
314+ * See also: [SelectingColumns.ColumnNames].
315+ *
316+ * ### Example
317+ * ```kotlin
318+ * // Insert a new column "age" after the "name" column
319+ * df.insert(age).after("name")
320+ * ```
321+ *
322+ * @param column The [String] name of the column in this [DataFrame]
323+ * after which the new column will be inserted.
324+ * @return A new [DataFrame] with the inserted column placed after the specified column.
325+ */
85326public fun <T > InsertClause<T>.after (column : String ): DataFrame <T > = df.add(this .column).move(this .column).after(column)
86327
87328@Deprecated(DEPRECATED_ACCESS_API )
88329@AccessApiOverload
89- public fun <T > InsertClause<T>.after (column : ColumnAccessor <* >): DataFrame <T > = after (column.path())
330+ public fun <T > InsertClause<T>.after (column : ColumnAccessor <* >): DataFrame <T > = afterImpl (column.path())
90331
91332@Deprecated(DEPRECATED_ACCESS_API )
92333@AccessApiOverload
93334public fun <T > InsertClause<T>.after (column : KProperty <* >): DataFrame <T > = after(column.columnName)
94335
336+ @Deprecated(INSERT_AFTER_COL_PATH , ReplaceWith (INSERT_AFTER_COL_PATH_REPLACE ), DeprecationLevel .ERROR )
95337public fun <T > InsertClause<T>.after (columnPath : ColumnPath ): DataFrame <T > {
96338 val dstPath = ColumnPath (columnPath.removeAt(columnPath.size - 1 ) + column.name())
97339 return df.insertImpl(dstPath, column).move { dstPath }.after { columnPath }
98340}
99341
342+ internal fun <T > InsertClause<T>.afterImpl (columnPath : ColumnPath ): DataFrame <T > {
343+ val dstPath = ColumnPath (columnPath.removeAt(columnPath.size - 1 ) + column.name())
344+ return df.insertImpl(dstPath, column).move { dstPath }.after { columnPath }
345+ }
346+
100347// endregion
101348
102349// region at
103350
351+ /* *
352+ * Inserts the new column previously specified with [insert]
353+ * at the given [position] in the [DataFrame].
354+ *
355+ * The new column will be placed at the specified index, shifting existing columns to the right.
356+ *
357+ * For more information: {@include [DocumentationUrls.Insert]}
358+ *
359+ * See [Grammar][InsertDocs.Grammar] for more details.
360+ *
361+ * ### Example
362+ * ```kotlin
363+ * // Insert a new column "age" at index 3
364+ * df.insert(age).at(3)
365+ * ```
366+ *
367+ * @param position The [Int] index where the new column should be inserted.
368+ * Columns currently at this index and after will be shifted right.
369+ * @return A new [DataFrame] with the inserted column placed at the specified position.
370+ */
104371@Refine
105372@Interpretable(" InsertAt" )
106373public fun <T > InsertClause<T>.at (position : Int ): DataFrame <T > = df.add(column).move(column).to(position)
0 commit comments