From 6f433246360066e53b30f4cbc9875de32a28a4f1 Mon Sep 17 00:00:00 2001 From: James Stone Date: Tue, 13 Feb 2018 16:17:27 -0800 Subject: [PATCH 1/6] Preliminary work for queries over named backlinks --- src/js_results.hpp | 21 ++++++++++++++++++++- tests/js/linkingobjects-tests.js | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/js_results.hpp b/src/js_results.hpp index f3694d08..9a7b380b 100644 --- a/src/js_results.hpp +++ b/src/js_results.hpp @@ -141,6 +141,23 @@ typename T::Object ResultsClass::create_instance(ContextType ctx, SharedRealm return create_object>(ctx, new realm::js::Results(realm, *table)); } +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); + auto link_property = target_object_schema->property_for_name(property.link_origin_property_name); + 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; + //std::cout << "mapping named backlink: " << property.name << " to: " << native_name << std::endl; + mapping.add_mapping(table, property.name, native_backlink_name); + } + } + } +} + template template typename T::Object ResultsClass::create_filtered(ContextType ctx, const U &collection, Arguments args) { @@ -153,11 +170,13 @@ typename T::Object ResultsClass::create_filtered(ContextType ctx, const U &co auto const &realm = collection.get_realm(); auto const &object_schema = collection.get_object_schema(); DescriptorOrdering ordering; + parser::KeypathMapping mapping; + alias_backlinks(mapping, realm); parser::ParserResult result = parser::parse(query_string); NativeAccessor accessor(ctx, realm, object_schema); query_builder::ArgumentConverter> 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); return create_instance(ctx, collection.filter(std::move(query)).apply_ordering(std::move(ordering))); diff --git a/tests/js/linkingobjects-tests.js b/tests/js/linkingobjects-tests.js index fb07a0ff..943a6aac 100644 --- a/tests/js/linkingobjects-tests.js +++ b/tests/js/linkingobjects-tests.js @@ -124,4 +124,36 @@ module.exports = { TestCase.assertEqual(oliviersParents.length, 0); }); }, + + testFilterByLinkingObject: function() { + const Realm = require('realm') + + const ProductSchema = { + name: 'Product', + primaryKey:'productId', + properties: { + productId:'int', + product:'string', + combinations: {type: 'linkingObjects', objectType: 'Combination', property: 'products'} + } + } + + const CombinationSchema = { + name: 'Combination', + properties: { + onSale: {type: 'string'}, + products: {type: 'list', objectType:'Product'} + } + } + + Realm.open({ + schema: [ProductSchema, CombinationSchema] + }).then(function (realm) { + let queryFilter1 = 'onSale = "yes" AND products.productId = 1' + let data1 = realm.objects('Combination').filtered(queryFilter1) + + let queryFilter2 = 'combinations.onSale = "yes" AND productId = 1' + let data2 = realm.objects('Product').filtered(queryFilter2) + }) + }, }; From bd5c237b0f5bbaab1496171919bce1d6c17bf46b Mon Sep 17 00:00:00 2001 From: James Stone Date: Mon, 19 Feb 2018 16:14:10 -0800 Subject: [PATCH 2/6] Named backlink queries working with core 5.3.0 --- src/js_results.hpp | 8 ++--- tests/js/linkingobjects-tests.js | 52 ++++++++++++-------------------- 2 files changed, 23 insertions(+), 37 deletions(-) diff --git a/src/js_results.hpp b/src/js_results.hpp index 9a7b380b..f825692f 100644 --- a/src/js_results.hpp +++ b/src/js_results.hpp @@ -141,18 +141,16 @@ typename T::Object ResultsClass::create_instance(ContextType ctx, SharedRealm return create_object>(ctx, new realm::js::Results(realm, *table)); } -void alias_backlinks(parser::KeypathMapping &mapping, const realm::SharedRealm &realm) +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); - auto link_property = target_object_schema->property_for_name(property.link_origin_property_name); 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; - //std::cout << "mapping named backlink: " << property.name << " to: " << native_name << std::endl; - mapping.add_mapping(table, property.name, native_backlink_name); + mapping.add_mapping(table, property.name, native_name); } } } @@ -170,7 +168,7 @@ typename T::Object ResultsClass::create_filtered(ContextType ctx, const U &co auto const &realm = collection.get_realm(); auto const &object_schema = collection.get_object_schema(); DescriptorOrdering ordering; - parser::KeypathMapping mapping; + parser::KeyPathMapping mapping; alias_backlinks(mapping, realm); parser::ParserResult result = parser::parse(query_string); diff --git a/tests/js/linkingobjects-tests.js b/tests/js/linkingobjects-tests.js index 943a6aac..d5aff0e9 100644 --- a/tests/js/linkingobjects-tests.js +++ b/tests/js/linkingobjects-tests.js @@ -83,6 +83,26 @@ module.exports = { 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() { var realm = new Realm({schema: [schemas.PersonObject]}); @@ -124,36 +144,4 @@ module.exports = { TestCase.assertEqual(oliviersParents.length, 0); }); }, - - testFilterByLinkingObject: function() { - const Realm = require('realm') - - const ProductSchema = { - name: 'Product', - primaryKey:'productId', - properties: { - productId:'int', - product:'string', - combinations: {type: 'linkingObjects', objectType: 'Combination', property: 'products'} - } - } - - const CombinationSchema = { - name: 'Combination', - properties: { - onSale: {type: 'string'}, - products: {type: 'list', objectType:'Product'} - } - } - - Realm.open({ - schema: [ProductSchema, CombinationSchema] - }).then(function (realm) { - let queryFilter1 = 'onSale = "yes" AND products.productId = 1' - let data1 = realm.objects('Combination').filtered(queryFilter1) - - let queryFilter2 = 'combinations.onSale = "yes" AND productId = 1' - let data2 = realm.objects('Product').filtered(queryFilter2) - }) - }, }; From 1ceccd30fd07c578f0fb0e7135fc052d8a18bff9 Mon Sep 17 00:00:00 2001 From: Kenneth Geisshirt Date: Tue, 27 Feb 2018 11:40:36 +0100 Subject: [PATCH 3/6] Updating changelog. --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a23d782e..1ecd6d68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,13 +7,15 @@ ### Enhancements * [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. - 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`. - 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. - 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 class `Realm.Sync.Subscription` to support partial synced Realms. From fd69bf7fc43cdfe7ca930078ae4bacc10c7c9e06 Mon Sep 17 00:00:00 2001 From: Kenneth Geisshirt Date: Tue, 27 Feb 2018 13:24:39 +0100 Subject: [PATCH 4/6] Don't use latest NaN version. Use old version of node for tests. --- package.json | 2 +- scripts/test.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index b08bb4a2..ba7d6c9b 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,7 @@ "decompress": "^4.2.0", "fs-extra": "^4.0.2", "ini": "^1.3.4", - "nan": "^2.3.3", + "nan": "2.8.0", "node-fetch": "^1.6.3", "node-pre-gyp": "^0.6.36", "progress": "^2.0.0", diff --git a/scripts/test.sh b/scripts/test.sh index 16832ea2..f4bd0784 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -211,7 +211,7 @@ if [[ -z "$(command -v nvm)" ]]; then set -e fi if [[ "$(command -v nvm)" ]]; then - nvm install 7.10.0 + nvm install 6.11.3 fi # Remove cached packages From c90a5a49032a62adbe03532c15243110fad4b990 Mon Sep 17 00:00:00 2001 From: Kenneth Geisshirt Date: Tue, 27 Feb 2018 18:20:54 +0100 Subject: [PATCH 5/6] Update object store --- src/object-store | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/object-store b/src/object-store index d5fe9a62..703c391c 160000 --- a/src/object-store +++ b/src/object-store @@ -1 +1 @@ -Subproject commit d5fe9a626c0adc0345d128201e0df8bb4004725d +Subproject commit 703c391c64f73c812358940993942338f1bc706d From 187c4354f18ac0d2412175607df8a888a3a50c03 Mon Sep 17 00:00:00 2001 From: James Stone Date: Mon, 12 Mar 2018 10:48:57 -0700 Subject: [PATCH 6/6] Inline method in hpp to remove duplicate definitions --- src/js_results.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js_results.hpp b/src/js_results.hpp index 350cd836..f7d033e3 100644 --- a/src/js_results.hpp +++ b/src/js_results.hpp @@ -152,7 +152,7 @@ typename T::Object ResultsClass::create_instance(ContextType ctx, SharedRealm return create_object>(ctx, new realm::js::Results(realm, *table)); } -void alias_backlinks(parser::KeyPathMapping &mapping, const realm::SharedRealm &realm) +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) {