Hello, I employed claude to help me write this bug report. I'm willing to help support the resolution of this issue as well.
Ferry Generator Bug Report: Incorrect .replace() usage for primitive custom scalar types
Summary
When using type_overrides to map a custom GraphQL scalar to a primitive Dart type (e.g., DateTime), the ferry_generator incorrectly generates .replace() method calls in input type builders. Primitive types don't have a .replace() method - that's only for built_value types with builders.
Environment
- ferry:
^0.16.2-dev.4
- ferry_generator:
^0.14.0-dev.2
- built_value:
^8.9.3
- Dart SDK: 3.x
Configuration
# build.yaml
targets:
$default:
builders:
ferry_generator|graphql_builder:
enabled: true
options:
schema: li_nk_app|lib/graphql/schema.graphql
type_overrides:
OffsetDateTime:
name: DateTime
import: "dart:core"
ferry_generator|serializer_builder:
enabled: true
options:
schema: li_nk_app|lib/graphql/schema.graphql
type_overrides:
OffsetDateTime:
name: DateTime
import: "dart:core"
custom_serializers:
- import: "package:li_nk_app/graphql/serializers/offset_date_time_serializer.dart"
name: OffsetDateTimeSerializer
Custom Serializer
class OffsetDateTimeSerializer implements PrimitiveSerializer<DateTime> {
@override
DateTime deserialize(Serializers serializers, Object serialized, {
FullType specifiedType = FullType.unspecified,
}) {
return DateTime.parse(serialized as String);
}
@override
Object serialize(Serializers serializers, DateTime dateTime, {
FullType specifiedType = FullType.unspecified,
}) =>
dateTime.toUtc().toIso8601String();
@override
Iterable<Type> get types => [DateTime];
@override
String get wireName => 'OffsetDateTime';
}
GraphQL Schema (excerpt)
scalar OffsetDateTime
input CommentInput {
content: String!
createdAt: OffsetDateTime
lastUpdated: OffsetDateTime
}
Incorrect Generated Code
In lib/graphql/__generated__/schema.schema.gql.dart:
// In the GCommentInputSerializer._fromMap() method:
case 'createdAt':
var _$fieldValue = serializers.deserialize(value,
specifiedType: const FullType(DateTime)) as DateTime;
builder.createdAt.replace(_$fieldValue); // ERROR!
break;
Error Message
Error: The method 'replace' isn't defined for the type 'DateTime?'.
- 'DateTime' is from 'dart:core'.
Try correcting the name to the name of an existing method, or defining a method named 'replace'.
builder.createdAt.replace(_$fieldValue);
^^^^^^^
Expected Generated Code
case 'createdAt':
var _$fieldValue = serializers.deserialize(value,
specifiedType: const FullType(DateTime)) as DateTime;
builder.createdAt = _$fieldValue; // Direct assignment for primitives
break;
Root Cause Analysis
The generator appears to assume that any type mapped via type_overrides might be a BuiltValue type (which has builders and .replace() methods). However, when the target type is a primitive Dart type like DateTime, int, or String, the generator should use direct assignment (=) instead of .replace().
The .replace() method is only available on built_value builder fields for nested BuiltValue objects.
Workaround
Manually fix the generated code by replacing .replace() with direct assignment:
sed -i 's/builder\.createdAt\.replace(_\$fieldValue);/builder.createdAt = _\$fieldValue;/g' lib/graphql/__generated__/schema.schema.gql.dart
sed -i 's/builder\.lastUpdated\.replace(_\$fieldValue);/builder.lastUpdated = _\$fieldValue;/g' lib/graphql/__generated__/schema.schema.gql.dart
Affected Fields
Any nullable field in an input type that uses a custom scalar mapped to a primitive type:
createdAt: OffsetDateTime → DateTime
lastUpdated: OffsetDateTime → DateTime
dateOfBirth: OffsetDateTime → DateTime
Suggested Fix
In the generator, when emitting builder assignment code for deserialized values, check if the target type is a primitive (or mapped to a primitive via type_overrides) and use direct assignment instead of .replace().
Related
Hello, I employed claude to help me write this bug report. I'm willing to help support the resolution of this issue as well.
Ferry Generator Bug Report: Incorrect
.replace()usage for primitive custom scalar typesSummary
When using
type_overridesto map a custom GraphQL scalar to a primitive Dart type (e.g.,DateTime), the ferry_generator incorrectly generates.replace()method calls in input type builders. Primitive types don't have a.replace()method - that's only for built_value types with builders.Environment
^0.16.2-dev.4^0.14.0-dev.2^8.9.3Configuration
Custom Serializer
GraphQL Schema (excerpt)
Incorrect Generated Code
In
lib/graphql/__generated__/schema.schema.gql.dart:Error Message
Expected Generated Code
Root Cause Analysis
The generator appears to assume that any type mapped via
type_overridesmight be a BuiltValue type (which has builders and.replace()methods). However, when the target type is a primitive Dart type likeDateTime,int, orString, the generator should use direct assignment (=) instead of.replace().The
.replace()method is only available on built_value builder fields for nested BuiltValue objects.Workaround
Manually fix the generated code by replacing
.replace()with direct assignment:Affected Fields
Any nullable field in an input type that uses a custom scalar mapped to a primitive type:
createdAt: OffsetDateTime→DateTimelastUpdated: OffsetDateTime→DateTimedateOfBirth: OffsetDateTime→DateTimeSuggested Fix
In the generator, when emitting builder assignment code for deserialized values, check if the target type is a primitive (or mapped to a primitive via
type_overrides) and use direct assignment instead of.replace().Related