diff --git a/CHANGELOG.md b/CHANGELOG.md index c50d46e00..45d8c7193 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,10 @@ # CHANGELOG ## Not released + - Remove getUserDatasets method from api [#68](https://github.com/CartoDB/carto-react-lib/pull/68) - Fix hover color in secondary buttons [#65](https://github.com/CartoDB/carto-react-lib/pull/65) +- Fix min/max aggregated functions [#76](https://github.com/CartoDB/carto-react-lib/pull/76) ## 1.0.0-beta12 (2021-01-22) diff --git a/src/tests/widgets/operations/aggregation/values.test.js b/src/tests/widgets/operations/aggregation/values.test.js new file mode 100644 index 000000000..90122754f --- /dev/null +++ b/src/tests/widgets/operations/aggregation/values.test.js @@ -0,0 +1,31 @@ +import { aggregationFunctions } from 'src/widgets/operations/aggregation/values'; +import { AggregationTypes } from 'src/widgets/AggregationTypes'; + +const VALUES = [1, 2, 3, 4, 5]; + +describe('Aggregation functions', () => { + test(AggregationTypes.COUNT, () => { + const func = aggregationFunctions[AggregationTypes.COUNT]; + expect(func(VALUES)).toEqual(5); + }); + + test(AggregationTypes.AVG, () => { + const func = aggregationFunctions[AggregationTypes.AVG]; + expect(func(VALUES)).toEqual(3); + }); + + test(AggregationTypes.MIN, () => { + const func = aggregationFunctions[AggregationTypes.MIN]; + expect(func(VALUES)).toEqual(1); + }); + + test(AggregationTypes.MAX, () => { + const func = aggregationFunctions[AggregationTypes.MAX]; + expect(func(VALUES)).toEqual(5); + }); + + test(AggregationTypes.SUM, () => { + const func = aggregationFunctions[AggregationTypes.SUM]; + expect(func(VALUES)).toEqual(15); + }); +}); diff --git a/src/utils/pickValuesFromFeatures.js b/src/utils/pickValuesFromFeatures.js new file mode 100644 index 000000000..9beed42a2 --- /dev/null +++ b/src/utils/pickValuesFromFeatures.js @@ -0,0 +1,17 @@ +function isFeature(value) { + return typeof value === 'object' && 'properties' in value; +} + +function getValueFromFeature(feature, column) { + if (!isFeature(feature)) { + return 0; + } + + const value = feature.properties[column]; + const isValidValue = Number.isFinite(value); + return isValidValue ? value : 0; +} + +export function pickValuesFromFeatures(features, column) { + return features.map((feat) => getValueFromFeature(feat, column)); +} diff --git a/src/widgets/models/FormulaModel.js b/src/widgets/models/FormulaModel.js index f97e604dd..b166e7fba 100644 --- a/src/widgets/models/FormulaModel.js +++ b/src/widgets/models/FormulaModel.js @@ -4,6 +4,7 @@ import { executeSQL } from '../../api'; import { filtersToSQL } from '../../api/FilterQueryBuilder'; import { applyFilter } from '../../api/Filter'; import { aggregationFunctions } from '../operations/aggregation/values'; +import { pickValuesFromFeatures } from '../../utils/pickValuesFromFeatures'; import { LayerTypes } from '../LayerTypes'; export const getFormula = async (props) => { @@ -68,10 +69,10 @@ export const filterViewportFeaturesToGetFormula = ({ }) => { if (viewportFeatures) { const targetOperation = aggregationFunctions[operation]; - const filteredFeatures = viewportFeatures.filter(applyFilter({ filters })); + const featureValues = pickValuesFromFeatures(filteredFeatures, column); - return [{ value: targetOperation(filteredFeatures, column) }]; + return [{ value: targetOperation(featureValues) }]; } return [{ value: null }]; diff --git a/src/widgets/operations/aggregation/values.js b/src/widgets/operations/aggregation/values.js index 3af12c98e..41c0022cd 100644 --- a/src/widgets/operations/aggregation/values.js +++ b/src/widgets/operations/aggregation/values.js @@ -1,15 +1,11 @@ import { AggregationTypes } from '../../AggregationTypes'; -const sum = (v, column) => - v.reduce( - (a, b) => (typeof b === 'object' ? a + (b.properties[column] || 0) : a + b), - 0 - ); +const sum = (values) => values.reduce((a, b) => a + b, 0); export const aggregationFunctions = { - [AggregationTypes.COUNT]: (val) => val.length, - [AggregationTypes.MIN]: (val) => val.reduce((a, b) => Math.min(a, b), Infinity), - [AggregationTypes.MAX]: (val) => val.reduce((a, b) => Math.max(a, b), -Infinity), - [AggregationTypes.SUM]: (val, column) => sum(val, column), - [AggregationTypes.AVG]: (val, column) => sum(val, column) / val.length + [AggregationTypes.COUNT]: (values) => values.length, + [AggregationTypes.MIN]: (values) => values.reduce((a, b) => Math.min(a, b), Infinity), + [AggregationTypes.MAX]: (values) => values.reduce((a, b) => Math.max(a, b), -Infinity), + [AggregationTypes.SUM]: (values) => sum(values), + [AggregationTypes.AVG]: (values) => sum(values) / values.length };