convert more of Realm

This commit is contained in:
Ari Lazier 2016-03-29 13:36:01 -07:00
parent 9626842f8e
commit b4990fbbff
9 changed files with 734 additions and 118 deletions

View File

@ -125,6 +125,7 @@
02A3C7A41BC4341500B1A7BE /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; }; 02A3C7A41BC4341500B1A7BE /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; };
02AFE5871CA9B23400953DA3 /* jsc_list.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = jsc_list.cpp; path = jsc/jsc_list.cpp; sourceTree = "<group>"; }; 02AFE5871CA9B23400953DA3 /* jsc_list.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = jsc_list.cpp; path = jsc/jsc_list.cpp; sourceTree = "<group>"; };
02AFE5881CA9B23400953DA3 /* jsc_list.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = jsc_list.hpp; path = jsc/jsc_list.hpp; sourceTree = "<group>"; }; 02AFE5881CA9B23400953DA3 /* jsc_list.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = jsc_list.hpp; path = jsc/jsc_list.hpp; sourceTree = "<group>"; };
02AFE5B11CAB133500953DA3 /* js_compat.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = js_compat.hpp; path = jsc/js_compat.hpp; sourceTree = "<group>"; };
02B58CB11AE99CEC009B348C /* RealmJS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RealmJS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 02B58CB11AE99CEC009B348C /* RealmJS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RealmJS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
02B58CBC1AE99CEC009B348C /* RealmJSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RealmJSTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 02B58CBC1AE99CEC009B348C /* RealmJSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RealmJSTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
02B58CCD1AE99D4D009B348C /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; 02B58CCD1AE99D4D009B348C /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
@ -259,6 +260,7 @@
0290480C1C0428DF00ABDED4 /* js_schema.hpp */, 0290480C1C0428DF00ABDED4 /* js_schema.hpp */,
0290480D1C0428DF00ABDED4 /* js_util.cpp */, 0290480D1C0428DF00ABDED4 /* js_util.cpp */,
0290480E1C0428DF00ABDED4 /* js_util.hpp */, 0290480E1C0428DF00ABDED4 /* js_util.hpp */,
02AFE5B11CAB133500953DA3 /* js_compat.hpp */,
02AFE5871CA9B23400953DA3 /* jsc_list.cpp */, 02AFE5871CA9B23400953DA3 /* jsc_list.cpp */,
02AFE5881CA9B23400953DA3 /* jsc_list.hpp */, 02AFE5881CA9B23400953DA3 /* jsc_list.hpp */,
029048351C042A3C00ABDED4 /* platform.hpp */, 029048351C042A3C00ABDED4 /* platform.hpp */,

View File

@ -1,68 +0,0 @@
////////////////////////////////////////////////////////////////////////////
//
// 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.
//
////////////////////////////////////////////////////////////////////////////
#pragma once
#include "types.hpp"
#include <string>
namespace realm {
namespace js {
void *GetInternal(Types::ObjectType jsObject) {
return JSObjectGetPrivate(jsObject);
}
std::string StringForStringType(Types::StringType jsString);
std::string StringForValueType(Types::ContextType ctx, Types::ValueType value);
std::string ValidatedStringForValueType(Types::ContextType ctx, Types::ValueType value, const char * name = nullptr);
bool ValidatedBooleanForValueType(Types::ContextType ctx, Types::ValueType value, const char * name = nullptr);
Types::StringType StringTypeForString(const std::string &str);
Types::ValueType ValueTypeForString(Types::ContextType ctx, const std::string &str);
bool IsValueTypeArray(Types::ContextType ctx, Types::ValueType value);
bool IsValueTypeArrayBuffer(Types::ContextType ctx, Types::ValueType value);
bool IsValueTypeDate(Types::ContextType ctx, Types::ValueType value);
Types::ObjectType ValidatedValueTypeToObject(Types::ContextType ctx, Types::ValueType value, const char *message = NULL);
Types::ObjectType ValidatedValueTypeToDate(Types::ContextType ctx, Types::ValueType value, const char *message = NULL);
Types::ObjectType ValidatedValueTypeToFunction(Types::ContextType ctx, Types::ValueType value, const char *message = NULL);
double ValidatedValueTypeToNumber(Types::ContextType ctx, Types::ValueType value);
Types::ValueType ValidatedPropertyValue(Types::ContextType ctx, Types::ObjectType object, Types::StringType property);
Types::ValueType ValidatedPropertyAtIndex(Types::ContextType ctx, Types::ObjectType object, unsigned int index);
Types::ObjectType ValidatedObjectProperty(Types::ContextType ctx, Types::ObjectType object, Types::StringType property, const char *err = NULL);
Types::ObjectType ValidatedObjectAtIndex(Types::ContextType ctx, Types::ObjectType object, unsigned int index);
std::string ValidatedStringProperty(Types::ContextType ctx, Types::ObjectType object, Types::StringType property);
bool ValidatedBooleanProperty(Types::ContextType ctx, Types::ObjectType object, Types::StringType property, const char *err = NULL);
size_t ValidatedListLength(Types::ContextType ctx, Types::ObjectType object);
void ValidatedSetProperty(Types::ContextType ctx, Types::ObjectType object, Types::StringType propertyName, Types::ValueType value, JSPropertyAttributes attributes = 0);
bool IsValueTypeIsObject(Types::ContextType ctx, Types::ValueType value);
bool IsValueTypeObjectOfType(Types::ContextType ctx, Types::ValueType value, Types::StringType type);
bool ObjectTypeHasProperty(Types::ContextType ctx, Types::ObjectType object, Types::StringType propName);
template<typename T>
void SetReturnNumber(Types::ContextType ctx, Types::ValueType &returnObject, T number);
void SetReturnArray(Types::ContextType ctx, size_t count, const Types::ValueType *objects, Types::ValueType &returnObject);\
void SetReturnUndefined(Types::ContextType ctx, Types::ValueType &returnObject);
void SetException(Types::ContextType ctx, Types::ValueType * &exceptionObject, std::exception &exception);
}}

View File

@ -35,8 +35,8 @@
using RJSAccessor = realm::NativeAccessor<JSValueRef, JSContextRef>; using RJSAccessor = realm::NativeAccessor<JSValueRef, JSContextRef>;
using namespace realm; using namespace realm;
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType> template<typename ContextType, typename ObjectType, typename ValueType, typename ReturnType, typename ExceptionType>
void ListPush(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) { void ListPush(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject, ExceptionType &exceptionObject) {
try { try {
List *list = RJSGetInternal<List *>(thisObject); List *list = RJSGetInternal<List *>(thisObject);
RJSValidateArgumentCountIsAtLeast(argumentCount, 1); RJSValidateArgumentCountIsAtLeast(argumentCount, 1);
@ -50,8 +50,8 @@ void ListPush(ContextType ctx, ThisType thisObject, size_t argumentCount, const
} }
} }
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType> template<typename ContextType, typename ObjectType, typename ValueType, typename ReturnType, typename ExceptionType>
void ListPop(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) { void ListPop(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject, ExceptionType &exceptionObject) {
try { try {
List *list = RJSGetInternal<List *>(thisObject); List *list = RJSGetInternal<List *>(thisObject);
RJSValidateArgumentCount(argumentCount, 0); RJSValidateArgumentCount(argumentCount, 0);
@ -73,8 +73,8 @@ void ListPop(ContextType ctx, ThisType thisObject, size_t argumentCount, const A
} }
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType> template<typename ContextType, typename ObjectType, typename ValueType, typename ReturnType, typename ExceptionType>
void ListUnshift(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) { void ListUnshift(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject, ExceptionType &exceptionObject) {
try { try {
List *list = RJSGetInternal<List *>(thisObject); List *list = RJSGetInternal<List *>(thisObject);
RJSValidateArgumentCountIsAtLeast(argumentCount, 1); RJSValidateArgumentCountIsAtLeast(argumentCount, 1);
@ -88,8 +88,8 @@ void ListUnshift(ContextType ctx, ThisType thisObject, size_t argumentCount, con
} }
} }
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType> template<typename ContextType, typename ObjectType, typename ValueType, typename ReturnType, typename ExceptionType>
void ListShift(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) { void ListShift(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject, ExceptionType &exceptionObject) {
try { try {
List *list = RJSGetInternal<List *>(thisObject); List *list = RJSGetInternal<List *>(thisObject);
RJSValidateArgumentCount(argumentCount, 0); RJSValidateArgumentCount(argumentCount, 0);
@ -107,8 +107,8 @@ void ListShift(ContextType ctx, ThisType thisObject, size_t argumentCount, const
} }
} }
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType> template<typename ContextType, typename ObjectType, typename ValueType, typename ReturnType, typename ExceptionType>
void ListSplice(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) { void ListSplice(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject, ExceptionType &exceptionObject) {
try { try {
List *list = RJSGetInternal<List *>(thisObject); List *list = RJSGetInternal<List *>(thisObject);
size_t size = list->size(); size_t size = list->size();
@ -144,8 +144,8 @@ void ListSplice(ContextType ctx, ThisType thisObject, size_t argumentCount, cons
} }
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType> template<typename ContextType, typename ObjectType, typename ValueType, typename ReturnType, typename ExceptionType>
void ListStaticResults(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) { void ListStaticResults(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject, ExceptionType &exceptionObject) {
try { try {
List *list = RJSGetInternal<List *>(thisObject); List *list = RJSGetInternal<List *>(thisObject);
RJSValidateArgumentCount(argumentCount, 0); RJSValidateArgumentCount(argumentCount, 0);
@ -156,8 +156,8 @@ void ListStaticResults(ContextType ctx, ThisType thisObject, size_t argumentCoun
} }
} }
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType> template<typename ContextType, typename ObjectType, typename ValueType, typename ReturnType, typename ExceptionType>
void ListFiltered(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) { void ListFiltered(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject, ExceptionType &exceptionObject) {
try { try {
List *list = RJSGetInternal<List *>(thisObject); List *list = RJSGetInternal<List *>(thisObject);
RJSValidateArgumentCountIsAtLeast(argumentCount, 1); RJSValidateArgumentCountIsAtLeast(argumentCount, 1);
@ -170,8 +170,8 @@ void ListFiltered(ContextType ctx, ThisType thisObject, size_t argumentCount, co
} }
} }
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType> template<typename ContextType, typename ObjectType, typename ValueType, typename ReturnType, typename ExceptionType>
void ListSorted(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) { void ListSorted(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject, ExceptionType &exceptionObject) {
try { try {
List *list = RJSGetInternal<List *>(thisObject); List *list = RJSGetInternal<List *>(thisObject);
RJSValidateArgumentRange(argumentCount, 1, 2); RJSValidateArgumentRange(argumentCount, 1, 2);

View File

@ -238,34 +238,34 @@ static const JSStaticValue RealmStaticProperties[] = {
{NULL, NULL} {NULL, NULL}
}; };
JSValueRef RealmSchemaVersion(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) { template<typename ContextType, typename ObjectType, typename ValueType, typename ReturnType, typename ExceptionType>
void RealmSchemaVersion(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject, ExceptionType &exceptionObject) {
try { try {
RJSValidateArgumentRange(argumentCount, 1, 2); RJSValidateArgumentRange(argumentCount, 1, 2);
Realm::Config config; Realm::Config config;
config.path = RJSNormalizePath(RJSValidatedStringForValue(ctx, arguments[0])); config.path = RJSNormalizePath(RJSValidatedStringForValue(ctx, arguments[0]));
if (argumentCount == 2) { if (argumentCount == 2) {
JSValueRef encryptionKeyValue = arguments[1]; auto encryptionKeyValue = arguments[1];
std::string encryptionKey = RJSAccessor::to_binary(ctx, encryptionKeyValue); std::string encryptionKey = RJSAccessor::to_binary(ctx, encryptionKeyValue);
config.encryption_key = std::vector<char>(encryptionKey.begin(), encryptionKey.end()); config.encryption_key = std::vector<char>(encryptionKey.begin(), encryptionKey.end());
} }
auto version = Realm::get_schema_version(config); auto version = Realm::get_schema_version(config);
if (version == ObjectStore::NotVersioned) { if (version == ObjectStore::NotVersioned) {
return JSValueMakeNumber(ctx, -1); RJSSetReturnNumber(ctx, returnObject, -1);
} }
else { else {
return JSValueMakeNumber(ctx, version); RJSSetReturnNumber(ctx, returnObject, version);
} }
} }
catch (std::exception &exp) { catch (std::exception &exp) {
if (jsException) { RJSSetException(ctx, exceptionObject, exp);
*jsException = RJSMakeError(ctx, exp);
}
} }
return NULL;
} }
WRAP_METHOD(RealmSchemaVersion)
static const JSStaticFunction RealmConstructorFuncs[] = { static const JSStaticFunction RealmConstructorFuncs[] = {
{"schemaVersion", RealmSchemaVersion, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, {"schemaVersion", RealmSchemaVersion, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{NULL, NULL}, {NULL, NULL},
@ -311,8 +311,8 @@ std::string RJSValidatedObjectTypeForValue(SharedRealm &realm, JSContextRef ctx,
return RJSValidatedStringForValue(ctx, value, "objectType"); return RJSValidatedStringForValue(ctx, value, "objectType");
} }
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType> template<typename ContextType, typename ObjectType, typename ValueType, typename ReturnType, typename ExceptionType>
void RealmObjects(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) { try { void RealmObjects(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject, ExceptionType &exceptionObject) { try {
RJSValidateArgumentCount(argumentCount, 1); RJSValidateArgumentCount(argumentCount, 1);
SharedRealm sharedRealm = *RJSGetInternal<SharedRealm *>(thisObject); SharedRealm sharedRealm = *RJSGetInternal<SharedRealm *>(thisObject);
@ -324,8 +324,9 @@ void RealmObjects(ContextType ctx, ThisType thisObject, size_t argumentCount, co
} }
} }
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType> template<typename ContextType, typename ObjectType, typename ValueType, typename ReturnType, typename ExceptionType>
void RealmCreateObject(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) { try { void RealmCreateObject(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject, ExceptionType &exceptionObject) {
try {
RJSValidateArgumentRange(argumentCount, 2, 3); RJSValidateArgumentRange(argumentCount, 2, 3);
SharedRealm sharedRealm = *RJSGetInternal<SharedRealm *>(thisObject); SharedRealm sharedRealm = *RJSGetInternal<SharedRealm *>(thisObject);
@ -337,7 +338,7 @@ void RealmCreateObject(ContextType ctx, ThisType thisObject, size_t argumentCoun
throw std::runtime_error("Object type '" + className + "' not found in schema."); throw std::runtime_error("Object type '" + className + "' not found in schema.");
} }
JSObjectRef object = RJSValidatedValueToObject(ctx, arguments[1]); auto object = RJSValidatedValueToObject(ctx, arguments[1]);
if (RJSIsValueArray(ctx, arguments[1])) { if (RJSIsValueArray(ctx, arguments[1])) {
object = RJSDictForPropertyArray(ctx, *object_schema, object); object = RJSDictForPropertyArray(ctx, *object_schema, object);
} }
@ -347,15 +348,15 @@ void RealmCreateObject(ContextType ctx, ThisType thisObject, size_t argumentCoun
update = RJSValidatedValueToBoolean(ctx, arguments[2]); update = RJSValidatedValueToBoolean(ctx, arguments[2]);
} }
returnObject = RJSObjectCreate(ctx, Object::create<JSValueRef>(ctx, sharedRealm, *object_schema, object, update)); returnObject = RJSObjectCreate(ctx, Object::create<ValueType>(ctx, sharedRealm, *object_schema, object, update));
} }
catch (std::exception &exp) { catch (std::exception &exp) {
RJSSetException(ctx, exceptionObject, exp); RJSSetException(ctx, exceptionObject, exp);
} }
} }
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType> template<typename ContextType, typename ObjectType, typename ValueType, typename ReturnType, typename ExceptionType>
void RealmDelete(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) { try { void RealmDelete(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject, ExceptionType &exceptionObject) { try {
RJSValidateArgumentCount(argumentCount, 1); RJSValidateArgumentCount(argumentCount, 1);
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject); SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
@ -363,7 +364,7 @@ void RealmDelete(ContextType ctx, ThisType thisObject, size_t argumentCount, con
throw std::runtime_error("Can only delete objects within a transaction."); throw std::runtime_error("Can only delete objects within a transaction.");
} }
JSObjectRef arg = RJSValidatedValueToObject(ctx, arguments[0]); auto arg = RJSValidatedValueToObject(ctx, arguments[0]);
if (RJSValueIsObjectOfClass(ctx, arg, RJSObjectClass())) { if (RJSValueIsObjectOfClass(ctx, arg, RJSObjectClass())) {
Object *object = RJSGetInternal<Object *>(arg); Object *object = RJSGetInternal<Object *>(arg);
realm::TableRef table = ObjectStore::table_for_object_type(realm->read_group(), object->get_object_schema().name); realm::TableRef table = ObjectStore::table_for_object_type(realm->read_group(), object->get_object_schema().name);
@ -373,7 +374,7 @@ void RealmDelete(ContextType ctx, ThisType thisObject, size_t argumentCount, con
size_t length = RJSValidatedListLength(ctx, arg); size_t length = RJSValidatedListLength(ctx, arg);
for (long i = length-1; i >= 0; i--) { for (long i = length-1; i >= 0; i--) {
JSObjectRef jsObject = RJSValidatedValueToObject(ctx, RJSValidatedObjectAtIndex(ctx, arg, (unsigned int)i)); JSObjectRef jsObject = RJSValidatedValueToObject(ctx, RJSValidatedObjectAtIndex(ctx, arg, (unsigned int)i));
if (!JSValueIsObjectOfClass(ctx, jsObject, RJSObjectClass())) { if (!RJSValueIsObjectOfClass(ctx, jsObject, RJSObjectClass())) {
throw std::runtime_error("Argument to 'delete' must be a Realm object or a collection of Realm objects."); throw std::runtime_error("Argument to 'delete' must be a Realm object or a collection of Realm objects.");
} }
@ -399,8 +400,8 @@ void RealmDelete(ContextType ctx, ThisType thisObject, size_t argumentCount, con
} }
} }
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType> template<typename ContextType, typename ObjectType, typename ValueType, typename ReturnType, typename ExceptionType>
void RealmDeleteAll(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) { try { void RealmDeleteAll(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject, ExceptionType &exceptionObject) { try {
RJSValidateArgumentCount(argumentCount, 0); RJSValidateArgumentCount(argumentCount, 0);
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject); SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
@ -418,13 +419,13 @@ void RealmDeleteAll(ContextType ctx, ThisType thisObject, size_t argumentCount,
} }
} }
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType> template<typename ContextType, typename ObjectType, typename ValueType, typename ReturnType, typename ExceptionType>
void RealmWrite(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) { void RealmWrite(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject, ExceptionType &exceptionObject) {
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject); SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
try { try {
RJSValidateArgumentCount(argumentCount, 1); RJSValidateArgumentCount(argumentCount, 1);
JSObjectRef object = RJSValidatedValueToFunction(ctx, arguments[0]); auto object = RJSValidatedValueToFunction(ctx, arguments[0]);
realm->begin_transaction(); realm->begin_transaction();
RJSCallFunction(ctx, object, thisObject, 0, NULL); RJSCallFunction(ctx, object, thisObject, 0, NULL);
realm->commit_transaction(); realm->commit_transaction();
@ -445,11 +446,11 @@ std::string RJSValidatedNotificationName(JSContextRef ctx, JSValueRef value) {
return name; return name;
} }
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType> template<typename ContextType, typename ObjectType, typename ValueType, typename ReturnType, typename ExceptionType>
void RealmAddListener(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) { try { void RealmAddListener(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject, ExceptionType &exceptionObject) { try {
RJSValidateArgumentCount(argumentCount, 2); RJSValidateArgumentCount(argumentCount, 2);
__unused std::string name = RJSValidatedNotificationName(ctx, arguments[0]); __unused std::string name = RJSValidatedNotificationName(ctx, arguments[0]);
JSObjectRef callback = RJSValidatedValueToFunction(ctx, arguments[1]); auto callback = RJSValidatedValueToFunction(ctx, arguments[1]);
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject); SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
static_cast<RJSRealmDelegate *>(realm->m_binding_context.get())->add_notification(callback); static_cast<RJSRealmDelegate *>(realm->m_binding_context.get())->add_notification(callback);
@ -459,11 +460,11 @@ void RealmAddListener(ContextType ctx, ThisType thisObject, size_t argumentCount
} }
} }
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType> template<typename ContextType, typename ObjectType, typename ValueType, typename ReturnType, typename ExceptionType>
void RealmRemoveListener(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) { try { void RealmRemoveListener(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject, ExceptionType &exceptionObject) { try {
RJSValidateArgumentCount(argumentCount, 2); RJSValidateArgumentCount(argumentCount, 2);
__unused std::string name = RJSValidatedNotificationName(ctx, arguments[0]); __unused std::string name = RJSValidatedNotificationName(ctx, arguments[0]);
JSObjectRef callback = RJSValidatedValueToFunction(ctx, arguments[1]); auto callback = RJSValidatedValueToFunction(ctx, arguments[1]);
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject); SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
static_cast<RJSRealmDelegate *>(realm->m_binding_context.get())->remove_notification(callback); static_cast<RJSRealmDelegate *>(realm->m_binding_context.get())->remove_notification(callback);
@ -473,8 +474,8 @@ void RealmRemoveListener(ContextType ctx, ThisType thisObject, size_t argumentCo
} }
} }
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType> template<typename ContextType, typename ObjectType, typename ValueType, typename ReturnType, typename ExceptionType>
void RealmRemoveAllListeners(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) { try { void RealmRemoveAllListeners(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject, ExceptionType &exceptionObject) { try {
RJSValidateArgumentRange(argumentCount, 0, 1); RJSValidateArgumentRange(argumentCount, 0, 1);
if (argumentCount) { if (argumentCount) {
RJSValidatedNotificationName(ctx, arguments[0]); RJSValidatedNotificationName(ctx, arguments[0]);
@ -488,8 +489,8 @@ void RealmRemoveAllListeners(ContextType ctx, ThisType thisObject, size_t argume
} }
} }
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType> template<typename ContextType, typename ObjectType, typename ValueType, typename ReturnType, typename ExceptionType>
void RealmClose(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) { try { void RealmClose(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject, ExceptionType &exceptionObject) { try {
RJSValidateArgumentCount(argumentCount, 0); RJSValidateArgumentCount(argumentCount, 0);
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject); SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
realm->close(); realm->close();

View File

@ -29,6 +29,8 @@
#include <stdexcept> #include <stdexcept>
#include <cmath> #include <cmath>
#include "property.hpp" #include "property.hpp"
#include "js_compat.hpp"
#include "schema.hpp" #include "schema.hpp"
#define WRAP_METHOD(METHOD_NAME) \ #define WRAP_METHOD(METHOD_NAME) \
@ -38,7 +40,6 @@ JSValueRef METHOD_NAME(JSContextRef ctx, JSObjectRef function, JSObjectRef thisO
return returnObject; \ return returnObject; \
} }
template<typename T> template<typename T>
inline void RJSFinalize(JSObjectRef object) { inline void RJSFinalize(JSObjectRef object) {
delete static_cast<T>(JSObjectGetPrivate(object)); delete static_cast<T>(JSObjectGetPrivate(object));
@ -314,3 +315,4 @@ static void RJSCallFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef
static bool RJSValueIsObjectOfClass(JSContextRef ctx, JSValueRef value, JSClassRef jsClass) { static bool RJSValueIsObjectOfClass(JSContextRef ctx, JSValueRef value, JSClassRef jsClass) {
return JSValueIsObjectOfClass(ctx, value, jsClass); return JSValueIsObjectOfClass(ctx, value, jsClass);
} }

34
src/jsc/js_compat.hpp Normal file
View File

@ -0,0 +1,34 @@
////////////////////////////////////////////////////////////////////////////
//
// 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.
//
////////////////////////////////////////////////////////////////////////////
#pragma once
#include "types.hpp"
#include <string>
namespace realm {
namespace js {
static bool ValueIsUndefined(Types::Context ctx, Types::Value value) { return JSValueIsUndefined(ctx, value); }
static bool ValueIsNull(Types::Context ctx, Types::Value value) { return JSValueIsNull(ctx, value); }
static bool ValueIsBoolean(Types::Context ctx, Types::Value value) { return JSValueIsBoolean(ctx, value); }
static bool ValueIsNumber(Types::Context ctx, Types::Value value) { return JSValueIsNumber(ctx, value); }
static bool ValueIsString(Types::Context ctx, Types::Value value) { return JSValueIsString(ctx, value); }
static bool ValueIsObject(Types::Context ctx, Types::Value value) { return JSValueIsObject(ctx, value); }
}}

572
src/jsc/js_realm.cpp Normal file
View File

@ -0,0 +1,572 @@
////////////////////////////////////////////////////////////////////////////
//
// 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.
//
////////////////////////////////////////////////////////////////////////////
#include "js_realm.hpp"
#include "js_object.hpp"
#include "js_results.hpp"
#include "jsc_list.hpp"
#include "js_schema.hpp"
#include "platform.hpp"
#include "shared_realm.hpp"
#include "impl/realm_coordinator.hpp"
#include "object_accessor.hpp"
#include "binding_context.hpp"
#include <set>
#include <cassert>
using namespace realm;
using RJSAccessor = realm::NativeAccessor<JSValueRef, JSContextRef>;
class RJSRealmDelegate : public BindingContext {
public:
virtual void changes_available() {
assert(0);
}
virtual void did_change(std::vector<ObserverState> const& observers, std::vector<void*> const& invalidated) {
notify("change");
}
virtual std::vector<ObserverState> get_observed_rows() {
return std::vector<ObserverState>();
}
virtual void will_change(std::vector<ObserverState> const& observers,
std::vector<void*> const& invalidated) {}
RJSRealmDelegate(WeakRealm realm, JSGlobalContextRef ctx) : m_context(ctx), m_realm(realm) {
JSGlobalContextRetain(m_context);
}
~RJSRealmDelegate() {
remove_all_notifications();
for (auto constructor : m_constructors) {
JSValueUnprotect(m_context, constructor.second);
}
for (auto objectDefaults : m_defaults) {
for (auto value : objectDefaults.second) {
JSValueUnprotect(m_context, value.second);
}
}
JSGlobalContextRelease(m_context);
}
void add_notification(JSObjectRef notification) {
if (!m_notifications.count(notification)) {
JSValueProtect(m_context, notification);
m_notifications.insert(notification);
}
}
void remove_notification(JSObjectRef notification) {
if (m_notifications.count(notification)) {
JSValueUnprotect(m_context, notification);
m_notifications.erase(notification);
}
}
void remove_all_notifications() {
for (auto notification : m_notifications) {
JSValueUnprotect(m_context, notification);
}
m_notifications.clear();
}
std::map<std::string, ObjectDefaults> m_defaults;
std::map<std::string, JSObjectRef> m_constructors;
private:
std::set<JSObjectRef> m_notifications;
JSGlobalContextRef m_context;
WeakRealm m_realm;
void notify(const char *notification_name) {
JSValueRef arguments[2];
SharedRealm realm = m_realm.lock();
if (!realm) {
throw std::runtime_error("Realm no longer exists");
}
JSObjectRef realm_object = RJSWrapObject<SharedRealm *>(m_context, RJSRealmClass(), new SharedRealm(realm));
arguments[0] = realm_object;
arguments[1] = RJSValueForString(m_context, notification_name);
for (auto callback : m_notifications) {
JSValueRef ex = NULL;
JSObjectCallAsFunction(m_context, callback, realm_object, 2, arguments, &ex);
if (ex) {
throw RJSException(m_context, ex);
}
}
}
};
std::map<std::string, ObjectDefaults> &RJSDefaults(Realm *realm) {
return static_cast<RJSRealmDelegate *>(realm->m_binding_context.get())->m_defaults;
}
std::map<std::string, JSObjectRef> &RJSConstructors(Realm *realm) {
return static_cast<RJSRealmDelegate *>(realm->m_binding_context.get())->m_constructors;
}
// static std::string s_defaultPath = realm::default_realm_file_directory() + "/default.realm";
static std::string s_defaultPath = "";
std::string RJSDefaultPath() {
if (s_defaultPath.size() == 0) {
s_defaultPath = realm::default_realm_file_directory() + "/default.realm";
}
return s_defaultPath;
}
void RJSSetDefaultPath(std::string path) {
s_defaultPath = path;
}
static JSValueRef GetDefaultPath(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* jsException) {
return RJSValueForString(ctx, s_defaultPath);
}
static bool SetDefaultPath(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* jsException) {
try {
s_defaultPath = RJSValidatedStringForValue(ctx, value, "defaultPath");
}
catch (std::exception &ex) {
if (jsException) {
*jsException = RJSMakeError(ctx, ex);
}
}
return true;
}
inline std::string RJSNormalizePath(std::string path) {
if (path.size() && path[0] != '/') {
return default_realm_file_directory() + "/" + path;
}
return path;
}
JSObjectRef RealmConstructor(JSContextRef ctx, JSObjectRef constructor, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
try {
Realm::Config config;
std::map<std::string, realm::ObjectDefaults> defaults;
std::map<std::string, JSObjectRef> constructors;
if (argumentCount == 0) {
config.path = RJSDefaultPath();
}
else if (argumentCount == 1) {
JSValueRef value = arguments[0];
if (JSValueIsString(ctx, value)) {
config.path = RJSValidatedStringForValue(ctx, value, "path");
}
else if (JSValueIsObject(ctx, value)) {
JSObjectRef object = RJSValidatedValueToObject(ctx, value);
static JSStringRef pathString = JSStringCreateWithUTF8CString("path");
JSValueRef pathValue = RJSValidatedPropertyValue(ctx, object, pathString);
if (!JSValueIsUndefined(ctx, pathValue)) {
config.path = RJSValidatedStringForValue(ctx, pathValue, "path");
}
else {
config.path = RJSDefaultPath();
}
static JSStringRef schemaString = JSStringCreateWithUTF8CString("schema");
JSValueRef schemaValue = RJSValidatedPropertyValue(ctx, object, schemaString);
if (!JSValueIsUndefined(ctx, schemaValue)) {
config.schema.reset(new Schema(RJSParseSchema(ctx, RJSValidatedValueToObject(ctx, schemaValue), defaults, constructors)));
}
static JSStringRef schemaVersionString = JSStringCreateWithUTF8CString("schemaVersion");
JSValueRef versionValue = RJSValidatedPropertyValue(ctx, object, schemaVersionString);
if (JSValueIsNumber(ctx, versionValue)) {
config.schema_version = RJSValidatedValueToNumber(ctx, versionValue);
}
else {
config.schema_version = 0;
}
static JSStringRef encryptionKeyString = JSStringCreateWithUTF8CString("encryptionKey");
JSValueRef encryptionKeyValue = RJSValidatedPropertyValue(ctx, object, encryptionKeyString);
if (!JSValueIsUndefined(ctx, encryptionKeyValue)) {
std::string encryptionKey = RJSAccessor::to_binary(ctx, encryptionKeyValue);
config.encryption_key = std::vector<char>(encryptionKey.begin(), encryptionKey.end());;
}
}
}
else {
*jsException = RJSMakeError(ctx, "Invalid arguments when constructing 'Realm'");
return NULL;
}
config.path = RJSNormalizePath(config.path);
ensure_directory_exists_for_file(config.path);
SharedRealm realm = Realm::get_shared_realm(config);
if (!realm->m_binding_context) {
realm->m_binding_context.reset(new RJSRealmDelegate(realm, JSContextGetGlobalContext(ctx)));
}
RJSDefaults(realm.get()) = defaults;
RJSConstructors(realm.get()) = constructors;
return RJSWrapObject<SharedRealm *>(ctx, RJSRealmClass(), new SharedRealm(realm));
}
catch (std::exception &ex) {
if (jsException) {
*jsException = RJSMakeError(ctx, ex);
}
return NULL;
}
}
bool RealmHasInstance(JSContextRef ctx, JSObjectRef constructor, JSValueRef value, JSValueRef* exception) {
return JSValueIsObjectOfClass(ctx, value, RJSRealmClass());
}
static const JSStaticValue RealmStaticProperties[] = {
{"defaultPath", GetDefaultPath, SetDefaultPath, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{NULL, NULL}
};
JSValueRef RealmSchemaVersion(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
try {
RJSValidateArgumentRange(argumentCount, 1, 2);
Realm::Config config;
config.path = RJSNormalizePath(RJSValidatedStringForValue(ctx, arguments[0]));
if (argumentCount == 2) {
JSValueRef encryptionKeyValue = arguments[1];
std::string encryptionKey = RJSAccessor::to_binary(ctx, encryptionKeyValue);
config.encryption_key = std::vector<char>(encryptionKey.begin(), encryptionKey.end());
}
auto version = Realm::get_schema_version(config);
if (version == ObjectStore::NotVersioned) {
return JSValueMakeNumber(ctx, -1);
}
else {
return JSValueMakeNumber(ctx, version);
}
}
catch (std::exception &exp) {
if (jsException) {
*jsException = RJSMakeError(ctx, exp);
}
}
return NULL;
}
static const JSStaticFunction RealmConstructorFuncs[] = {
{"schemaVersion", RealmSchemaVersion, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{NULL, NULL},
};
JSClassRef RJSRealmConstructorClass() {
JSClassDefinition realmConstructorDefinition = kJSClassDefinitionEmpty;
realmConstructorDefinition.attributes = kJSClassAttributeNoAutomaticPrototype;
realmConstructorDefinition.className = "RealmConstructor";
realmConstructorDefinition.callAsConstructor = RealmConstructor;
realmConstructorDefinition.hasInstance = RealmHasInstance;
realmConstructorDefinition.staticValues = RealmStaticProperties;
realmConstructorDefinition.staticFunctions = RealmConstructorFuncs;
return JSClassCreate(&realmConstructorDefinition);
}
JSValueRef RealmGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) {
static JSStringRef s_pathString = JSStringCreateWithUTF8CString("path");
if (JSStringIsEqual(propertyName, s_pathString)) {
return RJSValueForString(ctx, RJSGetInternal<SharedRealm *>(object)->get()->config().path);
}
static JSStringRef s_schemaVersion = JSStringCreateWithUTF8CString("schemaVersion");
if (JSStringIsEqual(propertyName, s_schemaVersion)) {
return JSValueMakeNumber(ctx, RJSGetInternal<SharedRealm *>(object)->get()->config().schema_version);
}
return NULL;
}
std::string RJSValidatedObjectTypeForValue(SharedRealm &realm, JSContextRef ctx, JSValueRef value) {
if (JSValueIsObject(ctx, value) && JSObjectIsConstructor(ctx, (JSObjectRef)value)) {
JSObjectRef constructor = (JSObjectRef)value;
for (auto pair : RJSConstructors(realm.get())) {
if (pair.second == constructor) {
return pair.first;
}
}
throw std::runtime_error("Constructor was not registered in the schema for this Realm");
}
return RJSValidatedStringForValue(ctx, value, "objectType");
}
JSValueRef RealmObjects(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
try {
RJSValidateArgumentCount(argumentCount, 1);
SharedRealm sharedRealm = *RJSGetInternal<SharedRealm *>(thisObject);
std::string className = RJSValidatedObjectTypeForValue(sharedRealm, ctx, arguments[0]);
return RJSResultsCreate(ctx, sharedRealm, className);
}
catch (std::exception &exp) {
if (jsException) {
*jsException = RJSMakeError(ctx, exp);
}
return NULL;
}
}
JSObjectRef RJSDictForPropertyArray(JSContextRef ctx, const ObjectSchema &object_schema, JSObjectRef array) {
// copy to dictionary
if (object_schema.properties.size() != RJSValidatedListLength(ctx, array)) {
throw std::runtime_error("Array must contain values for all object properties");
}
JSValueRef exception = NULL;
JSObjectRef dict = JSObjectMake(ctx, NULL, NULL);
for (unsigned int i = 0; i < object_schema.properties.size(); i++) {
JSStringRef nameStr = JSStringCreateWithUTF8CString(object_schema.properties[i].name.c_str());
JSValueRef value = JSObjectGetPropertyAtIndex(ctx, array, i, &exception);
if (exception) {
throw RJSException(ctx, exception);
}
JSObjectSetProperty(ctx, dict, nameStr, value, kJSPropertyAttributeNone, &exception);
if (exception) {
throw RJSException(ctx, exception);
}
JSStringRelease(nameStr);
}
return dict;
}
JSValueRef RealmCreateObject(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
try {
RJSValidateArgumentRange(argumentCount, 2, 3);
SharedRealm sharedRealm = *RJSGetInternal<SharedRealm *>(thisObject);
std::string className = RJSValidatedObjectTypeForValue(sharedRealm, ctx, arguments[0]);
auto &schema = sharedRealm->config().schema;
auto object_schema = schema->find(className);
if (object_schema == schema->end()) {
*jsException = RJSMakeError(ctx, "Object type '" + className + "' not found in schema.");
return NULL;
}
JSObjectRef object = RJSValidatedValueToObject(ctx, arguments[1]);
if (RJSIsValueArray(ctx, arguments[1])) {
object = RJSDictForPropertyArray(ctx, *object_schema, object);
}
bool update = false;
if (argumentCount == 3) {
update = JSValueToBoolean(ctx, arguments[2]);
}
return RJSObjectCreate(ctx, Object::create<JSValueRef>(ctx, sharedRealm, *object_schema, object, update));
}
catch (std::exception &exp) {
if (jsException) {
*jsException = RJSMakeError(ctx, exp);
}
return NULL;
}
}
JSValueRef RealmDelete(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
try {
RJSValidateArgumentCount(argumentCount, 1);
if (RJSIsValueArray(ctx, arguments[0]) ||
JSValueIsObjectOfClass(ctx, arguments[0], RJSResultsClass()) ||
JSValueIsObjectOfClass(ctx, arguments[0], RJSListClass()))
{
JSObjectRef array = RJSValidatedValueToObject(ctx, arguments[0]);
size_t length = RJSValidatedListLength(ctx, array);
for (long i = length-1; i >= 0; i--) {
JSValueRef object = RJSValidatedObjectAtIndex(ctx, array, (unsigned int)i);
RealmDelete(ctx, function, thisObject, 1, &object, jsException);
if (*jsException) {
return NULL;
}
}
return NULL;
}
if (!JSValueIsObjectOfClass(ctx, arguments[0], RJSObjectClass())) {
throw std::runtime_error("Argument to 'delete' must be a Realm object or a collection of Realm objects.");
}
Object *object = RJSGetInternal<Object *>(RJSValidatedValueToObject(ctx, arguments[0]));
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
if (!realm->is_in_transaction()) {
throw std::runtime_error("Can only delete objects within a transaction.");
}
realm::TableRef table = ObjectStore::table_for_object_type(realm->read_group(), object->get_object_schema().name);
table->move_last_over(object->row().get_index());
return NULL;
}
catch (std::exception &exp) {
if (jsException) {
*jsException = RJSMakeError(ctx, exp);
}
return NULL;
}
}
JSValueRef RealmDeleteAll(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
try {
RJSValidateArgumentCount(argumentCount, 0);
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
if (!realm->is_in_transaction()) {
throw std::runtime_error("Can only delete objects within a transaction.");
}
for (auto objectSchema : *realm->config().schema) {
ObjectStore::table_for_object_type(realm->read_group(), objectSchema.name)->clear();
}
return NULL;
}
catch (std::exception &exp) {
if (jsException) {
*jsException = RJSMakeError(ctx, exp);
}
return NULL;
}
}
JSValueRef RealmWrite(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
try {
RJSValidateArgumentCount(argumentCount, 1);
JSObjectRef object = RJSValidatedValueToFunction(ctx, arguments[0]);
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
realm->begin_transaction();
JSObjectCallAsFunction(ctx, object, thisObject, 0, NULL, jsException);
if (*jsException) {
realm->cancel_transaction();
}
else {
realm->commit_transaction();
}
}
catch (std::exception &exp) {
if (jsException) {
*jsException = RJSMakeError(ctx, exp);
}
return NULL;
}
return NULL;
}
std::string RJSValidatedNotificationName(JSContextRef ctx, JSValueRef value) {
std::string name = RJSValidatedStringForValue(ctx, value);
if (name != "change") {
throw std::runtime_error("Only the 'change' notification name is supported.");
}
return name;
}
JSValueRef RealmAddListener(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
try {
RJSValidateArgumentCount(argumentCount, 2);
__unused std::string name = RJSValidatedNotificationName(ctx, arguments[0]);
JSObjectRef callback = RJSValidatedValueToFunction(ctx, arguments[1]);
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
static_cast<RJSRealmDelegate *>(realm->m_binding_context.get())->add_notification(callback);
return NULL;
}
catch (std::exception &exp) {
if (jsException) {
*jsException = RJSMakeError(ctx, exp);
}
return NULL;
}
}
JSValueRef RealmRemoveListener(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
try {
RJSValidateArgumentCount(argumentCount, 2);
__unused std::string name = RJSValidatedNotificationName(ctx, arguments[0]);
JSObjectRef callback = RJSValidatedValueToFunction(ctx, arguments[1]);
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
static_cast<RJSRealmDelegate *>(realm->m_binding_context.get())->remove_notification(callback);
return NULL;
}
catch (std::exception &exp) {
if (jsException) {
*jsException = RJSMakeError(ctx, exp);
}
return NULL;
}
}
JSValueRef RealmRemoveAllListeners(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
try {
RJSValidateArgumentRange(argumentCount, 0, 1);
if (argumentCount) {
RJSValidatedNotificationName(ctx, arguments[0]);
}
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
static_cast<RJSRealmDelegate *>(realm->m_binding_context.get())->remove_all_notifications();
return NULL;
}
catch (std::exception &exp) {
if (jsException) {
*jsException = RJSMakeError(ctx, exp);
}
return NULL;
}
}
JSValueRef RealmClose(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
try {
RJSValidateArgumentCount(argumentCount, 0);
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
realm->close();
}
catch (std::exception &exp) {
if (jsException) {
*jsException = RJSMakeError(ctx, exp);
}
}
return NULL;
}
static const JSStaticFunction RJSRealmFuncs[] = {
{"objects", RealmObjects, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{"create", RealmCreateObject, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{"delete", RealmDelete, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{"deleteAll", RealmDeleteAll, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{"write", RealmWrite, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{"addListener", RealmAddListener, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{"removeListener", RealmRemoveListener, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{"removeAllListeners", RealmRemoveAllListeners, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{"close", RealmClose, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{NULL, NULL},
};
JSClassRef RJSRealmClass() {
static JSClassRef s_realmClass = RJSCreateWrapperClass<SharedRealm *>("Realm", RealmGetProperty, NULL, RJSRealmFuncs);
return s_realmClass;
}

36
src/jsc/js_realm.hpp Normal file
View File

@ -0,0 +1,36 @@
////////////////////////////////////////////////////////////////////////////
//
// 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.
//
////////////////////////////////////////////////////////////////////////////
#pragma once
#include "js_util.hpp"
#include <map>
namespace realm {
class Realm;
using ObjectDefaults = std::map<std::string, JSValueRef>;
}
JSClassRef RJSRealmClass();
JSClassRef RJSRealmConstructorClass();
std::string RJSDefaultPath();
void RJSSetDefaultPath(std::string path);
std::map<std::string, realm::ObjectDefaults> &RJSDefaults(realm::Realm *realm);
std::map<std::string, JSObjectRef> &RJSConstructors(realm::Realm *realm);

37
src/jsc/types.hpp Normal file
View File

@ -0,0 +1,37 @@
////////////////////////////////////////////////////////////////////////////
//
// 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.
//
////////////////////////////////////////////////////////////////////////////
#pragma once
#include <JavaScriptCore/JSContextRef.h>
#include <JavaScriptCore/JSObjectRef.h>
#include <JavaScriptCore/JSStringRef.h>
namespace realm {
namespace js {
struct Types {
using Context = JSContextRef;
using Value = JSValueRef;
using Object = JSObjectRef;
using String = JSStringRef;
using Function = JSObjectRef;
using Return = JSValueRef;
};
}}