diff --git a/.gitignore b/.gitignore index 640fb48c..e8b2f3f9 100644 --- a/.gitignore +++ b/.gitignore @@ -93,3 +93,7 @@ build/ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: .rvmrc + +# node.js +node_modules/ +npm-debug.log diff --git a/lib/lists.js b/lib/lists.js index 92cdafa6..c74593cc 100644 --- a/lib/lists.js +++ b/lib/lists.js @@ -1,10 +1,11 @@ 'use strict'; let rpc = require('./rpc'); +let util = require('./util'); let idKey = Symbol(); let realmKey = Symbol(); -let prototype = {}; +let prototype = util.createListPrototype(getterForLength, getterForIndex, setterForIndex); exports.create = create; @@ -30,7 +31,7 @@ exports.create = create; // Since this method might have grown the list, ensure index properties are defined. if (growthMethod) { - defineIndexProperties(this.length); + prototype[util.growListPrototypeKey](this.length); } return result; @@ -38,12 +39,6 @@ exports.create = create; }); }); -Object.defineProperty(prototype, 'length', { - get() { - return rpc.getListSize(this[realmKey], this[idKey]); - } -}); - function create(realmId, info) { let list = Object.create(prototype); let size = info.size; @@ -51,27 +46,13 @@ function create(realmId, info) { list[realmKey] = realmId; list[idKey] = info.id; - defineIndexProperties(size); + list[util.growListPrototypeKey](size); + + return list; } -let maxSize = 0; -function defineIndexProperties(size) { - if (size < maxSize) { - return; - } - - let props = {}; - for (let i = maxSize; i <= size; i++) { - props[i] = { - get: getterForIndex(i), - set: setterForIndex(i), - }; - } - - // TODO: Use ES6 Proxy once it's supported on Chrome! - Object.defineProperties(prototype, props); - - maxSize = size + 1; +function getterForLength() { + return rpc.getListSize(this[realmKey], this[idKey]); } function getterForIndex(index) { diff --git a/lib/objects.js b/lib/objects.js index 4f14b48f..3ca11f1b 100644 --- a/lib/objects.js +++ b/lib/objects.js @@ -5,14 +5,14 @@ let rpc = require('./rpc'); let idKey = Symbol(); let realmKey = Symbol(); let schemaKey = Symbol(); -let registeredconstructors = {}; +let registeredConstructors = {}; exports.create = create; -exports.registerconstructors = registerconstructors; +exports.registerConstructors = registerConstructors; function create(realmId, info) { let schema = info.schema; - let constructor = (registeredconstructors[realmId] || {})[schema.name]; + let constructor = (registeredConstructors[realmId] || {})[schema.name]; let object = constructor ? Object.create(constructor.prototype) : {}; let props = {}; @@ -34,8 +34,8 @@ function create(realmId, info) { return object; } -function registerconstructors(realmId, constructors) { - registeredconstructors[realmId] = constructors; +function registerConstructors(realmId, constructors) { + registeredConstructors[realmId] = constructors; } function getterForProperty(name) { diff --git a/lib/realm.js b/lib/realm.js index 2a107a17..3e067cec 100644 --- a/lib/realm.js +++ b/lib/realm.js @@ -2,6 +2,7 @@ let lists = require('./lists'); let objects = require('./objects'); +let results = require('./results'); let rpc = require('./rpc'); let types = require('./types'); @@ -29,7 +30,7 @@ class Realm { let realmId = this[realmKey] = rpc.createRealm(config); - objects.registerconstructors(realmId, constructors); + objects.registerConstructors(realmId, constructors); } addNotification(callback) { @@ -51,8 +52,11 @@ class Realm { // TODO } - objects(type) { - // TODO + objects(type, predicate) { + let realmId = this[realmKey]; + let info = rpc.getObjects(realmId, type, predicate); + + return results.create(realmId, info); } write(callback) { diff --git a/lib/results.js b/lib/results.js new file mode 100644 index 00000000..a7abb187 --- /dev/null +++ b/lib/results.js @@ -0,0 +1,33 @@ +'use strict'; + +let rpc = require('./rpc'); +let util = require('./util'); + +let idKey = Symbol(); +let realmKey = Symbol(); +let prototype = util.createListPrototype(getterForLength, getterForIndex); + +exports.create = create; + +function create(realmId, info) { + let results = Object.create(prototype); + let size = info.size; + + results[realmKey] = realmId; + results[idKey] = info.resultsId; + + results[util.growListPrototypeKey](size); + + return results; +} + +function getterForLength() { + return rpc.getResultsSize(this[realmKey], this[idKey]); +} + +function getterForIndex(index) { + return function() { + let realmId = this[realmKey]; + return rpc.getResultsItem(realmId, this[idKey], index); + }; +} diff --git a/lib/rpc.js b/lib/rpc.js index df5c10bf..1fd0aba7 100644 --- a/lib/rpc.js +++ b/lib/rpc.js @@ -3,11 +3,21 @@ let DEVICE_HOST = 'localhost:8082'; let typeConverters = {}; +let XMLHttpRequest = window.XMLHttpRequest; + +// Check if XMLHttpRequest has been overridden, and get the native one if that's the case. +if (XMLHttpRequest.__proto__ != window.XMLHttpRequestEventTarget) { + let override = XMLHttpRequest; + delete window.XMLHttpRequest; + XMLHttpRequest = window.XMLHttpRequest; + window.XMLHttpRequest = override; +} exports.registerTypeConverter = registerTypeConverter; exports.createRealm = createRealm; exports.createObject = createObject; +exports.getObjects = getObjects; exports.getObjectProperty = getObjectProperty; exports.setObjectProperty = setObjectProperty; @@ -17,6 +27,9 @@ exports.setListItem = setListItem; exports.getListSize = getListSize; exports.callListMethod = callListMethod; +exports.getResultsItem = getResultsItem; +exports.getResultsSize = getResultsSize; + exports.beginTransaction = beginTransaction; exports.cancelTransaction = cancelTransaction; exports.commitTransaction = commitTransaction; @@ -33,6 +46,10 @@ function createObject(realmId, type, values) { return sendRequest('create_object', {realmId, type, values}); } +function getObjects(realmId, type, predicate) { + return sendRequest('get_objects', {realmId, type, predicate}); +} + function getObjectProperty(realmId, objectId, name) { let result = sendRequest('get_property', {realmId, objectId, name}); return convert(result); @@ -60,6 +77,15 @@ function callListMethod(realmId, listId, name, args) { return convert(result); } +function getResultsItem(realmId, resultsId, index) { + let result = sendRequest('get_results_item', {realmId, resultsId, index}); + return convert(result); +} + +function getResultsSize(realmId, resultsId) { + return sendRequest('get_results_size', {realmId, resultsId}); +} + function beginTransaction(realmId) { sendRequest('begin_transaction', {realmId}); } @@ -79,7 +105,7 @@ function convert(realmId, info) { function sendRequest(command, data) { let body = JSON.stringify(data); - let request = new XMLHttpRequestOriginal(); + let request = new XMLHttpRequest(); let url = 'http://' + DEVICE_HOST + '/' + command; request.open('POST', url, false); diff --git a/lib/util.js b/lib/util.js new file mode 100644 index 00000000..a01c641b --- /dev/null +++ b/lib/util.js @@ -0,0 +1,35 @@ +'use strict'; + +let growListPrototypeKey = exports.growListPrototypeKey = Symbol(); + +exports.createListPrototype = createListPrototype; + +function createListPrototype(getterForLength, getterForIndex, setterForIndex) { + let prototype = {}; + let maxSize = 0; + + Object.defineProperty(prototype, 'length', { + get: getterForLength + }); + + prototype[growListPrototypeKey] = function(size) { + if (size < maxSize) { + return; + } + + let props = {}; + for (let i = maxSize; i <= size; i++) { + props[i] = { + get: getterForIndex(i), + set: setterForIndex && setterForIndex(i), + }; + } + + // TODO: Use ES6 Proxy once it's supported on Chrome! + Object.defineProperties(prototype, props); + + maxSize = size + 1; + } + + return prototype; +}