Skip to content

Commit 42068e4

Browse files
Iaashish13claude
andauthored
fix(realtime_client): stop throwing internally when converting null cell values (#1612)
## What kind of change does this PR introduce? Bug fix (internal exception noise; no observable behavior change). ## What is the current behavior? `convertCell`'s doc comment says *"If the value of the cell is `null`, returns null"* — but the code never checks for null. A null value in an `int2/int4/int8/oid` (or `float4/float8/numeric`) column falls through to `toInt`/`toDouble`, which do: ```dart try { return int.parse(value.toString()); // null → "null" → FormatException } catch (_) { return null; } ``` So every `postgres_changes` payload containing a null numeric column throws (and immediately catches) `FormatException: Invalid radix-10 number (at character 1) null` inside the library. The converted result is correct, but the exception-as-control-flow fires on **every CDC frame** for any subscribed table with nullable numeric columns. In practice this means anyone debugging a realtime Flutter app with "break on all exceptions" enabled gets stopped in `integers_patch.dart` constantly, with no way to silence it from app code. For reference, realtime-js doesn't have this problem: its `toNumber` only parses `typeof value === 'string'` and passes null through untouched. ## What is the new behavior? - `convertCell` short-circuits `null` → `null`, matching its own documented behavior and realtime-js - `toInt`/`toDouble` use `tryParse` instead of `parse` inside try/catch, so unparseable strings also no longer throw internally Output is unchanged for every input — existing tests already pin `convertCell('int8', null) => null` and `convertCell('float8', null) => null`, and they still pass. Added direct unit tests for `toInt`/`toDouble` covering null, empty, and non-numeric inputs. ## Additional context Repro: subscribe to `postgres_changes` on any table with a nullable `integer` column, update a row while the column is null, run with a debugger set to break on all exceptions. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent 2c961c0 commit 42068e4

2 files changed

Lines changed: 25 additions & 8 deletions

File tree

packages/realtime_client/lib/src/transformers.dart

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@ dynamic convertColumn(
129129
/// => [1,2,3,4]
130130
/// ```
131131
dynamic convertCell(String type, dynamic value) {
132+
if (value == null) {
133+
return null;
134+
}
135+
132136
// if data type is an array
133137
if (type[0] == '_') {
134138
final dataType = type.substring(1);
@@ -197,24 +201,20 @@ double? toDouble(dynamic value) {
197201
if (value is double) {
198202
return value;
199203
}
200-
try {
201-
final temp = value.toString();
202-
return double.parse(temp);
203-
} catch (_) {
204+
if (value == null) {
204205
return null;
205206
}
207+
return double.tryParse(value.toString());
206208
}
207209

208210
int? toInt(dynamic value) {
209211
if (value is int) {
210212
return value;
211213
}
212-
try {
213-
final temp = value.toString();
214-
return int.parse(temp);
215-
} catch (_) {
214+
if (value == null) {
216215
return null;
217216
}
217+
return int.tryParse(value.toString());
218218
}
219219

220220
dynamic toJson(dynamic value) {

packages/realtime_client/test/transformers_test.dart

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,23 @@ void main() {
2020
expect(toBoolean(null), isNull);
2121
});
2222

23+
test('transformers toInt', () {
24+
expect(toInt(10), equals(10));
25+
expect(toInt('10'), equals(10));
26+
expect(toInt(null), isNull);
27+
expect(toInt(''), isNull);
28+
expect(toInt('not a number'), isNull);
29+
});
30+
31+
test('transformers toDouble', () {
32+
expect(toDouble(1.23), equals(1.23));
33+
expect(toDouble('1.23'), equals(1.23));
34+
expect(toDouble(1), equals(1.0));
35+
expect(toDouble(null), isNull);
36+
expect(toDouble(''), isNull);
37+
expect(toDouble('not a number'), isNull);
38+
});
39+
2340
test('transformers noop', () {
2441
expect(noop(null), equals(null));
2542
expect(noop(''), equals(''));

0 commit comments

Comments
 (0)