From 98b75a1317d5274cd2652c6a6e01a687a5e4e9fe Mon Sep 17 00:00:00 2001 From: Christian Melchior Date: Tue, 27 Nov 2018 14:46:30 +0100 Subject: [PATCH] Add better error message for wrong Realm types (#2151) --- CHANGELOG.md | 3 +-- lib/extensions.js | 9 +++++++++ lib/index.d.ts | 1 - src/js_realm.hpp | 17 +++++++++++++++++ tests/js/realm-tests.js | 27 +++++++++++++++++++++++++++ 5 files changed, 54 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24754ff9..89eea951 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,10 @@ x.x.x Release notes (yyyy-MM-dd) ============================================================= ### Enhancements -* None. +* Using methods only available for Query-based Realms now throw a better error message if called on the wrong Realm file type. ### Fixed * `_initializeSyncManager` missing when debugging React Native. Resulted in messages like `realmConstructor.Sync._initializeSyncManager is not a function` ([#2128](https://github.com/realm/realm-js/issues/2128), since v2.20.0) -* None. ### Compatibility * Realm Object Server: 3.11.0 or later. diff --git a/lib/extensions.js b/lib/extensions.js index 5dde31ee..9812e0fb 100644 --- a/lib/extensions.js +++ b/lib/extensions.js @@ -389,6 +389,9 @@ module.exports = function(realmConstructor) { // Add instance methods to the Realm object that are only applied if Sync is Object.defineProperties(realmConstructor.prototype, getOwnPropertyDescriptors({ permissions(arg) { + if (!this._isPartialRealm) { + throw new Error("Wrong Realm type. 'permissions()' is only available for Query-based Realms."); + } // If no argument is provided, return the Realm-level permissions if (arg === undefined) { return this.objects('__Realm').filtered(`id = 0`)[0]; @@ -404,6 +407,9 @@ module.exports = function(realmConstructor) { }, subscriptions(name) { + if (!this._isPartialRealm) { + throw new Error("Wrong Realm type. 'subscriptions()' is only available for Query-based Realms."); + } let all_subscriptions = this.objects('__ResultSets'); if (name) { if (typeof(name) !== 'string') { @@ -429,6 +435,9 @@ module.exports = function(realmConstructor) { }, unsubscribe(name) { + if (!this._isPartialRealm) { + throw new Error("Wrong Realm type. 'unsubscribe()' is only available for Query-based Realms."); + } if (typeof(name) === 'string') { if (name !== '') { let named_subscriptions = this.objects('__ResultSets').filtered(`name == '${name}'`); diff --git a/lib/index.d.ts b/lib/index.d.ts index e2b7743e..6cb10b7e 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -821,7 +821,6 @@ declare class Realm { */ writeCopyTo(path: string, encryptionKey?: ArrayBuffer | ArrayBufferView): void; - privileges() : Realm.Permissions.Realm; privileges() : Realm.Permissions.RealmPrivileges; privileges(objectType: string | Realm.ObjectSchema | Function) : Realm.Permissions.ClassPrivileges; privileges(obj: Realm.Object) : Realm.Permissions.ObjectPrivileges; diff --git a/src/js_realm.hpp b/src/js_realm.hpp index 058574d9..d8c5aa21 100644 --- a/src/js_realm.hpp +++ b/src/js_realm.hpp @@ -253,6 +253,7 @@ public: static void get_is_closed(ContextType, ObjectType, ReturnValue &); #if REALM_ENABLE_SYNC static void get_sync_session(ContextType, ObjectType, ReturnValue &); + static void get_is_partial_realm(ContextType, ObjectType, ReturnValue &); #endif // static methods @@ -318,6 +319,7 @@ public: {"isClosed", {wrap, nullptr}}, #if REALM_ENABLE_SYNC {"syncSession", {wrap, nullptr}}, + {"_isPartialRealm", {wrap, nullptr}}, #endif }; @@ -818,6 +820,13 @@ void RealmClass::get_sync_session(ContextType ctx, ObjectType object, ReturnV } } + +template +void RealmClass::get_is_partial_realm(ContextType ctx, ObjectType object, ReturnValue &return_value) { + auto realm = *get_internal>(object); + auto config = realm->config(); + return_value.set(config.sync_config && config.sync_config->is_partial); +} #endif #if REALM_ENABLE_SYNC @@ -1219,12 +1228,17 @@ template void RealmClass::privileges(ContextType ctx, ObjectType this_object, Arguments &args, ReturnValue &return_value) { args.validate_maximum(1); +#if REALM_ENABLE_SYNC using Privilege = realm::ComputedPrivileges; auto has_privilege = [](Privilege actual, Privilege expected) { return (static_cast(actual) & static_cast(expected)) == static_cast(expected); }; SharedRealm realm = *get_internal>(this_object); + auto config = realm->config(); + if (!(config.sync_config && config.sync_config->is_partial)) { + throw std::runtime_error("Wrong Realm type. 'privileges()' is only available for Query-based Realms."); + } if (args.count == 0) { auto p = realm->get_privileges(); ObjectType object = Object::create_empty(ctx); @@ -1261,6 +1275,9 @@ void RealmClass::privileges(ContextType ctx, ObjectType this_object, Argument Object::set_property(ctx, object, "subscribe", Value::from_boolean(ctx, has_privilege(p, Privilege::Query))); Object::set_property(ctx, object, "setPermissions", Value::from_boolean(ctx, has_privilege(p, Privilege::SetPermissions))); return_value.set(object); +#else + throw std::logic_error("Realm.privileges() can only be used with Query-based Realms."); +#endif } } // js diff --git a/tests/js/realm-tests.js b/tests/js/realm-tests.js index 0852098d..4376b977 100644 --- a/tests/js/realm-tests.js +++ b/tests/js/realm-tests.js @@ -1465,4 +1465,31 @@ module.exports = { realm.close(); }, + + testQueryBasedOnlyMethods: function() { + if (!global.enableSyncTests) { + return; + } + + const realm = new Realm({sync: true}); + TestCase.assertThrowsContaining(() => { + realm.privileges(); + }, 'Wrong Realm type'); + TestCase.assertThrowsContaining(() => { + realm.privileges('__Role'); + }, 'Wrong Realm type'); + TestCase.assertThrowsContaining(() => { + realm.permissions(); + }, 'Wrong Realm type'); + TestCase.assertThrowsContaining(() => { + realm.permissions('__Class'); + }, 'Wrong Realm type'); + TestCase.assertThrowsContaining(() => { + realm.subscriptions(); + }, 'Wrong Realm type'); + TestCase.assertThrowsContaining(() => { + realm.unsubscribe('foo'); + }, 'Wrong Realm type'); + } , + };