-
Notifications
You must be signed in to change notification settings - Fork 92
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
Support RealmValue (aka mixed) #1051
Conversation
Pull Request Test Coverage Report for Build 3713731875
💛 - Coveralls |
c077705
to
538e841
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.
Looks good as initial version,
Added some comments.
Also it would be good to check what additional tests .NET has and implement here. I think they have more elaborate tests like using embedded objects etc.
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.
We probably need to expose ObjectType
similarly to what we're doing in C#.
6 │ class _Bad { | ||
│ ━━━━ in realm model for 'Bad' | ||
7 │ RealmValue? wrong; | ||
│ ^^^^^^^^^^^ RealmValue? is nullable |
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.
Should we be more descriptive with these error messages? In my experience people don't understand short errors like these and reach out to support to ask them what they mean. We could rephrase that to something like: 'wrong' is declared as 'RealmValue?' which is not allowed. 'RealmValue' can already represent null with 'RealmValue.nullValue()', so you don't need to declare the property itself as nullable.
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.
In general I agree that we should have long descriptive error messages, but we need to agree on the team. Previously I was asked to simplify them.
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 would vote for short and clear messages. We could reword this to be more clear, but long error messages stand in the way after a while. So imo, this could be
`RealmValue?` is declared nullable. Use `RealmValue` or `RealmValue myfield = RealmValue.nullValue()` to assign a default null value.
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 don't think it gets in the way. The short version is at the top, the rest you can read if you are confused.
But I don't think this is specific to this PR. If we want more verbose error messages, I think we should change a lot of them.
final tuple = realm.metadata.getByClassKey(realmCore.getClassKey(value)); | ||
type = tuple.item1; | ||
targetMetadata = tuple.item2; |
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 don't think this handles the case where you open a Realm with an incomplete schema that contains RealmValue
properties linking to tables not in the user schema.
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 will add a test for this case.
What should be the expected outcome? Do we error out, or use dynamic realm objects?
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.
We should return dynamic objects.
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.
Hmm .. added a test, but it crashes in
realmCore.getProperty(object, propertyMeta.key);
At least the c-api don't support this
late RealmValue oneAny; | ||
late List<RealmValue> manyAny; |
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.
late RealmValue oneAny; | |
late List<RealmValue> manyAny; | |
late RealmValue oneValue; | |
late List<RealmValue> manyValues; |
Maybe will be better if you rename all the places where you have members any
to value
. 'Any' is confusing to me.
test/realm_value_test.dart
Outdated
Uuid.v4(), | ||
]; | ||
|
||
final config = Configuration.inMemory([AnythingGoes.schema]); |
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.
We are testing only with inMemory Realm. Is that enough?
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.
Yes, I don't see a reason test with other configurations.
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.
Okay, I had forgotten some things in dart, so I believe there's more work needed to support RealmValue, but that can probably be split into a different PR...
I will just comment that even trying to read a mixed property from core (via the c-api) containing a realm object with unknown schema will crash, and since the property is mixed we really have no way to detect this, so the crash is inevitable 😢
late List<RealmValue> manyAny; | ||
} | ||
|
||
void main() { |
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.
Will be good to make more tests for example:
- Query by RealmValue;
- Frozen objects with RealmValue;
- Embedded objects with RealmValue;
- Flexible sync with RealmValue;
- Subscriptions by RealmValue;
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.
This would test realm-core more than realm-dart.
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.
Some of these have the potential to surface symmetric bugs and may be valuable. Let's say you make a mistake and you store double values as negative the original value (e.g. 4.56 -> RealmValue(-4.56)
). This kind of bug will always pass a test like:
final value = 4.56;
realm.write(() {
myObj.any = value;
});
expect(myObj.any, value);
Ideally, that should be tested by serializing the object to json and comparing the stringified representation as seen by Core, but those other tests may also be valuable. While I agree it's testing Core, historically, SDKs have been the primary source of bug reports for the Core team and it doesn't hurt to have a few extra tests.
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.
As the 6th SDK I see less value in tests that essentially test realm-core. Adding them now will delay this PR, and require maintenance down the line.
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.
.. an argument can be made that we are only the 2nd SDK to use the c-api though
I assume this is to catch the error case that you cannot store embedded objects in a I have reworked the code to catch this misuse in the type system. |
@nirinchev I couldn't get your meaning for this one
Could you clarify this. Especially important if it is a reason to block a PR. |
Okay, I had forgotten some things in dart, so I believe there's more work needed to support RealmValue, but that can probably be split into a different PR. Here's an example of an issue that we can't handle today. Let's say you have a synchronized Realm with the following schema (this is v1 of your app). class MyDynamic {
RealmValue value;
}
class Person {
String name;
} In v2, you add a new type - final obj = myDynamic.value.as<RealmObjectBase>();
switch (obj.schema.name) {
case "Person": // do something
default:
final nameProp = obj.schema.properties.firstOrNull(p => p.name == "name");
if (nameProp != null && nameProp.propertyType == RealmPropertyType.string) {
// do something with the name
}
} My thinking with exposing public String getDisplayName(RealmValue value) {
switch (value.objectType) {
case null:
// value is not an object or is null - do nothing
return "unknown";
case "Person":
final person = value.as<Person>();
return '${person.firstName} ${person.lastName}';
case "Company":
final company = value.as<Company>();
return company.legalEntity.name;
default:
final obj = value.as<RealmObjectBase>();
final nameProp = obj.schema.properties.firstOrNull(p => p.name == "name");
if (nameProp != null || nameProp.propertyType == 'string') {
return obj.dynamic.get<string>('name');
}
return "unknown";
}
} But again, this depends on the schema being available on the realm object. |
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.
As discussed, I think it's fine to ship the feature as is while the C API limitation is addressed. I'd still recommend adding a json verification for the roundtrip test to protect us from symmetric bugs.
Support
RealmValue
that allows users to store different types in the same fieldResolves: #684