Merge pull request #1660 from realm/jas/backlink-queries

Preliminary work for queries over named backlinks
This commit is contained in:
James Stone 2018-03-12 15:47:30 -07:00 committed by GitHub
commit 8dc5149770
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 41 additions and 2 deletions

View File

@ -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.

View File

@ -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)));

View File

@ -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]});