Skip to content

Commit 06878ae

Browse files
authored
feat: Add withRecomputeOnModifiedRow to SelectColumn. (deephaven#6339)
1 parent 8832682 commit 06878ae

File tree

8 files changed

+338
-99
lines changed

8 files changed

+338
-99
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//
2+
// Copyright (c) 2016-2024 Deephaven Data Labs and Patent Pending
3+
//
4+
package io.deephaven.engine.table.impl.select;
5+
6+
import io.deephaven.api.ColumnName;
7+
import io.deephaven.api.expression.Expression;
8+
import io.deephaven.engine.rowset.TrackingRowSet;
9+
import io.deephaven.engine.table.ColumnDefinition;
10+
import io.deephaven.engine.table.ColumnSource;
11+
import io.deephaven.engine.table.WritableColumnSource;
12+
import io.deephaven.engine.table.impl.BaseTable;
13+
import io.deephaven.engine.table.impl.MatchPair;
14+
import io.deephaven.engine.table.impl.QueryCompilerRequestProcessor;
15+
import org.jetbrains.annotations.NotNull;
16+
17+
import java.util.List;
18+
import java.util.Map;
19+
20+
/**
21+
* {@link SelectColumn} implementation that wraps another {@link SelectColumn} and makes it report that values should be
22+
* recomputed when the row is modified via {@link #recomputeOnModifiedRow()}.
23+
*/
24+
class RecomputeOnModifiedRowSelectColumn extends WrappedSelectColumn {
25+
26+
RecomputeOnModifiedRowSelectColumn(@NotNull final SelectColumn inner) {
27+
super(inner);
28+
}
29+
30+
@Override
31+
public SelectColumn copy() {
32+
return new RecomputeOnModifiedRowSelectColumn(inner.copy());
33+
}
34+
35+
@Override
36+
public boolean recomputeOnModifiedRow() {
37+
return true;
38+
}
39+
40+
@Override
41+
public SelectColumn withRecomputeOnModifiedRow() {
42+
return copy();
43+
}
44+
}

engine/table/src/main/java/io/deephaven/engine/table/impl/select/SelectColumn.java

+27
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,17 @@ static SelectColumn ofStateless(@NotNull final Selectable selectable) {
6767
return new StatelessSelectColumn(of(selectable));
6868
}
6969

70+
/**
71+
* Produce a SelectColumn that {@link #recomputeOnModifiedRow()} recomputes values on any modified row} from
72+
* {@code selectable}.
73+
*
74+
* @param selectable The {@link Selectable} to adapt and mark as requiring row-level recomputation
75+
* @return The resulting SelectColumn
76+
*/
77+
static SelectColumn ofRecomputeOnModifiedRow(Selectable selectable) {
78+
return new RecomputeOnModifiedRowSelectColumn(of(selectable));
79+
}
80+
7081
/**
7182
* Convenient static final instance of a zero length Array of SelectColumns for use in toArray calls.
7283
*/
@@ -232,6 +243,22 @@ default boolean hasVirtualRowVariables() {
232243
*/
233244
SelectColumn copy();
234245

246+
/**
247+
* Should we ignore modified column sets, and always re-evaluate this column when the row changes?
248+
*
249+
* @return true if this column should be evaluated on every row modification
250+
*/
251+
default boolean recomputeOnModifiedRow() {
252+
return false;
253+
}
254+
255+
/**
256+
* Create a copy of this SelectColumn that always re-evaluates itself when a row is modified.
257+
*/
258+
default SelectColumn withRecomputeOnModifiedRow() {
259+
return new RecomputeOnModifiedRowSelectColumn(copy());
260+
}
261+
235262
class ExpressionAdapter implements Expression.Visitor<SelectColumn> {
236263
private final ColumnName lhs;
237264

engine/table/src/main/java/io/deephaven/engine/table/impl/select/StatelessSelectColumn.java

+2-95
Original file line numberDiff line numberDiff line change
@@ -21,93 +21,10 @@
2121
* {@link SelectColumn} implementation that wraps another {@link SelectColumn} and makes it report to be
2222
* {@link #isStateless() stateless}.
2323
*/
24-
class StatelessSelectColumn implements SelectColumn {
25-
26-
private final SelectColumn inner;
24+
class StatelessSelectColumn extends WrappedSelectColumn {
2725

2826
StatelessSelectColumn(@NotNull final SelectColumn inner) {
29-
this.inner = inner;
30-
}
31-
32-
@Override
33-
public List<String> initInputs(
34-
@NotNull final TrackingRowSet rowSet,
35-
@NotNull final Map<String, ? extends ColumnSource<?>> columnsOfInterest) {
36-
return inner.initInputs(rowSet, columnsOfInterest);
37-
}
38-
39-
@Override
40-
public List<String> initDef(@NotNull final Map<String, ColumnDefinition<?>> columnDefinitionMap) {
41-
return inner.initDef(columnDefinitionMap);
42-
}
43-
44-
@Override
45-
public List<String> initDef(
46-
@NotNull final Map<String, ColumnDefinition<?>> columnDefinitionMap,
47-
@NotNull final QueryCompilerRequestProcessor compilationRequestProcessor) {
48-
return inner.initDef(columnDefinitionMap, compilationRequestProcessor);
49-
}
50-
51-
@Override
52-
public Class<?> getReturnedType() {
53-
return inner.getReturnedType();
54-
}
55-
56-
@Override
57-
public Class<?> getReturnedComponentType() {
58-
return inner.getReturnedComponentType();
59-
}
60-
61-
@Override
62-
public List<String> getColumns() {
63-
return inner.getColumns();
64-
}
65-
66-
@Override
67-
public List<String> getColumnArrays() {
68-
return inner.getColumnArrays();
69-
}
70-
71-
@Override
72-
@NotNull
73-
public ColumnSource<?> getDataView() {
74-
return inner.getDataView();
75-
}
76-
77-
@Override
78-
@NotNull
79-
public ColumnSource<?> getLazyView() {
80-
return inner.getLazyView();
81-
}
82-
83-
@Override
84-
public String getName() {
85-
return inner.getName();
86-
}
87-
88-
@Override
89-
public MatchPair getMatchPair() {
90-
return inner.getMatchPair();
91-
}
92-
93-
@Override
94-
public WritableColumnSource<?> newDestInstance(final long size) {
95-
return inner.newDestInstance(size);
96-
}
97-
98-
@Override
99-
public WritableColumnSource<?> newFlatDestInstance(final long size) {
100-
return inner.newFlatDestInstance(size);
101-
}
102-
103-
@Override
104-
public boolean isRetain() {
105-
return inner.isRetain();
106-
}
107-
108-
@Override
109-
public void validateSafeForRefresh(@NotNull final BaseTable<?> sourceTable) {
110-
inner.validateSafeForRefresh(sourceTable);
27+
super(inner);
11128
}
11229

11330
@Override
@@ -119,14 +36,4 @@ public boolean isStateless() {
11936
public SelectColumn copy() {
12037
return new StatelessSelectColumn(inner.copy());
12138
}
122-
123-
@Override
124-
public ColumnName newColumn() {
125-
return inner.newColumn();
126-
}
127-
128-
@Override
129-
public Expression expression() {
130-
return inner.expression();
131-
}
13239
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
//
2+
// Copyright (c) 2016-2024 Deephaven Data Labs and Patent Pending
3+
//
4+
package io.deephaven.engine.table.impl.select;
5+
6+
import io.deephaven.api.ColumnName;
7+
import io.deephaven.api.expression.Expression;
8+
import io.deephaven.engine.rowset.TrackingRowSet;
9+
import io.deephaven.engine.table.ColumnDefinition;
10+
import io.deephaven.engine.table.ColumnSource;
11+
import io.deephaven.engine.table.WritableColumnSource;
12+
import io.deephaven.engine.table.impl.BaseTable;
13+
import io.deephaven.engine.table.impl.MatchPair;
14+
import io.deephaven.engine.table.impl.QueryCompilerRequestProcessor;
15+
import org.jetbrains.annotations.NotNull;
16+
17+
import java.util.List;
18+
import java.util.Map;
19+
20+
/**
21+
* {@link SelectColumn} implementation that wraps another {@link SelectColumn}.
22+
*/
23+
abstract class WrappedSelectColumn implements SelectColumn {
24+
25+
/**
26+
* The select column that is being wrapped.
27+
*/
28+
protected final SelectColumn inner;
29+
30+
WrappedSelectColumn(@NotNull final SelectColumn inner) {
31+
this.inner = inner;
32+
}
33+
34+
@Override
35+
public List<String> initInputs(
36+
@NotNull final TrackingRowSet rowSet,
37+
@NotNull final Map<String, ? extends ColumnSource<?>> columnsOfInterest) {
38+
return inner.initInputs(rowSet, columnsOfInterest);
39+
}
40+
41+
@Override
42+
public List<String> initDef(@NotNull final Map<String, ColumnDefinition<?>> columnDefinitionMap) {
43+
return inner.initDef(columnDefinitionMap);
44+
}
45+
46+
@Override
47+
public List<String> initDef(
48+
@NotNull final Map<String, ColumnDefinition<?>> columnDefinitionMap,
49+
@NotNull final QueryCompilerRequestProcessor compilationRequestProcessor) {
50+
return inner.initDef(columnDefinitionMap, compilationRequestProcessor);
51+
}
52+
53+
@Override
54+
public Class<?> getReturnedType() {
55+
return inner.getReturnedType();
56+
}
57+
58+
@Override
59+
public Class<?> getReturnedComponentType() {
60+
return inner.getReturnedComponentType();
61+
}
62+
63+
@Override
64+
public List<String> getColumns() {
65+
return inner.getColumns();
66+
}
67+
68+
@Override
69+
public List<String> getColumnArrays() {
70+
return inner.getColumnArrays();
71+
}
72+
73+
@Override
74+
@NotNull
75+
public ColumnSource<?> getDataView() {
76+
return inner.getDataView();
77+
}
78+
79+
@Override
80+
@NotNull
81+
public ColumnSource<?> getLazyView() {
82+
return inner.getLazyView();
83+
}
84+
85+
@Override
86+
public String getName() {
87+
return inner.getName();
88+
}
89+
90+
@Override
91+
public MatchPair getMatchPair() {
92+
return inner.getMatchPair();
93+
}
94+
95+
@Override
96+
public WritableColumnSource<?> newDestInstance(final long size) {
97+
return inner.newDestInstance(size);
98+
}
99+
100+
@Override
101+
public WritableColumnSource<?> newFlatDestInstance(final long size) {
102+
return inner.newFlatDestInstance(size);
103+
}
104+
105+
@Override
106+
public boolean isRetain() {
107+
return inner.isRetain();
108+
}
109+
110+
@Override
111+
public void validateSafeForRefresh(@NotNull final BaseTable<?> sourceTable) {
112+
inner.validateSafeForRefresh(sourceTable);
113+
}
114+
115+
@Override
116+
public boolean isStateless() {
117+
return inner.isStateless();
118+
}
119+
120+
@Override
121+
public boolean recomputeOnModifiedRow() {
122+
return inner.recomputeOnModifiedRow();
123+
}
124+
125+
@Override
126+
public ColumnName newColumn() {
127+
return inner.newColumn();
128+
}
129+
130+
@Override
131+
public Expression expression() {
132+
return inner.expression();
133+
}
134+
}

engine/table/src/main/java/io/deephaven/engine/table/impl/select/analyzers/ConstantColumnLayer.java

+4
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ public class ConstantColumnLayer extends SelectOrViewColumnLayer {
2222
final String[] deps,
2323
final ModifiedColumnSet mcsBuilder) {
2424
super(context, sc, ws, null, deps, mcsBuilder);
25+
if (sc.recomputeOnModifiedRow()) {
26+
throw new IllegalArgumentException(
27+
"SelectColumn may not have alwaysEvaluate set for a constant column: " + sc);
28+
}
2529
initialize(ws);
2630
}
2731

engine/table/src/main/java/io/deephaven/engine/table/impl/select/analyzers/DependencyLayerBase.java

+3
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ public abstract class DependencyLayerBase extends SelectAndViewAnalyzer.Layer {
3030
selectColumnHoldsVector = Vector.class.isAssignableFrom(selectColumn.getReturnedType());
3131
this.columnSource = columnSource;
3232
context.populateParentDependenciesMCS(mcsBuilder, dependencies);
33+
if (selectColumn.recomputeOnModifiedRow()) {
34+
mcsBuilder.setAll(ModifiedColumnSet.ALL);
35+
}
3336
this.myModifiedColumnSet = mcsBuilder;
3437
this.myLayerDependencySet = new BitSet();
3538
context.populateLayerDependencySet(myLayerDependencySet, dependencies);

engine/table/src/main/java/io/deephaven/engine/table/impl/select/analyzers/ViewColumnLayer.java

+4
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ final public class ViewColumnLayer extends SelectOrViewColumnLayer {
2323
final String[] deps,
2424
final ModifiedColumnSet mcsBuilder) {
2525
super(context, sc, checkResultType(cs), null, deps, mcsBuilder);
26+
if (sc.recomputeOnModifiedRow()) {
27+
throw new IllegalArgumentException(
28+
"SelectColumn may not have recomputeOnModifiedRow set for a view column: " + sc);
29+
}
2630
}
2731

2832
@Override

0 commit comments

Comments
 (0)