realm-js/lib/browser/index.js
Scott Kyle e8cd20d7bb Use RPC callback mechanism for writes and listeners
The callbacks are stored by their id in the RPCServer so they are properly uniqued. This prevents the same callback from being added multiple times as a change listener.
2016-05-02 12:41:53 -07:00

176 lines
5.3 KiB
JavaScript

////////////////////////////////////////////////////////////////////////////
//
// 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.
//
////////////////////////////////////////////////////////////////////////////
'use strict';
import { NativeModules } from 'react-native';
import { keys, propTypes, objectTypes } from './constants';
import Collection, * as collections from './collections';
import List, { createList } from './lists';
import Results, { createResults } from './results';
import RealmObject, { createObject, registerConstructors, typeForConstructor } from './objects';
import * as rpc from './rpc';
import * as util from './util';
const {debugHosts, debugPort} = NativeModules.Realm;
rpc.registerTypeConverter(objectTypes.LIST, createList);
rpc.registerTypeConverter(objectTypes.RESULTS, createResults);
rpc.registerTypeConverter(objectTypes.OBJECT, createObject);
rpc.registerTypeConverter(objectTypes.REALM, createRealm);
function createRealm(_, info) {
let realm = Object.create(Realm.prototype);
setupRealm(realm, info.id);
return realm;
}
function setupRealm(realm, realmId) {
realm[keys.id] = realmId;
realm[keys.realm] = realmId;
realm[keys.type] = objectTypes.REALM;
[
'path',
'readOnly',
'schema',
'schemaVersion',
].forEach((name) => {
Object.defineProperty(realm, name, {get: util.getterForProperty(name)});
});
}
export default class Realm {
constructor(config) {
let schemas = typeof config == 'object' && config.schema;
let constructors = {};
for (let i = 0, len = schemas ? schemas.length : 0; i < len; i++) {
let item = schemas[i];
if (typeof item == 'function') {
let schema = item.schema;
if (!schema || typeof schema != 'object') {
throw new Error("Realm object constructor must have 'schema' property");
}
let {name, properties} = schema;
if (!name || typeof name != 'string') {
throw new Error("Realm object schema must have 'name' property");
} else if (!properties || typeof properties != 'object') {
throw new Error("Realm object schema must have 'properties' property");
}
schemas.splice(i, 1, schema);
constructors[name] = item;
}
}
let realmId = rpc.createRealm(Array.from(arguments));
registerConstructors(realmId, constructors);
setupRealm(this, realmId);
}
create(type, ...args) {
if (typeof type == 'function') {
type = typeForConstructor(this[keys.realm], type);
}
let method = util.createMethod(objectTypes.REALM, 'create', true);
return method.apply(this, [type, ...args]);
}
objects(type, ...args) {
if (typeof type == 'function') {
type = typeForConstructor(this[keys.realm], type);
}
let method = util.createMethod(objectTypes.REALM, 'objects');
return method.apply(this, [type, ...args]);
}
}
// Non-mutating methods:
util.createMethods(Realm.prototype, objectTypes.REALM, [
'addListener',
'removeListener',
'removeAllListeners',
'close',
]);
// Mutating methods:
util.createMethods(Realm.prototype, objectTypes.REALM, [
'delete',
'deleteAll',
'write',
], true);
Object.defineProperties(Realm, {
Collection: {
value: Collection,
},
List: {
value: List,
},
Results: {
value: Results,
},
Object: {
value: RealmObject,
},
defaultPath: {
get: util.getterForProperty('defaultPath'),
set: util.setterForProperty('defaultPath'),
},
schemaVersion: {
value: function(path, encryptionKey) {
return rpc.callMethod(undefined, Realm[keys.id], 'schemaVersion', Array.from(arguments));
}
},
clearTestState: {
value: function() {
collections.clearMutationListeners();
rpc.clearTestState();
},
},
});
for (let i = 0, len = debugHosts.length; i < len; i++) {
try {
// The session ID refers to the Realm constructor object in the RPC server.
Realm[keys.id] = rpc.createSession(debugHosts[i] + ':' + debugPort);
break;
} catch (e) {
// Only throw exception after all hosts have been tried.
if (i < len - 1) {
continue;
}
// Log the original exception for debugging purposes.
console.error(e);
throw new Error(
'Realm failed to connect to the embedded debug server inside the app. ' +
'If attempting to use Chrome debugging from a device, ensure the device is ' +
'reachable on the same network as this machine.'
);
}
}