From ab1965c27eeb61d89f69687085f10f5a6372e1d7 Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Mon, 26 Oct 2015 16:03:32 -0700 Subject: [PATCH 1/6] no more notification token --- src/RJSRealm.hpp | 1 - src/RJSRealm.mm | 118 +++++++++++++++++++++-------------------------- src/RealmRPC.cpp | 6 --- 3 files changed, 52 insertions(+), 73 deletions(-) diff --git a/src/RJSRealm.hpp b/src/RJSRealm.hpp index dfad0d58..0f15bac2 100644 --- a/src/RJSRealm.hpp +++ b/src/RJSRealm.hpp @@ -26,7 +26,6 @@ namespace realm { JSClassRef RJSRealmClass(); JSClassRef RJSRealmConstructorClass(); -JSClassRef RJSNotificationClass(); std::string RJSDefaultPath(); void RJSSetDefaultPath(std::string path); diff --git a/src/RJSRealm.mm b/src/RJSRealm.mm index 8ec0b84c..5b6560c1 100644 --- a/src/RJSRealm.mm +++ b/src/RJSRealm.mm @@ -32,43 +32,25 @@ using namespace realm; class RJSRealmDelegate : public RealmDelegate { public: - typedef std::shared_ptr> NotificationFunction; - void add_notification(NotificationFunction ¬ification) { m_notifications.insert(notification); } - void remove_notification(NotificationFunction notification) { m_notifications.erase(notification); } - void remove_all_notifications() { m_notifications.clear(); } - std::set m_notifications; - virtual void changes_available() { - for (NotificationFunction notification : m_notifications) { - (*notification)("RefreshRequiredNotification"); - } + notify("RefreshRequiredNotification"); } - - virtual void did_change(std::vector const& observers, - std::vector const& invalidated) { - for (NotificationFunction notification : m_notifications) { - (*notification)("DidChangeNotification"); - } + virtual void did_change(std::vector const& observers, std::vector const& invalidated) { + notify("DidChangeNotification"); } - virtual std::vector get_observed_rows() { return std::vector(); } - virtual void will_change(std::vector const& observers, - std::vector const& invalidated) { + std::vector const& invalidated) {} - } - - JSGlobalContextRef m_context; - std::map m_defaults; - std::map m_prototypes; - - RJSRealmDelegate(JSGlobalContextRef ctx) : m_context(ctx) { + RJSRealmDelegate(WeakRealm realm, JSGlobalContextRef ctx) : m_context(ctx), m_realm(realm) { JSGlobalContextRetain(m_context); } ~RJSRealmDelegate() { + remove_all_notifications(); + for (auto prototype : m_prototypes) { JSValueUnprotect(m_context, prototype.second); } @@ -79,6 +61,48 @@ public: } JSGlobalContextRelease(m_context); } + + void add_notification(JSObjectRef notification) { + JSValueProtect(m_context, notification); + m_notifications.insert(notification); + } + void remove_notification(JSObjectRef notification) { + JSValueUnprotect(m_context, notification); + m_notifications.erase(notification); + } + void remove_all_notifications() { + for (auto notification : m_notifications) { + JSValueUnprotect(m_context, notification); + } + m_notifications.clear(); + } + + std::map m_defaults; + std::map m_prototypes; + + private: + std::set m_notifications; + JSGlobalContextRef m_context; + WeakRealm m_realm; + + void notify(const char *notification_name) { + for (auto callback : m_notifications) { + JSValueRef arguments[2]; + SharedRealm realm = m_realm.lock(); + if (!realm) { + throw std::runtime_error("Realm no longer exists"); + } + JSObjectRef realm_object = RJSWrapObject(m_context, RJSRealmClass(), new SharedRealm(realm)); + arguments[0] = realm_object; + arguments[1] = RJSValueForString(m_context, notification_name); + + JSValueRef ex = NULL; + JSObjectCallAsFunction(m_context, callback, realm_object, 2, arguments, &ex); + if (ex) { + throw RJSException(m_context, ex); + } + } + } }; std::map &RJSDefaults(Realm *realm) { @@ -189,7 +213,7 @@ JSObjectRef RealmConstructor(JSContextRef ctx, JSObjectRef constructor, size_t a } SharedRealm realm = Realm::get_shared_realm(config); if (!realm->m_delegate) { - realm->m_delegate = std::make_unique(JSContextGetGlobalContext(ctx)); + realm->m_delegate = std::make_unique(realm, JSContextGetGlobalContext(ctx)); } RJSDefaults(realm.get()) = defaults; RJSPrototypes(realm.get()) = prototypes; @@ -399,48 +423,14 @@ JSValueRef RealmWrite(JSContextRef ctx, JSObjectRef function, JSObjectRef thisOb return NULL; } -namespace realm { - struct Notification { - JSGlobalContextRef ctx; - JSObjectRef realmObject; - JSObjectRef callbackObject; - RJSRealmDelegate::NotificationFunction func; - - Notification(JSGlobalContextRef c, JSObjectRef r, JSObjectRef cb, RJSRealmDelegate::NotificationFunction f) : ctx(c), realmObject(r), callbackObject(cb), func(f) { - JSGlobalContextRetain(ctx); - JSValueProtect(ctx, realmObject); - JSValueProtect(ctx, callbackObject); - } - - ~Notification() { - JSValueUnprotect(ctx, callbackObject); - JSValueUnprotect(ctx, realmObject); - JSGlobalContextRelease(ctx); - } - }; -} - JSValueRef RealmAddNotification(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) { try { RJSValidateArgumentCount(argumentCount, 1); JSObjectRef callback = RJSValidatedValueToFunction(ctx, arguments[0]); SharedRealm realm = *RJSGetInternal(thisObject); - JSGlobalContextRef gCtx = JSContextGetGlobalContext(ctx); - - RJSRealmDelegate::NotificationFunction func = std::make_shared>([=](std::string notification_name) { - JSValueRef arguments[2]; - arguments[0] = thisObject; - arguments[1] = RJSValueForString(gCtx, notification_name); - JSValueRef ex = NULL; - JSObjectCallAsFunction(gCtx, callback, thisObject, 2, arguments, &ex); - if (ex) { - throw RJSException(gCtx, ex); - } - }); - - static_cast(realm->m_delegate.get())->add_notification(func); - return RJSWrapObject(ctx, RJSNotificationClass(), new Notification { gCtx, thisObject, callback, func }); + static_cast(realm->m_delegate.get())->add_notification(callback); + return NULL; } catch (std::exception &exp) { if (jsException) { @@ -482,8 +472,4 @@ JSClassRef RJSRealmClass() { return s_realmClass; } -JSClassRef RJSNotificationClass() { - static JSClassRef s_notificationClass = RJSCreateWrapperClass("Notification", NULL, NULL, NULL); - return s_notificationClass; -} diff --git a/src/RealmRPC.cpp b/src/RealmRPC.cpp index 6152a185..32392e24 100644 --- a/src/RealmRPC.cpp +++ b/src/RealmRPC.cpp @@ -254,12 +254,6 @@ json RPCServer::serialize_json_value(JSValueRef value) { {"schema", serialize_object_schema(results->object_schema)} }; } - else if (JSValueIsObjectOfClass(m_context, value, RJSNotificationClass())) { - return { - {"type", RealmObjectTypesNotification}, - {"id", store_object(js_object)}, - }; - } else if (RJSIsValueArray(m_context, value)) { size_t length = RJSValidatedListLength(m_context, js_object); std::vector array; From 246ccc7bde82dd2929da42c64d675c284be89be2 Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Mon, 26 Oct 2015 16:15:46 -0700 Subject: [PATCH 2/6] add other notification methods --- src/RJSRealm.mm | 40 ++++++++++++++++++++++++++++++++++++++-- tests/RealmTests.js | 22 +++++++++++++++++++++- 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/src/RJSRealm.mm b/src/RJSRealm.mm index 5b6560c1..0ac77cd8 100644 --- a/src/RJSRealm.mm +++ b/src/RJSRealm.mm @@ -423,7 +423,7 @@ JSValueRef RealmWrite(JSContextRef ctx, JSObjectRef function, JSObjectRef thisOb return NULL; } -JSValueRef RealmAddNotification(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) { +JSValueRef RealmAddListener(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) { try { RJSValidateArgumentCount(argumentCount, 1); @@ -440,6 +440,40 @@ JSValueRef RealmAddNotification(JSContextRef ctx, JSObjectRef function, JSObject } } +JSValueRef RealmRemoveListener(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) { + try { + RJSValidateArgumentCount(argumentCount, 1); + + JSObjectRef callback = RJSValidatedValueToFunction(ctx, arguments[0]); + SharedRealm realm = *RJSGetInternal(thisObject); + static_cast(realm->m_delegate.get())->remove_notification(callback); + return NULL; + } + catch (std::exception &exp) { + if (jsException) { + *jsException = RJSMakeError(ctx, exp); + } + return NULL; + } +} + +JSValueRef RealmRemoveAllListeners(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) { + try { + RJSValidateArgumentCount(argumentCount, 0); + SharedRealm realm = *RJSGetInternal(thisObject); + static_cast(realm->m_delegate.get())->remove_all_notifications(); + return NULL; + } + catch (std::exception &exp) { + if (jsException) { + *jsException = RJSMakeError(ctx, exp); + } + return NULL; + } +} + + + JSValueRef RealmClose(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) { try { RJSValidateArgumentCount(argumentCount, 0); @@ -462,7 +496,9 @@ static const JSStaticFunction RJSRealmFuncs[] = { {"delete", RealmDelete, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, {"deleteAll", RealmDeleteAll, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, {"write", RealmWrite, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, - {"addNotification", RealmAddNotification, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, + {"addListener", RealmAddListener, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, + {"removeListener", RealmRemoveListener, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, + {"removeAllListeners", RealmRemoveAllListeners, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, {"close", RealmClose, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, {NULL, NULL}, }; diff --git a/tests/RealmTests.js b/tests/RealmTests.js index b75360f2..258366c8 100644 --- a/tests/RealmTests.js +++ b/tests/RealmTests.js @@ -282,7 +282,7 @@ module.exports = BaseTest.extend({ var notificationCount = 0; var notificationName; - var notification = realm.addNotification(function(realm, name) { + realm.addListener(function(realm, name) { notificationCount++; notificationName = name; }); @@ -291,5 +291,25 @@ module.exports = BaseTest.extend({ realm.write(function() {}); TestCase.assertEqual(notificationCount, 1); TestCase.assertEqual(notificationName, 'DidChangeNotification'); + + var secondNotificationCount = 0; + function secondNotification(realm, name) { + secondNotificationCount++; + }; + realm.addListener(secondNotification) + + realm.write(function() {}); + TestCase.assertEqual(notificationCount, 2); + TestCase.assertEqual(secondNotificationCount, 1); + + realm.removeListener(secondNotification); + realm.write(function() {}); + TestCase.assertEqual(notificationCount, 3); + TestCase.assertEqual(secondNotificationCount, 1); + + realm.removeAllListeners(); + realm.write(function() {}); + TestCase.assertEqual(notificationCount, 3); + TestCase.assertEqual(secondNotificationCount, 1); }, }); From 6f57500972a7cdf09afb5743afb3d05a1af19db1 Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Mon, 26 Oct 2015 16:19:12 -0700 Subject: [PATCH 3/6] change notification name to change --- src/RJSRealm.mm | 4 ++-- tests/RealmTests.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/RJSRealm.mm b/src/RJSRealm.mm index 0ac77cd8..b999961b 100644 --- a/src/RJSRealm.mm +++ b/src/RJSRealm.mm @@ -33,10 +33,10 @@ using namespace realm; class RJSRealmDelegate : public RealmDelegate { public: virtual void changes_available() { - notify("RefreshRequiredNotification"); + assert(0); } virtual void did_change(std::vector const& observers, std::vector const& invalidated) { - notify("DidChangeNotification"); + notify("change"); } virtual std::vector get_observed_rows() { return std::vector(); diff --git a/tests/RealmTests.js b/tests/RealmTests.js index 258366c8..74f04135 100644 --- a/tests/RealmTests.js +++ b/tests/RealmTests.js @@ -290,7 +290,7 @@ module.exports = BaseTest.extend({ TestCase.assertEqual(notificationCount, 0); realm.write(function() {}); TestCase.assertEqual(notificationCount, 1); - TestCase.assertEqual(notificationName, 'DidChangeNotification'); + TestCase.assertEqual(notificationName, 'change'); var secondNotificationCount = 0; function secondNotification(realm, name) { From bb68e45250fdd01b57e2140f6942e2cf0f0ea8b6 Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Mon, 26 Oct 2015 16:49:46 -0700 Subject: [PATCH 4/6] support notifications in chrome --- lib/constants.js | 1 - lib/notifications.js | 21 --------------------- lib/realm.js | 30 +++++++++++++++++------------- 3 files changed, 17 insertions(+), 35 deletions(-) delete mode 100644 lib/notifications.js diff --git a/lib/constants.js b/lib/constants.js index 813db4aa..37ec3dcd 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -15,7 +15,6 @@ let propTypes = {}; [ 'FUNCTION', - 'NOTIFICATION', 'REALM', 'RESULTS', ].forEach(function(type) { diff --git a/lib/notifications.js b/lib/notifications.js deleted file mode 100644 index e6da21bd..00000000 --- a/lib/notifications.js +++ /dev/null @@ -1,21 +0,0 @@ -'use strict'; - -const constants = require('./constants'); - -const {keys} = constants; - -module.exports = { - create, -}; - -class Notification {} - -function create(realmId, info) { - let notification = new Notification(); - - notification[keys.realm] = realmId; - notification[keys.id] = info.id; - notification[keys.type] = info.type; - - return notification; -} diff --git a/lib/realm.js b/lib/realm.js index e951d316..6a22be88 100644 --- a/lib/realm.js +++ b/lib/realm.js @@ -3,21 +3,18 @@ const constants = require('./constants'); const lists = require('./lists'); const objects = require('./objects'); -const notifications = require('./notifications'); const results = require('./results'); const rpc = require('./rpc'); const util = require('./util'); const {keys, propTypes, objectTypes} = constants; const notificationsKey = Symbol(); -const notificationCallbackKey = Symbol(); const resultsKey = Symbol(); // TODO: DATA rpc.registerTypeConverter(propTypes.DATE, (_, info) => new Date(info.value)); rpc.registerTypeConverter(propTypes.LIST, lists.create); rpc.registerTypeConverter(propTypes.OBJECT, objects.create); -rpc.registerTypeConverter(objectTypes.NOTIFICATION, notifications.create); rpc.registerTypeConverter(objectTypes.RESULTS, results.create); class Realm { @@ -53,18 +50,26 @@ class Realm { }); } - addNotification(callback) { + addListener(callback) { if (typeof callback != 'function') { - throw new Error('Realm.addNotification must be passed a function!'); + throw new Error('Realm.addListener must be passed a function!'); } + this[notificationsKey].push(callback); + } - let method = util.createMethod(objectTypes.REALM, 'addNotification'); - let notification = method.apply(this, arguments); - notification[notificationCallbackKey] = callback; + removeListener(callback) { + if (typeof callback != 'function') { + throw new Error('Realm.addListener must be passed a function!'); + } + var index = 0; + while((index = this[notificationsKey].indexOf(callback, index)) != -1) { + this[notificationsKey].splice(index, 1); + }; + } - this[notificationsKey].push(notification); - return notification; + removeAllListeners() { + this[notificationsKey] = []; } objects() { @@ -100,9 +105,8 @@ class Realm { results[keys.resize](); } - for (let notification of this[notificationsKey]) { - let callback = notification[notificationCallbackKey]; - callback(this, 'DidChangeNotification'); + for (let callback of this[notificationsKey]) { + callback(this, 'change'); } } } From 6f41c3cf68f07c7564c823ddb035e0001a72d8e7 Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Mon, 26 Oct 2015 19:18:24 -0700 Subject: [PATCH 5/6] take notification name --- lib/realm.js | 15 ++++++++++++--- src/RJSRealm.mm | 24 +++++++++++++++++++----- tests/RealmTests.js | 6 +++--- 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/lib/realm.js b/lib/realm.js index 6a22be88..7b90e35d 100644 --- a/lib/realm.js +++ b/lib/realm.js @@ -50,25 +50,34 @@ class Realm { }); } - addListener(callback) { + addListener(name, callback) { if (typeof callback != 'function') { throw new Error('Realm.addListener must be passed a function!'); } + if (name != 'change') { + throw new Error("Only 'change' notification is supported."); + } this[notificationsKey].push(callback); } - removeListener(callback) { + removeListener(name, callback) { if (typeof callback != 'function') { throw new Error('Realm.addListener must be passed a function!'); } + if (name != 'change') { + throw new Error("Only 'change' notification is supported."); + } var index = 0; while((index = this[notificationsKey].indexOf(callback, index)) != -1) { this[notificationsKey].splice(index, 1); }; } - removeAllListeners() { + removeAllListeners(name) { + if (name != undefined && name != 'change') { + throw new Error("Only 'change' notification is supported."); + } this[notificationsKey] = []; } diff --git a/src/RJSRealm.mm b/src/RJSRealm.mm index b999961b..f609abec 100644 --- a/src/RJSRealm.mm +++ b/src/RJSRealm.mm @@ -423,11 +423,20 @@ JSValueRef RealmWrite(JSContextRef ctx, JSObjectRef function, JSObjectRef thisOb return NULL; } +std::string RJSValidatedNotificationName(JSContextRef ctx, JSValueRef value) { + std::string name = RJSValidatedStringForValue(ctx, value); + if (name != "change") { + throw std::runtime_error("Only the 'change' notification name is supported."); + } + return name; +} + JSValueRef RealmAddListener(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) { try { - RJSValidateArgumentCount(argumentCount, 1); + RJSValidateArgumentCount(argumentCount, 2); + __unused std::string name = RJSValidatedNotificationName(ctx, arguments[0]); + JSObjectRef callback = RJSValidatedValueToFunction(ctx, arguments[1]); - JSObjectRef callback = RJSValidatedValueToFunction(ctx, arguments[0]); SharedRealm realm = *RJSGetInternal(thisObject); static_cast(realm->m_delegate.get())->add_notification(callback); return NULL; @@ -442,9 +451,10 @@ JSValueRef RealmAddListener(JSContextRef ctx, JSObjectRef function, JSObjectRef JSValueRef RealmRemoveListener(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) { try { - RJSValidateArgumentCount(argumentCount, 1); + RJSValidateArgumentCount(argumentCount, 2); + __unused std::string name = RJSValidatedNotificationName(ctx, arguments[0]); + JSObjectRef callback = RJSValidatedValueToFunction(ctx, arguments[1]); - JSObjectRef callback = RJSValidatedValueToFunction(ctx, arguments[0]); SharedRealm realm = *RJSGetInternal(thisObject); static_cast(realm->m_delegate.get())->remove_notification(callback); return NULL; @@ -459,7 +469,11 @@ JSValueRef RealmRemoveListener(JSContextRef ctx, JSObjectRef function, JSObjectR JSValueRef RealmRemoveAllListeners(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) { try { - RJSValidateArgumentCount(argumentCount, 0); + RJSValidateArgumentRange(argumentCount, 0, 1); + if (argumentCount) { + RJSValidatedNotificationName(ctx, arguments[0]); + } + SharedRealm realm = *RJSGetInternal(thisObject); static_cast(realm->m_delegate.get())->remove_all_notifications(); return NULL; diff --git a/tests/RealmTests.js b/tests/RealmTests.js index 74f04135..84f21971 100644 --- a/tests/RealmTests.js +++ b/tests/RealmTests.js @@ -282,7 +282,7 @@ module.exports = BaseTest.extend({ var notificationCount = 0; var notificationName; - realm.addListener(function(realm, name) { + realm.addListener('change', function(realm, name) { notificationCount++; notificationName = name; }); @@ -296,13 +296,13 @@ module.exports = BaseTest.extend({ function secondNotification(realm, name) { secondNotificationCount++; }; - realm.addListener(secondNotification) + realm.addListener('change', secondNotification) realm.write(function() {}); TestCase.assertEqual(notificationCount, 2); TestCase.assertEqual(secondNotificationCount, 1); - realm.removeListener(secondNotification); + realm.removeListener('change', secondNotification); realm.write(function() {}); TestCase.assertEqual(notificationCount, 3); TestCase.assertEqual(secondNotificationCount, 1); From a1c4cd570222db73a0ae830822da5475bc15c893 Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Tue, 27 Oct 2015 07:48:11 -0700 Subject: [PATCH 6/6] pr fixes --- lib/realm.js | 14 +++++++------- src/RJSRealm.mm | 22 +++++++++------------- tests/RealmTests.js | 12 ++++++++++++ 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/lib/realm.js b/lib/realm.js index 7b90e35d..2e007cc5 100644 --- a/lib/realm.js +++ b/lib/realm.js @@ -8,7 +8,7 @@ const rpc = require('./rpc'); const util = require('./util'); const {keys, propTypes, objectTypes} = constants; -const notificationsKey = Symbol(); +const listenersKey = Symbol(); const resultsKey = Symbol(); // TODO: DATA @@ -39,7 +39,7 @@ class Realm { this[keys.id] = realmId; this[keys.realm] = realmId; this[keys.type] = objectTypes.REALM; - this[notificationsKey] = []; + this[listenersKey] = []; this[resultsKey] = []; [ @@ -57,7 +57,7 @@ class Realm { if (name != 'change') { throw new Error("Only 'change' notification is supported."); } - this[notificationsKey].push(callback); + this[listenersKey].push(callback); } @@ -69,8 +69,8 @@ class Realm { throw new Error("Only 'change' notification is supported."); } var index = 0; - while((index = this[notificationsKey].indexOf(callback, index)) != -1) { - this[notificationsKey].splice(index, 1); + while((index = this[listenersKey].indexOf(callback, index)) != -1) { + this[listenersKey].splice(index, 1); }; } @@ -78,7 +78,7 @@ class Realm { if (name != undefined && name != 'change') { throw new Error("Only 'change' notification is supported."); } - this[notificationsKey] = []; + this[listenersKey] = []; } objects() { @@ -114,7 +114,7 @@ class Realm { results[keys.resize](); } - for (let callback of this[notificationsKey]) { + for (let callback of this[listenersKey]) { callback(this, 'change'); } } diff --git a/src/RJSRealm.mm b/src/RJSRealm.mm index f609abec..3cfb5b57 100644 --- a/src/RJSRealm.mm +++ b/src/RJSRealm.mm @@ -86,16 +86,16 @@ public: WeakRealm m_realm; void notify(const char *notification_name) { - for (auto callback : m_notifications) { - JSValueRef arguments[2]; - SharedRealm realm = m_realm.lock(); - if (!realm) { - throw std::runtime_error("Realm no longer exists"); - } - JSObjectRef realm_object = RJSWrapObject(m_context, RJSRealmClass(), new SharedRealm(realm)); - arguments[0] = realm_object; - arguments[1] = RJSValueForString(m_context, notification_name); + JSValueRef arguments[2]; + SharedRealm realm = m_realm.lock(); + if (!realm) { + throw std::runtime_error("Realm no longer exists"); + } + JSObjectRef realm_object = RJSWrapObject(m_context, RJSRealmClass(), new SharedRealm(realm)); + arguments[0] = realm_object; + arguments[1] = RJSValueForString(m_context, notification_name); + for (auto callback : m_notifications) { JSValueRef ex = NULL; JSObjectCallAsFunction(m_context, callback, realm_object, 2, arguments, &ex); if (ex) { @@ -486,8 +486,6 @@ JSValueRef RealmRemoveAllListeners(JSContextRef ctx, JSObjectRef function, JSObj } } - - JSValueRef RealmClose(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) { try { RJSValidateArgumentCount(argumentCount, 0); @@ -521,5 +519,3 @@ JSClassRef RJSRealmClass() { static JSClassRef s_realmClass = RJSCreateWrapperClass("Realm", RealmGetProperty, NULL, RJSRealmFuncs); return s_realmClass; } - - diff --git a/tests/RealmTests.js b/tests/RealmTests.js index 84f21971..c1986474 100644 --- a/tests/RealmTests.js +++ b/tests/RealmTests.js @@ -311,5 +311,17 @@ module.exports = BaseTest.extend({ realm.write(function() {}); TestCase.assertEqual(notificationCount, 3); TestCase.assertEqual(secondNotificationCount, 1); + + TestCase.assertThrows(function() { + realm.addListener('invalid', function() {}); + }); + + realm.addListener('change', function() { + throw new Error('error'); + }); + + TestCase.assertThrows(function() { + realm.write(function() {}); + }); }, });