mirror of
https://github.com/status-im/realm-js.git
synced 2025-01-10 14:25:58 +00:00
be0c2a91ea
Specifically for objects with lists, since the mutation listener would fire on a list that no longer is attached. If during the mutation listener that error is thrown, then the listener will be removed and the error will not be propagated.
165 lines
3.9 KiB
JavaScript
165 lines
3.9 KiB
JavaScript
/* Copyright 2015 Realm Inc - All Rights Reserved
|
|
* Proprietary and Confidential
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
const constants = require('./constants');
|
|
const rpc = require('./rpc');
|
|
|
|
const {keys} = constants;
|
|
const mutationListeners = {};
|
|
|
|
module.exports = {
|
|
fireMutationListeners,
|
|
createList,
|
|
createMethods,
|
|
createMethod,
|
|
getterForProperty,
|
|
setterForProperty,
|
|
};
|
|
|
|
function addMutationListener(realmId, callback) {
|
|
let listeners = mutationListeners[realmId] || (mutationListeners[realmId] = new Set());
|
|
listeners.add(callback);
|
|
}
|
|
|
|
function removeMutationListener(realmId, callback) {
|
|
let listeners = mutationListeners[realmId];
|
|
if (listeners) {
|
|
listeners.delete(callback);
|
|
}
|
|
}
|
|
|
|
function fireMutationListeners(realmId) {
|
|
let listeners = mutationListeners[realmId];
|
|
if (listeners) {
|
|
listeners.forEach((cb) => cb());
|
|
}
|
|
}
|
|
|
|
function createList(prototype, realmId, info, mutable) {
|
|
let list = Object.create(prototype);
|
|
let size = 0;
|
|
|
|
Object.defineProperties(list, {
|
|
'length': {
|
|
get: getterForProperty('length'),
|
|
},
|
|
'-1': {
|
|
value: undefined,
|
|
},
|
|
});
|
|
|
|
let resize = function(length) {
|
|
if (length == null) {
|
|
length = list.length;
|
|
}
|
|
if (length == size) {
|
|
return;
|
|
}
|
|
|
|
let props = {};
|
|
|
|
if (length > size) {
|
|
for (let i = size; i < length; i++) {
|
|
props[i] = {
|
|
get: getterForProperty(i),
|
|
set: mutable ? setterForProperty(i) : undefined,
|
|
enumerable: true,
|
|
configurable: true,
|
|
};
|
|
}
|
|
}
|
|
else if (length < size) {
|
|
for (let i = size; i >= length; i--) {
|
|
delete list[i];
|
|
}
|
|
}
|
|
|
|
// Helpfully throw an exception on attempts to set to list[list.length].
|
|
props[length] = {
|
|
value: undefined,
|
|
configurable: true,
|
|
};
|
|
|
|
Object.defineProperties(list, props);
|
|
|
|
size = length;
|
|
};
|
|
|
|
list[keys.realm] = realmId;
|
|
list[keys.id] = info.id;
|
|
list[keys.type] = info.type;
|
|
|
|
resize(info.size);
|
|
|
|
addMutationListener(realmId, function listener() {
|
|
try {
|
|
resize();
|
|
} catch (e) {
|
|
// If the error indicates the list was deleted, then remove this listener.
|
|
if (e.message == 'Tableview is not attached') {
|
|
removeMutationListener(realmId, listener);
|
|
} else {
|
|
throw e;
|
|
}
|
|
}
|
|
});
|
|
|
|
return list;
|
|
}
|
|
|
|
function createMethods(prototype, type, methodNames, mutates) {
|
|
let props = {};
|
|
|
|
methodNames.forEach((name) => {
|
|
props[name] = {
|
|
value: createMethod(type, name, mutates),
|
|
};
|
|
});
|
|
|
|
Object.defineProperties(prototype, props);
|
|
}
|
|
|
|
function createMethod(type, name, mutates) {
|
|
return function() {
|
|
let realmId = this[keys.realm];
|
|
let id = this[keys.id];
|
|
|
|
if (!realmId || !id) {
|
|
throw new TypeError(name + ' method was not called a Realm object!');
|
|
}
|
|
if (this[keys.type] !== type) {
|
|
throw new TypeError(name + ' method was called on an object of the wrong type!');
|
|
}
|
|
|
|
let result = rpc.callMethod(realmId, id, name, Array.from(arguments));
|
|
|
|
if (mutates) {
|
|
fireMutationListeners(realmId);
|
|
}
|
|
|
|
return result;
|
|
};
|
|
}
|
|
|
|
function getterForProperty(name) {
|
|
return function() {
|
|
return rpc.getProperty(this[keys.realm], this[keys.id], name);
|
|
};
|
|
}
|
|
|
|
function setterForProperty(name) {
|
|
return function(value) {
|
|
let realmId = this[keys.realm];
|
|
|
|
rpc.setProperty(realmId, this[keys.id], name, value);
|
|
|
|
// If this isn't a primitive value, then it might create a new object in the Realm.
|
|
if (value && typeof value == 'object') {
|
|
fireMutationListeners(realmId);
|
|
}
|
|
};
|
|
}
|