store schema and prototypes on the realm object

This commit is contained in:
Ari Lazier 2015-10-19 13:39:21 -07:00
parent 8ee6e757ee
commit 167c3e97b5
8 changed files with 63 additions and 50 deletions

View File

@ -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];
}

View File

@ -17,6 +17,12 @@
////////////////////////////////////////////////////////////////////////////
#import "RJSUtil.hpp"
#include <map>
namespace realm {
class Realm;
using ObjectDefaults = std::map<std::string, JSValueRef>;
}
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<std::string, realm::ObjectDefaults> &RJSDefaults(realm::Realm *realm);
std::map<std::string, JSValueRef> &RJSPrototypes(realm::Realm *realm);

View File

@ -59,8 +59,36 @@ public:
std::vector<void*> const& invalidated) {
}
JSGlobalContextRef m_context;
std::map<std::string, ObjectDefaults> m_defaults;
std::map<std::string, JSValueRef> 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<std::string, ObjectDefaults> &RJSDefaults(Realm *realm) {
return static_cast<RJSRealmDelegate *>(realm->m_delegate.get())->m_defaults;
}
std::map<std::string, JSValueRef> &RJSPrototypes(Realm *realm) {
return static_cast<RJSRealmDelegate *>(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<std::string, realm::ObjectDefaults> defaults;
std::map<std::string, JSValueRef> 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<Schema>(RJSParseSchema(ctx, RJSValidatedValueToObject(ctx, schemaValue)));
config.schema = std::make_unique<Schema>(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<RJSRealmDelegate>();
realm->m_delegate = std::make_unique<RJSRealmDelegate>(JSContextGetGlobalContext(ctx));
}
RJSDefaults(realm.get()) = defaults;
RJSPrototypes(realm.get()) = prototypes;
return RJSWrapObject<SharedRealm *>(ctx, RJSRealmClass(), new SharedRealm(realm));
}
catch (std::exception &ex) {
@ -424,6 +456,7 @@ JSValueRef RealmClose(JSContextRef ctx, JSObjectRef function, JSObjectRef thisOb
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
realm->invalidate();
realm::Realm::s_global_cache.remove(realm->config().path, realm->thread_id());
}
catch (std::exception &exp) {
if (jsException) {

View File

@ -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<std::string, realm::ObjectDefaults> &defaults, std::map<std::string, JSValueRef> &prototypes);

View File

@ -45,30 +45,6 @@ JSObjectRef RJSSchemaCreate(JSContextRef ctx, Schema &schema) {
return RJSWrapObject(ctx, RJSSchemaClass(), wrapper);
}
static std::map<std::string, ObjectDefaults> s_defaults;
ObjectDefaults &RJSDefaultsForClassName(const std::string &className) {
return s_defaults[className];
}
static std::map<std::string, JSValueRef> 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<std::string, realm::ObjectDefaults> &defaults, std::map<std::string, JSValueRef> &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<std::string, realm::ObjectDefaults> &defaults, std::map<std::string, JSValueRef> &prototypes) {
std::vector<ObjectSchema> 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));
}

View File

@ -24,7 +24,7 @@
// add realm apis to the given js context
+ (void)initializeContext:(JSContextRef)ctx;
+ (void)disposeContext:(JSContextRef)ctx;
+ (void)clearTestState;
@end

View File

@ -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;
}

View File

@ -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);