Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions lib/features/workspace/grid_selection_calc_engine.dart
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,11 @@ abstract final class GridSelectionCalcEngine {

distinctSet.add(trimmed);

// Try parsing numeric values (stripping commas if present)
final normalized = trimmed.replaceAll(',', '');
final parsed = double.tryParse(normalized);
// Try parsing numeric values (stripping commas if present). Most cells
// have none, so the stripped copy is only made when there is one.
final parsed = double.tryParse(
trimmed.contains(',') ? trimmed.replaceAll(',', '') : trimmed,
);
if (parsed != null && !parsed.isNaN && !parsed.isInfinite) {
numericList.add(parsed);
sum += parsed;
Expand Down Expand Up @@ -260,6 +262,13 @@ abstract final class GridSelectionCalcEngine {
}
// Limit decimal precision to 4 decimal places
final formatted = val.toStringAsFixed(4);
return formatted.replaceAll(RegExp(r'0+$'), '').replaceAll(RegExp(r'\.$'), '');
// Drop the trailing zeros, then one trailing dot (`3.1400` -> `3.14`,
// `10.0000` -> `10`): an index walk, no regex (#1531).
var end = formatted.length;
while (end > 0 && formatted.codeUnitAt(end - 1) == 0x30) {
end--;
}
if (end > 0 && formatted.codeUnitAt(end - 1) == 0x2E) end--;
return end == formatted.length ? formatted : formatted.substring(0, end);
}
}
40 changes: 40 additions & 0 deletions test/features/workspace/grid_selection_calc_format_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:querya_desktop/features/workspace/grid_selection_calc_engine.dart';

void main() {
group('GridSelectionCalcEngine.formatNum (#1531)', () {
test('trims trailing zeros and a dangling dot', () {
expect(GridSelectionCalcEngine.formatNum(null), '-');
expect(GridSelectionCalcEngine.formatNum(3.0), '3');
expect(GridSelectionCalcEngine.formatNum(3.14), '3.14');
expect(GridSelectionCalcEngine.formatNum(0.5), '0.5');
expect(GridSelectionCalcEngine.formatNum(-2.5), '-2.5');
expect(GridSelectionCalcEngine.formatNum(1 / 3), '0.3333');
expect(GridSelectionCalcEngine.formatNum(0.1 + 0.2), '0.3');
expect(GridSelectionCalcEngine.formatNum(1234.5678), '1234.5678');
});

test('values that round to a whole number keep their integer zeros', () {
expect(GridSelectionCalcEngine.formatNum(2.5000001), '2.5');
expect(GridSelectionCalcEngine.formatNum(10.00001), '10');
expect(GridSelectionCalcEngine.formatNum(100.00004), '100');
expect(GridSelectionCalcEngine.formatNum(0.00001), '0');
});
});

group('GridSelectionCalcEngine.compute with thousands separators (#1520)', () {
test('commas are stripped only for parsing, distinct keeps the text', () {
final stats = GridSelectionCalcEngine.compute(
['1,000', ' 2,500.5 ', 'NULL', '', 'abc', '3', '3'],
);
expect(stats.totalCount, 7);
expect(stats.nullCount, 2);
expect(stats.distinctCount, 4); // '1,000', '2,500.5', 'abc', '3'
expect(stats.numericCount, 4);
expect(stats.sum, 3506.5);
expect(stats.min, 3);
expect(stats.max, 2500.5);
expect(stats.median, closeTo(501.5, 1e-9)); // (3 + 1000) / 2
});
});
}
Loading