Merge pull request #1660 from realm/jas/backlink-queries
Preliminary work for queries over named backlinks
This commit is contained in:
commit
8dc5149770
|
@ -7,13 +7,15 @@
|
||||||
|
|
||||||
### Enhancements
|
### Enhancements
|
||||||
* [Sync] Reduced initial download times in Realms with long transaction histories.
|
* [Sync] Reduced initial download times in Realms with long transaction histories.
|
||||||
* [Sync] Wait for pending notifications to complete when removing a sync listener (1648).
|
* [Sync] Wait for pending notifications to complete when removing a sync listener (#1648).
|
||||||
* Enabled sort and distinct in the query string. If sort or distinct are also applied outside of the query string, the conditions are stacked.
|
* Enabled sort and distinct in the query string. If sort or distinct are also applied outside of the query string, the conditions are stacked.
|
||||||
- Example syntax: `age > 20 SORT(name ASC, age DESC) DISTINCT(name)`
|
- Example syntax: `age > 20 SORT(name ASC, age DESC) DISTINCT(name)`
|
||||||
- The ordering for sorting can be one of the following case insensitive literals: `ASC`, `ASCENDING`, `DESC`, `DESCENDING`.
|
- The ordering for sorting can be one of the following case insensitive literals: `ASC`, `ASCENDING`, `DESC`, `DESCENDING`.
|
||||||
- Any number of properties can appear inside the brackets in a comma separated list.
|
- Any number of properties can appear inside the brackets in a comma separated list.
|
||||||
- Any number of sort/distinct conditions can be indicated, they will be applied in the specified order.
|
- Any number of sort/distinct conditions can be indicated, they will be applied in the specified order.
|
||||||
- Sort or distinct cannot operate independently, these conditions must be attached to at least one query filter.
|
- Sort or distinct cannot operate independently, these conditions must be attached to at least one query filter.
|
||||||
|
* Added support for queries over named backlinks (#1498/#1660).
|
||||||
|
- Example syntax: `parents.age > 25` and `parents.@count == 2`.
|
||||||
* [Sync] Added `Realm.Results.subscribe()` to subscribe to partial synced Realms.
|
* [Sync] Added `Realm.Results.subscribe()` to subscribe to partial synced Realms.
|
||||||
* [Sync] Added class `Realm.Sync.Subscription` and enum `Realm.Sync.SubscriptionState` to support partial synced Realms.
|
* [Sync] Added class `Realm.Sync.Subscription` and enum `Realm.Sync.SubscriptionState` to support partial synced Realms.
|
||||||
* [Sync] Added an object-level permission subsystem. It is possible to grant fine-grained priviliges to users.
|
* [Sync] Added an object-level permission subsystem. It is possible to grant fine-grained priviliges to users.
|
||||||
|
|
|
@ -152,6 +152,21 @@ typename T::Object ResultsClass<T>::create_instance(ContextType ctx, SharedRealm
|
||||||
return create_object<T, ResultsClass<T>>(ctx, new realm::js::Results<T>(realm, *table));
|
return create_object<T, ResultsClass<T>>(ctx, new realm::js::Results<T>(realm, *table));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void alias_backlinks(parser::KeyPathMapping &mapping, const realm::SharedRealm &realm)
|
||||||
|
{
|
||||||
|
const realm::Schema &schema = realm->schema();
|
||||||
|
for (auto it = schema.begin(); it != schema.end(); ++it) {
|
||||||
|
for (const Property &property : it->computed_properties) {
|
||||||
|
if (property.type == realm::PropertyType::LinkingObjects) {
|
||||||
|
auto target_object_schema = schema.find(property.object_type);
|
||||||
|
const TableRef table = ObjectStore::table_for_object_type(realm->read_group(), target_object_schema->name);
|
||||||
|
std::string native_name = "@links." + std::string(table->get_name()) + "." + property.link_origin_property_name;
|
||||||
|
mapping.add_mapping(table, property.name, native_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
template<typename U>
|
template<typename U>
|
||||||
typename T::Object ResultsClass<T>::create_filtered(ContextType ctx, const U &collection, Arguments args) {
|
typename T::Object ResultsClass<T>::create_filtered(ContextType ctx, const U &collection, Arguments args) {
|
||||||
|
@ -164,11 +179,13 @@ typename T::Object ResultsClass<T>::create_filtered(ContextType ctx, const U &co
|
||||||
auto const &realm = collection.get_realm();
|
auto const &realm = collection.get_realm();
|
||||||
auto const &object_schema = collection.get_object_schema();
|
auto const &object_schema = collection.get_object_schema();
|
||||||
DescriptorOrdering ordering;
|
DescriptorOrdering ordering;
|
||||||
|
parser::KeyPathMapping mapping;
|
||||||
|
alias_backlinks(mapping, realm);
|
||||||
|
|
||||||
parser::ParserResult result = parser::parse(query_string);
|
parser::ParserResult result = parser::parse(query_string);
|
||||||
NativeAccessor<T> accessor(ctx, realm, object_schema);
|
NativeAccessor<T> accessor(ctx, realm, object_schema);
|
||||||
query_builder::ArgumentConverter<ValueType, NativeAccessor<T>> converter(accessor, &args.value[1], args.count - 1);
|
query_builder::ArgumentConverter<ValueType, NativeAccessor<T>> converter(accessor, &args.value[1], args.count - 1);
|
||||||
query_builder::apply_predicate(query, result.predicate, converter);
|
query_builder::apply_predicate(query, result.predicate, converter, mapping);
|
||||||
query_builder::apply_ordering(ordering, query.get_table(), result.ordering);
|
query_builder::apply_ordering(ordering, query.get_table(), result.ordering);
|
||||||
|
|
||||||
return create_instance(ctx, collection.filter(std::move(query)).apply_ordering(std::move(ordering)));
|
return create_instance(ctx, collection.filter(std::move(query)).apply_ordering(std::move(ordering)));
|
||||||
|
|
|
@ -83,6 +83,26 @@ module.exports = {
|
||||||
TestCase.assertArraysEqual(names(resultsC), ['JP']);
|
TestCase.assertArraysEqual(names(resultsC), ['JP']);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
testFilteredLinkingObjectsByName: function() {
|
||||||
|
var realm = new Realm({schema: [schemas.PersonObject]});
|
||||||
|
|
||||||
|
var christine, olivier;
|
||||||
|
realm.write(function() {
|
||||||
|
olivier = realm.create('PersonObject', {name: 'Olivier', age: 0});
|
||||||
|
christine = realm.create('PersonObject', {name: 'Christine', age: 25, children: [olivier]});
|
||||||
|
realm.create('PersonObject', {name: 'JP', age: 28, children: [olivier]});
|
||||||
|
});
|
||||||
|
|
||||||
|
let people = realm.objects('PersonObject')
|
||||||
|
|
||||||
|
TestCase.assertEqual(people.filtered('parents.age > 25').length, 1);
|
||||||
|
TestCase.assertEqual(people.filtered('parents.age > 25')[0].name, 'Olivier');
|
||||||
|
TestCase.assertEqual(people.filtered('parents.@count == 2').length, 1);
|
||||||
|
TestCase.assertEqual(people.filtered('parents.name CONTAINS[c] "chris"').length, 1);
|
||||||
|
TestCase.assertEqual(people.filtered('parents.name.@size == 2').length, 1);
|
||||||
|
TestCase.assertEqual(people.filtered('25 IN parents.age').length, 1);
|
||||||
|
},
|
||||||
|
|
||||||
testMethod: function() {
|
testMethod: function() {
|
||||||
var realm = new Realm({schema: [schemas.PersonObject]});
|
var realm = new Realm({schema: [schemas.PersonObject]});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue