RPC now keeps object keys in the same order

Maintaining insertion order when passing objects through the RPC is essential to make the new schema API work.
This commit is contained in:
Scott Kyle 2015-11-02 16:36:24 -08:00
parent 43e14093cc
commit c928ab716e
3 changed files with 58 additions and 21 deletions

View File

@ -17,6 +17,7 @@ let propTypes = {};
});
[
'DICT',
'FUNCTION',
'REALM',
'RESULTS',

View File

@ -10,6 +10,7 @@ const constants = require('./constants');
const DEVICE_HOST = 'localhost:8082';
const {keys, objectTypes, propTypes} = constants;
const {id: idKey, realm: realmKey} = keys;
const typeConverters = {};
let XMLHttpRequest = global.originalXMLHttpRequest || global.XMLHttpRequest;
@ -40,6 +41,7 @@ module.exports = {
registerTypeConverter(propTypes.DATA, (_, {value}) => base64.decode(value));
registerTypeConverter(propTypes.DATE, (_, {value}) => new Date(value));
registerTypeConverter(objectTypes.DICT, deserializeDict);
function registerTypeConverter(type, handler) {
typeConverters[type] = handler;
@ -106,9 +108,9 @@ function serialize(realmId, value) {
return {value: value};
}
let id = value[keys.id];
let id = value[idKey];
if (id) {
if (value[keys.realm] != realmId) {
if (value[realmKey] != realmId) {
throw new Error('Unable to serialize value from another Realm');
}
@ -128,11 +130,9 @@ function serialize(realmId, value) {
return {type: propTypes.DATA, value: base64.encode(value)};
}
let object = {};
for (let key in value) {
object[key] = serialize(realmId, value[key]);
}
return {value: object};
let keys = Object.keys(value);
let values = keys.map((key) => serialize(realmId, value[key]));
return {type: objectTypes.DICT, keys, values};
}
function deserialize(realmId, info) {
@ -150,6 +150,17 @@ function deserialize(realmId, info) {
return value;
}
function deserializeDict(realmId, info) {
let {keys, values} = info;
let object = {};
for (let i = 0, len = keys.length; i < len; i++) {
object[keys[i]] = values[i];
}
return object;
}
function sendRequest(command, data) {
data = Object.assign({}, data, sessionId ? {sessionId} : null);

View File

@ -22,6 +22,7 @@
using RJSAccessor = realm::NativeAccessor<JSValueRef, JSContextRef>;
using namespace realm_js;
static const char * const RealmObjectTypesDictionary = "ObjectTypesDICT";
static const char * const RealmObjectTypesFunction = "ObjectTypesFUNCTION";
static const char * const RealmObjectTypesResults = "ObjectTypesRESULTS";
@ -262,6 +263,28 @@ json RPCServer::serialize_json_value(JSValueRef value) {
{"value", RJSValidatedValueToNumber(m_context, value)},
};
}
else {
JSPropertyNameArrayRef js_keys = JSObjectCopyPropertyNames(m_context, js_object);
size_t count = JSPropertyNameArrayGetCount(js_keys);
std::vector<std::string> keys;
std::vector<json> values;
for (size_t i = 0; i < count; i++) {
JSStringRef js_key = JSPropertyNameArrayGetNameAtIndex(js_keys, i);
JSValueRef js_value = RJSValidatedPropertyValue(m_context, js_object, js_key);
keys.push_back(RJSStringForJSString(js_key));
values.push_back(serialize_json_value(js_value));
}
JSPropertyNameArrayRelease(js_keys);
return {
{"type", RealmObjectTypesDictionary},
{"keys", keys},
{"values", values},
};
}
assert(0);
}
@ -299,6 +322,22 @@ JSValueRef RPCServer::deserialize_json_value(const json dict)
return js_function;
}
else if (type_string == RealmObjectTypesDictionary) {
JSObjectRef js_object = JSObjectMake(m_context, NULL, NULL);
json keys = dict["keys"];
json values = dict["values"];
size_t count = keys.size();
for (size_t i = 0; i < count; i++) {
JSStringRef js_key = RJSStringForString(keys.at(i));
JSValueRef js_value = deserialize_json_value(values.at(i));
JSObjectSetProperty(m_context, js_object, js_key, js_value, 0, NULL);
JSStringRelease(js_key);
}
return js_object;
}
else if (type_string == RJSTypeGet(realm::PropertyTypeData)) {
std::string bytes;
if (!base64_decode(value.get<std::string>(), &bytes)) {
@ -344,19 +383,5 @@ JSValueRef RPCServer::deserialize_json_value(const json dict)
return JSObjectMakeArray(m_context, count, js_values, NULL);
}
else if (value.is_object()) {
JSObjectRef js_object = JSObjectMake(m_context, NULL, NULL);
for (json::iterator it = value.begin(); it != value.end(); ++it) {
JSValueRef js_value = deserialize_json_value(it.value());
JSStringRef js_key = JSStringCreateWithUTF8CString(it.key().c_str());
JSObjectSetProperty(m_context, js_object, js_key, js_value, 0, NULL);
JSStringRelease(js_key);
}
return js_object;
}
assert(0);
}