mirror of
https://github.com/status-im/realm-js.git
synced 2025-02-23 11:48:17 +00:00
Ensure Lists and Results live-update in Chrome
Results needed to live-update during a transaction (not just as the end), and Lists needed to update on deletions as well.
This commit is contained in:
parent
7a02ff29a1
commit
0eb3b49970
@ -7,7 +7,6 @@ let propTypes = {};
|
|||||||
[
|
[
|
||||||
'id',
|
'id',
|
||||||
'realm',
|
'realm',
|
||||||
'resize',
|
|
||||||
'type',
|
'type',
|
||||||
].forEach(function(name) {
|
].forEach(function(name) {
|
||||||
keys[name] = Symbol();
|
keys[name] = Symbol();
|
||||||
|
31
lib/realm.js
31
lib/realm.js
@ -9,7 +9,6 @@ const util = require('./util');
|
|||||||
|
|
||||||
const {keys, propTypes, objectTypes} = constants;
|
const {keys, propTypes, objectTypes} = constants;
|
||||||
const listenersKey = Symbol();
|
const listenersKey = 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));
|
||||||
@ -40,7 +39,6 @@ class Realm {
|
|||||||
this[keys.realm] = realmId;
|
this[keys.realm] = realmId;
|
||||||
this[keys.type] = objectTypes.REALM;
|
this[keys.type] = objectTypes.REALM;
|
||||||
this[listenersKey] = [];
|
this[listenersKey] = [];
|
||||||
this[resultsKey] = [];
|
|
||||||
|
|
||||||
[
|
[
|
||||||
'path',
|
'path',
|
||||||
@ -60,7 +58,6 @@ class Realm {
|
|||||||
this[listenersKey].push(callback);
|
this[listenersKey].push(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
removeListener(name, callback) {
|
removeListener(name, callback) {
|
||||||
if (typeof callback != 'function') {
|
if (typeof callback != 'function') {
|
||||||
throw new Error('Realm.addListener must be passed a function!');
|
throw new Error('Realm.addListener must be passed a function!');
|
||||||
@ -68,10 +65,11 @@ class Realm {
|
|||||||
if (name != 'change') {
|
if (name != 'change') {
|
||||||
throw new Error("Only 'change' notification is supported.");
|
throw new Error("Only 'change' notification is supported.");
|
||||||
}
|
}
|
||||||
var index = 0;
|
|
||||||
while((index = this[listenersKey].indexOf(callback, index)) != -1) {
|
let index = 0;
|
||||||
|
while ((index = this[listenersKey].indexOf(callback, index)) != -1) {
|
||||||
this[listenersKey].splice(index, 1);
|
this[listenersKey].splice(index, 1);
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
removeAllListeners(name) {
|
removeAllListeners(name) {
|
||||||
@ -81,14 +79,6 @@ class Realm {
|
|||||||
this[listenersKey] = [];
|
this[listenersKey] = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
objects() {
|
|
||||||
let method = util.createMethod(objectTypes.REALM, 'objects');
|
|
||||||
let results = method.apply(this, arguments);
|
|
||||||
|
|
||||||
this[resultsKey].push(results);
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
write(callback) {
|
write(callback) {
|
||||||
let realmId = this[keys.realm];
|
let realmId = this[keys.realm];
|
||||||
|
|
||||||
@ -105,27 +95,30 @@ class Realm {
|
|||||||
callback();
|
callback();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
rpc.cancelTransaction(realmId);
|
rpc.cancelTransaction(realmId);
|
||||||
|
util.fireMutationListeners(realmId);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc.commitTransaction(realmId);
|
rpc.commitTransaction(realmId);
|
||||||
|
|
||||||
for (let results of this[resultsKey]) {
|
|
||||||
results[keys.resize]();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let callback of this[listenersKey]) {
|
for (let callback of this[listenersKey]) {
|
||||||
callback(this, 'change');
|
callback(this, 'change');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Non-mutating methods:
|
||||||
util.createMethods(Realm.prototype, objectTypes.REALM, [
|
util.createMethods(Realm.prototype, objectTypes.REALM, [
|
||||||
'close',
|
'close',
|
||||||
|
'objects',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Mutating methods:
|
||||||
|
util.createMethods(Realm.prototype, objectTypes.REALM, [
|
||||||
'create',
|
'create',
|
||||||
'delete',
|
'delete',
|
||||||
'deleteAll',
|
'deleteAll',
|
||||||
]);
|
], true);
|
||||||
|
|
||||||
Object.defineProperties(Realm, {
|
Object.defineProperties(Realm, {
|
||||||
Types: {
|
Types: {
|
||||||
|
42
lib/util.js
42
lib/util.js
@ -4,8 +4,11 @@ const constants = require('./constants');
|
|||||||
const rpc = require('./rpc');
|
const rpc = require('./rpc');
|
||||||
|
|
||||||
const {keys} = constants;
|
const {keys} = constants;
|
||||||
|
const mutationListeners = {};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
addMutationListener,
|
||||||
|
fireMutationListeners,
|
||||||
createList,
|
createList,
|
||||||
createMethods,
|
createMethods,
|
||||||
createMethod,
|
createMethod,
|
||||||
@ -13,6 +16,20 @@ module.exports = {
|
|||||||
setterForProperty,
|
setterForProperty,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function addMutationListener(realmId, callback) {
|
||||||
|
let listeners = mutationListeners[realmId] || (mutationListeners[realmId] = new Set());
|
||||||
|
listeners.add(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
function fireMutationListeners(realmId) {
|
||||||
|
let listeners = mutationListeners[realmId];
|
||||||
|
if (listeners) {
|
||||||
|
for (let callback of listeners) {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function createList(prototype, realmId, info, mutable) {
|
function createList(prototype, realmId, info, mutable) {
|
||||||
let list = Object.create(prototype);
|
let list = Object.create(prototype);
|
||||||
let size = 0;
|
let size = 0;
|
||||||
@ -26,7 +43,7 @@ function createList(prototype, realmId, info, mutable) {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
list[keys.resize] = function(length) {
|
let resize = function(length) {
|
||||||
if (length == null) {
|
if (length == null) {
|
||||||
length = list.length;
|
length = list.length;
|
||||||
}
|
}
|
||||||
@ -66,24 +83,26 @@ function createList(prototype, realmId, info, mutable) {
|
|||||||
list[keys.realm] = realmId;
|
list[keys.realm] = realmId;
|
||||||
list[keys.id] = info.id;
|
list[keys.id] = info.id;
|
||||||
list[keys.type] = info.type;
|
list[keys.type] = info.type;
|
||||||
list[keys.resize](info.size);
|
|
||||||
|
resize(info.size);
|
||||||
|
addMutationListener(realmId, resize);
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createMethods(prototype, type, methodNames, resize) {
|
function createMethods(prototype, type, methodNames, mutates) {
|
||||||
let props = {};
|
let props = {};
|
||||||
|
|
||||||
for (let name of methodNames) {
|
for (let name of methodNames) {
|
||||||
props[name] = {
|
props[name] = {
|
||||||
value: createMethod(type, name, resize),
|
value: createMethod(type, name, mutates),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.defineProperties(prototype, props);
|
Object.defineProperties(prototype, props);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createMethod(type, name, resize) {
|
function createMethod(type, name, mutates) {
|
||||||
return function() {
|
return function() {
|
||||||
let realmId = this[keys.realm];
|
let realmId = this[keys.realm];
|
||||||
let id = this[keys.id];
|
let id = this[keys.id];
|
||||||
@ -97,8 +116,8 @@ function createMethod(type, name, resize) {
|
|||||||
|
|
||||||
let result = rpc.callMethod(realmId, id, name, Array.from(arguments));
|
let result = rpc.callMethod(realmId, id, name, Array.from(arguments));
|
||||||
|
|
||||||
if (resize) {
|
if (mutates) {
|
||||||
this[keys.resize]();
|
fireMutationListeners(realmId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -113,6 +132,13 @@ function getterForProperty(name) {
|
|||||||
|
|
||||||
function setterForProperty(name) {
|
function setterForProperty(name) {
|
||||||
return function(value) {
|
return function(value) {
|
||||||
rpc.setProperty(this[keys.realm], this[keys.id], name, 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);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,11 @@
|
|||||||
"env": {
|
"env": {
|
||||||
"commonjs": true
|
"commonjs": true
|
||||||
},
|
},
|
||||||
|
"ecmaFeatures": {
|
||||||
|
"forOf": true
|
||||||
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
|
"no-empty": 0,
|
||||||
"no-unused-vars": 0
|
"no-unused-vars": 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -270,7 +270,64 @@ module.exports = BaseTest.extend({
|
|||||||
});
|
});
|
||||||
|
|
||||||
TestCase.assertThrows(function() {
|
TestCase.assertThrows(function() {
|
||||||
obj.arrayCol.splice(0, 0, obj.objectCol);
|
array.splice(0, 0, [1]);
|
||||||
}, 'can only splice in a write transaction');
|
}, 'can only splice in a write transaction');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
testDeletions: function() {
|
||||||
|
var realm = new Realm({schema: [schemas.LinkTypes, schemas.TestObject]});
|
||||||
|
var array;
|
||||||
|
|
||||||
|
realm.write(function() {
|
||||||
|
var obj = realm.create('LinkTypesObject', [[1], [2], [[3], [4]]]);
|
||||||
|
array = obj.arrayCol;
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
realm.write(function() {
|
||||||
|
realm.delete(array[0]);
|
||||||
|
TestCase.assertEqual(array.length, 1);
|
||||||
|
TestCase.assertEqual(array[0].doubleCol, 4);
|
||||||
|
|
||||||
|
throw new Error('Transaction FAIL');
|
||||||
|
});
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
|
TestCase.assertEqual(array.length, 2);
|
||||||
|
TestCase.assertEqual(array[0].doubleCol, 3);
|
||||||
|
},
|
||||||
|
|
||||||
|
testLiveUpdatingResults: function() {
|
||||||
|
var realm = new Realm({schema: [schemas.LinkTypes, schemas.TestObject]});
|
||||||
|
var objects = realm.objects('TestObject');
|
||||||
|
var array;
|
||||||
|
|
||||||
|
realm.write(function() {
|
||||||
|
var obj = realm.create('LinkTypesObject', [[1], [2], [[3], [4]]]);
|
||||||
|
array = obj.arrayCol;
|
||||||
|
});
|
||||||
|
|
||||||
|
TestCase.assertEqual(objects.length, 4);
|
||||||
|
|
||||||
|
try {
|
||||||
|
realm.write(function() {
|
||||||
|
array.push([5]);
|
||||||
|
TestCase.assertEqual(objects.length, 5);
|
||||||
|
|
||||||
|
array.unshift([2]);
|
||||||
|
TestCase.assertEqual(objects.length, 6);
|
||||||
|
|
||||||
|
array.splice(0, 0, [1]);
|
||||||
|
TestCase.assertEqual(objects.length, 7);
|
||||||
|
|
||||||
|
array.push(objects[0], objects[1]);
|
||||||
|
TestCase.assertEqual(objects.length, 7);
|
||||||
|
|
||||||
|
throw new Error('Transaction FAIL');
|
||||||
|
});
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
|
TestCase.assertEqual(array.length, 2);
|
||||||
|
TestCase.assertEqual(objects.length, 4);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
@ -216,11 +216,13 @@ module.exports = BaseTest.extend({
|
|||||||
},
|
},
|
||||||
testLinkTypesPropertySetters: function() {
|
testLinkTypesPropertySetters: function() {
|
||||||
var realm = new Realm({schema: [schemas.LinkTypes, schemas.TestObject]});
|
var realm = new Realm({schema: [schemas.LinkTypes, schemas.TestObject]});
|
||||||
|
var objects = realm.objects('TestObject');
|
||||||
var obj = null;
|
var obj = null;
|
||||||
|
|
||||||
realm.write(function() {
|
realm.write(function() {
|
||||||
obj = realm.create('LinkTypesObject', [[1], null, [[3]]]);
|
obj = realm.create('LinkTypesObject', [[1], null, [[3]]]);
|
||||||
});
|
});
|
||||||
TestCase.assertEqual(realm.objects('TestObject').length, 2);
|
TestCase.assertEqual(objects.length, 2);
|
||||||
|
|
||||||
TestCase.assertThrows(function() {
|
TestCase.assertThrows(function() {
|
||||||
obj.objectCol1 = obj.objectCol;
|
obj.objectCol1 = obj.objectCol;
|
||||||
@ -232,7 +234,7 @@ module.exports = BaseTest.extend({
|
|||||||
});
|
});
|
||||||
TestCase.assertEqual(obj.objectCol1.doubleCol, 1);
|
TestCase.assertEqual(obj.objectCol1.doubleCol, 1);
|
||||||
//TestCase.assertEqual(obj.objectCol, obj.objectCol1);
|
//TestCase.assertEqual(obj.objectCol, obj.objectCol1);
|
||||||
TestCase.assertEqual(realm.objects('TestObject').length, 2);
|
TestCase.assertEqual(objects.length, 2);
|
||||||
|
|
||||||
realm.write(function() {
|
realm.write(function() {
|
||||||
obj.objectCol = null;
|
obj.objectCol = null;
|
||||||
@ -246,12 +248,13 @@ module.exports = BaseTest.extend({
|
|||||||
obj.objectCol = { doubleCol: 1 };
|
obj.objectCol = { doubleCol: 1 };
|
||||||
});
|
});
|
||||||
TestCase.assertEqual(obj.objectCol.doubleCol, 1);
|
TestCase.assertEqual(obj.objectCol.doubleCol, 1);
|
||||||
TestCase.assertEqual(realm.objects('TestObject').length, 3);
|
TestCase.assertEqual(objects.length, 3);
|
||||||
|
|
||||||
// set array property
|
// set array property
|
||||||
realm.write(function() {
|
realm.write(function() {
|
||||||
obj.arrayCol = [obj.arrayCol[0], obj.objectCol, realm.create('TestObject', [2])];
|
obj.arrayCol = [obj.arrayCol[0], obj.objectCol, realm.create('TestObject', [2])];
|
||||||
});
|
});
|
||||||
|
TestCase.assertEqual(objects.length, 4);
|
||||||
TestCase.assertEqual(obj.arrayCol.length, 3);
|
TestCase.assertEqual(obj.arrayCol.length, 3);
|
||||||
TestCase.assertEqual(obj.arrayCol[0].doubleCol, 3);
|
TestCase.assertEqual(obj.arrayCol[0].doubleCol, 3);
|
||||||
TestCase.assertEqual(obj.arrayCol[1].doubleCol, 1);
|
TestCase.assertEqual(obj.arrayCol[1].doubleCol, 1);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user