2016-02-18 19:59:34 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// Copyright 2016 Realm Inc.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
//
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
2015-10-28 17:37:17 +00:00
|
|
|
|
2015-10-08 00:08:19 +00:00
|
|
|
'use strict';
|
|
|
|
|
2015-10-21 20:25:12 +00:00
|
|
|
const constants = require('./constants');
|
|
|
|
const rpc = require('./rpc');
|
2015-10-08 00:08:19 +00:00
|
|
|
|
2015-10-21 20:25:12 +00:00
|
|
|
const {keys} = constants;
|
2015-11-03 00:29:13 +00:00
|
|
|
let mutationListeners = {};
|
2015-10-19 23:19:43 +00:00
|
|
|
|
2015-10-19 19:06:47 +00:00
|
|
|
module.exports = {
|
2015-11-03 00:29:13 +00:00
|
|
|
clearMutationListeners,
|
2015-10-28 17:21:32 +00:00
|
|
|
fireMutationListeners,
|
2015-10-19 19:06:47 +00:00
|
|
|
createList,
|
|
|
|
createMethods,
|
2015-10-20 00:28:20 +00:00
|
|
|
createMethod,
|
2015-10-19 22:26:42 +00:00
|
|
|
getterForProperty,
|
|
|
|
setterForProperty,
|
2015-10-19 19:06:47 +00:00
|
|
|
};
|
2015-10-08 00:08:19 +00:00
|
|
|
|
2015-10-28 17:21:32 +00:00
|
|
|
function addMutationListener(realmId, callback) {
|
|
|
|
let listeners = mutationListeners[realmId] || (mutationListeners[realmId] = new Set());
|
|
|
|
listeners.add(callback);
|
|
|
|
}
|
|
|
|
|
2015-12-01 22:05:33 +00:00
|
|
|
function removeMutationListener(realmId, callback) {
|
|
|
|
let listeners = mutationListeners[realmId];
|
|
|
|
if (listeners) {
|
|
|
|
listeners.delete(callback);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-03 00:29:13 +00:00
|
|
|
function clearMutationListeners() {
|
|
|
|
mutationListeners = {};
|
|
|
|
}
|
|
|
|
|
2015-10-28 17:21:32 +00:00
|
|
|
function fireMutationListeners(realmId) {
|
|
|
|
let listeners = mutationListeners[realmId];
|
|
|
|
if (listeners) {
|
2015-11-06 00:10:52 +00:00
|
|
|
listeners.forEach((cb) => cb());
|
2015-10-28 17:21:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-19 22:26:42 +00:00
|
|
|
function createList(prototype, realmId, info, mutable) {
|
2015-10-19 19:06:47 +00:00
|
|
|
let list = Object.create(prototype);
|
2015-10-14 23:05:49 +00:00
|
|
|
let size = 0;
|
2015-10-08 00:08:19 +00:00
|
|
|
|
2015-10-21 20:09:51 +00:00
|
|
|
Object.defineProperties(list, {
|
|
|
|
'length': {
|
|
|
|
get: getterForProperty('length'),
|
|
|
|
},
|
|
|
|
'-1': {
|
|
|
|
value: undefined,
|
|
|
|
},
|
|
|
|
});
|
2015-10-08 00:08:19 +00:00
|
|
|
|
2015-10-28 17:21:32 +00:00
|
|
|
let resize = function(length) {
|
2015-10-08 04:20:14 +00:00
|
|
|
if (length == null) {
|
2015-10-20 00:43:51 +00:00
|
|
|
length = list.length;
|
2015-10-08 04:20:14 +00:00
|
|
|
}
|
|
|
|
if (length == size) {
|
2015-10-08 00:08:19 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-10-21 20:09:51 +00:00
|
|
|
let props = {};
|
2015-10-08 04:20:14 +00:00
|
|
|
|
2015-10-21 20:09:51 +00:00
|
|
|
if (length > size) {
|
2015-10-08 04:20:14 +00:00
|
|
|
for (let i = size; i < length; i++) {
|
|
|
|
props[i] = {
|
2015-10-19 22:26:42 +00:00
|
|
|
get: getterForProperty(i),
|
|
|
|
set: mutable ? setterForProperty(i) : undefined,
|
2015-10-08 04:20:14 +00:00
|
|
|
enumerable: true,
|
|
|
|
configurable: true,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (length < size) {
|
2015-10-21 20:09:51 +00:00
|
|
|
for (let i = size; i >= length; i--) {
|
2015-10-20 00:43:51 +00:00
|
|
|
delete list[i];
|
2015-10-08 04:20:14 +00:00
|
|
|
}
|
|
|
|
}
|
2015-10-08 00:08:19 +00:00
|
|
|
|
2015-10-21 20:09:51 +00:00
|
|
|
// Helpfully throw an exception on attempts to set to list[list.length].
|
|
|
|
props[length] = {
|
|
|
|
value: undefined,
|
|
|
|
configurable: true,
|
|
|
|
};
|
|
|
|
|
|
|
|
Object.defineProperties(list, props);
|
|
|
|
|
2015-10-08 04:20:14 +00:00
|
|
|
size = length;
|
|
|
|
};
|
2015-10-08 00:08:19 +00:00
|
|
|
|
2015-10-19 19:06:47 +00:00
|
|
|
list[keys.realm] = realmId;
|
|
|
|
list[keys.id] = info.id;
|
|
|
|
list[keys.type] = info.type;
|
2015-10-28 17:21:32 +00:00
|
|
|
|
|
|
|
resize(info.size);
|
2015-12-01 22:05:33 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2015-10-19 19:06:47 +00:00
|
|
|
|
2015-10-08 04:20:14 +00:00
|
|
|
return list;
|
2015-10-08 00:08:19 +00:00
|
|
|
}
|
2015-10-19 19:06:47 +00:00
|
|
|
|
2015-10-28 17:21:32 +00:00
|
|
|
function createMethods(prototype, type, methodNames, mutates) {
|
2015-10-19 19:06:47 +00:00
|
|
|
let props = {};
|
|
|
|
|
2015-11-06 00:10:52 +00:00
|
|
|
methodNames.forEach((name) => {
|
2015-10-19 19:06:47 +00:00
|
|
|
props[name] = {
|
2015-10-28 17:21:32 +00:00
|
|
|
value: createMethod(type, name, mutates),
|
2015-10-20 00:28:20 +00:00
|
|
|
};
|
2015-11-06 00:10:52 +00:00
|
|
|
});
|
2015-10-19 19:06:47 +00:00
|
|
|
|
2015-10-20 00:28:20 +00:00
|
|
|
Object.defineProperties(prototype, props);
|
|
|
|
}
|
2015-10-19 19:06:47 +00:00
|
|
|
|
2015-10-28 17:21:32 +00:00
|
|
|
function createMethod(type, name, mutates) {
|
2015-10-20 00:28:20 +00:00
|
|
|
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!');
|
|
|
|
}
|
2015-10-19 19:06:47 +00:00
|
|
|
|
2015-10-20 00:28:20 +00:00
|
|
|
let result = rpc.callMethod(realmId, id, name, Array.from(arguments));
|
2015-10-19 19:06:47 +00:00
|
|
|
|
2015-10-28 17:21:32 +00:00
|
|
|
if (mutates) {
|
|
|
|
fireMutationListeners(realmId);
|
2015-10-20 00:28:20 +00:00
|
|
|
}
|
2015-10-19 19:06:47 +00:00
|
|
|
|
2015-10-20 00:28:20 +00:00
|
|
|
return result;
|
|
|
|
};
|
2015-10-19 19:06:47 +00:00
|
|
|
}
|
2015-10-19 22:26:42 +00:00
|
|
|
|
|
|
|
function getterForProperty(name) {
|
|
|
|
return function() {
|
|
|
|
return rpc.getProperty(this[keys.realm], this[keys.id], name);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
function setterForProperty(name) {
|
|
|
|
return function(value) {
|
2015-10-28 17:21:32 +00:00
|
|
|
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);
|
|
|
|
}
|
2015-10-19 22:26:42 +00:00
|
|
|
};
|
|
|
|
}
|