start refactoring realm
This commit is contained in:
parent
20bac8e2c7
commit
9626842f8e
|
@ -20,6 +20,7 @@
|
|||
029048201C0428DF00ABDED4 /* rpc.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 029048101C0428DF00ABDED4 /* rpc.hpp */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
029048371C042A3C00ABDED4 /* platform.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 029048351C042A3C00ABDED4 /* platform.hpp */; };
|
||||
0290483B1C042EE200ABDED4 /* RealmJS.h in Headers */ = {isa = PBXBuildFile; fileRef = 0290483A1C042EE200ABDED4 /* RealmJS.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
02AFE5891CA9B23400953DA3 /* jsc_list.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02AFE5871CA9B23400953DA3 /* jsc_list.cpp */; };
|
||||
02B58CCE1AE99D4D009B348C /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CCD1AE99D4D009B348C /* JavaScriptCore.framework */; };
|
||||
02D8D1F71B601984006DB49D /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CCD1AE99D4D009B348C /* JavaScriptCore.framework */; };
|
||||
02F59EBF1C88F17D007F774C /* index_set.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02F59EAF1C88F17D007F774C /* index_set.cpp */; };
|
||||
|
@ -38,7 +39,6 @@
|
|||
02F59EE31C88F2BB007F774C /* transact_log_handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02F59EDD1C88F2BB007F774C /* transact_log_handler.cpp */; };
|
||||
F61378791C18EAC5008BFC51 /* js in Resources */ = {isa = PBXBuildFile; fileRef = F61378781C18EAAC008BFC51 /* js */; };
|
||||
F63FF2C61C12469E00B3B8E0 /* js_init.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 029048011C0428DF00ABDED4 /* js_init.cpp */; };
|
||||
F63FF2C71C12469E00B3B8E0 /* js_list.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 029048031C0428DF00ABDED4 /* js_list.cpp */; };
|
||||
F63FF2C81C12469E00B3B8E0 /* js_object.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 029048051C0428DF00ABDED4 /* js_object.cpp */; };
|
||||
F63FF2C91C12469E00B3B8E0 /* js_realm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 029048071C0428DF00ABDED4 /* js_realm.cpp */; };
|
||||
F63FF2CA1C12469E00B3B8E0 /* js_results.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 029048091C0428DF00ABDED4 /* js_results.cpp */; };
|
||||
|
@ -106,7 +106,6 @@
|
|||
0270BC7B1B7D020100010E03 /* RealmJSTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = RealmJSTests.mm; path = ios/RealmJSTests.mm; sourceTree = "<group>"; };
|
||||
029048011C0428DF00ABDED4 /* js_init.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = js_init.cpp; sourceTree = "<group>"; };
|
||||
029048021C0428DF00ABDED4 /* js_init.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = js_init.h; sourceTree = "<group>"; };
|
||||
029048031C0428DF00ABDED4 /* js_list.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = js_list.cpp; sourceTree = "<group>"; };
|
||||
029048041C0428DF00ABDED4 /* js_list.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = js_list.hpp; sourceTree = "<group>"; };
|
||||
029048051C0428DF00ABDED4 /* js_object.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = js_object.cpp; sourceTree = "<group>"; };
|
||||
029048061C0428DF00ABDED4 /* js_object.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = js_object.hpp; sourceTree = "<group>"; };
|
||||
|
@ -124,6 +123,8 @@
|
|||
029048381C042A8F00ABDED4 /* platform.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = platform.mm; sourceTree = "<group>"; };
|
||||
0290483A1C042EE200ABDED4 /* RealmJS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RealmJS.h; sourceTree = "<group>"; };
|
||||
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>"; };
|
||||
02AFE5881CA9B23400953DA3 /* jsc_list.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = jsc_list.hpp; path = jsc/jsc_list.hpp; sourceTree = "<group>"; };
|
||||
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; };
|
||||
02B58CCD1AE99D4D009B348C /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
|
||||
|
@ -247,7 +248,6 @@
|
|||
029048021C0428DF00ABDED4 /* js_init.h */,
|
||||
F6CB30FC1C8EDD760070EF3F /* js_collection.cpp */,
|
||||
F6CB30FD1C8EDD760070EF3F /* js_collection.hpp */,
|
||||
029048031C0428DF00ABDED4 /* js_list.cpp */,
|
||||
029048041C0428DF00ABDED4 /* js_list.hpp */,
|
||||
029048051C0428DF00ABDED4 /* js_object.cpp */,
|
||||
029048061C0428DF00ABDED4 /* js_object.hpp */,
|
||||
|
@ -259,6 +259,8 @@
|
|||
0290480C1C0428DF00ABDED4 /* js_schema.hpp */,
|
||||
0290480D1C0428DF00ABDED4 /* js_util.cpp */,
|
||||
0290480E1C0428DF00ABDED4 /* js_util.hpp */,
|
||||
02AFE5871CA9B23400953DA3 /* jsc_list.cpp */,
|
||||
02AFE5881CA9B23400953DA3 /* jsc_list.hpp */,
|
||||
029048351C042A3C00ABDED4 /* platform.hpp */,
|
||||
0290480F1C0428DF00ABDED4 /* rpc.cpp */,
|
||||
029048101C0428DF00ABDED4 /* rpc.hpp */,
|
||||
|
@ -652,10 +654,10 @@
|
|||
02F59EE31C88F2BB007F774C /* transact_log_handler.cpp in Sources */,
|
||||
F63FF2E81C159C4B00B3B8E0 /* platform.mm in Sources */,
|
||||
02F59EC31C88F17D007F774C /* results.cpp in Sources */,
|
||||
02AFE5891CA9B23400953DA3 /* jsc_list.cpp in Sources */,
|
||||
F63FF2E21C15921A00B3B8E0 /* base64.cpp in Sources */,
|
||||
F63FF2C61C12469E00B3B8E0 /* js_init.cpp in Sources */,
|
||||
02F59ECA1C88F190007F774C /* parser.cpp in Sources */,
|
||||
F63FF2C71C12469E00B3B8E0 /* js_list.cpp in Sources */,
|
||||
F63FF2C81C12469E00B3B8E0 /* js_object.cpp in Sources */,
|
||||
02F59EE11C88F2BB007F774C /* async_query.cpp in Sources */,
|
||||
02F59EC01C88F17D007F774C /* list.cpp in Sources */,
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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);
|
||||
|
||||
}}
|
|
@ -20,7 +20,7 @@
|
|||
#include "js_realm.hpp"
|
||||
#include "js_object.hpp"
|
||||
#include "js_collection.hpp"
|
||||
#include "js_list.hpp"
|
||||
#include "jsc_list.hpp"
|
||||
#include "js_results.hpp"
|
||||
#include "js_util.hpp"
|
||||
#include "js_schema.hpp"
|
||||
|
|
300
src/js_list.cpp
300
src/js_list.cpp
|
@ -1,300 +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.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "js_list.hpp"
|
||||
#include "js_collection.hpp"
|
||||
#include "js_object.hpp"
|
||||
#include "js_results.hpp"
|
||||
#include "js_util.hpp"
|
||||
|
||||
#include "object_accessor.hpp"
|
||||
#include "parser.hpp"
|
||||
#include "query_builder.hpp"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
using RJSAccessor = realm::NativeAccessor<JSValueRef, JSContextRef>;
|
||||
using namespace realm;
|
||||
|
||||
|
||||
void RJSSetReturnUndefined(JSContextRef ctx, JSValueRef &returnObject) {
|
||||
returnObject = JSValueMakeUndefined(ctx);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void RJSSetReturnNumber(JSContextRef ctx, JSValueRef &returnObject, T number) {
|
||||
returnObject = JSValueMakeNumber(ctx, number);
|
||||
}
|
||||
|
||||
void RJSSetReturnArray(JSContextRef ctx, size_t count, const JSValueRef *objects, JSValueRef &returnObject) {
|
||||
returnObject = JSObjectMakeArray(ctx, count, objects, NULL);
|
||||
}
|
||||
|
||||
void RJSSetException(JSContextRef ctx, JSValueRef * &exceptionObject, std::exception &exception) {
|
||||
if (exceptionObject) {
|
||||
*exceptionObject = RJSMakeError(ctx, exception);
|
||||
}
|
||||
}
|
||||
|
||||
JSValueRef ListGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* jsException) {
|
||||
try {
|
||||
List *list = RJSGetInternal<List *>(object);
|
||||
std::string indexStr = RJSStringForJSString(propertyName);
|
||||
if (indexStr == "length") {
|
||||
return JSValueMakeNumber(ctx, list->size());
|
||||
}
|
||||
|
||||
return RJSObjectCreate(ctx, Object(list->get_realm(), list->get_object_schema(), list->get(RJSValidatedPositiveIndex(indexStr))));
|
||||
}
|
||||
catch (std::out_of_range &exp) {
|
||||
// getters for nonexistent properties in JS should always return undefined
|
||||
return JSValueMakeUndefined(ctx);
|
||||
}
|
||||
catch (std::invalid_argument &exp) {
|
||||
// for stol failure this could be another property that is handled externally, so ignore
|
||||
return NULL;
|
||||
}
|
||||
catch (std::exception &exp) {
|
||||
if (jsException) {
|
||||
*jsException = RJSMakeError(ctx, exp);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool ListSetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* jsException) {
|
||||
try {
|
||||
List *list = RJSGetInternal<List *>(object);
|
||||
std::string indexStr = RJSStringForJSString(propertyName);
|
||||
if (indexStr == "length") {
|
||||
throw std::runtime_error("The 'length' property is readonly.");
|
||||
}
|
||||
|
||||
list->set(ctx, value, RJSValidatedPositiveIndex(indexStr));
|
||||
return true;
|
||||
}
|
||||
catch (std::invalid_argument &exp) {
|
||||
// for stol failure this could be another property that is handled externally, so ignore
|
||||
return false;
|
||||
}
|
||||
catch (std::exception &exp) {
|
||||
if (jsException) {
|
||||
*jsException = RJSMakeError(ctx, exp);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ListPropertyNames(JSContextRef ctx, JSObjectRef object, JSPropertyNameAccumulatorRef propertyNames) {
|
||||
List *list = RJSGetInternal<List *>(object);
|
||||
size_t size = list->size();
|
||||
|
||||
char str[32];
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
sprintf(str, "%zu", i);
|
||||
JSStringRef name = JSStringCreateWithUTF8CString(str);
|
||||
JSPropertyNameAccumulatorAddName(propertyNames, name);
|
||||
JSStringRelease(name);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType>
|
||||
void ListPush(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) {
|
||||
try {
|
||||
List *list = RJSGetInternal<List *>(thisObject);
|
||||
RJSValidateArgumentCountIsAtLeast(argumentCount, 1);
|
||||
for (size_t i = 0; i < argumentCount; i++) {
|
||||
list->add(ctx, arguments[i]);
|
||||
}
|
||||
RJSSetReturnNumber(ctx, returnObject, list->size());
|
||||
}
|
||||
catch (std::exception &exp) {
|
||||
RJSSetException(ctx, exceptionObject, exp);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType>
|
||||
void ListPop(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) {
|
||||
try {
|
||||
List *list = RJSGetInternal<List *>(thisObject);
|
||||
RJSValidateArgumentCount(argumentCount, 0);
|
||||
|
||||
size_t size = list->size();
|
||||
if (size == 0) {
|
||||
list->verify_in_transaction();
|
||||
RJSSetReturnUndefined(ctx, returnObject);
|
||||
}
|
||||
else {
|
||||
size_t index = size - 1;
|
||||
returnObject = RJSObjectCreate(ctx, Object(list->get_realm(), list->get_object_schema(), list->get(index)));
|
||||
list->remove(index);
|
||||
}
|
||||
}
|
||||
catch (std::exception &exception) {
|
||||
RJSSetException(ctx, exceptionObject, exception);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType>
|
||||
void ListUnshift(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) {
|
||||
try {
|
||||
List *list = RJSGetInternal<List *>(thisObject);
|
||||
RJSValidateArgumentCountIsAtLeast(argumentCount, 1);
|
||||
for (size_t i = 0; i < argumentCount; i++) {
|
||||
list->insert(ctx, arguments[i], i);
|
||||
}
|
||||
RJSSetReturnNumber(ctx, returnObject, list->size());
|
||||
}
|
||||
catch (std::exception &exp) {
|
||||
RJSSetException(ctx, exceptionObject, exp);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType>
|
||||
void ListShift(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) {
|
||||
try {
|
||||
List *list = RJSGetInternal<List *>(thisObject);
|
||||
RJSValidateArgumentCount(argumentCount, 0);
|
||||
if (list->size() == 0) {
|
||||
list->verify_in_transaction();
|
||||
RJSSetReturnUndefined(ctx, returnObject);
|
||||
}
|
||||
else {
|
||||
returnObject = RJSObjectCreate(ctx, Object(list->get_realm(), list->get_object_schema(), list->get(0)));
|
||||
list->remove(0);
|
||||
}
|
||||
}
|
||||
catch (std::exception &exp) {
|
||||
RJSSetException(ctx, exceptionObject, exp);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType>
|
||||
void ListSplice(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) {
|
||||
try {
|
||||
List *list = RJSGetInternal<List *>(thisObject);
|
||||
size_t size = list->size();
|
||||
|
||||
RJSValidateArgumentCountIsAtLeast(argumentCount, 1);
|
||||
long index = std::min<long>(RJSValidatedValueToNumber(ctx, arguments[0]), size);
|
||||
if (index < 0) {
|
||||
index = std::max<long>(size + index, 0);
|
||||
}
|
||||
|
||||
long remove;
|
||||
if (argumentCount < 2) {
|
||||
remove = size - index;
|
||||
}
|
||||
else {
|
||||
remove = std::max<long>(RJSValidatedValueToNumber(ctx, arguments[1]), 0);
|
||||
remove = std::min<long>(remove, size - index);
|
||||
}
|
||||
|
||||
std::vector<ReturnType> removedObjects(remove);
|
||||
for (size_t i = 0; i < remove; i++) {
|
||||
removedObjects[i] = RJSObjectCreate(ctx, Object(list->get_realm(), list->get_object_schema(), list->get(index)));
|
||||
list->remove(index);
|
||||
}
|
||||
for (size_t i = 2; i < argumentCount; i++) {
|
||||
list->insert(ctx, arguments[i], index + i - 2);
|
||||
}
|
||||
RJSSetReturnArray(ctx, remove, removedObjects.data(), returnObject);
|
||||
}
|
||||
catch (std::exception &exp) {
|
||||
RJSSetException(ctx, exceptionObject, exp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType>
|
||||
void ListStaticResults(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) {
|
||||
try {
|
||||
List *list = RJSGetInternal<List *>(thisObject);
|
||||
RJSValidateArgumentCount(argumentCount, 0);
|
||||
returnObject = RJSResultsCreate(ctx, list->get_realm(), list->get_object_schema(), std::move(list->get_query()), false);
|
||||
}
|
||||
catch (std::exception &exp) {
|
||||
RJSSetException(ctx, exceptionObject, exp);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType>
|
||||
void ListFiltered(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) {
|
||||
try {
|
||||
List *list = RJSGetInternal<List *>(thisObject);
|
||||
RJSValidateArgumentCountIsAtLeast(argumentCount, 1);
|
||||
|
||||
SharedRealm sharedRealm = *RJSGetInternal<SharedRealm *>(thisObject);
|
||||
returnObject = RJSResultsCreateFiltered(ctx, sharedRealm, list->get_object_schema(), std::move(list->get_query()), argumentCount, arguments);
|
||||
}
|
||||
catch (std::exception &exp) {
|
||||
RJSSetException(ctx, exceptionObject, exp);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType>
|
||||
void ListSorted(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) {
|
||||
try {
|
||||
List *list = RJSGetInternal<List *>(thisObject);
|
||||
RJSValidateArgumentRange(argumentCount, 1, 2);
|
||||
|
||||
SharedRealm sharedRealm = *RJSGetInternal<SharedRealm *>(thisObject);
|
||||
returnObject = RJSResultsCreateSorted(ctx, sharedRealm, list->get_object_schema(), std::move(list->get_query()), argumentCount, arguments);
|
||||
}
|
||||
catch (std::exception &exp) {
|
||||
RJSSetException(ctx, exceptionObject, exp);
|
||||
}
|
||||
}
|
||||
|
||||
#define LIST_METHOD(METHOD_NAME) \
|
||||
JSValueRef METHOD_NAME(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) { \
|
||||
JSValueRef returnObject = NULL; \
|
||||
METHOD_NAME(ctx, thisObject, argumentCount, arguments, returnObject, jsException); \
|
||||
return returnObject; \
|
||||
}
|
||||
|
||||
LIST_METHOD(ListPush)
|
||||
LIST_METHOD(ListPop)
|
||||
LIST_METHOD(ListUnshift)
|
||||
LIST_METHOD(ListShift)
|
||||
LIST_METHOD(ListSplice)
|
||||
LIST_METHOD(ListStaticResults)
|
||||
LIST_METHOD(ListFiltered)
|
||||
LIST_METHOD(ListSorted)
|
||||
|
||||
JSObjectRef RJSListCreate(JSContextRef ctx, List &list) {
|
||||
return RJSWrapObject<List *>(ctx, RJSListClass(), new List(list));
|
||||
}
|
||||
|
||||
static const JSStaticFunction RJSListFuncs[] = {
|
||||
{"push", ListPush, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
||||
{"pop", ListPop, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
||||
{"shift", ListShift, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
||||
{"unshift", ListUnshift, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
||||
{"splice", ListSplice, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
||||
{"filtered", ListFiltered, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
||||
{"sorted", ListSorted, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
||||
{"snapshot", ListStaticResults, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
JSClassRef RJSListClass() {
|
||||
static JSClassRef s_listClass = RJSCreateWrapperClass<List *>("List", ListGetProperty, ListSetProperty, RJSListFuncs, ListPropertyNames, RJSCollectionClass());
|
||||
return s_listClass;
|
||||
}
|
163
src/js_list.hpp
163
src/js_list.hpp
|
@ -18,9 +18,168 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "js_list.hpp"
|
||||
#include "js_collection.hpp"
|
||||
#include "js_object.hpp"
|
||||
#include "js_results.hpp"
|
||||
#include "js_util.hpp"
|
||||
|
||||
#include "shared_realm.hpp"
|
||||
#include "list.hpp"
|
||||
#include "object_accessor.hpp"
|
||||
#include "parser.hpp"
|
||||
#include "query_builder.hpp"
|
||||
|
||||
JSClassRef RJSListClass();
|
||||
JSObjectRef RJSListCreate(JSContextRef ctx, realm::List &list);
|
||||
#include <assert.h>
|
||||
|
||||
using RJSAccessor = realm::NativeAccessor<JSValueRef, JSContextRef>;
|
||||
using namespace realm;
|
||||
|
||||
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType>
|
||||
void ListPush(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) {
|
||||
try {
|
||||
List *list = RJSGetInternal<List *>(thisObject);
|
||||
RJSValidateArgumentCountIsAtLeast(argumentCount, 1);
|
||||
for (size_t i = 0; i < argumentCount; i++) {
|
||||
list->add(ctx, arguments[i]);
|
||||
}
|
||||
RJSSetReturnNumber(ctx, returnObject, list->size());
|
||||
}
|
||||
catch (std::exception &exp) {
|
||||
RJSSetException(ctx, exceptionObject, exp);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType>
|
||||
void ListPop(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) {
|
||||
try {
|
||||
List *list = RJSGetInternal<List *>(thisObject);
|
||||
RJSValidateArgumentCount(argumentCount, 0);
|
||||
|
||||
size_t size = list->size();
|
||||
if (size == 0) {
|
||||
list->verify_in_transaction();
|
||||
RJSSetReturnUndefined(ctx, returnObject);
|
||||
}
|
||||
else {
|
||||
size_t index = size - 1;
|
||||
returnObject = RJSObjectCreate(ctx, Object(list->get_realm(), list->get_object_schema(), list->get(index)));
|
||||
list->remove(index);
|
||||
}
|
||||
}
|
||||
catch (std::exception &exception) {
|
||||
RJSSetException(ctx, exceptionObject, exception);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType>
|
||||
void ListUnshift(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) {
|
||||
try {
|
||||
List *list = RJSGetInternal<List *>(thisObject);
|
||||
RJSValidateArgumentCountIsAtLeast(argumentCount, 1);
|
||||
for (size_t i = 0; i < argumentCount; i++) {
|
||||
list->insert(ctx, arguments[i], i);
|
||||
}
|
||||
RJSSetReturnNumber(ctx, returnObject, list->size());
|
||||
}
|
||||
catch (std::exception &exp) {
|
||||
RJSSetException(ctx, exceptionObject, exp);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType>
|
||||
void ListShift(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) {
|
||||
try {
|
||||
List *list = RJSGetInternal<List *>(thisObject);
|
||||
RJSValidateArgumentCount(argumentCount, 0);
|
||||
if (list->size() == 0) {
|
||||
list->verify_in_transaction();
|
||||
RJSSetReturnUndefined(ctx, returnObject);
|
||||
}
|
||||
else {
|
||||
returnObject = RJSObjectCreate(ctx, Object(list->get_realm(), list->get_object_schema(), list->get(0)));
|
||||
list->remove(0);
|
||||
}
|
||||
}
|
||||
catch (std::exception &exp) {
|
||||
RJSSetException(ctx, exceptionObject, exp);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType>
|
||||
void ListSplice(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) {
|
||||
try {
|
||||
List *list = RJSGetInternal<List *>(thisObject);
|
||||
size_t size = list->size();
|
||||
|
||||
RJSValidateArgumentCountIsAtLeast(argumentCount, 1);
|
||||
long index = std::min<long>(RJSValidatedValueToNumber(ctx, arguments[0]), size);
|
||||
if (index < 0) {
|
||||
index = std::max<long>(size + index, 0);
|
||||
}
|
||||
|
||||
long remove;
|
||||
if (argumentCount < 2) {
|
||||
remove = size - index;
|
||||
}
|
||||
else {
|
||||
remove = std::max<long>(RJSValidatedValueToNumber(ctx, arguments[1]), 0);
|
||||
remove = std::min<long>(remove, size - index);
|
||||
}
|
||||
|
||||
std::vector<ReturnType> removedObjects(remove);
|
||||
for (size_t i = 0; i < remove; i++) {
|
||||
removedObjects[i] = RJSObjectCreate(ctx, Object(list->get_realm(), list->get_object_schema(), list->get(index)));
|
||||
list->remove(index);
|
||||
}
|
||||
for (size_t i = 2; i < argumentCount; i++) {
|
||||
list->insert(ctx, arguments[i], index + i - 2);
|
||||
}
|
||||
RJSSetReturnArray(ctx, remove, removedObjects.data(), returnObject);
|
||||
}
|
||||
catch (std::exception &exp) {
|
||||
RJSSetException(ctx, exceptionObject, exp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType>
|
||||
void ListStaticResults(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) {
|
||||
try {
|
||||
List *list = RJSGetInternal<List *>(thisObject);
|
||||
RJSValidateArgumentCount(argumentCount, 0);
|
||||
returnObject = RJSResultsCreate(ctx, list->get_realm(), list->get_object_schema(), std::move(list->get_query()), false);
|
||||
}
|
||||
catch (std::exception &exp) {
|
||||
RJSSetException(ctx, exceptionObject, exp);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType>
|
||||
void ListFiltered(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) {
|
||||
try {
|
||||
List *list = RJSGetInternal<List *>(thisObject);
|
||||
RJSValidateArgumentCountIsAtLeast(argumentCount, 1);
|
||||
|
||||
SharedRealm sharedRealm = *RJSGetInternal<SharedRealm *>(thisObject);
|
||||
returnObject = RJSResultsCreateFiltered(ctx, sharedRealm, list->get_object_schema(), std::move(list->get_query()), argumentCount, arguments);
|
||||
}
|
||||
catch (std::exception &exp) {
|
||||
RJSSetException(ctx, exceptionObject, exp);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType>
|
||||
void ListSorted(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) {
|
||||
try {
|
||||
List *list = RJSGetInternal<List *>(thisObject);
|
||||
RJSValidateArgumentRange(argumentCount, 1, 2);
|
||||
|
||||
SharedRealm sharedRealm = *RJSGetInternal<SharedRealm *>(thisObject);
|
||||
returnObject = RJSResultsCreateSorted(ctx, sharedRealm, list->get_object_schema(), std::move(list->get_query()), argumentCount, arguments);
|
||||
}
|
||||
catch (std::exception &exp) {
|
||||
RJSSetException(ctx, exceptionObject, exp);
|
||||
}
|
||||
}
|
|
@ -20,7 +20,7 @@
|
|||
#include "js_object.hpp"
|
||||
#include "js_results.hpp"
|
||||
#include "js_schema.hpp"
|
||||
#include "js_list.hpp"
|
||||
#include "jsc_list.hpp"
|
||||
#include "js_realm.hpp"
|
||||
|
||||
#include "object_store.hpp"
|
||||
|
@ -93,8 +93,6 @@ JSObjectRef RJSObjectCreate(JSContextRef ctx, Object object) {
|
|||
return jsObject;
|
||||
}
|
||||
|
||||
extern JSObjectRef RJSDictForPropertyArray(JSContextRef ctx, const ObjectSchema &object_schema, JSObjectRef array);
|
||||
|
||||
namespace realm {
|
||||
|
||||
template<> bool RJSAccessor::dict_has_value_for_key(JSContextRef ctx, JSValueRef dict, const std::string &prop_name) {
|
||||
|
|
198
src/js_realm.cpp
198
src/js_realm.cpp
|
@ -19,7 +19,7 @@
|
|||
#include "js_realm.hpp"
|
||||
#include "js_object.hpp"
|
||||
#include "js_results.hpp"
|
||||
#include "js_list.hpp"
|
||||
#include "jsc_list.hpp"
|
||||
#include "js_schema.hpp"
|
||||
#include "platform.hpp"
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
|||
#include "impl/realm_coordinator.hpp"
|
||||
#include "object_accessor.hpp"
|
||||
#include "binding_context.hpp"
|
||||
#include "results.hpp"
|
||||
|
||||
#include <set>
|
||||
#include <cassert>
|
||||
|
@ -310,47 +311,21 @@ std::string RJSValidatedObjectTypeForValue(SharedRealm &realm, JSContextRef ctx,
|
|||
return RJSValidatedStringForValue(ctx, value, "objectType");
|
||||
}
|
||||
|
||||
JSValueRef RealmObjects(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
|
||||
try {
|
||||
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType>
|
||||
void RealmObjects(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) { try {
|
||||
RJSValidateArgumentCount(argumentCount, 1);
|
||||
|
||||
SharedRealm sharedRealm = *RJSGetInternal<SharedRealm *>(thisObject);
|
||||
std::string className = RJSValidatedObjectTypeForValue(sharedRealm, ctx, arguments[0]);
|
||||
return RJSResultsCreate(ctx, sharedRealm, className);
|
||||
returnObject = RJSResultsCreate(ctx, sharedRealm, className);
|
||||
}
|
||||
catch (std::exception &exp) {
|
||||
if (jsException) {
|
||||
*jsException = RJSMakeError(ctx, exp);
|
||||
}
|
||||
return NULL;
|
||||
RJSSetException(ctx, exceptionObject, exp);
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType>
|
||||
void RealmCreateObject(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) { try {
|
||||
RJSValidateArgumentRange(argumentCount, 2, 3);
|
||||
|
||||
SharedRealm sharedRealm = *RJSGetInternal<SharedRealm *>(thisObject);
|
||||
|
@ -359,8 +334,7 @@ JSValueRef RealmCreateObject(JSContextRef ctx, JSObjectRef function, JSObjectRef
|
|||
auto object_schema = schema->find(className);
|
||||
|
||||
if (object_schema == schema->end()) {
|
||||
*jsException = RJSMakeError(ctx, "Object type '" + className + "' not found in schema.");
|
||||
return NULL;
|
||||
throw std::runtime_error("Object type '" + className + "' not found in schema.");
|
||||
}
|
||||
|
||||
JSObjectRef object = RJSValidatedValueToObject(ctx, arguments[1]);
|
||||
|
@ -370,66 +344,63 @@ JSValueRef RealmCreateObject(JSContextRef ctx, JSObjectRef function, JSObjectRef
|
|||
|
||||
bool update = false;
|
||||
if (argumentCount == 3) {
|
||||
update = JSValueToBoolean(ctx, arguments[2]);
|
||||
update = RJSValidatedValueToBoolean(ctx, arguments[2]);
|
||||
}
|
||||
|
||||
return RJSObjectCreate(ctx, Object::create<JSValueRef>(ctx, sharedRealm, *object_schema, object, update));
|
||||
returnObject = RJSObjectCreate(ctx, Object::create<JSValueRef>(ctx, sharedRealm, *object_schema, object, update));
|
||||
}
|
||||
catch (std::exception &exp) {
|
||||
if (jsException) {
|
||||
*jsException = RJSMakeError(ctx, exp);
|
||||
}
|
||||
return NULL;
|
||||
RJSSetException(ctx, exceptionObject, exp);
|
||||
}
|
||||
}
|
||||
|
||||
JSValueRef RealmDelete(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
|
||||
try {
|
||||
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType>
|
||||
void RealmDelete(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) { 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());
|
||||
JSObjectRef arg = RJSValidatedValueToObject(ctx, arguments[0]);
|
||||
if (RJSValueIsObjectOfClass(ctx, arg, RJSObjectClass())) {
|
||||
Object *object = RJSGetInternal<Object *>(arg);
|
||||
realm::TableRef table = ObjectStore::table_for_object_type(realm->read_group(), object->get_object_schema().name);
|
||||
table->move_last_over(object->row().get_index());
|
||||
}
|
||||
else if (RJSIsValueArray(ctx, arg)) {
|
||||
size_t length = RJSValidatedListLength(ctx, arg);
|
||||
for (long i = length-1; i >= 0; i--) {
|
||||
JSObjectRef jsObject = RJSValidatedValueToObject(ctx, RJSValidatedObjectAtIndex(ctx, arg, (unsigned int)i));
|
||||
if (!JSValueIsObjectOfClass(ctx, jsObject, RJSObjectClass())) {
|
||||
throw std::runtime_error("Argument to 'delete' must be a Realm object or a collection of Realm objects.");
|
||||
}
|
||||
|
||||
return NULL;
|
||||
Object *object = RJSGetInternal<Object *>(jsObject);
|
||||
realm::TableRef table = ObjectStore::table_for_object_type(realm->read_group(), object->get_object_schema().name);
|
||||
table->move_last_over(object->row().get_index());
|
||||
}
|
||||
}
|
||||
else if(RJSValueIsObjectOfClass(ctx, arg, RJSResultsClass())) {
|
||||
Results *results = RJSGetInternal<Results *>(arg);
|
||||
results->clear();
|
||||
}
|
||||
else if(RJSValueIsObjectOfClass(ctx, arg, RJSListClass())) {
|
||||
List *list = RJSGetInternal<List *>(arg);
|
||||
list->delete_all();
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("Argument to 'delete' must be a Realm object or a collection of Realm objects.");
|
||||
}
|
||||
}
|
||||
catch (std::exception &exp) {
|
||||
if (jsException) {
|
||||
*jsException = RJSMakeError(ctx, exp);
|
||||
}
|
||||
return NULL;
|
||||
RJSSetException(ctx, exceptionObject, exp);
|
||||
}
|
||||
}
|
||||
|
||||
JSValueRef RealmDeleteAll(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
|
||||
try {
|
||||
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType>
|
||||
void RealmDeleteAll(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) { try {
|
||||
RJSValidateArgumentCount(argumentCount, 0);
|
||||
|
||||
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
|
||||
|
@ -441,39 +412,29 @@ JSValueRef RealmDeleteAll(JSContextRef ctx, JSObjectRef function, JSObjectRef th
|
|||
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;
|
||||
RJSSetException(ctx, exceptionObject, exp);
|
||||
}
|
||||
}
|
||||
|
||||
JSValueRef RealmWrite(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
|
||||
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType>
|
||||
void RealmWrite(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) {
|
||||
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
|
||||
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();
|
||||
}
|
||||
RJSCallFunction(ctx, object, thisObject, 0, NULL);
|
||||
realm->commit_transaction();
|
||||
}
|
||||
catch (std::exception &exp) {
|
||||
if (jsException) {
|
||||
*jsException = RJSMakeError(ctx, exp);
|
||||
if (realm->is_in_transaction()) {
|
||||
realm->cancel_transaction();
|
||||
}
|
||||
return NULL;
|
||||
RJSSetException(ctx, exceptionObject, exp);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::string RJSValidatedNotificationName(JSContextRef ctx, JSValueRef value) {
|
||||
|
@ -484,44 +445,36 @@ std::string RJSValidatedNotificationName(JSContextRef ctx, JSValueRef value) {
|
|||
return name;
|
||||
}
|
||||
|
||||
JSValueRef RealmAddListener(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
|
||||
try {
|
||||
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType>
|
||||
void RealmAddListener(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) { 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;
|
||||
RJSSetException(ctx, exceptionObject, exp);
|
||||
}
|
||||
}
|
||||
|
||||
JSValueRef RealmRemoveListener(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
|
||||
try {
|
||||
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType>
|
||||
void RealmRemoveListener(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) { 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;
|
||||
RJSSetException(ctx, exceptionObject, exp);
|
||||
}
|
||||
}
|
||||
|
||||
JSValueRef RealmRemoveAllListeners(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
|
||||
try {
|
||||
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType>
|
||||
void RealmRemoveAllListeners(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) { try {
|
||||
RJSValidateArgumentRange(argumentCount, 0, 1);
|
||||
if (argumentCount) {
|
||||
RJSValidatedNotificationName(ctx, arguments[0]);
|
||||
|
@ -529,30 +482,33 @@ JSValueRef RealmRemoveAllListeners(JSContextRef ctx, JSObjectRef function, JSObj
|
|||
|
||||
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;
|
||||
RJSSetException(ctx, exceptionObject, exp);
|
||||
}
|
||||
}
|
||||
|
||||
JSValueRef RealmClose(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
|
||||
try {
|
||||
template<typename ContextType, typename ThisType, typename ArgumentsType, typename ReturnType, typename ExceptionType>
|
||||
void RealmClose(ContextType ctx, ThisType thisObject, size_t argumentCount, const ArgumentsType &arguments, ReturnType &returnObject, ExceptionType &exceptionObject) { try {
|
||||
RJSValidateArgumentCount(argumentCount, 0);
|
||||
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
|
||||
realm->close();
|
||||
}
|
||||
catch (std::exception &exp) {
|
||||
if (jsException) {
|
||||
*jsException = RJSMakeError(ctx, exp);
|
||||
}
|
||||
RJSSetException(ctx, exceptionObject, exp);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
WRAP_METHOD(RealmObjects)
|
||||
WRAP_METHOD(RealmCreateObject)
|
||||
WRAP_METHOD(RealmDelete)
|
||||
WRAP_METHOD(RealmDeleteAll)
|
||||
WRAP_METHOD(RealmWrite)
|
||||
WRAP_METHOD(RealmAddListener)
|
||||
WRAP_METHOD(RealmRemoveListener)
|
||||
WRAP_METHOD(RealmRemoveAllListeners)
|
||||
WRAP_METHOD(RealmClose)
|
||||
|
||||
static const JSStaticFunction RJSRealmFuncs[] = {
|
||||
{"objects", RealmObjects, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
||||
{"create", RealmCreateObject, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
||||
|
|
|
@ -31,6 +31,13 @@
|
|||
#include "property.hpp"
|
||||
#include "schema.hpp"
|
||||
|
||||
#define WRAP_METHOD(METHOD_NAME) \
|
||||
JSValueRef METHOD_NAME(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) { \
|
||||
JSValueRef returnObject = NULL; \
|
||||
METHOD_NAME(ctx, thisObject, argumentCount, arguments, returnObject, jsException); \
|
||||
return returnObject; \
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
inline void RJSFinalize(JSObjectRef object) {
|
||||
|
@ -149,6 +156,13 @@ static inline double RJSValidatedValueToNumber(JSContextRef ctx, JSValueRef valu
|
|||
return number;
|
||||
}
|
||||
|
||||
static inline double RJSValidatedValueToBoolean(JSContextRef ctx, JSValueRef value) {
|
||||
if (!JSValueIsBoolean(ctx, value)) {
|
||||
throw std::invalid_argument("Value is not a boolean.");
|
||||
}
|
||||
return JSValueToBoolean(ctx, value);
|
||||
}
|
||||
|
||||
static inline JSValueRef RJSValidatedPropertyValue(JSContextRef ctx, JSObjectRef object, JSStringRef property) {
|
||||
JSValueRef exception = NULL;
|
||||
JSValueRef propertyValue = JSObjectGetProperty(ctx, object, property, &exception);
|
||||
|
@ -245,3 +259,58 @@ static inline bool RJSIsValueObjectOfType(JSContextRef ctx, JSValueRef value, JS
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void RJSSetReturnUndefined(JSContextRef ctx, JSValueRef &returnObject) {
|
||||
returnObject = JSValueMakeUndefined(ctx);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline void RJSSetReturnNumber(JSContextRef ctx, JSValueRef &returnObject, T number) {
|
||||
returnObject = JSValueMakeNumber(ctx, number);
|
||||
}
|
||||
|
||||
static inline void RJSSetReturnArray(JSContextRef ctx, size_t count, const JSValueRef *objects, JSValueRef &returnObject) {
|
||||
returnObject = JSObjectMakeArray(ctx, count, objects, NULL);
|
||||
}
|
||||
|
||||
static inline void RJSSetException(JSContextRef ctx, JSValueRef * &exceptionObject, std::exception &exception) {
|
||||
if (exceptionObject) {
|
||||
*exceptionObject = RJSMakeError(ctx, exception);
|
||||
}
|
||||
}
|
||||
|
||||
static JSObjectRef RJSDictForPropertyArray(JSContextRef ctx, const realm::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;
|
||||
}
|
||||
|
||||
static void RJSCallFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef object, size_t argumentCount, const JSValueRef *arguments) {
|
||||
JSValueRef exception = NULL;
|
||||
JSObjectCallAsFunction(ctx, function, object, argumentCount, arguments, &exception);
|
||||
if (exception) {
|
||||
throw RJSException(ctx, exception);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static bool RJSValueIsObjectOfClass(JSContextRef ctx, JSValueRef value, JSClassRef jsClass) {
|
||||
return JSValueIsObjectOfClass(ctx, value, jsClass);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "jsc_list.hpp"
|
||||
#include "js_list.hpp"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
using RJSAccessor = realm::NativeAccessor<JSValueRef, JSContextRef>;
|
||||
using namespace realm;
|
||||
|
||||
JSValueRef ListGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* jsException) {
|
||||
try {
|
||||
List *list = RJSGetInternal<List *>(object);
|
||||
std::string indexStr = RJSStringForJSString(propertyName);
|
||||
if (indexStr == "length") {
|
||||
return JSValueMakeNumber(ctx, list->size());
|
||||
}
|
||||
|
||||
return RJSObjectCreate(ctx, Object(list->get_realm(), list->get_object_schema(), list->get(RJSValidatedPositiveIndex(indexStr))));
|
||||
}
|
||||
catch (std::out_of_range &exp) {
|
||||
// getters for nonexistent properties in JS should always return undefined
|
||||
return JSValueMakeUndefined(ctx);
|
||||
}
|
||||
catch (std::invalid_argument &exp) {
|
||||
// for stol failure this could be another property that is handled externally, so ignore
|
||||
return NULL;
|
||||
}
|
||||
catch (std::exception &exp) {
|
||||
if (jsException) {
|
||||
*jsException = RJSMakeError(ctx, exp);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool ListSetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* jsException) {
|
||||
try {
|
||||
List *list = RJSGetInternal<List *>(object);
|
||||
std::string indexStr = RJSStringForJSString(propertyName);
|
||||
if (indexStr == "length") {
|
||||
throw std::runtime_error("The 'length' property is readonly.");
|
||||
}
|
||||
|
||||
list->set(ctx, value, RJSValidatedPositiveIndex(indexStr));
|
||||
return true;
|
||||
}
|
||||
catch (std::invalid_argument &exp) {
|
||||
// for stol failure this could be another property that is handled externally, so ignore
|
||||
return false;
|
||||
}
|
||||
catch (std::exception &exp) {
|
||||
if (jsException) {
|
||||
*jsException = RJSMakeError(ctx, exp);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ListPropertyNames(JSContextRef ctx, JSObjectRef object, JSPropertyNameAccumulatorRef propertyNames) {
|
||||
List *list = RJSGetInternal<List *>(object);
|
||||
size_t size = list->size();
|
||||
|
||||
char str[32];
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
sprintf(str, "%zu", i);
|
||||
JSStringRef name = JSStringCreateWithUTF8CString(str);
|
||||
JSPropertyNameAccumulatorAddName(propertyNames, name);
|
||||
JSStringRelease(name);
|
||||
}
|
||||
}
|
||||
|
||||
WRAP_METHOD(ListPush)
|
||||
WRAP_METHOD(ListPop)
|
||||
WRAP_METHOD(ListUnshift)
|
||||
WRAP_METHOD(ListShift)
|
||||
WRAP_METHOD(ListSplice)
|
||||
WRAP_METHOD(ListStaticResults)
|
||||
WRAP_METHOD(ListFiltered)
|
||||
WRAP_METHOD(ListSorted)
|
||||
|
||||
JSObjectRef RJSListCreate(JSContextRef ctx, List &list) {
|
||||
return RJSWrapObject<List *>(ctx, RJSListClass(), new List(list));
|
||||
}
|
||||
|
||||
static const JSStaticFunction RJSListFuncs[] = {
|
||||
{"push", ListPush, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
||||
{"pop", ListPop, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
||||
{"shift", ListShift, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
||||
{"unshift", ListUnshift, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
||||
{"splice", ListSplice, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
||||
{"filtered", ListFiltered, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
||||
{"sorted", ListSorted, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
||||
{"snapshot", ListStaticResults, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
JSClassRef RJSListClass() {
|
||||
static JSClassRef s_listClass = RJSCreateWrapperClass<List *>("List", ListGetProperty, ListSetProperty, RJSListFuncs, ListPropertyNames, RJSCollectionClass());
|
||||
return s_listClass;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "list.hpp"
|
||||
|
||||
JSClassRef RJSListClass();
|
||||
JSObjectRef RJSListCreate(JSContextRef ctx, realm::List &list);
|
|
@ -0,0 +1,251 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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>
|
||||
|
||||
#include <math.h>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <cmath>
|
||||
#include "property.hpp"
|
||||
#include "schema.hpp"
|
||||
|
||||
namespace realm {
|
||||
namespace js {
|
||||
|
||||
template<typename T>
|
||||
inline void RJSFinalize(JSObjectRef object) {
|
||||
delete static_cast<T>(JSObjectGetPrivate(object));
|
||||
JSObjectSetPrivate(object, NULL);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline JSObjectRef RJSWrapObject(JSContextRef ctx, JSClassRef jsClass, T object, JSValueRef prototype = NULL) {
|
||||
JSObjectRef ref = JSObjectMake(ctx, jsClass, (void *)object);
|
||||
if (prototype) {
|
||||
JSObjectSetPrototype(ctx, ref, prototype);
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T RJSGetInternal(JSObjectRef jsObject) {
|
||||
return static_cast<T>(JSObjectGetPrivate(jsObject));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
JSClassRef RJSCreateWrapperClass(const char * name, JSObjectGetPropertyCallback getter = NULL, JSObjectSetPropertyCallback setter = NULL, const JSStaticFunction *funcs = NULL,
|
||||
JSObjectGetPropertyNamesCallback propertyNames = NULL, JSClassRef parentClass = NULL) {
|
||||
JSClassDefinition classDefinition = kJSClassDefinitionEmpty;
|
||||
classDefinition.className = name;
|
||||
classDefinition.finalize = RJSFinalize<T>;
|
||||
classDefinition.getProperty = getter;
|
||||
classDefinition.setProperty = setter;
|
||||
classDefinition.staticFunctions = funcs;
|
||||
classDefinition.getPropertyNames = propertyNames;
|
||||
classDefinition.parentClass = parentClass;
|
||||
return JSClassCreate(&classDefinition);
|
||||
}
|
||||
|
||||
std::string RJSStringForJSString(JSStringRef jsString);
|
||||
std::string RJSStringForValue(JSContextRef ctx, JSValueRef value);
|
||||
std::string RJSValidatedStringForValue(JSContextRef ctx, JSValueRef value, const char * name = nullptr);
|
||||
|
||||
JSStringRef RJSStringForString(const std::string &str);
|
||||
JSValueRef RJSValueForString(JSContextRef ctx, const std::string &str);
|
||||
|
||||
inline void RJSValidateArgumentCount(size_t argumentCount, size_t expected, const char *message = NULL) {
|
||||
if (argumentCount != expected) {
|
||||
throw std::invalid_argument(message ?: "Invalid arguments");
|
||||
}
|
||||
}
|
||||
|
||||
inline void RJSValidateArgumentCountIsAtLeast(size_t argumentCount, size_t expected, const char *message = NULL) {
|
||||
if (argumentCount < expected) {
|
||||
throw std::invalid_argument(message ?: "Invalid arguments");
|
||||
}
|
||||
}
|
||||
|
||||
inline void RJSValidateArgumentRange(size_t argumentCount, size_t min, size_t max, const char *message = NULL) {
|
||||
if (argumentCount < min || argumentCount > max) {
|
||||
throw std::invalid_argument(message ?: "Invalid arguments");
|
||||
}
|
||||
}
|
||||
|
||||
class RJSException : public std::runtime_error {
|
||||
public:
|
||||
RJSException(JSContextRef ctx, JSValueRef &ex) : std::runtime_error(RJSStringForValue(ctx, ex)),
|
||||
m_jsException(ex) {}
|
||||
JSValueRef exception() { return m_jsException; }
|
||||
|
||||
private:
|
||||
JSValueRef m_jsException;
|
||||
};
|
||||
|
||||
JSValueRef RJSMakeError(JSContextRef ctx, RJSException &exp);
|
||||
JSValueRef RJSMakeError(JSContextRef ctx, std::exception &exp);
|
||||
JSValueRef RJSMakeError(JSContextRef ctx, const std::string &message);
|
||||
|
||||
bool RJSIsValueArray(JSContextRef ctx, JSValueRef value);
|
||||
bool RJSIsValueArrayBuffer(JSContextRef ctx, JSValueRef value);
|
||||
bool RJSIsValueDate(JSContextRef ctx, JSValueRef value);
|
||||
|
||||
static inline JSObjectRef RJSValidatedValueToObject(JSContextRef ctx, JSValueRef value, const char *message = NULL) {
|
||||
JSObjectRef object = JSValueToObject(ctx, value, NULL);
|
||||
if (!object) {
|
||||
throw std::runtime_error(message ?: "Value is not an object.");
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
static inline JSObjectRef RJSValidatedValueToDate(JSContextRef ctx, JSValueRef value, const char *message = NULL) {
|
||||
JSObjectRef object = JSValueToObject(ctx, value, NULL);
|
||||
if (!object || !RJSIsValueDate(ctx, object)) {
|
||||
throw std::runtime_error(message ?: "Value is not a date.");
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
static inline JSObjectRef RJSValidatedValueToFunction(JSContextRef ctx, JSValueRef value, const char *message = NULL) {
|
||||
JSObjectRef object = JSValueToObject(ctx, value, NULL);
|
||||
if (!object || !JSObjectIsFunction(ctx, object)) {
|
||||
throw std::runtime_error(message ?: "Value is not a function.");
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
static inline double RJSValidatedValueToNumber(JSContextRef ctx, JSValueRef value) {
|
||||
if (JSValueIsNull(ctx, value)) {
|
||||
throw std::invalid_argument("`null` is not a number.");
|
||||
}
|
||||
|
||||
JSValueRef exception = NULL;
|
||||
double number = JSValueToNumber(ctx, value, &exception);
|
||||
if (exception) {
|
||||
throw RJSException(ctx, exception);
|
||||
}
|
||||
if (isnan(number)) {
|
||||
throw std::invalid_argument("Value not convertible to a number.");
|
||||
}
|
||||
return number;
|
||||
}
|
||||
|
||||
static inline JSValueRef RJSValidatedPropertyValue(JSContextRef ctx, JSObjectRef object, JSStringRef property) {
|
||||
JSValueRef exception = NULL;
|
||||
JSValueRef propertyValue = JSObjectGetProperty(ctx, object, property, &exception);
|
||||
if (exception) {
|
||||
throw RJSException(ctx, exception);
|
||||
}
|
||||
return propertyValue;
|
||||
}
|
||||
|
||||
static inline JSValueRef RJSValidatedPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned int index) {
|
||||
JSValueRef exception = NULL;
|
||||
JSValueRef propertyValue = JSObjectGetPropertyAtIndex(ctx, object, index, &exception);
|
||||
if (exception) {
|
||||
throw RJSException(ctx, exception);
|
||||
}
|
||||
return propertyValue;
|
||||
}
|
||||
|
||||
static inline JSObjectRef RJSValidatedObjectProperty(JSContextRef ctx, JSObjectRef object, JSStringRef property, const char *err = NULL) {
|
||||
JSValueRef propertyValue = RJSValidatedPropertyValue(ctx, object, property);
|
||||
if (JSValueIsUndefined(ctx, propertyValue)) {
|
||||
throw std::runtime_error(err ?: "Object property '" + RJSStringForJSString(property) + "' is undefined");
|
||||
}
|
||||
return RJSValidatedValueToObject(ctx, propertyValue, err);
|
||||
}
|
||||
|
||||
static inline JSObjectRef RJSValidatedObjectAtIndex(JSContextRef ctx, JSObjectRef object, unsigned int index) {
|
||||
return RJSValidatedValueToObject(ctx, RJSValidatedPropertyAtIndex(ctx, object, index));
|
||||
}
|
||||
|
||||
static inline std::string RJSValidatedStringProperty(JSContextRef ctx, JSObjectRef object, JSStringRef property) {
|
||||
JSValueRef exception = NULL;
|
||||
JSValueRef propertyValue = JSObjectGetProperty(ctx, object, property, &exception);
|
||||
if (exception) {
|
||||
throw RJSException(ctx, exception);
|
||||
}
|
||||
return RJSValidatedStringForValue(ctx, propertyValue, RJSStringForJSString(property).c_str());
|
||||
}
|
||||
|
||||
static inline size_t RJSValidatedListLength(JSContextRef ctx, JSObjectRef object) {
|
||||
JSValueRef exception = NULL;
|
||||
static JSStringRef lengthString = JSStringCreateWithUTF8CString("length");
|
||||
JSValueRef lengthValue = JSObjectGetProperty(ctx, object, lengthString, &exception);
|
||||
if (exception) {
|
||||
throw RJSException(ctx, exception);
|
||||
}
|
||||
if (!JSValueIsNumber(ctx, lengthValue)) {
|
||||
throw std::runtime_error("Missing property 'length'");
|
||||
}
|
||||
|
||||
return RJSValidatedValueToNumber(ctx, lengthValue);
|
||||
}
|
||||
|
||||
static inline void RJSValidatedSetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSPropertyAttributes attributes = 0) {
|
||||
JSValueRef exception = NULL;
|
||||
JSObjectSetProperty(ctx, object, propertyName, value, attributes, &exception);
|
||||
if (exception) {
|
||||
throw RJSException(ctx, exception);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T stot(const std::string s) {
|
||||
std::istringstream iss(s);
|
||||
T value;
|
||||
iss >> value;
|
||||
if (iss.fail()) {
|
||||
throw std::invalid_argument("Cannot convert string '" + s + "'");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static inline size_t RJSValidatedPositiveIndex(std::string indexStr) {
|
||||
long index = stot<long>(indexStr);
|
||||
if (index < 0) {
|
||||
throw std::out_of_range(std::string("Index ") + indexStr + " cannot be less than zero.");
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
static inline bool RJSIsValueObjectOfType(JSContextRef ctx, JSValueRef value, JSStringRef type) {
|
||||
JSObjectRef globalObject = JSContextGetGlobalObject(ctx);
|
||||
|
||||
JSValueRef exception = NULL;
|
||||
JSValueRef constructorValue = JSObjectGetProperty(ctx, globalObject, type, &exception);
|
||||
if (exception) {
|
||||
throw RJSException(ctx, exception);
|
||||
}
|
||||
|
||||
bool ret = JSValueIsInstanceOfConstructor(ctx, value, RJSValidatedValueToObject(ctx, constructorValue), &exception);
|
||||
if (exception) {
|
||||
throw RJSException(ctx, exception);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
}}
|
|
@ -24,7 +24,7 @@
|
|||
#include "js_init.h"
|
||||
#include "js_object.hpp"
|
||||
#include "js_results.hpp"
|
||||
#include "js_list.hpp"
|
||||
#include "jsc_list.hpp"
|
||||
#include "js_realm.hpp"
|
||||
#include "js_util.hpp"
|
||||
|
||||
|
|
Loading…
Reference in New Issue