Merge pull request #100 from realm/al-notification
improve notification api
This commit is contained in:
commit
8e1eb661c5
|
@ -15,7 +15,6 @@ let propTypes = {};
|
||||||
|
|
||||||
[
|
[
|
||||||
'FUNCTION',
|
'FUNCTION',
|
||||||
'NOTIFICATION',
|
|
||||||
'REALM',
|
'REALM',
|
||||||
'RESULTS',
|
'RESULTS',
|
||||||
].forEach(function(type) {
|
].forEach(function(type) {
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
43
lib/realm.js
43
lib/realm.js
|
@ -3,21 +3,18 @@
|
||||||
const constants = require('./constants');
|
const constants = require('./constants');
|
||||||
const lists = require('./lists');
|
const lists = require('./lists');
|
||||||
const objects = require('./objects');
|
const objects = require('./objects');
|
||||||
const notifications = require('./notifications');
|
|
||||||
const results = require('./results');
|
const results = require('./results');
|
||||||
const rpc = require('./rpc');
|
const rpc = require('./rpc');
|
||||||
const util = require('./util');
|
const util = require('./util');
|
||||||
|
|
||||||
const {keys, propTypes, objectTypes} = constants;
|
const {keys, propTypes, objectTypes} = constants;
|
||||||
const notificationsKey = Symbol();
|
const listenersKey = Symbol();
|
||||||
const notificationCallbackKey = Symbol();
|
|
||||||
const resultsKey = Symbol();
|
const resultsKey = Symbol();
|
||||||
|
|
||||||
// TODO: DATA
|
// TODO: DATA
|
||||||
rpc.registerTypeConverter(propTypes.DATE, (_, info) => new Date(info.value));
|
rpc.registerTypeConverter(propTypes.DATE, (_, info) => new Date(info.value));
|
||||||
rpc.registerTypeConverter(propTypes.LIST, lists.create);
|
rpc.registerTypeConverter(propTypes.LIST, lists.create);
|
||||||
rpc.registerTypeConverter(propTypes.OBJECT, objects.create);
|
rpc.registerTypeConverter(propTypes.OBJECT, objects.create);
|
||||||
rpc.registerTypeConverter(objectTypes.NOTIFICATION, notifications.create);
|
|
||||||
rpc.registerTypeConverter(objectTypes.RESULTS, results.create);
|
rpc.registerTypeConverter(objectTypes.RESULTS, results.create);
|
||||||
|
|
||||||
class Realm {
|
class Realm {
|
||||||
|
@ -42,7 +39,7 @@ class Realm {
|
||||||
this[keys.id] = realmId;
|
this[keys.id] = realmId;
|
||||||
this[keys.realm] = realmId;
|
this[keys.realm] = realmId;
|
||||||
this[keys.type] = objectTypes.REALM;
|
this[keys.type] = objectTypes.REALM;
|
||||||
this[notificationsKey] = [];
|
this[listenersKey] = [];
|
||||||
this[resultsKey] = [];
|
this[resultsKey] = [];
|
||||||
|
|
||||||
[
|
[
|
||||||
|
@ -53,18 +50,35 @@ class Realm {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
addNotification(callback) {
|
addListener(name, callback) {
|
||||||
if (typeof callback != 'function') {
|
if (typeof callback != 'function') {
|
||||||
throw new Error('Realm.addNotification must be passed a function!');
|
throw new Error('Realm.addListener must be passed a function!');
|
||||||
}
|
}
|
||||||
|
if (name != 'change') {
|
||||||
|
throw new Error("Only 'change' notification is supported.");
|
||||||
|
}
|
||||||
|
this[listenersKey].push(callback);
|
||||||
|
}
|
||||||
|
|
||||||
let method = util.createMethod(objectTypes.REALM, 'addNotification');
|
|
||||||
let notification = method.apply(this, arguments);
|
|
||||||
|
|
||||||
notification[notificationCallbackKey] = 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[listenersKey].indexOf(callback, index)) != -1) {
|
||||||
|
this[listenersKey].splice(index, 1);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
this[notificationsKey].push(notification);
|
removeAllListeners(name) {
|
||||||
return notification;
|
if (name != undefined && name != 'change') {
|
||||||
|
throw new Error("Only 'change' notification is supported.");
|
||||||
|
}
|
||||||
|
this[listenersKey] = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
objects() {
|
objects() {
|
||||||
|
@ -100,9 +114,8 @@ class Realm {
|
||||||
results[keys.resize]();
|
results[keys.resize]();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let notification of this[notificationsKey]) {
|
for (let callback of this[listenersKey]) {
|
||||||
let callback = notification[notificationCallbackKey];
|
callback(this, 'change');
|
||||||
callback(this, 'DidChangeNotification');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@ namespace realm {
|
||||||
|
|
||||||
JSClassRef RJSRealmClass();
|
JSClassRef RJSRealmClass();
|
||||||
JSClassRef RJSRealmConstructorClass();
|
JSClassRef RJSRealmConstructorClass();
|
||||||
JSClassRef RJSNotificationClass();
|
|
||||||
|
|
||||||
std::string RJSDefaultPath();
|
std::string RJSDefaultPath();
|
||||||
void RJSSetDefaultPath(std::string path);
|
void RJSSetDefaultPath(std::string path);
|
||||||
|
|
168
src/RJSRealm.mm
168
src/RJSRealm.mm
|
@ -32,43 +32,25 @@ using namespace realm;
|
||||||
|
|
||||||
class RJSRealmDelegate : public RealmDelegate {
|
class RJSRealmDelegate : public RealmDelegate {
|
||||||
public:
|
public:
|
||||||
typedef std::shared_ptr<std::function<void(const std::string)>> 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<NotificationFunction> m_notifications;
|
|
||||||
|
|
||||||
virtual void changes_available() {
|
virtual void changes_available() {
|
||||||
for (NotificationFunction notification : m_notifications) {
|
assert(0);
|
||||||
(*notification)("RefreshRequiredNotification");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
virtual void did_change(std::vector<ObserverState> const& observers, std::vector<void*> const& invalidated) {
|
||||||
virtual void did_change(std::vector<ObserverState> const& observers,
|
notify("change");
|
||||||
std::vector<void*> const& invalidated) {
|
|
||||||
for (NotificationFunction notification : m_notifications) {
|
|
||||||
(*notification)("DidChangeNotification");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::vector<ObserverState> get_observed_rows() {
|
virtual std::vector<ObserverState> get_observed_rows() {
|
||||||
return std::vector<ObserverState>();
|
return std::vector<ObserverState>();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void will_change(std::vector<ObserverState> const& observers,
|
virtual void will_change(std::vector<ObserverState> const& observers,
|
||||||
std::vector<void*> const& invalidated) {
|
std::vector<void*> const& invalidated) {}
|
||||||
|
|
||||||
}
|
RJSRealmDelegate(WeakRealm realm, JSGlobalContextRef ctx) : m_context(ctx), m_realm(realm) {
|
||||||
|
|
||||||
JSGlobalContextRef m_context;
|
|
||||||
std::map<std::string, ObjectDefaults> m_defaults;
|
|
||||||
std::map<std::string, JSValueRef> m_prototypes;
|
|
||||||
|
|
||||||
RJSRealmDelegate(JSGlobalContextRef ctx) : m_context(ctx) {
|
|
||||||
JSGlobalContextRetain(m_context);
|
JSGlobalContextRetain(m_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
~RJSRealmDelegate() {
|
~RJSRealmDelegate() {
|
||||||
|
remove_all_notifications();
|
||||||
|
|
||||||
for (auto prototype : m_prototypes) {
|
for (auto prototype : m_prototypes) {
|
||||||
JSValueUnprotect(m_context, prototype.second);
|
JSValueUnprotect(m_context, prototype.second);
|
||||||
}
|
}
|
||||||
|
@ -79,6 +61,48 @@ public:
|
||||||
}
|
}
|
||||||
JSGlobalContextRelease(m_context);
|
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<std::string, ObjectDefaults> m_defaults;
|
||||||
|
std::map<std::string, JSValueRef> m_prototypes;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::set<JSObjectRef> m_notifications;
|
||||||
|
JSGlobalContextRef m_context;
|
||||||
|
WeakRealm m_realm;
|
||||||
|
|
||||||
|
void notify(const char *notification_name) {
|
||||||
|
JSValueRef arguments[2];
|
||||||
|
SharedRealm realm = m_realm.lock();
|
||||||
|
if (!realm) {
|
||||||
|
throw std::runtime_error("Realm no longer exists");
|
||||||
|
}
|
||||||
|
JSObjectRef realm_object = RJSWrapObject<SharedRealm *>(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) {
|
||||||
|
throw RJSException(m_context, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::map<std::string, ObjectDefaults> &RJSDefaults(Realm *realm) {
|
std::map<std::string, ObjectDefaults> &RJSDefaults(Realm *realm) {
|
||||||
|
@ -189,7 +213,7 @@ JSObjectRef RealmConstructor(JSContextRef ctx, JSObjectRef constructor, size_t a
|
||||||
}
|
}
|
||||||
SharedRealm realm = Realm::get_shared_realm(config);
|
SharedRealm realm = Realm::get_shared_realm(config);
|
||||||
if (!realm->m_delegate) {
|
if (!realm->m_delegate) {
|
||||||
realm->m_delegate = std::make_unique<RJSRealmDelegate>(JSContextGetGlobalContext(ctx));
|
realm->m_delegate = std::make_unique<RJSRealmDelegate>(realm, JSContextGetGlobalContext(ctx));
|
||||||
}
|
}
|
||||||
RJSDefaults(realm.get()) = defaults;
|
RJSDefaults(realm.get()) = defaults;
|
||||||
RJSPrototypes(realm.get()) = prototypes;
|
RJSPrototypes(realm.get()) = prototypes;
|
||||||
|
@ -399,48 +423,60 @@ JSValueRef RealmWrite(JSContextRef ctx, JSObjectRef function, JSObjectRef thisOb
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace realm {
|
std::string RJSValidatedNotificationName(JSContextRef ctx, JSValueRef value) {
|
||||||
struct Notification {
|
std::string name = RJSValidatedStringForValue(ctx, value);
|
||||||
JSGlobalContextRef ctx;
|
if (name != "change") {
|
||||||
JSObjectRef realmObject;
|
throw std::runtime_error("Only the 'change' notification name is supported.");
|
||||||
JSObjectRef callbackObject;
|
}
|
||||||
RJSRealmDelegate::NotificationFunction func;
|
return name;
|
||||||
|
|
||||||
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) {
|
JSValueRef RealmAddListener(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
|
||||||
try {
|
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<SharedRealm *>(thisObject);
|
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
|
||||||
JSGlobalContextRef gCtx = JSContextGetGlobalContext(ctx);
|
static_cast<RJSRealmDelegate *>(realm->m_delegate.get())->add_notification(callback);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
catch (std::exception &exp) {
|
||||||
|
if (jsException) {
|
||||||
|
*jsException = RJSMakeError(ctx, exp);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RJSRealmDelegate::NotificationFunction func = std::make_shared<std::function<void(const std::string)>>([=](std::string notification_name) {
|
JSValueRef RealmRemoveListener(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
|
||||||
JSValueRef arguments[2];
|
try {
|
||||||
arguments[0] = thisObject;
|
RJSValidateArgumentCount(argumentCount, 2);
|
||||||
arguments[1] = RJSValueForString(gCtx, notification_name);
|
__unused std::string name = RJSValidatedNotificationName(ctx, arguments[0]);
|
||||||
JSValueRef ex = NULL;
|
JSObjectRef callback = RJSValidatedValueToFunction(ctx, arguments[1]);
|
||||||
JSObjectCallAsFunction(gCtx, callback, thisObject, 2, arguments, &ex);
|
|
||||||
if (ex) {
|
|
||||||
throw RJSException(gCtx, ex);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
static_cast<RJSRealmDelegate *>(realm->m_delegate.get())->add_notification(func);
|
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
|
||||||
return RJSWrapObject<Notification *>(ctx, RJSNotificationClass(), new Notification { gCtx, thisObject, callback, func });
|
static_cast<RJSRealmDelegate *>(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 {
|
||||||
|
RJSValidateArgumentRange(argumentCount, 0, 1);
|
||||||
|
if (argumentCount) {
|
||||||
|
RJSValidatedNotificationName(ctx, arguments[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
|
||||||
|
static_cast<RJSRealmDelegate *>(realm->m_delegate.get())->remove_all_notifications();
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
catch (std::exception &exp) {
|
catch (std::exception &exp) {
|
||||||
if (jsException) {
|
if (jsException) {
|
||||||
|
@ -472,7 +508,9 @@ static const JSStaticFunction RJSRealmFuncs[] = {
|
||||||
{"delete", RealmDelete, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
{"delete", RealmDelete, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
||||||
{"deleteAll", RealmDeleteAll, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
{"deleteAll", RealmDeleteAll, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
||||||
{"write", RealmWrite, 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},
|
{"close", RealmClose, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
||||||
{NULL, NULL},
|
{NULL, NULL},
|
||||||
};
|
};
|
||||||
|
@ -481,9 +519,3 @@ JSClassRef RJSRealmClass() {
|
||||||
static JSClassRef s_realmClass = RJSCreateWrapperClass<SharedRealm *>("Realm", RealmGetProperty, NULL, RJSRealmFuncs);
|
static JSClassRef s_realmClass = RJSCreateWrapperClass<SharedRealm *>("Realm", RealmGetProperty, NULL, RJSRealmFuncs);
|
||||||
return s_realmClass;
|
return s_realmClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSClassRef RJSNotificationClass() {
|
|
||||||
static JSClassRef s_notificationClass = RJSCreateWrapperClass<Notification *>("Notification", NULL, NULL, NULL);
|
|
||||||
return s_notificationClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -254,12 +254,6 @@ json RPCServer::serialize_json_value(JSValueRef value) {
|
||||||
{"schema", serialize_object_schema(results->object_schema)}
|
{"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)) {
|
else if (RJSIsValueArray(m_context, value)) {
|
||||||
size_t length = RJSValidatedListLength(m_context, js_object);
|
size_t length = RJSValidatedListLength(m_context, js_object);
|
||||||
std::vector<json> array;
|
std::vector<json> array;
|
||||||
|
|
|
@ -282,7 +282,7 @@ module.exports = BaseTest.extend({
|
||||||
var notificationCount = 0;
|
var notificationCount = 0;
|
||||||
var notificationName;
|
var notificationName;
|
||||||
|
|
||||||
var notification = realm.addNotification(function(realm, name) {
|
realm.addListener('change', function(realm, name) {
|
||||||
notificationCount++;
|
notificationCount++;
|
||||||
notificationName = name;
|
notificationName = name;
|
||||||
});
|
});
|
||||||
|
@ -290,6 +290,38 @@ module.exports = BaseTest.extend({
|
||||||
TestCase.assertEqual(notificationCount, 0);
|
TestCase.assertEqual(notificationCount, 0);
|
||||||
realm.write(function() {});
|
realm.write(function() {});
|
||||||
TestCase.assertEqual(notificationCount, 1);
|
TestCase.assertEqual(notificationCount, 1);
|
||||||
TestCase.assertEqual(notificationName, 'DidChangeNotification');
|
TestCase.assertEqual(notificationName, 'change');
|
||||||
|
|
||||||
|
var secondNotificationCount = 0;
|
||||||
|
function secondNotification(realm, name) {
|
||||||
|
secondNotificationCount++;
|
||||||
|
};
|
||||||
|
realm.addListener('change', secondNotification)
|
||||||
|
|
||||||
|
realm.write(function() {});
|
||||||
|
TestCase.assertEqual(notificationCount, 2);
|
||||||
|
TestCase.assertEqual(secondNotificationCount, 1);
|
||||||
|
|
||||||
|
realm.removeListener('change', 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);
|
||||||
|
|
||||||
|
TestCase.assertThrows(function() {
|
||||||
|
realm.addListener('invalid', function() {});
|
||||||
|
});
|
||||||
|
|
||||||
|
realm.addListener('change', function() {
|
||||||
|
throw new Error('error');
|
||||||
|
});
|
||||||
|
|
||||||
|
TestCase.assertThrows(function() {
|
||||||
|
realm.write(function() {});
|
||||||
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue