Generalize getting/setting properties through RPC

This commit is contained in:
Scott Kyle 2015-10-19 15:26:42 -07:00
parent 4c0cc578d5
commit 1b7653206a
9 changed files with 62 additions and 177 deletions

View File

@ -1,7 +1,5 @@
'use strict';
let keys = require('./keys');
let rpc = require('./rpc');
let types = require('./types');
let util = require('./util');
@ -20,21 +18,5 @@ util.createMethods(List.prototype, types.LIST, [
], true);
function create(realmId, info) {
return util.createList(List.prototype, realmId, info, getterForLength, getterForIndex, setterForIndex);
}
function getterForLength() {
return rpc.getListSize(this[keys.realm], this[keys.id]);
}
function getterForIndex(index) {
return function() {
return rpc.getListItem(this[keys.realm], this[keys.id], index);
};
}
function setterForIndex(index) {
return function(value) {
rpc.setListItem(this[keys.realm], this[keys.id], index, value);
};
return util.createList(List.prototype, realmId, info, true);
}

View File

@ -1,7 +1,7 @@
'use strict';
let keys = require('./keys');
let rpc = require('./rpc');
let util = require('./util');
let registeredConstructors = {};
@ -24,8 +24,8 @@ function create(realmId, info) {
let name = prop.name;
props[name] = {
get: getterForProperty(name),
set: setterForProperty(name),
get: util.getterForProperty(name),
set: util.setterForProperty(name),
};
}
@ -37,15 +37,3 @@ function create(realmId, info) {
function registerConstructors(realmId, constructors) {
registeredConstructors[realmId] = constructors;
}
function getterForProperty(name) {
return function() {
return rpc.getObjectProperty(this[keys.realm], this[keys.id], name);
};
}
function setterForProperty(name) {
return function(value) {
rpc.setObjectProperty(this[keys.realm], this[keys.id], name, value);
};
}

View File

@ -1,8 +1,6 @@
'use strict';
let internal = require('./internal-types');
let keys = require('./keys');
let rpc = require('./rpc');
let util = require('./util');
module.exports = {
@ -16,15 +14,5 @@ util.createMethods(Results.prototype, internal.RESULTS, [
]);
function create(realmId, info) {
return util.createList(Results.prototype, realmId, info, getterForLength, getterForIndex);
}
function getterForLength() {
return rpc.getResultsSize(this[keys.realm], this[keys.id]);
}
function getterForIndex(index) {
return function() {
return rpc.getResultsItem(this[keys.realm], this[keys.id], index);
};
return util.createList(Results.prototype, realmId, info);
}

View File

@ -21,17 +21,8 @@ module.exports = {
createRealm,
callMethod,
getObjectProperty,
setObjectProperty,
getListItem,
setListItem,
getListSize,
getResultsItem,
getResultsSize,
getProperty,
setProperty,
beginTransaction,
cancelTransaction,
commitTransaction,
@ -60,39 +51,16 @@ function callMethod(realmId, id, type, name, args) {
return deserialize(realmId, result);
}
function getObjectProperty(realmId, id, name) {
function getProperty(realmId, id, name) {
let result = sendRequest('get_property', {realmId, id, name});
return deserialize(realmId, result);
}
function setObjectProperty(realmId, id, name, value) {
function setProperty(realmId, id, name, value) {
value = serialize(realmId, value);
sendRequest('set_property', {realmId, id, name, value});
}
function getListItem(realmId, id, index) {
let result = sendRequest('get_list_item', {realmId, id, index});
return deserialize(realmId, result);
}
function setListItem(realmId, id, index, value) {
value = serialize(realmId, value);
sendRequest('set_list_item', {realmId, id, index, value});
}
function getListSize(realmId, id) {
return sendRequest('get_list_size', {realmId, id});
}
function getResultsItem(realmId, id, index) {
let result = sendRequest('get_results_item', {realmId, id, index});
return deserialize(realmId, result);
}
function getResultsSize(realmId, id) {
return sendRequest('get_results_size', {realmId, id});
}
function beginTransaction(realmId) {
sendRequest('begin_transaction', {realmId});
}

View File

@ -6,13 +6,15 @@ let rpc = require('./rpc');
module.exports = {
createList,
createMethods,
getterForProperty,
setterForProperty,
};
function createList(prototype, realmId, info, getterForLength, getterForIndex, setterForIndex) {
function createList(prototype, realmId, info, mutable) {
let list = Object.create(prototype);
let size = 0;
Object.defineProperty(list, 'length', {get: getterForLength});
Object.defineProperty(list, 'length', {get: getterForProperty('length')});
list[keys.resize] = function(length) {
if (length == null) {
@ -27,8 +29,8 @@ function createList(prototype, realmId, info, getterForLength, getterForIndex, s
for (let i = size; i < length; i++) {
props[i] = {
get: getterForIndex(i),
set: setterForIndex && setterForIndex(i),
get: getterForProperty(i),
set: mutable ? setterForProperty(i) : undefined,
enumerable: true,
configurable: true,
};
@ -82,3 +84,15 @@ function createMethods(prototype, type, methodNames, resize) {
Object.defineProperties(prototype, props);
}
function getterForProperty(name) {
return function() {
return rpc.getProperty(this[keys.realm], this[keys.id], name);
};
}
function setterForProperty(name) {
return function(value) {
rpc.setProperty(this[keys.realm], this[keys.id], name, value);
};
}

View File

@ -23,6 +23,3 @@
extern const JSStaticFunction RJSListFuncs[];
JSClassRef RJSListClass();
JSObjectRef RJSListCreate(JSContextRef ctx, realm::List &list);
JSValueRef ListGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* jsException);
bool ListSetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* jsException);

View File

@ -24,7 +24,3 @@ namespace realm {
JSClassRef RJSObjectClass();
JSObjectRef RJSObjectCreate(JSContextRef ctx, realm::Object object);
JSValueRef ObjectGetProperty(JSContextRef ctx, JSObjectRef jsObject, JSStringRef jsPropertyName, JSValueRef* exception);
bool ObjectSetProperty(JSContextRef ctx, JSObjectRef jsObject, JSStringRef jsPropertyName, JSValueRef value, JSValueRef* exception);

View File

@ -27,6 +27,3 @@ extern const JSStaticFunction RJSResultsFuncs[];
JSClassRef RJSResultsClass();
JSObjectRef RJSResultsCreate(JSContextRef ctx, realm::SharedRealm realm, std::string className);
JSObjectRef RJSResultsCreate(JSContextRef ctx, realm::SharedRealm realm, std::string className, std::string query);
JSValueRef ResultsGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* jsException);

View File

@ -19,6 +19,7 @@
#import "RealmRPC.h"
#import <JavaScriptCore/JavaScriptCore.h>
#include <dlfcn.h>
#include <map>
#include <string>
#include "RealmJS.h"
@ -68,6 +69,13 @@ static std::map<std::string, const JSStaticFunction *> s_objectTypeMethods;
if (self) {
_context = JSGlobalContextCreate(NULL);
// JavaScriptCore crashes when trying to walk up the native stack to print the stacktrace.
// FIXME: Avoid having to do this!
static void (*setIncludesNativeCallStack)(JSGlobalContextRef, bool) = (void (*)(JSGlobalContextRef, bool))dlsym(RTLD_DEFAULT, "JSGlobalContextSetIncludesNativeCallStackWhenReportingExceptions");
if (setIncludesNativeCallStack) {
setIncludesNativeCallStack(_context, false);
}
id _self = self;
__weak __typeof__(self) self = _self;
@ -112,28 +120,44 @@ static std::map<std::string, const JSStaticFunction *> s_objectTypeMethods;
objectId:[dict[@"id"] unsignedLongValue]];
};
_requests["/get_property"] = [=](NSDictionary *dict) {
RPCObjectID oid = [dict[@"id"] unsignedLongValue];
id name = dict[@"name"];
JSValueRef value = NULL;
JSValueRef exception = NULL;
NSString *name = dict[@"name"];
JSStringRef propString = RJSStringForString(name.UTF8String);
RPCObjectID objectId = [dict[@"id"] unsignedLongValue];
JSValueRef propertyValue = ObjectGetProperty(_context, _objects[objectId], propString, &exception);
JSStringRelease(propString);
if ([name isKindOfClass:[NSNumber class]]) {
value = JSObjectGetPropertyAtIndex(_context, _objects[oid], [name unsignedIntValue], &exception);
}
else {
JSStringRef propString = RJSStringForString([name UTF8String]);
value = JSObjectGetProperty(_context, _objects[oid], propString, &exception);
JSStringRelease(propString);
}
if (exception) {
return @{@"error": @(RJSStringForValue(_context, exception).c_str())};
}
return @{@"result": [self resultForJSValue:propertyValue]};
return @{@"result": [self resultForJSValue:value]};
};
_requests["/set_property"] = [=](NSDictionary *dict) {
JSStringRef propString = RJSStringForString([dict[@"name"] UTF8String]);
RPCObjectID objectId = [dict[@"id"] unsignedLongValue];
RPCObjectID oid = [dict[@"id"] unsignedLongValue];
id name = dict[@"name"];
JSValueRef value = [self deserializeDictionaryValue:dict[@"value"]];
JSValueRef exception = NULL;
ObjectSetProperty(_context, _objects[objectId], propString, value, &exception);
JSStringRelease(propString);
if ([name isKindOfClass:[NSNumber class]]) {
JSObjectSetPropertyAtIndex(_context, _objects[oid], [name unsignedIntValue], value, &exception);
}
else {
JSStringRef propString = RJSStringForString([name UTF8String]);
JSObjectSetProperty(_context, _objects[oid], propString, value, 0, &exception);
JSStringRelease(propString);
}
return exception ? @{@"error": @(RJSStringForValue(_context, exception).c_str())} : @{};
if (exception) {
return @{@"error": @(RJSStringForValue(_context, exception).c_str())};
}
return @{};
};
_requests["/dispose_object"] = [=](NSDictionary *dict) {
RPCObjectID oid = [dict[@"id"] unsignedLongValue];
@ -141,75 +165,6 @@ static std::map<std::string, const JSStaticFunction *> s_objectTypeMethods;
_objects.erase(oid);
return nil;
};
_requests["/get_results_size"] = [=](NSDictionary *dict) {
RPCObjectID resultsId = [dict[@"id"] unsignedLongValue];
JSValueRef exception = NULL;
static JSStringRef lengthPropertyName = JSStringCreateWithUTF8CString("length");
JSValueRef lengthValue = ResultsGetProperty(_context, _objects[resultsId], lengthPropertyName, &exception);
size_t length = JSValueToNumber(_context, lengthValue, &exception);
if (exception) {
return @{@"error": @(RJSStringForValue(_context, exception).c_str())};
}
return @{@"result": @(length)};
};
_requests["/get_results_item"] = [=](NSDictionary *dict) {
RPCObjectID resultsId = [dict[@"id"] unsignedLongValue];
long index = [dict[@"index"] longValue];
JSValueRef exception = NULL;
JSStringRef indexPropertyName = JSStringCreateWithUTF8CString(std::to_string(index).c_str());
JSValueRef objectValue = ResultsGetProperty(_context, _objects[resultsId], indexPropertyName, &exception);
JSStringRelease(indexPropertyName);
if (exception) {
return @{@"error": @(RJSStringForValue(_context, exception).c_str())};
}
return @{@"result": [self resultForJSValue:objectValue]};
};
_requests["/get_list_size"] = [=](NSDictionary *dict) {
RPCObjectID listId = [dict[@"id"] unsignedLongValue];
JSValueRef exception = NULL;
static JSStringRef lengthPropertyName = JSStringCreateWithUTF8CString("length");
JSValueRef lengthValue = ListGetProperty(_context, _objects[listId], lengthPropertyName, &exception);
size_t length = JSValueToNumber(_context, lengthValue, &exception);
if (exception) {
return @{@"error": @(RJSStringForValue(_context, exception).c_str())};
}
return @{@"result": @(length)};
};
_requests["/get_list_item"] = [=](NSDictionary *dict) {
RPCObjectID listId = [dict[@"id"] unsignedLongValue];
long index = [dict[@"index"] longValue];
JSValueRef exception = NULL;
JSStringRef indexPropertyName = JSStringCreateWithUTF8CString(std::to_string(index).c_str());
JSValueRef objectValue = ListGetProperty(_context, _objects[listId], indexPropertyName, &exception);
JSStringRelease(indexPropertyName);
if (exception) {
return @{@"error": @(RJSStringForValue(_context, exception).c_str())};
}
return @{@"result": [self resultForJSValue:objectValue]};
};
_requests["/set_list_item"] = [=](NSDictionary *dict) {
RPCObjectID listId = [dict[@"id"] unsignedLongValue];
long index = [dict[@"index"] longValue];
JSValueRef exception = NULL;
JSStringRef indexPropertyName = JSStringCreateWithUTF8CString(std::to_string(index).c_str());
JSValueRef value = [self deserializeDictionaryValue:dict[@"value"]];
ListSetProperty(_context, _objects[listId], indexPropertyName, value, &exception);
JSStringRelease(indexPropertyName);
if (exception) {
return @{@"error": @(RJSStringForValue(_context, exception).c_str())};
}
return @{};
};
_requests["/clear_test_state"] = [=](NSDictionary *dict) {
for (auto object : _objects) {
JSValueUnprotect(_context, object.second);