google / built_collection.dart

Immutable Dart collections via the builder pattern.
https://pub.dev/packages/built_collection
BSD 3-Clause "New" or "Revised" License
275 stars 53 forks source link

Storing null values in collections #215

Closed jimmyff closed 4 years ago

jimmyff commented 4 years ago

I was hoping to store lists that can also contain null values. However I'm getting iterable contained invalid element: null I'm assuming this is by design.

Is there any way around this? Could be something like: BuiltList<NullOr<DateTime>> although not sure if that would mess up the serializer?

jimmyff commented 4 years ago

Just found https://github.com/google/built_collection.dart/issues/140 which solves my issue although the solution is a tad on the verbose side.

I'm now just having difficulty getting it to serialize: StateError (Bad state: No serializer for 'Optional<DateTime>'.)

I love the built_value & built_collection packages but I always get in a mess trying to implement serializers when it's for something thats not a standard built class. Could you let me know what I need to put where to make Optional work as expected?

jimmyff commented 4 years ago

I think I've got it working! 🎉

class OptionalSerializer implements PrimitiveSerializer<Optional> {
  @override
  final Iterable<Type> types = [Optional];

  @override
  final String wireName = 'Optional';

  @override
  Object serialize(Serializers serializers, Optional optional,
      {FullType specifiedType = FullType.unspecified}) {
    return optional.isPresent ? optional.value : null;
  }

  @override
  Optional deserialize(Serializers serializers, Object serialized,
      {FullType specifiedType: FullType.unspecified}) {
    return Optional.fromNullable(serialized);
  }
}

I wasn't sure if possible how to get the generic type of Optional to infer it's typing in the deserialize method?

jimmyff commented 4 years ago

Yeah that seems to be causing an issue:

[ERROR:flutter/lib/ui/ui_dart_state.cc(166)] Unhandled Exception: Deserializing '[uids, [00000000-0000-0000-0000-000000000001, c0dffd2e-6ab8-55b3-9fea-0238f1b...' to 'Conversation' failed due to: Deserializing '[null, null]' to 'BuiltList<Optional<DateTime>>' failed due to: type 'Optional<dynamic>' is not a subtype of type 'Optional<DateTime>'
davidmorgan commented 4 years ago

You might be able to make it work by returning Optional<Null>.absent() if the value is null.

jimmyff commented 4 years ago

that worked @davidmorgan ! thanks. Seems a little fragile though, might this all break when null aware datatypes are released for dart? If so I'll probably restructure this to avoid using nulls in collections

jimmyff commented 4 years ago

I've refactored to get rid of the nulls int he collection, feels a bit more robust. Thanks for help