2015-10-27 13:59:15 -07:00
|
|
|
/* Copyright 2015 Realm Inc - All Rights Reserved
|
|
|
|
* Proprietary and Confidential
|
|
|
|
*/
|
2015-08-13 09:12:48 -07:00
|
|
|
|
|
|
|
#import "RJSRealm.hpp"
|
|
|
|
#import "RJSObject.hpp"
|
|
|
|
#import "RJSResults.hpp"
|
2015-10-13 15:27:24 -07:00
|
|
|
#import "RJSList.hpp"
|
2015-08-13 09:12:48 -07:00
|
|
|
#import "RJSSchema.hpp"
|
|
|
|
|
|
|
|
#import "shared_realm.hpp"
|
|
|
|
#import "object_accessor.hpp"
|
2015-09-09 17:16:32 -07:00
|
|
|
#import "realm_delegate.hpp"
|
|
|
|
|
|
|
|
#import <set>
|
2015-08-13 09:12:48 -07:00
|
|
|
|
|
|
|
using namespace realm;
|
|
|
|
|
2015-09-09 17:16:32 -07:00
|
|
|
class RJSRealmDelegate : public RealmDelegate {
|
|
|
|
public:
|
|
|
|
virtual void changes_available() {
|
2015-10-26 16:19:12 -07:00
|
|
|
assert(0);
|
2015-09-09 17:16:32 -07:00
|
|
|
}
|
2015-10-26 16:03:32 -07:00
|
|
|
virtual void did_change(std::vector<ObserverState> const& observers, std::vector<void*> const& invalidated) {
|
2015-10-26 16:19:12 -07:00
|
|
|
notify("change");
|
2015-09-09 17:16:32 -07:00
|
|
|
}
|
|
|
|
virtual std::vector<ObserverState> get_observed_rows() {
|
|
|
|
return std::vector<ObserverState>();
|
|
|
|
}
|
|
|
|
virtual void will_change(std::vector<ObserverState> const& observers,
|
2015-10-26 16:03:32 -07:00
|
|
|
std::vector<void*> const& invalidated) {}
|
2015-10-19 13:39:21 -07:00
|
|
|
|
2015-10-26 16:03:32 -07:00
|
|
|
RJSRealmDelegate(WeakRealm realm, JSGlobalContextRef ctx) : m_context(ctx), m_realm(realm) {
|
2015-10-19 13:39:21 -07:00
|
|
|
JSGlobalContextRetain(m_context);
|
|
|
|
}
|
|
|
|
|
|
|
|
~RJSRealmDelegate() {
|
2015-10-26 16:03:32 -07:00
|
|
|
remove_all_notifications();
|
|
|
|
|
2015-10-19 13:39:21 -07:00
|
|
|
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);
|
|
|
|
}
|
2015-10-26 16:03:32 -07:00
|
|
|
|
|
|
|
void add_notification(JSObjectRef notification) {
|
2015-11-03 02:43:29 -08:00
|
|
|
if (!m_notifications.count(notification)) {
|
|
|
|
JSValueProtect(m_context, notification);
|
|
|
|
m_notifications.insert(notification);
|
|
|
|
}
|
2015-10-26 16:03:32 -07:00
|
|
|
}
|
|
|
|
void remove_notification(JSObjectRef notification) {
|
2015-11-03 02:43:29 -08:00
|
|
|
if (m_notifications.count(notification)) {
|
|
|
|
JSValueUnprotect(m_context, notification);
|
|
|
|
m_notifications.erase(notification);
|
|
|
|
}
|
2015-10-26 16:03:32 -07:00
|
|
|
}
|
|
|
|
void remove_all_notifications() {
|
|
|
|
for (auto notification : m_notifications) {
|
|
|
|
JSValueUnprotect(m_context, notification);
|
|
|
|
}
|
|
|
|
m_notifications.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::map<std::string, ObjectDefaults> m_defaults;
|
|
|
|
std::map<std::string, JSValueRef> m_prototypes;
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::set<JSObjectRef> m_notifications;
|
|
|
|
JSGlobalContextRef m_context;
|
|
|
|
WeakRealm m_realm;
|
|
|
|
|
|
|
|
void notify(const char *notification_name) {
|
2015-10-27 07:48:11 -07:00
|
|
|
JSValueRef arguments[2];
|
|
|
|
SharedRealm realm = m_realm.lock();
|
|
|
|
if (!realm) {
|
|
|
|
throw std::runtime_error("Realm no longer exists");
|
|
|
|
}
|
|
|
|
JSObjectRef realm_object = RJSWrapObject<SharedRealm *>(m_context, RJSRealmClass(), new SharedRealm(realm));
|
|
|
|
arguments[0] = realm_object;
|
|
|
|
arguments[1] = RJSValueForString(m_context, notification_name);
|
2015-10-26 16:03:32 -07:00
|
|
|
|
2015-10-27 07:48:11 -07:00
|
|
|
for (auto callback : m_notifications) {
|
2015-10-26 16:03:32 -07:00
|
|
|
JSValueRef ex = NULL;
|
|
|
|
JSObjectCallAsFunction(m_context, callback, realm_object, 2, arguments, &ex);
|
|
|
|
if (ex) {
|
|
|
|
throw RJSException(m_context, ex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-09-09 17:16:32 -07:00
|
|
|
};
|
|
|
|
|
2015-10-19 13:39:21 -07:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-08-13 09:12:48 -07:00
|
|
|
std::string writeablePathForFile(const std::string &fileName) {
|
|
|
|
#if TARGET_OS_IPHONE
|
|
|
|
// On iOS the Documents directory isn't user-visible, so put files there
|
|
|
|
NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
|
|
|
|
#else
|
|
|
|
// On OS X it is, so put files in Application Support. If we aren't running
|
|
|
|
// in a sandbox, put it in a subdirectory based on the bundle identifier
|
|
|
|
// to avoid accidentally sharing files between applications
|
|
|
|
NSString *path = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES)[0];
|
|
|
|
if (![[NSProcessInfo processInfo] environment][@"APP_SANDBOX_CONTAINER_ID"]) {
|
|
|
|
NSString *identifier = [[NSBundle mainBundle] bundleIdentifier];
|
|
|
|
if ([identifier length] == 0) {
|
|
|
|
identifier = [[[NSBundle mainBundle] executablePath] lastPathComponent];
|
|
|
|
}
|
|
|
|
path = [path stringByAppendingPathComponent:identifier];
|
|
|
|
|
|
|
|
// create directory
|
|
|
|
[[NSFileManager defaultManager] createDirectoryAtPath:path
|
|
|
|
withIntermediateDirectories:YES
|
|
|
|
attributes:nil
|
|
|
|
error:nil];
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return std::string(path.UTF8String) + "/" + fileName;
|
|
|
|
}
|
|
|
|
|
2015-10-28 14:39:42 -07:00
|
|
|
void ensureDirectoryForFile(const std::string &fileName) {
|
|
|
|
NSString *docsDir = [[NSString stringWithUTF8String:fileName.c_str()] stringByDeletingLastPathComponent];
|
|
|
|
NSFileManager *manager = [NSFileManager defaultManager];
|
|
|
|
|
|
|
|
if (![manager fileExistsAtPath:docsDir]) {
|
|
|
|
NSError *error = nil;
|
|
|
|
[manager createDirectoryAtPath:docsDir withIntermediateDirectories:YES attributes:nil error:&error];
|
|
|
|
if (error) {
|
|
|
|
throw std::runtime_error([[error description] UTF8String]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-13 09:12:48 -07:00
|
|
|
static std::string s_defaultPath = writeablePathForFile("default.realm");
|
|
|
|
std::string RJSDefaultPath() {
|
|
|
|
return s_defaultPath;
|
|
|
|
}
|
|
|
|
void RJSSetDefaultPath(std::string path) {
|
|
|
|
s_defaultPath = path;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSValueRef GetDefaultPath(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* jsException) {
|
|
|
|
return RJSValueForString(ctx, s_defaultPath);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool SetDefaultPath(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* jsException) {
|
|
|
|
try {
|
|
|
|
s_defaultPath = RJSValidatedStringForValue(ctx, value, "defaultPath");
|
|
|
|
}
|
|
|
|
catch (std::exception &ex) {
|
|
|
|
if (jsException) {
|
|
|
|
*jsException = RJSMakeError(ctx, ex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSObjectRef RealmConstructor(JSContextRef ctx, JSObjectRef constructor, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
|
|
|
|
try {
|
|
|
|
Realm::Config config;
|
2015-10-19 13:39:21 -07:00
|
|
|
std::map<std::string, realm::ObjectDefaults> defaults;
|
|
|
|
std::map<std::string, JSValueRef> prototypes;
|
2015-08-13 09:12:48 -07:00
|
|
|
switch (argumentCount) {
|
|
|
|
case 0:
|
|
|
|
config.path = RJSDefaultPath();
|
|
|
|
break;
|
|
|
|
case 1: {
|
|
|
|
JSValueRef value = arguments[0];
|
|
|
|
if (JSValueIsString(ctx, value)) {
|
|
|
|
config.path = RJSValidatedStringForValue(ctx, value, "path");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
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 = RJSDefaultPath();
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSStringRef schemaString = JSStringCreateWithUTF8CString("schema");
|
|
|
|
JSValueRef schemaValue = RJSValidatedPropertyValue(ctx, object, schemaString);
|
|
|
|
if (!JSValueIsUndefined(ctx, schemaValue)) {
|
2015-10-19 13:39:21 -07:00
|
|
|
config.schema = std::make_unique<Schema>(RJSParseSchema(ctx, RJSValidatedValueToObject(ctx, schemaValue), defaults, prototypes));
|
2015-08-13 09:12:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
*jsException = RJSMakeError(ctx, "Invalid arguments when constructing 'Realm'");
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-10-28 14:39:42 -07:00
|
|
|
ensureDirectoryForFile(config.path);
|
2015-09-09 17:30:42 -07:00
|
|
|
SharedRealm realm = Realm::get_shared_realm(config);
|
|
|
|
if (!realm->m_delegate) {
|
2015-10-26 16:03:32 -07:00
|
|
|
realm->m_delegate = std::make_unique<RJSRealmDelegate>(realm, JSContextGetGlobalContext(ctx));
|
2015-09-09 17:30:42 -07:00
|
|
|
}
|
2015-10-19 13:39:21 -07:00
|
|
|
RJSDefaults(realm.get()) = defaults;
|
|
|
|
RJSPrototypes(realm.get()) = prototypes;
|
2015-09-09 17:30:42 -07:00
|
|
|
return RJSWrapObject<SharedRealm *>(ctx, RJSRealmClass(), new SharedRealm(realm));
|
2015-08-13 09:12:48 -07:00
|
|
|
}
|
|
|
|
catch (std::exception &ex) {
|
|
|
|
if (jsException) {
|
|
|
|
*jsException = RJSMakeError(ctx, ex);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
JSClassRef RJSRealmConstructorClass() {
|
|
|
|
JSClassDefinition realmConstructorDefinition = kJSClassDefinitionEmpty;
|
|
|
|
realmConstructorDefinition.className = "Realm";
|
|
|
|
realmConstructorDefinition.callAsConstructor = RealmConstructor;
|
|
|
|
|
|
|
|
JSStaticValue realmStaticProperties[] = {
|
|
|
|
{"defaultPath", GetDefaultPath, SetDefaultPath, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
|
|
|
{NULL, NULL}
|
|
|
|
};
|
|
|
|
realmConstructorDefinition.staticValues = realmStaticProperties;
|
|
|
|
return JSClassCreate(&realmConstructorDefinition);
|
|
|
|
}
|
|
|
|
|
|
|
|
JSValueRef RealmGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) {
|
|
|
|
static JSStringRef s_pathString = JSStringCreateWithUTF8CString("path");
|
|
|
|
if (JSStringIsEqual(propertyName, s_pathString)) {
|
|
|
|
return RJSValueForString(ctx, RJSGetInternal<SharedRealm *>(object)->get()->config().path);
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSStringRef s_schemaVersion = JSStringCreateWithUTF8CString("schemaVersion");
|
|
|
|
if (JSStringIsEqual(propertyName, s_schemaVersion)) {
|
|
|
|
return JSValueMakeNumber(ctx, RJSGetInternal<SharedRealm *>(object)->get()->config().schema_version);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSValueRef RealmObjects(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
|
|
|
|
try {
|
|
|
|
RJSValidateArgumentRange(argumentCount, 1, 2);
|
|
|
|
std::string className = RJSValidatedStringForValue(ctx, arguments[0], "objectType");
|
|
|
|
SharedRealm sharedRealm = *RJSGetInternal<SharedRealm *>(thisObject);
|
|
|
|
|
|
|
|
if (argumentCount == 1) {
|
|
|
|
return RJSResultsCreate(ctx, sharedRealm, className);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
std::string predicate = RJSValidatedStringForValue(ctx, arguments[1], "predicate");
|
|
|
|
return RJSResultsCreate(ctx, sharedRealm, className, predicate);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (std::exception &exp) {
|
|
|
|
if (jsException) {
|
|
|
|
*jsException = RJSMakeError(ctx, exp);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
JSObjectRef RJSDictForPropertyArray(JSContextRef ctx, ObjectSchema &object_schema, JSObjectRef array) {
|
|
|
|
// copy to dictionary
|
2015-10-13 15:25:06 -07:00
|
|
|
if (object_schema.properties.size() != RJSValidatedListLength(ctx, array)) {
|
2015-08-13 09:12:48 -07:00
|
|
|
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 {
|
|
|
|
RJSValidateArgumentRange(argumentCount, 2, 3);
|
|
|
|
|
|
|
|
std::string className = RJSValidatedStringForValue(ctx, arguments[0], "objectType");
|
|
|
|
SharedRealm sharedRealm = *RJSGetInternal<SharedRealm *>(thisObject);
|
2015-09-01 15:47:06 -07:00
|
|
|
auto object_schema = sharedRealm->config().schema->find(className);
|
|
|
|
if (object_schema == sharedRealm->config().schema->end()) {
|
|
|
|
*jsException = RJSMakeError(ctx, "Object type '" + className + "' not found in schema.");
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-08-13 09:12:48 -07:00
|
|
|
|
2015-08-14 09:47:33 -07:00
|
|
|
JSObjectRef object = RJSValidatedValueToObject(ctx, arguments[1]);
|
|
|
|
if (RJSIsValueArray(ctx, arguments[1])) {
|
2015-09-09 17:16:32 -07:00
|
|
|
object = RJSDictForPropertyArray(ctx, *object_schema, object);
|
2015-08-14 09:47:33 -07:00
|
|
|
}
|
|
|
|
|
2015-09-03 14:05:56 -07:00
|
|
|
bool update = false;
|
|
|
|
if (argumentCount == 3) {
|
2015-10-12 15:42:56 -07:00
|
|
|
update = JSValueToBoolean(ctx, arguments[2]);
|
2015-09-03 14:05:56 -07:00
|
|
|
}
|
|
|
|
|
2015-09-09 17:16:32 -07:00
|
|
|
return RJSObjectCreate(ctx, Object::create<JSValueRef>(ctx, sharedRealm, *object_schema, object, update));
|
2015-08-14 09:47:33 -07:00
|
|
|
}
|
|
|
|
catch (std::exception &exp) {
|
|
|
|
if (jsException) {
|
|
|
|
*jsException = RJSMakeError(ctx, exp);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
JSValueRef RealmDelete(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
|
|
|
|
try {
|
|
|
|
RJSValidateArgumentCount(argumentCount, 1);
|
|
|
|
|
2015-09-02 21:31:29 -07:00
|
|
|
if (RJSIsValueArray(ctx, arguments[0]) ||
|
|
|
|
JSValueIsObjectOfClass(ctx, arguments[0], RJSResultsClass()) ||
|
2015-10-13 15:27:24 -07:00
|
|
|
JSValueIsObjectOfClass(ctx, arguments[0], RJSListClass()))
|
2015-09-02 21:31:29 -07:00
|
|
|
{
|
2015-08-14 09:47:33 -07:00
|
|
|
JSObjectRef array = RJSValidatedValueToObject(ctx, arguments[0]);
|
2015-10-13 15:25:06 -07:00
|
|
|
size_t length = RJSValidatedListLength(ctx, array);
|
2015-09-02 21:31:29 -07:00
|
|
|
for (long i = length-1; i >= 0; i--) {
|
2015-08-14 09:47:33 -07:00
|
|
|
JSValueRef object = RJSValidatedObjectAtIndex(ctx, array, (unsigned int)i);
|
|
|
|
RealmDelete(ctx, function, thisObject, 1, &object, jsException);
|
2015-09-02 21:31:29 -07:00
|
|
|
if (*jsException) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-08-14 09:47:33 -07:00
|
|
|
}
|
2015-08-13 09:12:48 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-08-14 09:47:33 -07:00
|
|
|
if (!JSValueIsObjectOfClass(ctx, arguments[0], RJSObjectClass())) {
|
2015-09-08 14:07:14 -07:00
|
|
|
throw std::runtime_error("Argument to 'delete' must be a Realm object or a collection of Realm objects.");
|
2015-08-13 09:12:48 -07:00
|
|
|
}
|
|
|
|
|
2015-08-14 09:47:33 -07:00
|
|
|
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->object_schema.name);
|
2015-10-26 15:27:43 -07:00
|
|
|
table->move_last_over(object->row().get_index());
|
2015-08-14 09:47:33 -07:00
|
|
|
|
|
|
|
return NULL;
|
2015-08-13 09:12:48 -07:00
|
|
|
}
|
|
|
|
catch (std::exception &exp) {
|
|
|
|
if (jsException) {
|
|
|
|
*jsException = RJSMakeError(ctx, exp);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-08 14:07:14 -07:00
|
|
|
JSValueRef RealmDeleteAll(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
|
|
|
|
try {
|
|
|
|
RJSValidateArgumentCount(argumentCount, 0);
|
|
|
|
|
|
|
|
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
|
|
|
|
|
|
|
|
if (!realm->is_in_transaction()) {
|
|
|
|
throw std::runtime_error("Can only delete objects within a transaction.");
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto objectSchema : *realm->config().schema) {
|
2015-09-09 17:16:32 -07:00
|
|
|
ObjectStore::table_for_object_type(realm->read_group(), objectSchema.name)->clear();
|
2015-09-08 14:07:14 -07:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
catch (std::exception &exp) {
|
|
|
|
if (jsException) {
|
|
|
|
*jsException = RJSMakeError(ctx, exp);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-13 09:12:48 -07:00
|
|
|
JSValueRef RealmWrite(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
|
|
|
|
try {
|
|
|
|
RJSValidateArgumentCount(argumentCount, 1);
|
|
|
|
|
2015-10-12 17:17:43 -07:00
|
|
|
JSObjectRef object = RJSValidatedValueToFunction(ctx, arguments[0]);
|
2015-08-14 09:47:33 -07:00
|
|
|
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
|
|
|
|
realm->begin_transaction();
|
|
|
|
JSObjectCallAsFunction(ctx, object, thisObject, 0, NULL, jsException);
|
|
|
|
if (*jsException) {
|
|
|
|
realm->cancel_transaction();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
realm->commit_transaction();
|
2015-08-13 09:12:48 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (std::exception &exp) {
|
|
|
|
if (jsException) {
|
|
|
|
*jsException = RJSMakeError(ctx, exp);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-10-26 19:18:24 -07:00
|
|
|
std::string RJSValidatedNotificationName(JSContextRef ctx, JSValueRef value) {
|
|
|
|
std::string name = RJSValidatedStringForValue(ctx, value);
|
|
|
|
if (name != "change") {
|
|
|
|
throw std::runtime_error("Only the 'change' notification name is supported.");
|
|
|
|
}
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
2015-10-26 16:15:46 -07:00
|
|
|
JSValueRef RealmAddListener(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
|
2015-08-13 09:12:48 -07:00
|
|
|
try {
|
2015-10-26 19:18:24 -07:00
|
|
|
RJSValidateArgumentCount(argumentCount, 2);
|
|
|
|
__unused std::string name = RJSValidatedNotificationName(ctx, arguments[0]);
|
|
|
|
JSObjectRef callback = RJSValidatedValueToFunction(ctx, arguments[1]);
|
2015-08-13 09:12:48 -07:00
|
|
|
|
|
|
|
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
|
2015-10-26 16:03:32 -07:00
|
|
|
static_cast<RJSRealmDelegate *>(realm->m_delegate.get())->add_notification(callback);
|
|
|
|
return NULL;
|
2015-08-13 09:12:48 -07:00
|
|
|
}
|
|
|
|
catch (std::exception &exp) {
|
|
|
|
if (jsException) {
|
|
|
|
*jsException = RJSMakeError(ctx, exp);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-26 16:15:46 -07:00
|
|
|
JSValueRef RealmRemoveListener(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
|
|
|
|
try {
|
2015-10-26 19:18:24 -07:00
|
|
|
RJSValidateArgumentCount(argumentCount, 2);
|
|
|
|
__unused std::string name = RJSValidatedNotificationName(ctx, arguments[0]);
|
|
|
|
JSObjectRef callback = RJSValidatedValueToFunction(ctx, arguments[1]);
|
2015-10-26 16:15:46 -07:00
|
|
|
|
|
|
|
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
|
|
|
|
static_cast<RJSRealmDelegate *>(realm->m_delegate.get())->remove_notification(callback);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
catch (std::exception &exp) {
|
|
|
|
if (jsException) {
|
|
|
|
*jsException = RJSMakeError(ctx, exp);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
JSValueRef RealmRemoveAllListeners(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
|
|
|
|
try {
|
2015-10-26 19:18:24 -07:00
|
|
|
RJSValidateArgumentRange(argumentCount, 0, 1);
|
|
|
|
if (argumentCount) {
|
|
|
|
RJSValidatedNotificationName(ctx, arguments[0]);
|
|
|
|
}
|
|
|
|
|
2015-10-26 16:15:46 -07:00
|
|
|
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
|
|
|
|
static_cast<RJSRealmDelegate *>(realm->m_delegate.get())->remove_all_notifications();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
catch (std::exception &exp) {
|
|
|
|
if (jsException) {
|
|
|
|
*jsException = RJSMakeError(ctx, exp);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-12 17:01:51 -07:00
|
|
|
JSValueRef RealmClose(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
|
|
|
|
try {
|
|
|
|
RJSValidateArgumentCount(argumentCount, 0);
|
|
|
|
SharedRealm realm = *RJSGetInternal<SharedRealm *>(thisObject);
|
2015-10-19 14:25:35 -07:00
|
|
|
realm->close();
|
2015-10-12 17:01:51 -07:00
|
|
|
realm::Realm::s_global_cache.remove(realm->config().path, realm->thread_id());
|
2015-10-19 13:39:21 -07:00
|
|
|
|
2015-10-12 17:01:51 -07:00
|
|
|
}
|
|
|
|
catch (std::exception &exp) {
|
|
|
|
if (jsException) {
|
|
|
|
*jsException = RJSMakeError(ctx, exp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-10-19 15:52:32 -07:00
|
|
|
static const JSStaticFunction RJSRealmFuncs[] = {
|
2015-10-08 10:43:38 -06:00
|
|
|
{"objects", RealmObjects, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
|
|
|
{"create", RealmCreateObject, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
|
|
|
{"delete", RealmDelete, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
|
|
|
{"deleteAll", RealmDeleteAll, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
|
|
|
{"write", RealmWrite, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
2015-10-26 16:15:46 -07:00
|
|
|
{"addListener", RealmAddListener, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
|
|
|
{"removeListener", RealmRemoveListener, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
|
|
|
{"removeAllListeners", RealmRemoveAllListeners, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
2015-10-12 17:01:51 -07:00
|
|
|
{"close", RealmClose, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
|
2015-10-08 10:43:38 -06:00
|
|
|
{NULL, NULL},
|
|
|
|
};
|
2015-08-13 09:12:48 -07:00
|
|
|
|
|
|
|
JSClassRef RJSRealmClass() {
|
2015-10-08 10:43:38 -06:00
|
|
|
static JSClassRef s_realmClass = RJSCreateWrapperClass<SharedRealm *>("Realm", RealmGetProperty, NULL, RJSRealmFuncs);
|
2015-08-13 09:12:48 -07:00
|
|
|
return s_realmClass;
|
|
|
|
}
|