Skip to content

Commit 66afa5b

Browse files
authored
feat: DH-18856: Add Median to jsapi Aggregation Options (#6700)
https://deephaven.atlassian.net/browse/DH-18856 Tested using the following branch from `web-client-ui`: https://github.com/dgodinez-dh/web-client-ui/tree/dag_MedianAgg Tested median on numeric, string, and date columns.
1 parent 4838894 commit 66afa5b

3 files changed

Lines changed: 69 additions & 1 deletion

File tree

web/client-api/src/main/java/io/deephaven/web/client/api/JsTotalsTableConfig.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import io.deephaven.javascript.proto.dhinternal.io.deephaven_core.proto.table_pb.aggspec.AggSpecFirst;
2121
import io.deephaven.javascript.proto.dhinternal.io.deephaven_core.proto.table_pb.aggspec.AggSpecLast;
2222
import io.deephaven.javascript.proto.dhinternal.io.deephaven_core.proto.table_pb.aggspec.AggSpecMax;
23+
import io.deephaven.javascript.proto.dhinternal.io.deephaven_core.proto.table_pb.aggspec.AggSpecMedian;
2324
import io.deephaven.javascript.proto.dhinternal.io.deephaven_core.proto.table_pb.aggspec.AggSpecMin;
2425
import io.deephaven.javascript.proto.dhinternal.io.deephaven_core.proto.table_pb.aggspec.AggSpecNonUniqueSentinel;
2526
import io.deephaven.javascript.proto.dhinternal.io.deephaven_core.proto.table_pb.aggspec.AggSpecStd;
@@ -70,14 +71,15 @@ public class JsTotalsTableConfig {
7071
LAST = "Last",
7172
// ARRAY = "Array",
7273
SKIP = "Skip";
73-
private static final List<String> knownAggTypes = Arrays.asList(
74+
protected static final List<String> knownAggTypes = Arrays.asList(
7475
JsAggregationOperation.COUNT,
7576
JsAggregationOperation.MIN,
7677
JsAggregationOperation.MAX,
7778
JsAggregationOperation.SUM,
7879
JsAggregationOperation.ABS_SUM,
7980
JsAggregationOperation.VAR,
8081
JsAggregationOperation.AVG,
82+
JsAggregationOperation.MEDIAN,
8183
JsAggregationOperation.STD,
8284
JsAggregationOperation.FIRST,
8385
JsAggregationOperation.LAST,
@@ -357,6 +359,15 @@ public AggregateRequest buildRequest(JsArray<Column> allColumns) {
357359
agg.setColumns(columns);
358360
break;
359361
}
362+
case JsAggregationOperation.MEDIAN: {
363+
AggSpec spec = new AggSpec();
364+
spec.setMedian(new AggSpecMedian());
365+
columns = new AggregationColumns();
366+
columns.setSpec(spec);
367+
columns.setMatchPairsList(aggColumns);
368+
agg.setColumns(columns);
369+
break;
370+
}
360371
case JsAggregationOperation.STD: {
361372
AggSpec spec = new AggSpec();
362373
spec.setStd(new AggSpecStd());

web/client-api/src/main/java/io/deephaven/web/client/api/tree/enums/JsAggregationOperation.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@ public class JsAggregationOperation {
5858
* "Avg".
5959
*/
6060
AVG = "Avg",
61+
/**
62+
* The median of all values in the specified column. Can only apply to numeric types. String value is
63+
* "Median".
64+
*/
65+
MEDIAN = "Median",
6166
/**
6267
* The sample standard deviation of all values in the specified column. Can only apply to numeric types.
6368
* String value is "Std". Sample standard deviation is computed using Bessel's correction
@@ -111,6 +116,7 @@ public static boolean canAggregateType(String aggregationType, String columnType
111116
case STD: {
112117
return isNumeric(columnType);
113118
}
119+
case MEDIAN:
114120
case MIN:
115121
case MAX: {
116122
// Can only apply to Comparables - JS can't work this out, so we'll stick to known types

web/client-api/src/test/java/io/deephaven/web/client/api/TotalsTableTestGwt.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,16 @@
1111
import io.deephaven.web.client.api.filter.FilterCondition;
1212
import io.deephaven.web.client.api.filter.FilterValue;
1313
import io.deephaven.web.client.api.subscription.ViewportData;
14+
import io.deephaven.web.client.api.tree.enums.JsAggregationOperation;
1415
import jsinterop.base.Js;
1516

17+
import java.util.ArrayList;
18+
import java.util.List;
19+
import java.util.Map;
1620
import java.util.function.Consumer;
21+
import java.util.function.Supplier;
22+
23+
import static java.util.Map.entry;
1724

1825
public class TotalsTableTestGwt extends AbstractAsyncGwtTestCase {
1926
private final TableSourceBuilder tables = new TableSourceBuilder()
@@ -24,6 +31,20 @@ public class TotalsTableTestGwt extends AbstractAsyncGwtTestCase {
2431
+
2532
".with_attributes({'TotalsTable':'false,false,Count;J=Min:Avg,K=Skip,;'})");
2633

34+
// This will need to be updated to reflect values from JsTotalsTableConfig.knownAggTypes
35+
// These are the values calculated for each Agg for column I of the "hasTotals" table
36+
private final Map<String, Double> AggValueMap = Map.ofEntries(
37+
entry(JsAggregationOperation.MIN, 0.0),
38+
entry(JsAggregationOperation.MAX, 4.0),
39+
entry(JsAggregationOperation.SUM, 10.0),
40+
entry(JsAggregationOperation.ABS_SUM, 10.0),
41+
entry(JsAggregationOperation.VAR, 2.5),
42+
entry(JsAggregationOperation.AVG, 2.0),
43+
entry(JsAggregationOperation.MEDIAN, 2.0),
44+
entry(JsAggregationOperation.STD, 1.5811388300841898),
45+
entry(JsAggregationOperation.FIRST, 0.0),
46+
entry(JsAggregationOperation.LAST, 4.0));
47+
2748
public void testQueryDefinedConfigs() {
2849
connect(tables)
2950
.then(session -> {
@@ -371,6 +392,36 @@ public void testGroupedTotals() {
371392
.then(this::finish).catch_(this::report);
372393
}
373394

395+
public void testCreateTotalsTableAggTypes() {
396+
connect(tables)
397+
.then(table("hasTotals"))
398+
.then(table -> {
399+
List<Supplier<Promise<JsTotalsTable>>> tests = new ArrayList<>();
400+
List<String> aggs = JsTotalsTableConfig.knownAggTypes;
401+
for (int i = 0; i < aggs.size(); i++) {
402+
String operation = aggs.get(i);
403+
JsTotalsTableConfig config = new JsTotalsTableConfig();
404+
config.operationMap.set("I",
405+
Js.uncheckedCast(new JsString[] {toJsString(operation)}));
406+
tests.add(() -> table.getTotalsTable(config).then(totals -> {
407+
totals.setViewport(0, 100, null, null, null);
408+
409+
return waitForEvent(totals, JsTable.EVENT_UPDATED, update -> {
410+
ViewportData viewportData = (ViewportData) update.getDetail();
411+
assertEquals(1, viewportData.getRows().length);
412+
if (AggValueMap.containsKey(operation)) {
413+
assertEquals(AggValueMap.get(operation),
414+
viewportData.getRows().getAt(0).get(totals.findColumn("I")).asDouble());
415+
}
416+
}, 1500);
417+
}));
418+
}
419+
420+
return tests.stream().reduce((p1, p2) -> () -> p1.get().then(result -> p2.get())).get().get();
421+
})
422+
.then(this::finish).catch_(this::report);
423+
}
424+
374425
private static class TotalsResults {
375426
int k;
376427
long i;

0 commit comments

Comments
 (0)