realm-dart icon indicating copy to clipboard operation
realm-dart copied to clipboard

Access RealmObject property name and mapToName, for use in Realm .query

Open dotjon0 opened this issue 2 years ago • 9 comments

Description

We build Realm .query's dynamically, for example when allowing users within the Flutter UI to filter/sort/search a Realm model/collection via .query

  • allowing the user to filter by XYZ params, etc by clicking on checkboxes, etc. Currently the 'keys' in the .query have to be hard coded using the @MapTo key from the RealmObject property, which is not ideal from a maintenance perspective. I.e. final hobbits = fellowshipOfTheRing.members.query('first_name == "Hobbit"');

To get over this 'hard coding', it would be great if we could access the RealmObject property (as a string) and related @MapTo property (as a string) as follows:

  1. p.firstName.name // outputs string firstName
  2. p.firstName.mapToName // outputs string first_name (@MapTo property for p.firstName)
  3. p.firstName.mapToNameOrName // outputs no 2 above, falls back to option 1 if no 2 @MapTo does not exist

Or it may be better to p.firstName.reamlName (or similar) which outputs whatever the property is in the Realm local DB...i.e. as .query essentially needs this whether its no 1 or 2 above.

This allows us to take advantage of darts strict typing when building Realm .query's, which would be amazing;

// i.e. p.firstName.name would output firstName as a string Option 1: final hobbits = fellowshipOfTheRing.members.query('${p.firstName.name} == "Hobbit"');

or

// i.e. p.firstName.mapToName would output first_name as a string (i.e. the p.firstName @MapTo) Option 2: final hobbits = fellowshipOfTheRing.members.query('${p.firstName.mapToName} == "Hobbit"');

Either route would work very well. There are also lots of other use cases for this...such as dynamically building CSVs from RealmResults, please see https://github.com/realm/realm-dart/issues/1076

To add to this re .query params in embedded objects/lists

It would also be good if we could access embedded arrays/lists via dot notation (or by some other way to give the same effect as the above two options). So for example (we have not tested .query with params within embedded lists/objects yet so we are 'assuming' this is possible) if we could:

// i.e. {{p.friends.friends.name }}would output friends.firstName as a string Option 1: final hobbits = fellowshipOfTheRing.members.query('${p.friends.firstName.name} == "Hobbit"');

or

// i.e. p.friends.firstName.mapToName would output friends.first_name as a string (i.e. the p.firstName @MapTo) Option 2: final hobbits = fellowshipOfTheRing.members.query('${p.friends.firstName.mapToName} == "Hobbit"');

How important is this improvement for you?

Would be a major improvement

dotjon0 avatar Dec 20 '22 16:12 dotjon0

We do have plans to support LINQ (as known from .NET) style queries. Would allow you to do queries like:

realm.all<Fellow>().where((f) => f.race == 'Hobbit');

or something similarly expressive. Tracked here #781. But I must warn that it is not right around the corner.

nielsenko avatar Dec 20 '22 16:12 nielsenko

ooo that sounds amazing @nielsenko - ok will keep an eye on this and thanks for the heads up. This LINQ does not help the use case in this issue https://github.com/realm/realm-dart/issues/1077 as the user dynamically builds the query based on filters selected, so for #1077 it would have to be a query string?

dotjon0 avatar Dec 20 '22 17:12 dotjon0

The realmObject.property.name syntax is not easily achieved, since the realmObject.property is itself a getter for the value of said property. Maybe something like realmObject.propertyProperty.name as an alternative?

I'm speaking on my own accord here. Wiser people may have objections to this.

nielsenko avatar Dec 20 '22 19:12 nielsenko

BTW, what about realmObject.properties['property'].name? Wouldn't that work better for your filter use-case?

nielsenko avatar Dec 20 '22 19:12 nielsenko

We could also generate a type specific schema class. Then something like Fellow.schema.firstName.name would be possible. Could still allow Fellow.schema.properties['firstName'].name as well

nielsenko avatar Dec 20 '22 21:12 nielsenko

I put up https://github.com/realm/realm-dart/pull/1078 - it doesn't cover all the requirements of this issue, but it makes it possible to use the model name rather than the mapTo-name when creating queries (i.e. fellowshipOfTheRing.members.query('firstName == "Hobbit"') rather than .query(first_name == ...)

nirinchev avatar Dec 21 '22 14:12 nirinchev

I put up https://github.com/realm/realm-dart/pull/1078 - it doesn't cover all the requirements of this issue, but it makes it possible to use the model name rather than the mapTo-name when creating queries (i.e. fellowshipOfTheRing.members.query('firstName == "Hobbit"') rather than .query(first_name == ...)

Brilliant @nirinchev , this makes a ton of sense and will be very helpful. We did think it was odd to use the @MapTo properties in Realm .query's. Thank you so much for raising this.

dotjon0 avatar Dec 22 '22 13:12 dotjon0

We could also generate a type specific schema class. Then something like Fellow.schema.firstName.name would be possible. Could still allow Fellow.schema.properties['firstName'].name as well

@nielsenko this would be perfect ;-) (both Fellow.schema.firstName.name and Fellow.schema.properties['firstName'].name) as we can then build a ListView in Flutter dynamically, as each Column (in the ListView) and its (the Columns) filters can then be dynamically built:

  1. Get the value (FellowRealmObjectInstance.firstName)
  2. Get the type (Fellow.schema.firstName.type) so we can then build a range of filters the user (in the Flutter UI) can use (does not contain, contains, etc) - we can use these to dynamically populate the Realm .query for the opted for filters.
  3. Get the name (Fellow.schema.firstName.name) to use in the Realm .query in point 2 above via #1078

This would open up lots of other use cases around dynamically building widgets based on the type of the RealmObject property... i.e. TextFormField could automatically generated in different ways if it is a String, int, etc... Also will be very helpful when streaming RealmResults from a Realm .query, etc...

The above and #1078 certainly removes lots of pain initially and ongoing (maintainability via strict typing i.e. re Realm schema changes), so would be amazing to have in place. Lots of value.

dotjon0 avatar Dec 22 '22 13:12 dotjon0

Great to see https://github.com/realm/realm-dart/pull/1078 merged, thank you all. Will look forward to your further thoughts.

dotjon0 avatar Jan 05 '23 23:01 dotjon0