gql-dart / ferry

Stream-based strongly typed GraphQL client for Dart
https://ferrygraphql.com/
MIT License
593 stars 113 forks source link

Custom scalar serializer - InvalidType error #569

Closed igbenic closed 6 months ago

igbenic commented 6 months ago

Hi! I'm stuck with using a custom scalar serializer, the code generation worked fine before I added the serializer code. I was getting this error in runtime: _type 'double' is not a subtype of type 'String?' in type cast_ in relation to Decimal fields, which are being sent as Strings from backend, here is the query:


type ItemReturnDto {
  id: Int!
  unitOfMeasure: ItemReturnUnitOfMeasureDto
  isDeleted: Boolean!
  name: String
  description: String
  unitOfMeasureId: Int
  unitsContained: Decimal
  unitPrice: Decimal
}

I wanted to make a custom serializer for that scalar Decimal that would use Decimal in the decimal package.

My schema is lib/schema.graphql GraphQL files in lib/graphql/[grouped by folders]/xyz.graphql, the failing file is lib/graphql/Sync/getItemsForSync.graphql

Here is my build.yaml:

targets:
  $default:
    builders:
      ferry_generator|serializer_builder:
        enabled: true
        options:
          schema: waste_wise|lib/schema.graphql
          type_overrides:
            Decimal:
              name: Decimal
              import: "package:decimal/decimal.dart"
          custom_serializers:
            - import: "package:waste_wise/serializers/decimal_serializer.dart"
              name: DecimalSerializer
      ferry_generator|graphql_builder:
        enabled: true
        options:
          schema: waste_wise|lib/schema.graphql
          type_overrides:
            Decimal:
              name: Decimal
              import: "package:decimal/decimal.dart"

Here is the error log after adding the serializer code to build.yaml:

[INFO] Generating SDK summary completed, took 2.4s [SEVERE] built_value_generator:builtvalue on lib/graphql/Sync/__generated_\/getItemsForSync.data.gql.dart: Error in BuiltValueGenerator for abstract class GgetItemsForSyncData_itemsForSync implements Built<GgetItemsForSyncData_itemsForSync, InvalidType>. Please make the following changes to use BuiltValue:

  1. Make field unitsContained have non-dynamic type. If you are already specifying a type, please make sure the type is correctly imported.
  2. Make field unitPrice have non-dynamic type. If you are already specifying a type, please make sure the type is correctly imported. [INFO] Running build completed, took 28.3s [INFO] Caching finalized dependency graph completed, took 160ms [SEVERE] Failed after 28.4s

And finally here is my lib/serializers/decimal_serializer.dart:

import 'package:decimal/decimal.dart';
import 'package:built_value/serializer.dart';

class DecimalSerializer implements PrimitiveSerializer<Decimal> {
  final bool structured = false;

  @override
  Decimal deserialize(Serializers serializers, Object serialized, {FullType specifiedType = FullType.unspecified}) {
    assert(serialized is String, 'serialized is not a String');
    return Decimal.parse(serialized as String);
  }

  @override
  Iterable<Type> get types => [Decimal];

  @override
  String get wireName => 'Decimal';

  @override
  Object serialize(Serializers serializers, Decimal object, {FullType specifiedType = FullType.unspecified}) {
    return object.toString();
  }
}

Even the generated code looks mostly fine, without errors, as far as I can tell, the Decimal type is correctly imported. I'm not sure where to look. Thank you in advance

igbenic commented 6 months ago

For some reason it worked after I flattened my GraphQL folder. Instead of lib/graphql/[some folder]/getDataForSync.graphql I made it lib/graphql/getDataForSync.graphql for all my graphql files