diff --git a/src/js_realm.hpp b/src/js_realm.hpp index 0702391b..a04dcb04 100644 --- a/src/js_realm.hpp +++ b/src/js_realm.hpp @@ -19,10 +19,12 @@ #pragma once #include "js_util.hpp" +#include "js_schema.hpp" #include "shared_realm.hpp" #include "binding_context.hpp" #include "object_accessor.hpp" #include "results.hpp" +#include "platform.hpp" #include #include @@ -127,6 +129,7 @@ public: using ReturnType = typename T::Return; using ExceptionType = typename T::Exception; + // member methods static void Objects(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject); static void Create(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject); static void Delete(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject); @@ -136,6 +139,10 @@ public: static void RemoveListener(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject); static void RemoveAllListeners(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject); static void Close(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject); + + // constructor methods + static void Constructor(ContextType ctx, ObjectType constructor, size_t argumentCount, const ValueType arguments[], ObjectType &returnObject); + static void SchemaVersion(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject); static std::string validated_notification_name(JSContextRef ctx, JSValueRef value) { std::string name = RJSValidatedStringForValue(ctx, value); @@ -161,8 +168,104 @@ public: return RJSValidatedStringForValue(ctx, value, "objectType"); } - + static std::string RJSNormalizePath(std::string path) { + if (path.size() && path[0] != '/') { + return default_realm_file_directory() + "/" + path; + } + return path; + } }; + + +template +void Realm::Constructor(ContextType ctx, ObjectType constructor, size_t argumentCount, const ValueType arguments[], ObjectType &returnObject) { + using RJSAccessor = realm::NativeAccessor; + + realm::Realm::Config config; + std::map defaults; + std::map constructors; + if (argumentCount == 0) { + config.path = default_path(); + } + else if (argumentCount == 1) { + ValueType value = arguments[0]; + if (ValueIsString(ctx, value)) { + config.path = RJSValidatedStringForValue(ctx, value, "path"); + } + else if (ValueIsObject(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 = js::default_path(); + } + + 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(encryptionKey.begin(), encryptionKey.end());; + } + } + } + else { + throw std::runtime_error("Invalid arguments when constructing 'Realm'"); + } + + config.path = RJSNormalizePath(config.path); + + ensure_directory_exists_for_file(config.path); + SharedRealm realm = realm::Realm::get_shared_realm(config); + auto delegate = new RealmDelegate(realm, JSContextGetGlobalContext(ctx)); + if (!realm->m_binding_context) { + realm->m_binding_context.reset(delegate); + } + delegate->m_defaults = defaults; + delegate->m_constructors = constructors; + returnObject = WrapObject(ctx, realm_class(), new SharedRealm(realm)); +} + +template +void Realm::SchemaVersion(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject) { + using RJSAccessor = realm::NativeAccessor; + + RJSValidateArgumentRange(argumentCount, 1, 2); + + realm::Realm::Config config; + config.path = RJSNormalizePath(RJSValidatedStringForValue(ctx, arguments[0])); + if (argumentCount == 2) { + auto encryptionKeyValue = arguments[1]; + std::string encryptionKey = RJSAccessor::to_binary(ctx, encryptionKeyValue); + config.encryption_key = std::vector(encryptionKey.begin(), encryptionKey.end()); + } + + auto version = realm::Realm::get_schema_version(config); + if (version == ObjectStore::NotVersioned) { + RJSSetReturnNumber(ctx, returnObject, -1); + } + else { + RJSSetReturnNumber(ctx, returnObject, version); + } +} template void Realm::Objects(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject) { diff --git a/src/js_util.hpp b/src/js_util.hpp index 8c8789ce..3c6222c6 100644 --- a/src/js_util.hpp +++ b/src/js_util.hpp @@ -33,18 +33,21 @@ #include "js_compat.hpp" #include "schema.hpp" +#define WRAP_EXCEPTION(METHOD, EXCEPTION, ARGS...) \ +try { METHOD(ARGS); } \ +catch(std::exception &e) { RJSSetException(ctx, EXCEPTION, e); } + #define WRAP_CLASS_METHOD(CLASS_NAME, METHOD_NAME) \ -JSValueRef CLASS_NAME ## METHOD_NAME(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) { \ +JSValueRef CLASS_NAME ## METHOD_NAME(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* ex) { \ JSValueRef returnObject = NULL; \ - try { CLASS_NAME::METHOD_NAME(ctx, thisObject, argumentCount, arguments, returnObject); } \ - catch(std::exception &ex) { RJSSetException(ctx, *jsException, ex); } \ + WRAP_EXCEPTION(CLASS_NAME::METHOD_NAME, *ex, ctx, thisObject, argumentCount, arguments, returnObject); \ return returnObject; \ } -#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); \ +#define WRAP_CONSTRUCTOR(CLASS_NAME, METHOD_NAME) \ +JSObjectRef CLASS_NAME ## METHOD_NAME(JSContextRef ctx, JSObjectRef constructor, size_t argumentCount, const JSValueRef arguments[], JSValueRef* ex) { \ + JSObjectRef returnObject = NULL; \ + WRAP_EXCEPTION(CLASS_NAME::METHOD_NAME, *ex, ctx, constructor, argumentCount, arguments, returnObject); \ return returnObject; \ } @@ -313,3 +316,4 @@ static bool RJSValueIsObjectOfClass(JSContextRef ctx, JSValueRef value, JSClassR return JSValueIsObjectOfClass(ctx, value, jsClass); } + diff --git a/src/jsc/jsc_realm.cpp b/src/jsc/jsc_realm.cpp index 258ffe51..7623454c 100644 --- a/src/jsc/jsc_realm.cpp +++ b/src/jsc/jsc_realm.cpp @@ -52,86 +52,6 @@ static bool SetDefaultPath(JSContextRef ctx, JSObjectRef object, JSStringRef pro 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 defaults; - std::map constructors; - if (argumentCount == 0) { - config.path = js::default_path(); - } - 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 = js::default_path(); - } - - 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(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); - auto delegate = new js::RealmDelegate(realm, JSContextGetGlobalContext(ctx)); - if (!realm->m_binding_context) { - realm->m_binding_context.reset(delegate); - } - delegate->m_defaults = defaults; - delegate->m_constructors = constructors; - return js::WrapObject(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()); } @@ -141,36 +61,13 @@ static const JSStaticValue RealmStaticProperties[] = { {NULL, NULL} }; -template -void RealmSchemaVersion(ContextType ctx, ObjectType thisObject, size_t argumentCount, const ValueType arguments[], ReturnType &returnObject, ExceptionType &exceptionObject) { - try { - RJSValidateArgumentRange(argumentCount, 1, 2); - - Realm::Config config; - config.path = RJSNormalizePath(RJSValidatedStringForValue(ctx, arguments[0])); - if (argumentCount == 2) { - auto encryptionKeyValue = arguments[1]; - std::string encryptionKey = RJSAccessor::to_binary(ctx, encryptionKeyValue); - config.encryption_key = std::vector(encryptionKey.begin(), encryptionKey.end()); - } - auto version = Realm::get_schema_version(config); - if (version == ObjectStore::NotVersioned) { - RJSSetReturnNumber(ctx, returnObject, -1); - } - else { - RJSSetReturnNumber(ctx, returnObject, version); - } - } - catch (std::exception &exp) { - RJSSetException(ctx, exceptionObject, exp); - } -} - -WRAP_METHOD(RealmSchemaVersion) +using RJSRealm = realm::js::Realm; +WRAP_CONSTRUCTOR(RJSRealm, Constructor); +WRAP_CLASS_METHOD(RJSRealm, SchemaVersion) static const JSStaticFunction RealmConstructorFuncs[] = { - {"schemaVersion", RealmSchemaVersion, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, + {"schemaVersion", RJSRealmSchemaVersion, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, {NULL, NULL}, }; @@ -178,7 +75,7 @@ JSClassRef RJSRealmConstructorClass() { JSClassDefinition realmConstructorDefinition = kJSClassDefinitionEmpty; realmConstructorDefinition.attributes = kJSClassAttributeNoAutomaticPrototype; realmConstructorDefinition.className = "RealmConstructor"; - realmConstructorDefinition.callAsConstructor = RealmConstructor; + realmConstructorDefinition.callAsConstructor = RJSRealmConstructor; realmConstructorDefinition.hasInstance = RealmHasInstance; realmConstructorDefinition.staticValues = RealmStaticProperties; realmConstructorDefinition.staticFunctions = RealmConstructorFuncs; @@ -198,7 +95,6 @@ JSValueRef RealmGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef pr return NULL; } -using RJSRealm = realm::js::Realm; WRAP_CLASS_METHOD(RJSRealm, Objects) WRAP_CLASS_METHOD(RJSRealm, Create) WRAP_CLASS_METHOD(RJSRealm, Delete)