From 167c3e97b5f67fc638aa23f3ff7d962ce567a490 Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Mon, 19 Oct 2015 13:39:21 -0700 Subject: [PATCH] store schema and prototypes on the realm object --- src/RJSObject.mm | 11 ++++---- src/RJSRealm.hpp | 9 +++++++ src/RJSRealm.mm | 37 ++++++++++++++++++++++++-- src/RJSSchema.hpp | 6 +---- src/RJSSchema.mm | 39 +++++----------------------- src/RealmJS.h | 2 +- src/RealmJS.mm | 1 - src/object-store/object_accessor.hpp | 8 +++--- 8 files changed, 63 insertions(+), 50 deletions(-) diff --git a/src/RJSObject.mm b/src/RJSObject.mm index b56c2801..9a927286 100644 --- a/src/RJSObject.mm +++ b/src/RJSObject.mm @@ -21,6 +21,7 @@ #import "RJSResults.hpp" #import "RJSSchema.hpp" #import "RJSList.hpp" +#import "RJSRealm.hpp" #import "object_store.hpp" #import "object_accessor.hpp" @@ -63,7 +64,7 @@ JSClassRef RJSObjectClass() { } JSObjectRef RJSObjectCreate(JSContextRef ctx, Object object) { - JSValueRef prototype = RJSPrototypeForClassName(object.object_schema.name); + JSValueRef prototype = RJSPrototypes(object.realm.get())[object.object_schema.name]; JSObjectRef jsObject = RJSWrapObject(ctx, RJSObjectClass(), new Object(object), prototype); return jsObject; } @@ -86,13 +87,13 @@ template<> JSValueRef RJSAccessor::dict_value_for_key(JSContextRef ctx, JSValueR return ret; } -template<> bool RJSAccessor::has_default_value_for_property(JSContextRef ctx, const ObjectSchema &object_schema, const std::string &prop_name) { - ObjectDefaults &defaults = RJSDefaultsForClassName(object_schema.name); +template<> bool RJSAccessor::has_default_value_for_property(JSContextRef ctx, Realm *realm, const ObjectSchema &object_schema, const std::string &prop_name) { + ObjectDefaults &defaults = RJSDefaults(realm)[object_schema.name]; return defaults.find(prop_name) != defaults.end(); } -template<> JSValueRef RJSAccessor::default_value_for_property(JSContextRef ctx, const ObjectSchema &object_schema, const std::string &prop_name) { - ObjectDefaults &defaults = RJSDefaultsForClassName(object_schema.name); +template<> JSValueRef RJSAccessor::default_value_for_property(JSContextRef ctx, Realm *realm, const ObjectSchema &object_schema, const std::string &prop_name) { + ObjectDefaults &defaults = RJSDefaults(realm)[object_schema.name]; return defaults[prop_name]; } diff --git a/src/RJSRealm.hpp b/src/RJSRealm.hpp index d2002ea1..b575e19b 100644 --- a/src/RJSRealm.hpp +++ b/src/RJSRealm.hpp @@ -17,6 +17,12 @@ //////////////////////////////////////////////////////////////////////////// #import "RJSUtil.hpp" +#include + +namespace realm { + class Realm; + using ObjectDefaults = std::map; +} extern const JSStaticFunction RJSRealmFuncs[]; @@ -28,3 +34,6 @@ std::string RJSDefaultPath(); void RJSSetDefaultPath(std::string path); JSObjectRef RealmConstructor(JSContextRef ctx, JSObjectRef constructor, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException); + +std::map &RJSDefaults(realm::Realm *realm); +std::map &RJSPrototypes(realm::Realm *realm); \ No newline at end of file diff --git a/src/RJSRealm.mm b/src/RJSRealm.mm index 78d45c5c..5966052d 100644 --- a/src/RJSRealm.mm +++ b/src/RJSRealm.mm @@ -59,8 +59,36 @@ public: std::vector const& invalidated) { } + + JSGlobalContextRef m_context; + std::map m_defaults; + std::map m_prototypes; + + RJSRealmDelegate(JSGlobalContextRef ctx) : m_context(ctx) { + JSGlobalContextRetain(m_context); + } + + ~RJSRealmDelegate() { + for (auto prototype : m_prototypes) { + JSValueUnprotect(m_context, prototype.second); + } + for (auto objectDefaults : m_defaults) { + for (auto value : objectDefaults.second) { + JSValueUnprotect(m_context, value.second); + } + } + JSGlobalContextRelease(m_context); + } }; +std::map &RJSDefaults(Realm *realm) { + return static_cast(realm->m_delegate.get())->m_defaults; +} + +std::map &RJSPrototypes(Realm *realm) { + return static_cast(realm->m_delegate.get())->m_prototypes; +} + std::string writeablePathForFile(const std::string &fileName) { #if TARGET_OS_IPHONE // On iOS the Documents directory isn't user-visible, so put files there @@ -114,6 +142,8 @@ static bool SetDefaultPath(JSContextRef ctx, JSObjectRef object, JSStringRef pro JSObjectRef RealmConstructor(JSContextRef ctx, JSObjectRef constructor, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) { try { Realm::Config config; + std::map defaults; + std::map prototypes; switch (argumentCount) { case 0: config.path = RJSDefaultPath(); @@ -139,7 +169,7 @@ JSObjectRef RealmConstructor(JSContextRef ctx, JSObjectRef constructor, size_t a static JSStringRef schemaString = JSStringCreateWithUTF8CString("schema"); JSValueRef schemaValue = RJSValidatedPropertyValue(ctx, object, schemaString); if (!JSValueIsUndefined(ctx, schemaValue)) { - config.schema = std::make_unique(RJSParseSchema(ctx, RJSValidatedValueToObject(ctx, schemaValue))); + config.schema = std::make_unique(RJSParseSchema(ctx, RJSValidatedValueToObject(ctx, schemaValue), defaults, prototypes)); } static JSStringRef schemaVersionString = JSStringCreateWithUTF8CString("schemaVersion"); @@ -159,8 +189,10 @@ JSObjectRef RealmConstructor(JSContextRef ctx, JSObjectRef constructor, size_t a } SharedRealm realm = Realm::get_shared_realm(config); if (!realm->m_delegate) { - realm->m_delegate = std::make_unique(); + realm->m_delegate = std::make_unique(JSContextGetGlobalContext(ctx)); } + RJSDefaults(realm.get()) = defaults; + RJSPrototypes(realm.get()) = prototypes; return RJSWrapObject(ctx, RJSRealmClass(), new SharedRealm(realm)); } catch (std::exception &ex) { @@ -424,6 +456,7 @@ JSValueRef RealmClose(JSContextRef ctx, JSObjectRef function, JSObjectRef thisOb SharedRealm realm = *RJSGetInternal(thisObject); realm->invalidate(); realm::Realm::s_global_cache.remove(realm->config().path, realm->thread_id()); + } catch (std::exception &exp) { if (jsException) { diff --git a/src/RJSSchema.hpp b/src/RJSSchema.hpp index 418725d4..f9a2e0bf 100644 --- a/src/RJSSchema.hpp +++ b/src/RJSSchema.hpp @@ -27,8 +27,4 @@ namespace realm { JSClassRef RJSSchemaClass(); JSObjectRef RJSSchemaCreate(JSContextRef ctx, realm::Schema *schema); -realm::Schema RJSParseSchema(JSContextRef ctx, JSObjectRef jsonObject); - -JSValueRef RJSPrototypeForClassName(const std::string &className); -realm::ObjectDefaults &RJSDefaultsForClassName(const std::string &className); -void RJSSchemaClearState(JSContextRef ctx); +realm::Schema RJSParseSchema(JSContextRef ctx, JSObjectRef jsonObject, std::map &defaults, std::map &prototypes); diff --git a/src/RJSSchema.mm b/src/RJSSchema.mm index 4b00eb96..da01f7f0 100644 --- a/src/RJSSchema.mm +++ b/src/RJSSchema.mm @@ -45,30 +45,6 @@ JSObjectRef RJSSchemaCreate(JSContextRef ctx, Schema &schema) { return RJSWrapObject(ctx, RJSSchemaClass(), wrapper); } -static std::map s_defaults; -ObjectDefaults &RJSDefaultsForClassName(const std::string &className) { - return s_defaults[className]; -} - -static std::map s_prototypes; -JSValueRef RJSPrototypeForClassName(const std::string &className) { - return s_prototypes[className]; -} - -void RJSSchemaClearState(JSContextRef ctx) { - for (auto prototype : s_prototypes) { - JSValueUnprotect(ctx, prototype.second); - } - s_prototypes.clear(); - - for (auto defaults : s_defaults) { - for (auto value : defaults.second) { - JSValueUnprotect(ctx, value.second); - } - } - s_defaults.clear(); -} - static inline Property RJSParseProperty(JSContextRef ctx, JSObjectRef propertyObject) { static JSStringRef nameString = JSStringCreateWithUTF8CString("name"); static JSStringRef typeString = JSStringCreateWithUTF8CString("type"); @@ -116,7 +92,7 @@ static inline Property RJSParseProperty(JSContextRef ctx, JSObjectRef propertyOb return prop; } -static inline ObjectSchema RJSParseObjectSchema(JSContextRef ctx, JSObjectRef objectSchemaObject) { +static inline ObjectSchema RJSParseObjectSchema(JSContextRef ctx, JSObjectRef objectSchemaObject, std::map &defaults, std::map &prototypes) { static JSStringRef schemaString = JSStringCreateWithUTF8CString("schema"); static JSStringRef prototypeString = JSStringCreateWithUTF8CString("prototype"); JSObjectRef prototypeObject = NULL; @@ -136,8 +112,7 @@ static inline ObjectSchema RJSParseObjectSchema(JSContextRef ctx, JSObjectRef ob JSObjectRef propertiesObject = RJSValidatedObjectProperty(ctx, objectSchemaObject, propertiesString, "ObjectSchema object must have a 'properties' array."); ObjectSchema objectSchema; - ObjectDefaults defaults; - + ObjectDefaults objectDefaults; static JSStringRef nameString = JSStringCreateWithUTF8CString("name"); objectSchema.name = RJSValidatedStringProperty(ctx, objectSchemaObject, nameString); @@ -150,10 +125,10 @@ static inline ObjectSchema RJSParseObjectSchema(JSContextRef ctx, JSObjectRef ob JSValueRef defaultValue = JSObjectGetProperty(ctx, property, defaultString, NULL); if (!JSValueIsUndefined(ctx, defaultValue)) { JSValueProtect(ctx, defaultValue); - defaults.emplace(objectSchema.properties.back().name, defaultValue); + objectDefaults.emplace(objectSchema.properties.back().name, defaultValue); } } - s_defaults.emplace(objectSchema.name, std::move(defaults)); + defaults.emplace(objectSchema.name, std::move(objectDefaults)); static JSStringRef primaryString = JSStringCreateWithUTF8CString("primaryKey"); JSValueRef primaryValue = RJSValidatedPropertyValue(ctx, objectSchemaObject, primaryString); @@ -169,18 +144,18 @@ static inline ObjectSchema RJSParseObjectSchema(JSContextRef ctx, JSObjectRef ob // store prototype if (prototypeObject) { JSValueProtect(ctx, prototypeObject); - s_prototypes[objectSchema.name] = std::move(prototypeObject); + prototypes[objectSchema.name] = std::move(prototypeObject); } return objectSchema; } -realm::Schema RJSParseSchema(JSContextRef ctx, JSObjectRef jsonObject) { +realm::Schema RJSParseSchema(JSContextRef ctx, JSObjectRef jsonObject, std::map &defaults, std::map &prototypes) { std::vector schema; size_t length = RJSValidatedListLength(ctx, jsonObject); for (unsigned int i = 0; i < length; i++) { JSObjectRef jsonObjectSchema = RJSValidatedObjectAtIndex(ctx, jsonObject, i); - ObjectSchema objectSchema = RJSParseObjectSchema(ctx, jsonObjectSchema); + ObjectSchema objectSchema = RJSParseObjectSchema(ctx, jsonObjectSchema, defaults, prototypes); schema.emplace_back(std::move(objectSchema)); } diff --git a/src/RealmJS.h b/src/RealmJS.h index ad65e68b..5bdd0b2f 100644 --- a/src/RealmJS.h +++ b/src/RealmJS.h @@ -24,7 +24,7 @@ // add realm apis to the given js context + (void)initializeContext:(JSContextRef)ctx; - ++ (void)disposeContext:(JSContextRef)ctx; + (void)clearTestState; @end diff --git a/src/RealmJS.mm b/src/RealmJS.mm index 13076b06..34edaac6 100644 --- a/src/RealmJS.mm +++ b/src/RealmJS.mm @@ -58,7 +58,6 @@ NSString *RealmFileDirectory() { static JSValueRef ClearTestState(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) { [RealmJS clearTestState]; - //RJSSchemaClearState(ctx); return NULL; } diff --git a/src/object-store/object_accessor.hpp b/src/object-store/object_accessor.hpp index 69bffa70..58802a06 100644 --- a/src/object-store/object_accessor.hpp +++ b/src/object-store/object_accessor.hpp @@ -60,8 +60,8 @@ namespace realm { static bool dict_has_value_for_key(ContextType ctx, ValueType dict, const std::string &prop_name); static ValueType dict_value_for_key(ContextType ctx, ValueType dict, const std::string &prop_name); - static bool has_default_value_for_property(ContextType ctx, const ObjectSchema &object_schema, const std::string &prop_name); - static ValueType default_value_for_property(ContextType ctx, const ObjectSchema &object_schema, const std::string &prop_name); + static bool has_default_value_for_property(ContextType ctx, Realm *realm, const ObjectSchema &object_schema, const std::string &prop_name); + static ValueType default_value_for_property(ContextType ctx, Realm *realm, const ObjectSchema &object_schema, const std::string &prop_name); static bool to_bool(ContextType, ValueType &); static ValueType from_bool(ContextType, bool); @@ -260,8 +260,8 @@ namespace realm { object.set_property_value_impl(ctx, prop, Accessor::dict_value_for_key(ctx, value, prop.name), try_update); } else if (created) { - if (Accessor::has_default_value_for_property(ctx, object_schema, prop.name)) { - object.set_property_value_impl(ctx, prop, Accessor::default_value_for_property(ctx, object_schema, prop.name), try_update); + if (Accessor::has_default_value_for_property(ctx, realm.get(), object_schema, prop.name)) { + object.set_property_value_impl(ctx, prop, Accessor::default_value_for_property(ctx, realm.get(), object_schema, prop.name), try_update); } else { throw std::runtime_error("Missing property value for property " + prop.name);