Merge pull request #66 from realm/al-per-realm
Store schema/defaults per Realm, Cleanup per Realm state and threads
This commit is contained in:
commit
3b5c78d29f
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
@ -422,8 +454,9 @@ JSValueRef RealmClose(JSContextRef ctx, JSObjectRef function, JSObjectRef thisOb
|
|||
try {
|
||||
RJSValidateArgumentCount(argumentCount, 0);
|
||||
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
|
||||
realm->invalidate();
|
||||
realm->close();
|
||||
realm::Realm::s_global_cache.remove(realm->config().path, realm->thread_id());
|
||||
|
||||
}
|
||||
catch (std::exception &exp) {
|
||||
if (jsException) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
|
||||
// add realm apis to the given js context
|
||||
+ (void)initializeContext:(JSContextRef)ctx;
|
||||
|
||||
+ (void)clearTestState;
|
||||
|
||||
@end
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -84,7 +83,7 @@ static JSValueRef ClearTestState(JSContextRef ctx, JSObjectRef function, JSObjec
|
|||
}
|
||||
|
||||
+ (void)clearTestState {
|
||||
realm::Realm::s_global_cache.invalidate_all();
|
||||
realm::Realm::s_global_cache.close_all();
|
||||
realm::Realm::s_global_cache.clear();
|
||||
|
||||
NSFileManager *manager = [NSFileManager defaultManager];
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -295,6 +295,16 @@ void Realm::invalidate()
|
|||
m_group = nullptr;
|
||||
}
|
||||
|
||||
void Realm::close()
|
||||
{
|
||||
invalidate();
|
||||
if (m_notifier) {
|
||||
m_notifier->remove_realm(this);
|
||||
m_notifier = nullptr;
|
||||
}
|
||||
m_delegate = nullptr;
|
||||
}
|
||||
|
||||
bool Realm::compact()
|
||||
{
|
||||
verify_thread();
|
||||
|
@ -440,14 +450,15 @@ void RealmCache::cache_realm(SharedRealm &realm, std::thread::id thread_id)
|
|||
}
|
||||
}
|
||||
|
||||
void RealmCache::invalidate_all()
|
||||
void RealmCache::close_all(std::thread::id thread_id)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
for (auto &path_realms : m_cache) {
|
||||
for (auto &realm_iter : path_realms.second) {
|
||||
if (auto realm = realm_iter.second.lock()) {
|
||||
realm->invalidate();
|
||||
auto thread_realm = path_realms.second.find(thread_id);
|
||||
if (thread_realm != path_realms.second.end()) {
|
||||
if (auto realm = thread_realm->second.lock()) {
|
||||
realm->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,6 +94,7 @@ namespace realm {
|
|||
|
||||
void invalidate();
|
||||
bool compact();
|
||||
void close();
|
||||
|
||||
std::thread::id thread_id() const { return m_thread_id; }
|
||||
void verify_thread() const;
|
||||
|
@ -131,7 +132,7 @@ namespace realm {
|
|||
SharedRealm get_any_realm(const std::string &path);
|
||||
void remove(const std::string &path, std::thread::id thread_id);
|
||||
void cache_realm(SharedRealm &realm, std::thread::id thread_id = std::this_thread::get_id());
|
||||
void invalidate_all();
|
||||
void close_all(std::thread::id thread_id = std::this_thread::get_id());
|
||||
void clear();
|
||||
|
||||
private:
|
||||
|
|
Loading…
Reference in New Issue