diff --git a/engine/api/src/main/java/io/deephaven/engine/table/Table.java b/engine/api/src/main/java/io/deephaven/engine/table/Table.java
index 56091230495..32664ee234f 100644
--- a/engine/api/src/main/java/io/deephaven/engine/table/Table.java
+++ b/engine/api/src/main/java/io/deephaven/engine/table/Table.java
@@ -326,10 +326,49 @@ public interface Table extends
@ConcurrentMethod
Table dropColumnFormats();
+ /**
+ * Produce a new table with the specified columns renamed using the syntax {@code "NewColumnName=OldColumnName"}.
+ *
+ * {@link IllegalArgumentException} will be thrown:
+ *
+ * - if a source column is used more than once
+ * - if a destination column is used more than once
+ *
+ *
+ * @param pairs The columns to rename
+ * @return The new table, with the columns renamed
+ */
+ @ConcurrentMethod
Table renameColumns(Collection pairs);
+ /**
+ * Produce a new table with the specified columns renamed using the syntax {@code "NewColumnName=OldColumnName"}.
+ *
+ * {@link IllegalArgumentException} will be thrown:
+ *
+ * - if a source column is used more than once
+ * - if a destination column is used more than once
+ *
+ *
+ * @param pairs The columns to rename
+ * @return The new table, with the columns renamed
+ */
+ @ConcurrentMethod
Table renameColumns(String... pairs);
+ /**
+ * Produce a new table with the specified columns renamed using the provided function.
+ *
+ * {@link IllegalArgumentException} will be thrown:
+ *
+ * - if a source column is used more than once
+ * - if a destination column is used more than once
+ *
+ *
+ * @param renameFunction The function to apply to each column name
+ * @return The new table, with the columns renamed
+ */
+ @ConcurrentMethod
Table renameAllColumns(UnaryOperator renameFunction);
@ConcurrentMethod
@@ -342,8 +381,14 @@ public interface Table extends
Table formatColumnWhere(String columnName, String condition, String formula);
/**
- * Produce a new table with the specified columns moved to the leftmost position. Columns can be renamed with the
+ * Produce a new table with the specified columns moved to the rightmost position. Columns can be renamed with the
* usual syntax, i.e. {@code "NewColumnName=OldColumnName")}.
+ *
+ * {@link IllegalArgumentException} will be thrown:
+ *
+ * - if a source column is used more than once
+ * - if a destination column is used more than once
+ *
*
* @param columnsToMove The columns to move to the left (and, optionally, to rename)
* @return The new table, with the columns rearranged as explained above {@link #moveColumns(int, String...)}
@@ -354,6 +399,12 @@ public interface Table extends
/**
* Produce a new table with the specified columns moved to the rightmost position. Columns can be renamed with the
* usual syntax, i.e. {@code "NewColumnName=OldColumnName")}.
+ *
+ * {@link IllegalArgumentException} will be thrown:
+ *
+ * - if a source column is used more than once
+ * - if a destination column is used more than once
+ *
*
* @param columnsToMove The columns to move to the right (and, optionally, to rename)
* @return The new table, with the columns rearranged as explained above {@link #moveColumns(int, String...)}
@@ -362,8 +413,14 @@ public interface Table extends
Table moveColumnsDown(String... columnsToMove);
/**
- * Produce a new table with the specified columns moved to the specified {@code index}. Column indices begin at 0.
- * Columns can be renamed with the usual syntax, i.e. {@code "NewColumnName=OldColumnName")}.
+ * Produce a new table with the specified columns moved to the rightmost position. Columns can be renamed with the
+ * usual syntax, i.e. {@code "NewColumnName=OldColumnName")}.
+ *
+ * {@link IllegalArgumentException} will be thrown:
+ *
+ * - if a source column is used more than once
+ * - if a destination column is used more than once
+ *
*
* @param index The index to which the specified columns should be moved
* @param columnsToMove The columns to move to the specified index (and, optionally, to rename)
@@ -372,9 +429,6 @@ public interface Table extends
@ConcurrentMethod
Table moveColumns(int index, String... columnsToMove);
- @ConcurrentMethod
- Table moveColumns(int index, boolean moveToEnd, String... columnsToMove);
-
// -----------------------------------------------------------------------------------------------------------------
// Slice Operations
// -----------------------------------------------------------------------------------------------------------------
diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/QueryTable.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/QueryTable.java
index 72c4d20aff0..45c71442f88 100644
--- a/engine/table/src/main/java/io/deephaven/engine/table/impl/QueryTable.java
+++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/QueryTable.java
@@ -3,7 +3,6 @@
*/
package io.deephaven.engine.table.impl;
-import io.deephaven.UncheckedDeephavenException;
import io.deephaven.api.AsOfJoinMatch;
import io.deephaven.api.AsOfJoinRule;
import io.deephaven.api.ColumnName;
@@ -48,7 +47,6 @@
import io.deephaven.engine.table.impl.perf.QueryPerformanceNugget;
import io.deephaven.engine.table.impl.rangejoin.RangeJoinOperation;
import io.deephaven.engine.table.impl.select.MatchPairFactory;
-import io.deephaven.engine.table.impl.select.SelectColumnFactory;
import io.deephaven.engine.table.impl.updateby.UpdateBy;
import io.deephaven.engine.table.impl.select.analyzers.SelectAndViewAnalyzerWrapper;
import io.deephaven.engine.table.impl.sources.ring.RingTableTools;
@@ -79,6 +77,7 @@
import io.deephaven.util.annotations.TestUseOnly;
import io.deephaven.util.annotations.VisibleForTesting;
import org.apache.commons.lang3.mutable.Mutable;
+import org.apache.commons.lang3.mutable.MutableInt;
import org.apache.commons.lang3.mutable.MutableObject;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -924,54 +923,11 @@ private String getCastFormulaInternal(Class> dataType) {
}
@Override
- public Table moveColumns(int index, boolean moveToEnd, String... columnsToMove) {
+ public Table moveColumns(final int index, String... columnsToMove) {
final UpdateGraph updateGraph = getUpdateGraph();
try (final SafeCloseable ignored = ExecutionContext.getContext().withUpdateGraph(updateGraph).open()) {
- // Get the current columns
- final List currentColumns = getDefinition().getColumnNames();
-
- // Create a Set from columnsToMove. This way, we can rename and rearrange columns at once.
- final Set leftColsToMove = new HashSet<>();
- final Set rightColsToMove = new HashSet<>();
- int extraCols = 0;
-
- for (final String columnToMove : columnsToMove) {
- final String left = MatchPairFactory.getExpression(columnToMove).leftColumn;
- final String right = MatchPairFactory.getExpression(columnToMove).rightColumn;
-
- if (!leftColsToMove.add(left) || !currentColumns.contains(left) || (rightColsToMove.contains(left)
- && !left.equals(right) && leftColsToMove.stream().anyMatch(col -> col.equals(right)))) {
- extraCols++;
- }
- if (currentColumns.stream().anyMatch(currentColumn -> currentColumn.equals(right))
- && !left.equals(right)
- && rightColsToMove.add(right) && !rightColsToMove.contains(left)) {
- extraCols--;
- }
- }
- index += moveToEnd ? extraCols : 0;
-
- // vci for write, cci for currentColumns, ctmi for columnsToMove
- final SelectColumn[] viewColumns = new SelectColumn[currentColumns.size() + extraCols];
- for (int vci = 0, cci = 0, ctmi = 0; vci < viewColumns.length;) {
- if (vci >= index && ctmi < columnsToMove.length) {
- viewColumns[vci++] = SelectColumnFactory.getExpression(columnsToMove[ctmi++]);
- } else {
- // Don't add the column if it's one of the columns we're moving or if it has been renamed.
- final String currentColumn = currentColumns.get(cci++);
- if (!leftColsToMove.contains(currentColumn)
- && Arrays.stream(viewColumns).noneMatch(
- viewCol -> viewCol != null
- && viewCol.getMatchPair().leftColumn.equals(currentColumn))
- && Arrays.stream(columnsToMove)
- .noneMatch(colToMove -> MatchPairFactory.getExpression(colToMove).rightColumn
- .equals(currentColumn))) {
-
- viewColumns[vci++] = SelectColumnFactory.getExpression(currentColumn);
- }
- }
- }
- return viewOrUpdateView(Flavor.View, viewColumns);
+ final MatchPair[] pairsToMove = MatchPairFactory.getExpressions(columnsToMove);
+ return renameColumnsImpl("moveColumns(" + index + ", ", Math.max(0, index), pairsToMove);
}
}
@@ -1820,73 +1776,121 @@ public void onUpdate(final TableUpdate upstream) {
public Table renameColumns(Collection pairs) {
final UpdateGraph updateGraph = getUpdateGraph();
try (final SafeCloseable ignored = ExecutionContext.getContext().withUpdateGraph(updateGraph).open()) {
- return renameColumnsImpl(MatchPair.fromPairs(pairs));
+ return renameColumnsImpl("renameColumns(", -1, MatchPair.fromPairs(pairs));
}
}
- private Table renameColumnsImpl(MatchPair... pairs) {
- return QueryPerformanceRecorder.withNugget("renameColumns(" + matchString(pairs) + ")",
+ private Table renameColumnsImpl(
+ @NotNull final String methodNuggetPrefix,
+ final int movePosition,
+ @NotNull final MatchPair... pairs) {
+ return QueryPerformanceRecorder.withNugget(methodNuggetPrefix + matchString(pairs) + ")",
sizeForInstrumentation(), () -> {
if (pairs == null || pairs.length == 0) {
return prepareReturnThis();
}
- checkInitiateOperation();
-
- final Map pairLookup = new HashMap<>();
+ final Set newNames = new HashSet<>();
+ final Map pairLookup = new LinkedHashMap<>();
for (final MatchPair pair : pairs) {
- if (pair.leftColumn == null || pair.leftColumn.equals("")) {
+ if (pair.leftColumn == null || pair.leftColumn.isEmpty()) {
throw new IllegalArgumentException(
"Bad left column in rename pair \"" + pair + "\"");
}
if (null == columns.get(pair.rightColumn)) {
throw new IllegalArgumentException("Column \"" + pair.rightColumn + "\" not found");
}
- pairLookup.put(pair.rightColumn, pair.leftColumn);
+ if (pairLookup.put(pair.rightColumn, pair.leftColumn) != null) {
+ throw new IllegalArgumentException(
+ "Duplicate source column \"" + pair.rightColumn + "\"");
+ }
+ if (!newNames.add(pair.leftColumn)) {
+ throw new IllegalArgumentException(
+ "Duplicate destination column \"" + pair.leftColumn + "\"");
+ }
}
- int mcsPairIdx = 0;
+ final MutableInt mcsPairIdx = new MutableInt();
final MatchPair[] modifiedColumnSetPairs = new MatchPair[columns.size()];
-
final Map> newColumns = new LinkedHashMap<>();
+
+ final Runnable moveColumns = () -> {
+ for (final Map.Entry rename : pairLookup.entrySet()) {
+ final String oldName = rename.getKey();
+ final String newName = rename.getValue();
+ final ColumnSource> columnSource = columns.get(oldName);
+ newColumns.put(newName, columnSource);
+ modifiedColumnSetPairs[mcsPairIdx.getAndIncrement()] = new MatchPair(newName, oldName);
+ }
+ };
+
for (final Map.Entry> entry : columns.entrySet()) {
final String oldName = entry.getKey();
final ColumnSource> columnSource = entry.getValue();
String newName = pairLookup.get(oldName);
if (newName == null) {
+ if (newNames.contains(oldName)) {
+ // this column is being replaced by a rename
+ continue;
+ }
newName = oldName;
+ } else if (movePosition >= 0) {
+ // we move this column when we get to the right position
+ continue;
+ }
+
+ if (mcsPairIdx.intValue() == movePosition) {
+ moveColumns.run();
}
- modifiedColumnSetPairs[mcsPairIdx++] = new MatchPair(newName, oldName);
+
+ modifiedColumnSetPairs[mcsPairIdx.getAndIncrement()] = new MatchPair(newName, oldName);
newColumns.put(newName, columnSource);
}
- final QueryTable queryTable = new QueryTable(rowSet, newColumns);
- if (isRefreshing()) {
- final ModifiedColumnSet.Transformer mcsTransformer =
- newModifiedColumnSetTransformer(queryTable, modifiedColumnSetPairs);
- addUpdateListener(new ListenerImpl("renameColumns(" + Arrays.deepToString(pairs) + ')',
- this, queryTable) {
- @Override
- public void onUpdate(final TableUpdate upstream) {
- final TableUpdateImpl downstream = TableUpdateImpl.copy(upstream);
- downstream.modifiedColumnSet = queryTable.getModifiedColumnSetForUpdates();
- if (upstream.modified().isNonempty()) {
- mcsTransformer.clearAndTransform(upstream.modifiedColumnSet(),
- downstream.modifiedColumnSet);
- } else {
- downstream.modifiedColumnSet.clear();
- }
- queryTable.notifyListeners(downstream);
- }
- });
+ if (mcsPairIdx.intValue() <= movePosition) {
+ moveColumns.run();
}
- propagateFlatness(queryTable);
- copyAttributes(queryTable, CopyAttributeOperation.RenameColumns);
- copySortableColumns(queryTable, pairs);
- maybeCopyColumnDescriptions(queryTable, pairs);
+ final Mutable result = new MutableObject<>();
+
+ final OperationSnapshotControl snapshotControl =
+ createSnapshotControlIfRefreshing(OperationSnapshotControl::new);
+ initializeWithSnapshot("renameColumns", snapshotControl, (usePrev, beforeClockValue) -> {
+ final QueryTable resultTable = new QueryTable(rowSet, newColumns);
+ propagateFlatness(resultTable);
+
+ copyAttributes(resultTable, CopyAttributeOperation.RenameColumns);
+ copySortableColumns(resultTable, pairs);
+ maybeCopyColumnDescriptions(resultTable, pairs);
+
+ if (snapshotControl != null) {
+ final ModifiedColumnSet.Transformer mcsTransformer =
+ newModifiedColumnSetTransformer(resultTable, modifiedColumnSetPairs);
+ final ListenerImpl listener = new ListenerImpl(
+ methodNuggetPrefix + Arrays.deepToString(pairs) + ')', this, resultTable) {
+ @Override
+ public void onUpdate(final TableUpdate upstream) {
+ final TableUpdateImpl downstream = TableUpdateImpl.copy(upstream);
+ downstream.modifiedColumnSet = resultTable.getModifiedColumnSetForUpdates();
+ if (upstream.modified().isNonempty()) {
+ mcsTransformer.clearAndTransform(upstream.modifiedColumnSet(),
+ downstream.modifiedColumnSet);
+ } else {
+ downstream.modifiedColumnSet.clear();
+ }
+ resultTable.notifyListeners(downstream);
+ }
+ };
+ snapshotControl.setListenerAndResult(listener, resultTable);
+ }
+
+ result.setValue(resultTable);
+
+ return true;
+ });
+
+ return result.getValue();
- return queryTable;
});
}
diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/TableAdapter.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/TableAdapter.java
index 4b25f59be2a..c724ad397bb 100644
--- a/engine/table/src/main/java/io/deephaven/engine/table/impl/TableAdapter.java
+++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/TableAdapter.java
@@ -219,7 +219,7 @@ default Table renameColumns(Collection pairs) {
}
@Override
- default Table moveColumns(int index, boolean moveToEnd, String... columnsToMove) {
+ default Table moveColumns(int index, String... columnsToMove) {
return throwUnsupported();
}
diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/TableDefaults.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/TableDefaults.java
index 836ca71260e..f4e251f227f 100644
--- a/engine/table/src/main/java/io/deephaven/engine/table/impl/TableDefaults.java
+++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/TableDefaults.java
@@ -243,14 +243,7 @@ default Table moveColumnsUp(String... columnsToMove) {
@ConcurrentMethod
@FinalDefault
default Table moveColumnsDown(String... columnsToMove) {
- return moveColumns(numColumns() - columnsToMove.length, true, columnsToMove);
- }
-
- @Override
- @ConcurrentMethod
- @FinalDefault
- default Table moveColumns(int index, String... columnsToMove) {
- return moveColumns(index, false, columnsToMove);
+ return moveColumns(numColumns() - columnsToMove.length, columnsToMove);
}
// -----------------------------------------------------------------------------------------------------------------
diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/UncoalescedTable.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/UncoalescedTable.java
index 4599d3cdd4b..23c827532e1 100644
--- a/engine/table/src/main/java/io/deephaven/engine/table/impl/UncoalescedTable.java
+++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/UncoalescedTable.java
@@ -271,8 +271,8 @@ public Table renameColumns(Collection pairs) {
@Override
@ConcurrentMethod
- public Table moveColumns(int index, boolean moveToEnd, String... columnsToMove) {
- return coalesce().moveColumns(index, moveToEnd, columnsToMove);
+ public Table moveColumns(int index, String... columnsToMove) {
+ return coalesce().moveColumns(index, columnsToMove);
}
@Override
diff --git a/engine/table/src/test/java/io/deephaven/engine/table/impl/QueryTableTest.java b/engine/table/src/test/java/io/deephaven/engine/table/impl/QueryTableTest.java
index 58ef8ac5996..4d8b0708dec 100644
--- a/engine/table/src/test/java/io/deephaven/engine/table/impl/QueryTableTest.java
+++ b/engine/table/src/test/java/io/deephaven/engine/table/impl/QueryTableTest.java
@@ -664,6 +664,25 @@ public void testRenameColumns() {
fail("Expected exception");
} catch (RuntimeException ignored) {
}
+
+ // Can't rename to a dest column twice.
+ Assert.assertThrows(IllegalArgumentException.class, () -> {
+ table.renameColumns("O = Int", "O = Int");
+ });
+
+ // Check what happens when we override a column by name
+ final Table override = table.renameColumns("Double = Int");
+ Assert.assertEquals(override.getColumnSource("Double").getType(), int.class);
+ Assert.assertFalse(override.getColumnSourceMap().containsKey("Int"));
+ // Check that ordering of source columns does not matter
+ final Table override2 = table.renameColumns("Int = Double");
+ Assert.assertEquals(override2.getColumnSource("Int").getType(), double.class);
+ Assert.assertFalse(override2.getColumnSourceMap().containsKey("Double"));
+
+ // Validate that we can swap two columns simultaneously
+ final Table swapped = table.renameColumns("Double = Int", "Int = Double");
+ Assert.assertEquals(swapped.getColumnSource("Double").getType(), int.class);
+ Assert.assertEquals(swapped.getColumnSource("Int").getType(), double.class);
}
public void testRenameColumnsIncremental() {
@@ -680,14 +699,9 @@ public void testRenameColumnsIncremental() {
final EvalNugget[] en = new EvalNugget[] {
EvalNugget.from(() -> queryTable.renameColumns(List.of())),
EvalNugget.from(() -> queryTable.renameColumns("Symbol=Sym")),
- EvalNugget.from(() -> queryTable.renameColumns("Symbol=Sym", "Symbols=Sym")),
EvalNugget.from(() -> queryTable.renameColumns("Sym2=Sym", "intCol2=intCol", "doubleCol2=doubleCol")),
};
- // Verify our assumption that columns can be renamed at most once.
- Assert.assertTrue(queryTable.renameColumns("Symbol=Sym", "Symbols=Sym").hasColumns("Symbols"));
- Assert.assertFalse(queryTable.renameColumns("Symbol=Sym", "Symbols=Sym").hasColumns("Symbol"));
-
final int steps = 100;
for (int i = 0; i < steps; i++) {
if (printTableUpdates) {
@@ -697,6 +711,175 @@ public void testRenameColumnsIncremental() {
}
}
+ public void testMoveColumnsUp() {
+ final Table table = emptyTable(1).update("A = 1", "B = 2", "C = 3", "D = 4", "E = 5");
+
+ assertTableEquals(
+ emptyTable(1).update("C = 3", "A = 1", "B = 2", "D = 4", "E = 5"),
+ table.moveColumnsUp("C"));
+
+ assertTableEquals(
+ emptyTable(1).update("C = 3", "B = 2", "A = 1", "D = 4", "E = 5"),
+ table.moveColumnsUp("C", "B"));
+
+ assertTableEquals(
+ emptyTable(1).update("D = 4", "A = 1", "C = 3", "B = 2", "E = 5"),
+ table.moveColumnsUp("D", "A", "C"));
+
+ // test trivial do nothing case
+ assertTableEquals(table, table.moveColumnsUp());
+
+ // Can't move a column up twice.
+ Assert.assertThrows(IllegalArgumentException.class, () -> {
+ table.moveColumnsUp("C", "C");
+ });
+
+ // Can't rename a source column twice.
+ Assert.assertThrows(IllegalArgumentException.class, () -> {
+ table.moveColumnsUp("A1 = A", "A2 = A");
+ });
+
+ // Can't rename to a dest column twice.
+ Assert.assertThrows(IllegalArgumentException.class, () -> {
+ table.moveColumnsUp("O = A", "O = B");
+ });
+
+ assertTableEquals(
+ emptyTable(1).update("B = 3", "A = 1", "D = 4", "E = 5"),
+ table.moveColumnsUp("B = C"));
+ assertTableEquals(
+ emptyTable(1).update("B = 1", "C = 3", "D = 4", "E = 5"),
+ table.moveColumnsUp("B = A"));
+ assertTableEquals(
+ emptyTable(1).update("B = 1", "A = 2", "C = 3", "D = 4", "E = 5"),
+ table.moveColumnsUp("B = A", "A = B"));
+ }
+
+ public void testMoveColumnsDown() {
+ final Table table = emptyTable(1).update("A = 1", "B = 2", "C = 3", "D = 4", "E = 5");
+
+ assertTableEquals(
+ emptyTable(1).update("A = 1", "B = 2", "D = 4", "E = 5", "C = 3"),
+ table.moveColumnsDown("C"));
+
+ assertTableEquals(
+ emptyTable(1).update("A = 1", "D = 4", "E = 5", "C = 3", "B = 2"),
+ table.moveColumnsDown("C", "B"));
+
+ assertTableEquals(
+ emptyTable(1).update("B = 2", "E = 5", "D = 4", "A = 1", "C = 3"),
+ table.moveColumnsDown("D", "A", "C"));
+
+ // test trivial do nothing case
+ assertTableEquals(table, table.moveColumnsDown());
+
+ // Can't move a column down twice.
+ Assert.assertThrows(IllegalArgumentException.class, () -> {
+ table.moveColumnsDown("C", "C");
+ });
+
+ // Can't rename a source column twice.
+ Assert.assertThrows(IllegalArgumentException.class, () -> {
+ table.moveColumnsDown("A1 = A", "A2 = A");
+ });
+
+ // Can't rename to a dest column twice.
+ Assert.assertThrows(IllegalArgumentException.class, () -> {
+ table.moveColumnsDown("O = A", "O = B");
+ });
+
+ assertTableEquals(
+ emptyTable(1).update("A = 1", "D = 4", "E = 5", "B = 3"),
+ table.moveColumnsDown("B = C"));
+ assertTableEquals(
+ emptyTable(1).update("C = 3", "D = 4", "E = 5", "B = 1"),
+ table.moveColumnsDown("B = A"));
+ assertTableEquals(
+ emptyTable(1).update("C = 3", "D = 4", "E = 5", "B = 1", "A = 2"),
+ table.moveColumnsDown("B = A", "A = B"));
+ }
+
+ public void testMoveColumns() {
+ final Table table = emptyTable(1).update("A = 1", "B = 2", "C = 3", "D = 4", "E = 5");
+
+ // single column
+ assertTableEquals(
+ emptyTable(1).update("C = 3", "A = 1", "B = 2", "D = 4", "E = 5"),
+ table.moveColumns(-1, "C"));
+ assertTableEquals(
+ emptyTable(1).update("C = 3", "A = 1", "B = 2", "D = 4", "E = 5"),
+ table.moveColumns(0, "C"));
+ assertTableEquals(
+ emptyTable(1).update("A = 1", "C = 3", "B = 2", "D = 4", "E = 5"),
+ table.moveColumns(1, "C"));
+ assertTableEquals(
+ emptyTable(1).update("A = 1", "B = 2", "C = 3", "D = 4", "E = 5"),
+ table.moveColumns(2, "C"));
+ assertTableEquals(
+ emptyTable(1).update("A = 1", "B = 2", "D = 4", "C = 3", "E = 5"),
+ table.moveColumns(3, "C"));
+ assertTableEquals(
+ emptyTable(1).update("A = 1", "B = 2", "D = 4", "E = 5", "C = 3"),
+ table.moveColumns(4, "C"));
+ assertTableEquals(
+ emptyTable(1).update("A = 1", "B = 2", "D = 4", "E = 5", "C = 3"),
+ table.moveColumns(10, "C"));
+
+ // two columns
+ assertTableEquals(
+ emptyTable(1).update("C = 3", "B = 2", "A = 1", "D = 4", "E = 5"),
+ table.moveColumns(-1, "C", "B"));
+ assertTableEquals(
+ emptyTable(1).update("C = 3", "B = 2", "A = 1", "D = 4", "E = 5"),
+ table.moveColumns(0, "C", "B"));
+ assertTableEquals(
+ emptyTable(1).update("A = 1", "C = 3", "B = 2", "D = 4", "E = 5"),
+ table.moveColumns(1, "C", "B"));
+ assertTableEquals(
+ emptyTable(1).update("A = 1", "D = 4", "C = 3", "B = 2", "E = 5"),
+ table.moveColumns(2, "C", "B"));
+ assertTableEquals(
+ emptyTable(1).update("A = 1", "D = 4", "E = 5", "C = 3", "B = 2"),
+ table.moveColumns(3, "C", "B"));
+ assertTableEquals(
+ emptyTable(1).update("A = 1", "D = 4", "E = 5", "C = 3", "B = 2"),
+ table.moveColumns(4, "C", "B"));
+ assertTableEquals(
+ emptyTable(1).update("A = 1", "D = 4", "E = 5", "C = 3", "B = 2"),
+ table.moveColumns(10, "C", "B"));
+
+ // test trivial do nothing case
+ for (int ii = -1; ii < 10; ++ii) {
+ assertTableEquals(table, table.moveColumns(ii));
+ }
+
+ // Can't move a column down twice.
+ Assert.assertThrows(IllegalArgumentException.class, () -> {
+ table.moveColumns(2, "C", "C");
+ });
+
+ // Can't rename a source column twice.
+ Assert.assertThrows(IllegalArgumentException.class, () -> {
+ table.moveColumns(2, "A1 = A", "A2 = A");
+ });
+
+ // Can't rename to a dest column twice.
+ Assert.assertThrows(IllegalArgumentException.class, () -> {
+ table.moveColumns(2, "O = A", "O = B");
+ });
+
+
+ assertTableEquals(
+ emptyTable(1).update("A = 1", "D = 4", "B = 3", "E = 5"),
+ table.moveColumns(2, "B = C"));
+ assertTableEquals(
+ emptyTable(1).update("C = 3", "D = 4", "B = 1", "E = 5"),
+ table.moveColumns(2, "B = A"));
+ assertTableEquals(
+ emptyTable(1).update("C = 3", "D = 4", "B = 1", "A = 2", "E = 5"),
+ table.moveColumns(2, "B = A", "A = B"));
+ }
+
public static WhereFilter stringContainsFilter(
String columnName,
String... values) {
diff --git a/engine/table/src/test/java/io/deephaven/engine/table/impl/TestMoveColumns.java b/engine/table/src/test/java/io/deephaven/engine/table/impl/TestMoveColumns.java
index 3edb395a20b..f82f26c7978 100644
--- a/engine/table/src/test/java/io/deephaven/engine/table/impl/TestMoveColumns.java
+++ b/engine/table/src/test/java/io/deephaven/engine/table/impl/TestMoveColumns.java
@@ -69,29 +69,13 @@ public void testMoveColumns() {
checkColumnOrder(temp, "dexab");
checkColumnValueOrder(temp, "45123");
- temp = table.moveColumns(0, "x=a", "b=x");
- checkColumnOrder(temp, "xbcde");
- checkColumnValueOrder(temp, "11345");
-
- temp = table.moveColumns(0, "x=a", "y=a", "z=a");
- checkColumnOrder(temp, "xyzbcde");
- checkColumnValueOrder(temp, "1112345");
+ temp = table.moveColumns(0, "x=a", "d");
+ checkColumnOrder(temp, "xdbce");
+ checkColumnValueOrder(temp, "14235");
temp = table.moveColumns(0, "b=a", "a=b");
checkColumnOrder(temp, "bacde");
- checkColumnValueOrder(temp, "11345");
-
- temp = table.moveColumns(0, "d=c", "d=a", "x=e");
- checkColumnOrder(temp, "dxb");
- checkColumnValueOrder(temp, "152");
-
- temp = table.moveColumns(0, "a=b", "a=c");
- checkColumnOrder(temp, "ade");
- checkColumnValueOrder(temp, "345");
-
- temp = table.moveColumns(0, "a=b", "a=c", "a=d", "a=e");
- checkColumnOrder(temp, "a");
- checkColumnValueOrder(temp, "5");
+ checkColumnValueOrder(temp, "12345");
}
public void testMoveUpColumns() {
@@ -110,14 +94,6 @@ public void testMoveUpColumns() {
temp = table.moveColumnsUp("x=e");
checkColumnOrder(temp, "xabcd");
checkColumnValueOrder(temp, "51234");
-
- temp = table.moveColumnsUp("x=a", "x=b");
- checkColumnOrder(temp, "xcde");
- checkColumnValueOrder(temp, "2345");
-
- temp = table.moveColumnsUp("x=a", "y=a");
- checkColumnOrder(temp, "xybcde");
- checkColumnValueOrder(temp, "112345");
}
public void testMoveDownColumns() {
@@ -134,19 +110,11 @@ public void testMoveDownColumns() {
temp = table.moveColumnsDown("b=a", "a=b", "c");
checkColumnOrder(temp, "debac");
- checkColumnValueOrder(temp, "45113");
-
- temp = table.moveColumnsDown("b=a", "a=b", "c", "d=a");
- checkColumnOrder(temp, "ebacd");
- checkColumnValueOrder(temp, "51131");
-
- temp = table.moveColumnsDown("x=a", "x=b");
- checkColumnOrder(temp, "cdex");
- checkColumnValueOrder(temp, "3452");
+ checkColumnValueOrder(temp, "45123");
- temp = table.moveColumnsDown("x=a", "y=a");
- checkColumnOrder(temp, "bcdexy");
- checkColumnValueOrder(temp, "234511");
+ temp = table.moveColumnsDown("b=a", "a=b", "c");
+ checkColumnOrder(temp, "debac");
+ checkColumnValueOrder(temp, "45123");
}
private void checkColumnOrder(Table t, String expectedOrder) {
diff --git a/py/server/deephaven/table.py b/py/server/deephaven/table.py
index 922e6b3dcd1..d09c34d865f 100644
--- a/py/server/deephaven/table.py
+++ b/py/server/deephaven/table.py
@@ -80,11 +80,11 @@ class NodeType(Enum):
"""An enum of node types for RollupTable"""
AGGREGATED = _JNodeType.Aggregated
"""Nodes at an aggregated (rolled up) level in the RollupTable. An aggregated level is above the constituent (
- leaf) level. These nodes have column names and types that result from applying aggregations on the source table
+ leaf) level. These nodes have column names and types that result from applying aggregations on the source table
of the RollupTable. """
CONSTITUENT = _JNodeType.Constituent
- """Nodes at the leaf level when :meth:`~deephaven.table.Table.rollup` method is called with
- include_constituent=True. The constituent level is the lowest in a rollup table. These nodes have column names
+ """Nodes at the leaf level when :meth:`~deephaven.table.Table.rollup` method is called with
+ include_constituent=True. The constituent level is the lowest in a rollup table. These nodes have column names
and types from the source table of the RollupTable. """
@@ -734,8 +734,7 @@ def rename_columns(self, cols: Union[str, Sequence[str]]) -> Table:
"""
try:
cols = to_sequence(cols)
- with auto_locking_ctx(self):
- return Table(j_table=self.j_table.renameColumns(*cols))
+ return Table(j_table=self.j_table.renameColumns(*cols))
except Exception as e:
raise DHError(e, "table rename_columns operation failed.") from e
diff --git a/py/server/tests/test_update_graph.py b/py/server/tests/test_update_graph.py
index 2cdf0d116cc..4da6db8e058 100644
--- a/py/server/tests/test_update_graph.py
+++ b/py/server/tests/test_update_graph.py
@@ -161,21 +161,6 @@ def test_auto_locking_joins(self):
with self.subTest(op=op):
result_table = left_table.aj(right_table, on="X")
- def test_auto_locking_rename_columns(self):
- with ug.shared_lock(self.test_update_graph):
- test_table = time_table("PT00:00:00.001").update(["X=i", "Y=i%13", "Z=X*Y"])
-
- cols_to_rename = [
- f"{f.name + '_2'} = {f.name}" for f in test_table.columns[::2]
- ]
-
- with self.assertRaises(DHError) as cm:
- result_table = test_table.rename_columns(cols_to_rename)
- self.assertRegex(str(cm.exception), r"IllegalStateException")
-
- ug.auto_locking = True
- result_table = test_table.rename_columns(cols_to_rename)
-
def test_auto_locking_ungroup(self):
with ug.shared_lock(self.test_update_graph):
test_table = time_table("PT00:00:00.001").update(["X=i", "Y=i%13"])