-
Notifications
You must be signed in to change notification settings - Fork 87
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RDART-1062: Allow missing values (implicit null) #1736
Conversation
57c6f15
to
a332fc8
Compare
Pull Request Test Coverage Report for Build 9696676877Details
💛 - Coveralls |
Pull Request Test Coverage Report for Build 9697576923Details
💛 - Coveralls |
Pull Request Test Coverage Report for Build 9699703151Details
💛 - Coveralls |
Pull Request Test Coverage Report for Build 9710791691Details
💛 - Coveralls |
8537712
to
4bd525d
Compare
Pull Request Test Coverage Report for Build 9761656848Details
💛 - Coveralls |
ce868ec
to
4b00042
Compare
4556668
to
08733cb
Compare
Pull Request Test Coverage Report for Build 10217657561Details
💛 - Coveralls |
a9fcf2d
to
1206d3d
Compare
1206d3d
to
da64c63
Compare
da64c63
to
154fa13
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to go more thoroughly through the tests, but here's some initial comments
packages/ejson/lib/src/decoding.dart
Outdated
final args = nullable ? [type.nonNull] : type.args; | ||
if (args.isEmpty) { | ||
return decoder(ejson) as T; // minor optimization | ||
T fromEJson<T>(EJsonValue ejson, {bool? allowCustom, T? defaultValue}) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing docs for allowCustom
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More broadly though, I'm not sure I fully understand the need for allowCustom
and the whole saving it, setting it, then restoring it logic seems awkward. Can you give me the tl;dr for what we're trying to achieve here or maybe we can just take it offline; though either way we probably need to add some code comments to make sure that is still understandable in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For _allowCustom
think thread local storage, but since dart don't have shared heaps, we can just use a static variable. If the allowCustom
parameter is set, it will use that for _allowCustom
on any recursive calls to fromEJson
such as would happen for list etc.
The problem I'm trying to solve is that you could register
a type T
with all optional values, meaning that {}
would deserialize to T
(and any other map for that matter, as redundant properties are already allowed). We don't try to search for best matching deserializer, so in the dynamic case, where the type to deserialize to is unknown (such as is the case for RealmValue
), the custom deserializers can get in the way.
Hence this flag. I deliberately didn't document it, as it is very internal thing only really meant for RealmValue
.
However, I will add, and elaborate the in-code comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The:
{'a': 1, 'b': 2}: {
// Even though Game could be deserialized from this (everything in Game
// is optional, hence {} and by extension any map can deserialize to Game),
// we always decode a map as a map inside a RealmValue.
'a': {'\$numberInt': '1'},
'b': {'\$numberInt': '2'},
},
test case illustrate the issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And the following case in _decodeAny
:
Map<dynamic, dynamic> _ => _tryDecodeCustomIfAllowed(ejson) ?? _decodeDocument<String, dynamic>(ejson), // other maps goes last!!
Obviously any map can decode as a map, so we need to check custom decoders first, but in some cases that is not what you want either, hence the flag.
One could perhaps argue that _decodeAny
should never even try the custom decoders, and always return a map for non BSON types. Would yor prefer that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, yeah, I guess I can follow the logic now. It does feel to me a bit more awkward than weaving the argument through subsequent calls, but I guess you chose the current implementation as it's more localized and non-breaking change. I'm fine with keeping it as is, just need to add more descriptive comments to make sure we can still follow along in a year from now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have been thinking about it since yesterday. How do you feel about never trying the custom decoders in _decodeAny
. Personally I think I prefer that for a couple of reasons:
- Custom decoders will only be invoked when the type to deserialize to is known. Calling
fromEJson<dynamic>(..)
(or implicitfromEJson(..)
will never try the custom decoders registered by the user. This removes any ambiguity. - It is slightly more performant, as we get rid of
_tryDecodeCustomIfAllowed
which tries each custom decoder in turn, until the first match. - I can get rid of the
allowCustom
/_allowCustom
shenanigans.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, that also sounds viable
7285bef
to
93e4d9d
Compare
…bject serialization
Co-authored-by: Nikola Irinchev <[email protected]>
f5fadc7
to
c610c49
Compare
Assuming:
then the following now works:
Previously the call to
fromEJson<Player>(ejson)
would fail unlessejson
was a map with shape{ 'name': ..., 'game': ..., scoresByRound: ...}
despitegame
being nullable, andscoresByRound
being optional.This PR also rectifies and oversight regarding
RealmValue
andDecimal128
. These types are now supported without explicit calls toregister
.Also, sets are now supported:
and
RealValue
can be deserialized fromDBRef
:Fixes: #1735
Fixes: #1737
Fixes: #1761
Fixes: #1757