Skip to content

Commit bd9a77a

Browse files
committed
[Fix] incorrect multi-dataset filter domain
Signed-off-by: Ihor Dykhta <[email protected]>
1 parent 3b46abd commit bd9a77a

File tree

3 files changed

+73
-29
lines changed

3 files changed

+73
-29
lines changed

src/reducers/src/vis-state-updaters.ts

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ import {
6666
parseFieldValue,
6767
removeLayerFromSplitMaps,
6868
set,
69-
mergeFilterDomainStep,
7069
updateFilterPlot,
7170
removeFilterPlot,
7271
isLayerAnimatable
@@ -142,7 +141,8 @@ import {
142141
updateTimeFilterPlotType,
143142
getDefaultTimeFormat,
144143
LayerToFilterTimeInterval,
145-
TIME_INTERVALS_ORDERED
144+
TIME_INTERVALS_ORDERED,
145+
mergeFilterDomain
146146
} from '@kepler.gl/utils';
147147
import {createEffect} from '@kepler.gl/effects';
148148
import {PayloadAction} from '@reduxjs/toolkit';
@@ -1192,20 +1192,12 @@ function _removeFilterDataIdAtValueIndex(filter, valueIndex, datasets) {
11921192
}
11931193

11941194
// mergeFieldDomain for the remaining fields
1195-
// @ts-expect-error figure out correct types to use with mergeFilterDomainStep
1196-
let domainSteps: Filter & {step?: number | undefined} = {};
1197-
filter.dataId.forEach((filterDataId, idx) => {
1198-
const dataset = datasets[filterDataId];
1199-
const filterProps = dataset.getColumnFilterProps(filter.name[idx]);
1200-
// @ts-expect-error figure out correct types to use with mergeFilterDomainStep
1201-
domainSteps = mergeFilterDomainStep(domainSteps, filterProps);
1202-
});
1195+
const domainSteps = mergeFilterDomain(filter, datasets);
12031196

12041197
const nextFilter = {
12051198
...filter,
12061199
// value: nextValue,
1207-
domain: domainSteps.domain,
1208-
step: domainSteps.step
1200+
...(domainSteps ? {domain: domainSteps?.domain, step: domainSteps?.step} : {})
12091201
};
12101202

12111203
const nextValue = adjustValueToFilterDomain(nextFilter.value, nextFilter);
@@ -1237,7 +1229,8 @@ function _updateFilterProp(state, filter, prop, value, valueIndex, datasetIds?)
12371229
const datasetId = filter.dataId[valueIndex];
12381230
const {filter: updatedFilter, dataset: newDataset} = applyFilterFieldName(
12391231
filter,
1240-
state.datasets[datasetId],
1232+
state.datasets,
1233+
datasetId,
12411234
value,
12421235
valueIndex,
12431236
{mergeDomain: valueIndex > 0}

src/utils/src/filter-utils.ts

Lines changed: 60 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -207,14 +207,17 @@ const filterValidators = {
207207

208208
/**
209209
* Default validate filter function
210-
* @param dataset
210+
* @param datasets
211+
* @param datasetId
211212
* @param filter
212213
* @return - {filter, dataset}
213214
*/
214215
export function validateFilter<K extends KeplerTableModel<K, L>, L>(
215-
dataset: K,
216+
datasets: Record<string, K>,
217+
datasetId: string,
216218
filter: ParsedFilter
217219
): {filter: Filter | null; dataset: K} {
220+
const dataset = datasets[datasetId];
218221
// match filter.dataId
219222
const failed = {dataset, filter: null};
220223
const filterDataId = toArray(filter.dataId);
@@ -235,7 +238,8 @@ export function validateFilter<K extends KeplerTableModel<K, L>, L>(
235238
const fieldName = initializeFilter.name[filterDatasetIndex];
236239
const {filter: updatedFilter, dataset: updatedDataset} = applyFilterFieldName(
237240
initializeFilter,
238-
dataset,
241+
datasets,
242+
datasetId,
239243
fieldName,
240244
filterDatasetIndex,
241245
{mergeDomain: true}
@@ -262,19 +266,21 @@ export function validateFilter<K extends KeplerTableModel<K, L>, L>(
262266
/**
263267
* Validate saved filter config with new data
264268
*
265-
* @param dataset
269+
* @param datasets
270+
* @param datasetId
266271
* @param filter - filter to be validate
267272
* @param layers - layers
268273
* @return validated filter
269274
*/
270275
export function validateFilterWithData<K extends KeplerTableModel<K, L>, L>(
271-
dataset: K,
276+
datasets: Record<string, K>,
277+
datasetId: string,
272278
filter: ParsedFilter,
273279
layers: L[]
274280
): {filter: Filter; dataset: K} {
275281
return filter.type && Object.prototype.hasOwnProperty.call(filterValidators, filter.type)
276-
? filterValidators[filter.type](dataset, filter, layers)
277-
: validateFilter(dataset, filter);
282+
? filterValidators[filter.type](datasets[datasetId], filter, layers)
283+
: validateFilter(datasets, datasetId, filter);
278284
}
279285

280286
/**
@@ -913,15 +919,17 @@ export function applyFiltersToDatasets<
913919
/**
914920
* Applies a new field name value to filter and update both filter and dataset
915921
* @param filter - to be applied the new field name on
916-
* @param dataset - dataset the field belongs to
922+
* @param datasets - All datasets
923+
* @param datasetId - Id of the dataset the field belongs to
917924
* @param fieldName - field.name
918925
* @param filterDatasetIndex - field.name
919926
* @param option
920927
* @return - {filter, datasets}
921928
*/
922929
export function applyFilterFieldName<K extends KeplerTableModel<K, L>, L>(
923930
filter: Filter,
924-
dataset: K,
931+
datasets: Record<string, K>,
932+
datasetId: string,
925933
fieldName: string,
926934
filterDatasetIndex = 0,
927935
option?: {mergeDomain: boolean}
@@ -935,9 +943,10 @@ export function applyFilterFieldName<K extends KeplerTableModel<K, L>, L>(
935943
? option.mergeDomain
936944
: false;
937945

938-
const fieldIndex = dataset.getColumnFieldIdx(fieldName);
946+
const dataset = datasets[datasetId];
947+
const fieldIndex = dataset?.getColumnFieldIdx(fieldName);
939948
// if no field with same name is found, move to the next datasets
940-
if (fieldIndex === -1) {
949+
if (!dataset || fieldIndex === -1) {
941950
// throw new Error(`fieldIndex not found. Dataset must contain a property with name: ${fieldName}`);
942951
return {filter: null, dataset};
943952
}
@@ -946,7 +955,8 @@ export function applyFilterFieldName<K extends KeplerTableModel<K, L>, L>(
946955
const filterProps = dataset.getColumnFilterProps(fieldName);
947956

948957
let newFilter = {
949-
...(mergeDomain ? mergeFilterDomainStep(filter, filterProps) : {...filter, ...filterProps}),
958+
...filter,
959+
...filterProps,
950960
name: Object.assign([...toArray(filter.name)], {[filterDatasetIndex]: fieldName}),
951961
fieldIdx: Object.assign([...toArray(filter.fieldIdx)], {
952962
[filterDatasetIndex]: fieldIndex
@@ -955,6 +965,18 @@ export function applyFilterFieldName<K extends KeplerTableModel<K, L>, L>(
955965
...(filter.plotType ? {plotType: filter.plotType} : {})
956966
};
957967

968+
if (mergeDomain) {
969+
const domainSteps: (Filter & {step?: number}) | null =
970+
mergeFilterDomain(newFilter, datasets) ?? ({} as Filter);
971+
if (domainSteps) {
972+
const {domain, step} = domainSteps;
973+
newFilter.domain = domain;
974+
if (newFilter.step !== step) {
975+
newFilter.step = step;
976+
}
977+
}
978+
}
979+
958980
// TODO: if we don't set filter value in filterProps, we don't need to do this
959981
if (filterDatasetIndex > 0) {
960982
// don't reset the filter value if we are just adding a synced dataset
@@ -970,12 +992,31 @@ export function applyFilterFieldName<K extends KeplerTableModel<K, L>, L>(
970992
};
971993
}
972994

995+
/**
996+
* Merge the domains of a filter in case it applies to multiple datasets
997+
*/
998+
export function mergeFilterDomain(
999+
filter: Filter,
1000+
datasets: Record<string, KeplerTableModel<any, any>>
1001+
): (Filter & {step?: number}) | null {
1002+
let domainSteps: (Filter & {step?: number}) | null = null;
1003+
if (!filter?.dataId?.length) {
1004+
return filter;
1005+
}
1006+
filter.dataId.forEach((filterDataId, idx) => {
1007+
const dataset = datasets[filterDataId];
1008+
const filterProps = dataset.getColumnFilterProps(filter.name[idx]);
1009+
domainSteps = mergeFilterDomainStep(domainSteps ?? ({} as Filter), filterProps);
1010+
});
1011+
return domainSteps;
1012+
}
1013+
9731014
/**
9741015
* Merge one filter with other filter prop domain
9751016
*/
9761017
/* eslint-disable complexity */
9771018
export function mergeFilterDomainStep(
978-
filter: Filter,
1019+
filter: Filter | null,
9791020
filterProps?: Partial<Filter>
9801021
): (Filter & {step?: number}) | null {
9811022
if (!filter) {
@@ -1134,7 +1175,12 @@ export function validateFiltersUpdateDatasets<
11341175
const toValidate = acc.validatedFilter || filterToValidate;
11351176

11361177
const {filter: updatedFilter, dataset: updatedDataset} = validateFilterWithData(
1137-
acc.augmentedDatasets[datasetId] || dataset,
1178+
{
1179+
...updatedDatasets,
1180+
...acc.augmentedDatasets,
1181+
[datasetId]: acc.augmentedDatasets[datasetId] || dataset
1182+
},
1183+
datasetId,
11381184
toValidate,
11391185
datasetLayers
11401186
);

test/node/reducers/vis-state-test.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6007,8 +6007,13 @@ test('#visStateReducer -> applyFilterFieldName', t => {
60076007
const stateToSave = CloneDeep(StateWFilters);
60086008

60096009
const oldFilter = stateToSave.visState.filters[0];
6010-
const dataset = stateToSave.visState.datasets[oldFilter.dataId];
6011-
const {filter: newFilter} = applyFilterFieldName(oldFilter, dataset, oldFilter.name[0]);
6010+
const datasets = stateToSave.visState.datasets;
6011+
const {filter: newFilter} = applyFilterFieldName(
6012+
oldFilter,
6013+
datasets,
6014+
oldFilter.dataId,
6015+
oldFilter.name[0]
6016+
);
60126017
t.deepEqual(
60136018
oldFilter.plotType,
60146019
newFilter.plotType,

0 commit comments

Comments
 (0)