Skip to content

Commit 4fed93b

Browse files
author
Debjit Mandal
committed
fix(client-core): preserve zero values with fillWithValue in pivot (#10225)
The fillWithValue pivot config option was using the || (logical OR) operator, which treats 0 as falsy. This caused actual zero values in the data to be incorrectly replaced by fillWithValue, not just missing/undefined values. Changed the implementation to use the ?? (nullish coalescing) operator instead, which only falls through for null and undefined values, preserving actual 0 values in the data. Impact: Users can now use fillWithValue to display 'no data' indicators (like '-' or 'N/A') without also replacing legitimate zeros in their data. Fixes #10225
1 parent fb5a40f commit 4fed93b

File tree

2 files changed

+74
-2
lines changed

2 files changed

+74
-2
lines changed

packages/cubejs-client-core/src/ResultSet.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -535,8 +535,7 @@ export default class ResultSet<T extends Record<string, any> = any> {
535535

536536
const pivotImpl = (resultIndex = 0) => {
537537
let groupByXAxis = groupByToPairs<{ xValues: string[], row: Record<string, any> }, string>(({ xValues }) => this.axisValuesString(xValues));
538-
539-
const measureValue = (row: Record<string, any>, measure: string) => row[measure] || normalizedPivotConfig.fillWithValue || 0;
538+
const measureValue = (row: Record<string, any>, measure: string) => row[measure] ?? normalizedPivotConfig.fillWithValue ?? 0;
540539

541540
if (
542541
normalizedPivotConfig.fillMissingDates &&

packages/cubejs-client-core/test/ResultSet.test.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1694,6 +1694,79 @@ describe('ResultSet', () => {
16941694
]);
16951695
});
16961696

1697+
test('fillWithValue should preserve actual zero values (issue #10225)', () => {
1698+
const resultSet = new ResultSet({
1699+
query: {
1700+
measures: ['TestCube.value'],
1701+
dimensions: ['TestCube.category', 'TestCube.type'],
1702+
filters: [],
1703+
timezone: 'UTC'
1704+
},
1705+
data: [
1706+
{
1707+
'TestCube.category': 'A',
1708+
'TestCube.type': 'X',
1709+
'TestCube.value': 10
1710+
},
1711+
{
1712+
'TestCube.category': 'A',
1713+
'TestCube.type': 'Y',
1714+
'TestCube.value': 0
1715+
},
1716+
{
1717+
'TestCube.category': 'B',
1718+
'TestCube.type': 'X',
1719+
'TestCube.value': 30
1720+
}
1721+
],
1722+
annotation: {
1723+
measures: {
1724+
'TestCube.value': {
1725+
title: 'Value',
1726+
shortTitle: 'Value',
1727+
type: 'number'
1728+
}
1729+
},
1730+
dimensions: {
1731+
'TestCube.category': {
1732+
title: 'Category',
1733+
shortTitle: 'Category',
1734+
type: 'string'
1735+
},
1736+
'TestCube.type': {
1737+
title: 'Type',
1738+
shortTitle: 'Type',
1739+
type: 'string'
1740+
}
1741+
},
1742+
segments: {},
1743+
timeDimensions: {}
1744+
}
1745+
} as any);
1746+
1747+
const pivotConfig = {
1748+
x: ['TestCube.category'],
1749+
y: ['TestCube.type', 'measures'],
1750+
fillWithValue: '-'
1751+
};
1752+
1753+
const result = resultSet.tablePivot(pivotConfig);
1754+
1755+
// Actual zero values should be preserved, not replaced by fillWithValue
1756+
expect(result).toEqual([
1757+
{
1758+
'TestCube.category': 'A',
1759+
'X,TestCube.value': 10,
1760+
'Y,TestCube.value': 0 // Zero should be preserved, not replaced with '-'
1761+
},
1762+
{
1763+
'TestCube.category': 'B',
1764+
'X,TestCube.value': 30,
1765+
'Y,TestCube.value': '-' // Missing value should be replaced with '-'
1766+
}
1767+
]);
1768+
});
1769+
16971770
test('same dimension and time dimension without granularity', () => {
16981771
const resultSet = new ResultSet({
16991772
query: {

0 commit comments

Comments
 (0)