diff --git a/RealmJS.xcodeproj/project.pbxproj b/RealmJS.xcodeproj/project.pbxproj index 3366743b..125febe4 100644 --- a/RealmJS.xcodeproj/project.pbxproj +++ b/RealmJS.xcodeproj/project.pbxproj @@ -21,8 +21,8 @@ 02601F121BA10228007C91FF /* transact_log_handler.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 02601F101BA10228007C91FF /* transact_log_handler.hpp */; }; 0270BC4C1B7CFC0D00010E03 /* RealmJS.h in Headers */ = {isa = PBXBuildFile; fileRef = 0270BC3E1B7CFC0D00010E03 /* RealmJS.h */; settings = {ATTRIBUTES = (Public, ); }; }; 0270BC4D1B7CFC0D00010E03 /* RealmJS.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0270BC3F1B7CFC0D00010E03 /* RealmJS.mm */; }; - 0270BC4E1B7CFC0D00010E03 /* RJSArray.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0270BC401B7CFC0D00010E03 /* RJSArray.cpp */; }; - 0270BC4F1B7CFC0D00010E03 /* RJSArray.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0270BC411B7CFC0D00010E03 /* RJSArray.hpp */; settings = {ATTRIBUTES = (Private, ); }; }; + 0270BC4E1B7CFC0D00010E03 /* RJSList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0270BC401B7CFC0D00010E03 /* RJSList.cpp */; }; + 0270BC4F1B7CFC0D00010E03 /* RJSList.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0270BC411B7CFC0D00010E03 /* RJSList.hpp */; settings = {ATTRIBUTES = (Private, ); }; }; 0270BC501B7CFC0D00010E03 /* RJSObject.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0270BC421B7CFC0D00010E03 /* RJSObject.hpp */; settings = {ATTRIBUTES = (Private, ); }; }; 0270BC511B7CFC0D00010E03 /* RJSObject.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0270BC431B7CFC0D00010E03 /* RJSObject.mm */; }; 0270BC521B7CFC0D00010E03 /* RJSRealm.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0270BC441B7CFC0D00010E03 /* RJSRealm.hpp */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -33,7 +33,6 @@ 0270BC571B7CFC0D00010E03 /* RJSSchema.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0270BC491B7CFC0D00010E03 /* RJSSchema.mm */; }; 0270BC581B7CFC0D00010E03 /* RJSUtil.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0270BC4A1B7CFC0D00010E03 /* RJSUtil.hpp */; settings = {ATTRIBUTES = (Private, ); }; }; 0270BC591B7CFC0D00010E03 /* RJSUtil.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0270BC4B1B7CFC0D00010E03 /* RJSUtil.mm */; }; - 0270BC671B7CFC1C00010E03 /* object_accessor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0270BC5C1B7CFC1C00010E03 /* object_accessor.cpp */; }; 0270BC681B7CFC1C00010E03 /* object_accessor.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0270BC5D1B7CFC1C00010E03 /* object_accessor.hpp */; }; 0270BC691B7CFC1C00010E03 /* object_schema.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0270BC5E1B7CFC1C00010E03 /* object_schema.cpp */; }; 0270BC6A1B7CFC1C00010E03 /* object_schema.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0270BC5F1B7CFC1C00010E03 /* object_schema.hpp */; }; @@ -54,6 +53,8 @@ 0270BCD11B7D067300010E03 /* RealmReactModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 0270BCD01B7D067300010E03 /* RealmReactModule.m */; }; 02B29A311B7CF86D008A7E6B /* RealmJS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CB11AE99CEC009B348C /* RealmJS.framework */; }; 02B58CCE1AE99D4D009B348C /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CCD1AE99D4D009B348C /* JavaScriptCore.framework */; }; + 02C0864E1BCDB27000942F9C /* list.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02C0864C1BCDB27000942F9C /* list.cpp */; settings = {ASSET_TAGS = (); }; }; + 02C0864F1BCDB27000942F9C /* list.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 02C0864D1BCDB27000942F9C /* list.hpp */; settings = {ASSET_TAGS = (); }; }; 02D456DA1B7E59A500EE1299 /* ArrayTests.js in Resources */ = {isa = PBXBuildFile; fileRef = 02D456D91B7E59A500EE1299 /* ArrayTests.js */; }; 02D8D1F71B601984006DB49D /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CCD1AE99D4D009B348C /* JavaScriptCore.framework */; }; /* End PBXBuildFile section */ @@ -143,8 +144,8 @@ 02601F101BA10228007C91FF /* transact_log_handler.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = transact_log_handler.hpp; path = "src/object-store/transact_log_handler.hpp"; sourceTree = ""; }; 0270BC3E1B7CFC0D00010E03 /* RealmJS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RealmJS.h; path = src/RealmJS.h; sourceTree = ""; }; 0270BC3F1B7CFC0D00010E03 /* RealmJS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = RealmJS.mm; path = src/RealmJS.mm; sourceTree = ""; }; - 0270BC401B7CFC0D00010E03 /* RJSArray.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RJSArray.cpp; path = src/RJSArray.cpp; sourceTree = ""; }; - 0270BC411B7CFC0D00010E03 /* RJSArray.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = RJSArray.hpp; path = src/RJSArray.hpp; sourceTree = ""; }; + 0270BC401B7CFC0D00010E03 /* RJSList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RJSList.cpp; path = src/RJSList.cpp; sourceTree = ""; }; + 0270BC411B7CFC0D00010E03 /* RJSList.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = RJSList.hpp; path = src/RJSList.hpp; sourceTree = ""; }; 0270BC421B7CFC0D00010E03 /* RJSObject.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = RJSObject.hpp; path = src/RJSObject.hpp; sourceTree = ""; }; 0270BC431B7CFC0D00010E03 /* RJSObject.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = RJSObject.mm; path = src/RJSObject.mm; sourceTree = ""; }; 0270BC441B7CFC0D00010E03 /* RJSRealm.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = RJSRealm.hpp; path = src/RJSRealm.hpp; sourceTree = ""; }; @@ -156,7 +157,6 @@ 0270BC4A1B7CFC0D00010E03 /* RJSUtil.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = RJSUtil.hpp; path = src/RJSUtil.hpp; sourceTree = ""; }; 0270BC4B1B7CFC0D00010E03 /* RJSUtil.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = RJSUtil.mm; path = src/RJSUtil.mm; sourceTree = ""; }; 0270BC5A1B7CFC1300010E03 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = src/Info.plist; sourceTree = ""; }; - 0270BC5C1B7CFC1C00010E03 /* object_accessor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = object_accessor.cpp; path = "src/object-store/object_accessor.cpp"; sourceTree = ""; }; 0270BC5D1B7CFC1C00010E03 /* object_accessor.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = object_accessor.hpp; path = "src/object-store/object_accessor.hpp"; sourceTree = ""; }; 0270BC5E1B7CFC1C00010E03 /* object_schema.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = object_schema.cpp; path = "src/object-store/object_schema.cpp"; sourceTree = ""; }; 0270BC5F1B7CFC1C00010E03 /* object_schema.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = object_schema.hpp; path = "src/object-store/object_schema.hpp"; sourceTree = ""; }; @@ -183,6 +183,8 @@ 02B58CB11AE99CEC009B348C /* RealmJS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RealmJS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 02B58CBC1AE99CEC009B348C /* RealmJSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RealmJSTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 02B58CCD1AE99D4D009B348C /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; + 02C0864C1BCDB27000942F9C /* list.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = list.cpp; path = "src/object-store/list.cpp"; sourceTree = ""; }; + 02C0864D1BCDB27000942F9C /* list.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = list.hpp; path = "src/object-store/list.hpp"; sourceTree = ""; }; 02D456D91B7E59A500EE1299 /* ArrayTests.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ArrayTests.js; path = tests/ArrayTests.js; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ @@ -219,7 +221,6 @@ 0270BC3D1B7CFBFD00010E03 /* RealmJS */ = { isa = PBXGroup; children = ( - 0270BC5C1B7CFC1C00010E03 /* object_accessor.cpp */, 0270BC5D1B7CFC1C00010E03 /* object_accessor.hpp */, 0270BC5E1B7CFC1C00010E03 /* object_schema.cpp */, 0270BC5F1B7CFC1C00010E03 /* object_schema.hpp */, @@ -234,6 +235,8 @@ 02601F021BA0F0C4007C91FF /* external_commit_helper.hpp */, 02601F051BA0F0CD007C91FF /* index_set.cpp */, 02601F061BA0F0CD007C91FF /* index_set.hpp */, + 02C0864C1BCDB27000942F9C /* list.cpp */, + 02C0864D1BCDB27000942F9C /* list.hpp */, 02601F0B1BA0F3A7007C91FF /* schema.cpp */, 02601F0C1BA0F3A7007C91FF /* schema.hpp */, 02601F0F1BA10228007C91FF /* transact_log_handler.cpp */, @@ -243,8 +246,8 @@ 0270BC3F1B7CFC0D00010E03 /* RealmJS.mm */, 02258FB11BC6E2D00075F13A /* RealmRPC.h */, 02258FB21BC6E2D00075F13A /* RealmRPC.mm */, - 0270BC401B7CFC0D00010E03 /* RJSArray.cpp */, - 0270BC411B7CFC0D00010E03 /* RJSArray.hpp */, + 0270BC401B7CFC0D00010E03 /* RJSList.cpp */, + 0270BC411B7CFC0D00010E03 /* RJSList.hpp */, 0270BC421B7CFC0D00010E03 /* RJSObject.hpp */, 0270BC431B7CFC0D00010E03 /* RJSObject.mm */, 0270BC441B7CFC0D00010E03 /* RJSRealm.hpp */, @@ -337,7 +340,7 @@ files = ( 0270BC4C1B7CFC0D00010E03 /* RealmJS.h in Headers */, 02258FB31BC6E2D00075F13A /* RealmRPC.h in Headers */, - 0270BC4F1B7CFC0D00010E03 /* RJSArray.hpp in Headers */, + 0270BC4F1B7CFC0D00010E03 /* RJSList.hpp in Headers */, 0270BC541B7CFC0D00010E03 /* RJSResults.hpp in Headers */, 0270BC581B7CFC0D00010E03 /* RJSUtil.hpp in Headers */, 0270BC561B7CFC0D00010E03 /* RJSSchema.hpp in Headers */, @@ -353,6 +356,7 @@ 02601F041BA0F0C4007C91FF /* external_commit_helper.hpp in Headers */, 02601F091BA0F0CD007C91FF /* index_set.hpp in Headers */, 0270BC6D1B7CFC1C00010E03 /* property.hpp in Headers */, + 02C0864F1BCDB27000942F9C /* list.hpp in Headers */, 0270BC6F1B7CFC1C00010E03 /* results.hpp in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -563,11 +567,11 @@ 02601F111BA10228007C91FF /* transact_log_handler.cpp in Sources */, 0270BC591B7CFC0D00010E03 /* RJSUtil.mm in Sources */, 0270BC551B7CFC0D00010E03 /* RJSResults.mm in Sources */, + 02C0864E1BCDB27000942F9C /* list.cpp in Sources */, 02601F031BA0F0C4007C91FF /* external_commit_helper.cpp in Sources */, 0270BC6B1B7CFC1C00010E03 /* object_store.cpp in Sources */, 0270BC701B7CFC1C00010E03 /* shared_realm.cpp in Sources */, - 0270BC671B7CFC1C00010E03 /* object_accessor.cpp in Sources */, - 0270BC4E1B7CFC0D00010E03 /* RJSArray.cpp in Sources */, + 0270BC4E1B7CFC0D00010E03 /* RJSList.cpp in Sources */, 0270BC531B7CFC0D00010E03 /* RJSRealm.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/src/RJSArray.cpp b/src/RJSList.cpp similarity index 54% rename from src/RJSArray.cpp rename to src/RJSList.cpp index b11f1446..dfb35bb5 100644 --- a/src/RJSArray.cpp +++ b/src/RJSList.cpp @@ -16,7 +16,7 @@ // //////////////////////////////////////////////////////////////////////////// -#include "RJSArray.hpp" +#include "RJSList.hpp" #include "RJSObject.hpp" #include "RJSUtil.hpp" #include "object_accessor.hpp" @@ -24,60 +24,32 @@ using RJSAccessor = realm::NativeAccessor; using namespace realm; -size_t ObjectArray::size() { - return link_view->size(); +static inline List * RJSVerifiedList(JSObjectRef object) { + List *list = RJSGetInternal(object); + list->verify_attached(); + return list; } -Row ObjectArray::get(std::size_t row_ndx) { - verify_valid_row(row_ndx); - return link_view->get(row_ndx); -} - -void ObjectArray::set(std::size_t row_ndx, std::size_t target_row_ndx) { - verify_valid_row(row_ndx); - link_view->set(row_ndx, target_row_ndx); -} - -void ObjectArray::verify_valid_row(std::size_t row_ndx) { - size_t size = link_view->size(); - if (row_ndx >= size) { - throw std::out_of_range(std::string("Index ") + std::to_string(row_ndx) + " is outside of range 0..." + std::to_string(size) + "."); - } -} - -void ObjectArray::verify_attached() { - if (!link_view->is_attached()) { - throw std::runtime_error("Tableview is not attached"); - } - link_view->sync_if_needed(); -} - -static inline ObjectArray * RJSVerifiedArray(JSObjectRef object) { - ObjectArray *array = RJSGetInternal(object); - array->verify_attached(); - return array; -} - -static inline ObjectArray * RJSVerifiedMutableArray(JSObjectRef object) { - ObjectArray *array = RJSVerifiedArray(object); - if (!array->realm->is_in_transaction()) { +static inline List * RJSVerifiedMutableList(JSObjectRef object) { + List *list = RJSVerifiedList(object); + if (!list->realm->is_in_transaction()) { throw std::runtime_error("Can only mutate lists within a transaction."); } - return array; + return list; } -JSValueRef ArrayGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* jsException) { +JSValueRef ListGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* jsException) { try { // index subscripting - ObjectArray *array = RJSVerifiedArray(object); - size_t size = array->size(); + List *list = RJSVerifiedList(object); + size_t size = list->size(); std::string indexStr = RJSStringForJSString(propertyName); if (indexStr == "length") { return JSValueMakeNumber(ctx, size); } - return RJSObjectCreate(ctx, Object(array->realm, array->object_schema, array->get(RJSValidatedPositiveIndex(indexStr)))); + return RJSObjectCreate(ctx, Object(list->realm, list->object_schema, list->get(RJSValidatedPositiveIndex(indexStr)))); } catch (std::out_of_range &exp) { // getters for nonexistent properties in JS should always return undefined @@ -95,15 +67,15 @@ JSValueRef ArrayGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef pr } } -bool ArraySetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* jsException) { +bool ListSetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* jsException) { try { - ObjectArray *array = RJSVerifiedMutableArray(object); + List *list = RJSVerifiedMutableList(object); std::string indexStr = RJSStringForJSString(propertyName); if (indexStr == "length") { throw std::runtime_error("The 'length' property is readonly."); } - array->set(RJSValidatedPositiveIndex(indexStr), RJSAccessor::to_object_index(ctx, array->realm, const_cast(value), array->object_schema.name, false)); + list->set(RJSValidatedPositiveIndex(indexStr), RJSAccessor::to_object_index(ctx, list->realm, const_cast(value), list->object_schema.name, false)); return true; } catch (std::invalid_argument &exp) { @@ -118,9 +90,9 @@ bool ArraySetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef property } } -void ArrayPropertyNames(JSContextRef ctx, JSObjectRef object, JSPropertyNameAccumulatorRef propertyNames) { - ObjectArray *array = RJSVerifiedArray(object); - size_t size = array->size(); +void ListPropertyNames(JSContextRef ctx, JSObjectRef object, JSPropertyNameAccumulatorRef propertyNames) { + List *list = RJSVerifiedList(object); + size_t size = list->size(); char str[32]; for (size_t i = 0; i < size; i++) { @@ -131,9 +103,9 @@ void ArrayPropertyNames(JSContextRef ctx, JSObjectRef object, JSPropertyNameAccu } } -JSValueRef ArrayPush(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) { +JSValueRef ListPush(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) { try { - ObjectArray *array = RJSVerifiedMutableArray(thisObject); + List *array = RJSVerifiedMutableList(thisObject); RJSValidateArgumentCountIsAtLeast(argumentCount, 1); for (size_t i = 0; i < argumentCount; i++) { array->link_view->add(RJSAccessor::to_object_index(ctx, array->realm, const_cast(arguments[i]), array->object_schema.name, false)); @@ -148,18 +120,18 @@ JSValueRef ArrayPush(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObj return NULL; } -JSValueRef ArrayPop(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) { +JSValueRef ListPop(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) { try { - ObjectArray *array = RJSVerifiedMutableArray(thisObject); + List *list = RJSVerifiedMutableList(thisObject); RJSValidateArgumentCount(argumentCount, 0); - size_t size = array->size(); + size_t size = list->size(); if (size == 0) { return JSValueMakeUndefined(ctx); } size_t index = size - 1; - JSValueRef obj = RJSObjectCreate(ctx, Object(array->realm, array->object_schema, array->get(index))); - array->link_view->remove(index); + JSValueRef obj = RJSObjectCreate(ctx, Object(list->realm, list->object_schema, list->get(index))); + list->link_view->remove(index); return obj; } catch (std::exception &exp) { @@ -170,9 +142,9 @@ JSValueRef ArrayPop(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObje return NULL; } -JSValueRef ArrayUnshift(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) { +JSValueRef ListUnshift(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) { try { - ObjectArray *array = RJSVerifiedMutableArray(thisObject); + List *array = RJSVerifiedMutableList(thisObject); RJSValidateArgumentCountIsAtLeast(argumentCount, 1); for (size_t i = 0; i < argumentCount; i++) { array->link_view->insert(i, RJSAccessor::to_object_index(ctx, array->realm, const_cast(arguments[i]), array->object_schema.name, false)); @@ -187,15 +159,15 @@ JSValueRef ArrayUnshift(JSContextRef ctx, JSObjectRef function, JSObjectRef this return NULL; } -JSValueRef ArrayShift(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) { +JSValueRef ListShift(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) { try { - ObjectArray *array = RJSVerifiedMutableArray(thisObject); + List *list = RJSVerifiedMutableList(thisObject); RJSValidateArgumentCount(argumentCount, 0); - if (array->size() == 0) { + if (list->size() == 0) { return JSValueMakeUndefined(ctx); } - JSValueRef obj = RJSObjectCreate(ctx, Object(array->realm, array->object_schema, array->get(0))); - array->link_view->remove(0); + JSValueRef obj = RJSObjectCreate(ctx, Object(list->realm, list->object_schema, list->get(0))); + list->link_view->remove(0); return obj; } catch (std::exception &exp) { @@ -206,10 +178,10 @@ JSValueRef ArrayShift(JSContextRef ctx, JSObjectRef function, JSObjectRef thisOb return NULL; } -JSValueRef ArraySplice(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) { +JSValueRef ListSplice(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) { try { - ObjectArray *array = RJSVerifiedMutableArray(thisObject); - size_t size = array->size(); + List *list = RJSVerifiedMutableList(thisObject); + size_t size = list->size(); RJSValidateArgumentCountIsAtLeast(argumentCount, 2); long index = std::min(RJSValidatedValueToNumber(ctx, arguments[0]), size); @@ -222,11 +194,11 @@ JSValueRef ArraySplice(JSContextRef ctx, JSObjectRef function, JSObjectRef thisO std::vector removedObjects(remove); for (size_t i = 0; i < remove; i++) { - removedObjects[i] = RJSObjectCreate(ctx, Object(array->realm, array->object_schema, array->get(index))); - array->link_view->remove(index); + removedObjects[i] = RJSObjectCreate(ctx, Object(list->realm, list->object_schema, list->get(index))); + list->link_view->remove(index); } for (size_t i = 2; i < argumentCount; i++) { - array->link_view->insert(index + i - 2, RJSAccessor::to_object_index(ctx, array->realm, const_cast(arguments[i]), array->object_schema.name, false)); + list->link_view->insert(index + i - 2, RJSAccessor::to_object_index(ctx, list->realm, const_cast(arguments[i]), list->object_schema.name, false)); } return JSObjectMakeArray(ctx, remove, removedObjects.data(), jsException); } @@ -238,20 +210,20 @@ JSValueRef ArraySplice(JSContextRef ctx, JSObjectRef function, JSObjectRef thisO return NULL; } -JSObjectRef RJSArrayCreate(JSContextRef ctx, realm::ObjectArray *array) { - return RJSWrapObject(ctx, RJSArrayClass(), array); +JSObjectRef RJSListCreate(JSContextRef ctx, realm::List &list) { + return RJSWrapObject(ctx, RJSListClass(), new List(list)); } -const JSStaticFunction RJSArrayFuncs[] = { - {"push", ArrayPush, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, - {"pop", ArrayPop, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, - {"shift", ArrayShift, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, - {"unshift", ArrayUnshift, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, - {"splice", ArraySplice, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, +const JSStaticFunction RJSListFuncs[] = { + {"push", ListPush, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, + {"pop", ListPop, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, + {"shift", ListShift, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, + {"unshift", ListUnshift, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, + {"splice", ListSplice, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, {NULL, NULL}, }; -JSClassRef RJSArrayClass() { - static JSClassRef s_arrayClass = RJSCreateWrapperClass("RealmArray", ArrayGetProperty, ArraySetProperty, RJSArrayFuncs, NULL, ArrayPropertyNames); - return s_arrayClass; +JSClassRef RJSListClass() { + static JSClassRef s_listClass = RJSCreateWrapperClass("RealmList", ListGetProperty, ListSetProperty, RJSListFuncs, NULL, ListPropertyNames); + return s_listClass; } diff --git a/src/object-store/object_accessor.cpp b/src/RJSList.hpp similarity index 69% rename from src/object-store/object_accessor.cpp rename to src/RJSList.hpp index 2516cc5d..6dbe9dd0 100644 --- a/src/object-store/object_accessor.cpp +++ b/src/RJSList.hpp @@ -16,4 +16,12 @@ // //////////////////////////////////////////////////////////////////////////// -#include "object_accessor.hpp" +#import "RJSUtil.hpp" +#import "shared_realm.hpp" +#import "list.hpp" + +extern const JSStaticFunction RJSListFuncs[]; +JSClassRef RJSListClass(); +JSObjectRef RJSListCreate(JSContextRef ctx, realm::List &list); + +JSValueRef ListGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* jsException); diff --git a/src/RJSObject.mm b/src/RJSObject.mm index a9324bda..1d088469 100644 --- a/src/RJSObject.mm +++ b/src/RJSObject.mm @@ -20,7 +20,7 @@ #import "RJSObject.hpp" #import "RJSResults.hpp" #import "RJSSchema.hpp" -#import "RJSArray.hpp" +#import "RJSList.hpp" #import "object_store.hpp" #import "object_accessor.hpp" @@ -29,49 +29,15 @@ using RJSAccessor = realm::NativeAccessor; using namespace realm; JSValueRef ObjectGetProperty(JSContextRef ctx, JSObjectRef jsObject, JSStringRef jsPropertyName, JSValueRef* exception) { - Object *obj = RJSGetInternal(jsObject); - - std::string propName = RJSStringForJSString(jsPropertyName); - ObjectSchema &objectSchema = obj->object_schema; - Property *prop = objectSchema.property_for_name(propName); - if (!prop) { + try { + Object *obj = RJSGetInternal(jsObject); + return obj->get_property_value(ctx, RJSStringForJSString(jsPropertyName)); + } catch (std::exception &ex) { + if (exception) { + *exception = RJSMakeError(ctx, ex); + } return NULL; } - - switch (prop->type) { - case PropertyTypeBool: - return JSValueMakeBoolean(ctx, obj->row.get_bool(prop->table_column)); - case PropertyTypeInt: - return JSValueMakeNumber(ctx, obj->row.get_int(prop->table_column)); - case PropertyTypeFloat: - return JSValueMakeNumber(ctx, obj->row.get_float(prop->table_column)); - case PropertyTypeDouble: - return JSValueMakeNumber(ctx, obj->row.get_double(prop->table_column)); - case PropertyTypeString: - return RJSValueForString(ctx, obj->row.get_string(prop->table_column)); - case PropertyTypeData: - return RJSValueForString(ctx, (std::string)obj->row.get_binary(prop->table_column)); - case PropertyTypeAny: - *exception = RJSMakeError(ctx, "'Any' type not supported"); - return NULL; - case PropertyTypeDate: { - JSValueRef time = JSValueMakeNumber(ctx, obj->row.get_datetime(prop->table_column).get_datetime()); - return JSObjectMakeDate(ctx, 1, &time, exception); - } - case PropertyTypeObject: { - auto linkObjectSchema = obj->realm->config().schema->find(prop->object_type); - TableRef table = ObjectStore::table_for_object_type(obj->realm->read_group(), linkObjectSchema->name); - if (obj->row.is_null_link(prop->table_column)) { - return JSValueMakeNull(ctx); - } - return RJSObjectCreate(ctx, Object(obj->realm, *linkObjectSchema, table->get(obj->row.get_link(prop->table_column)))); - } - case PropertyTypeArray: { - auto arrayObjectSchema = obj->realm->config().schema->find(prop->object_type); - return RJSArrayCreate(ctx, new ObjectArray(obj->realm, *arrayObjectSchema, static_cast(obj->row.get_linklist(prop->table_column)))); - } - } - return NULL; } bool ObjectSetProperty(JSContextRef ctx, JSObjectRef jsObject, JSStringRef jsPropertyName, JSValueRef value, JSValueRef* exception) { @@ -133,6 +99,9 @@ template<> JSValueRef RJSAccessor::default_value_for_property(JSContextRef ctx, template<> bool RJSAccessor::is_null(JSContextRef ctx, JSValueRef &val) { return JSValueIsUndefined(ctx, val) || JSValueIsNull(ctx, val); } +template<> JSValueRef RJSAccessor::null_value(JSContextRef ctx) { + return JSValueMakeNull(ctx); +} template<> bool RJSAccessor::to_bool(JSContextRef ctx, JSValueRef &val) { if (!JSValueIsBoolean(ctx, val)) { @@ -140,22 +109,37 @@ template<> bool RJSAccessor::to_bool(JSContextRef ctx, JSValueRef &val) { } return JSValueToBoolean(ctx, val); } +template<> JSValueRef RJSAccessor::from_bool(JSContextRef ctx, bool b) { + return JSValueMakeBoolean(ctx, b); +} template<> long long RJSAccessor::to_long(JSContextRef ctx, JSValueRef &val) { return RJSValidatedValueToNumber(ctx, val); } +template<> JSValueRef RJSAccessor::from_long(JSContextRef ctx, long long l) { + return JSValueMakeNumber(ctx, l); +} template<> float RJSAccessor::to_float(JSContextRef ctx, JSValueRef &val) { return RJSValidatedValueToNumber(ctx, val); } +template<> JSValueRef RJSAccessor::from_float(JSContextRef ctx, float f) { + return JSValueMakeNumber(ctx, f); +} template<> double RJSAccessor::to_double(JSContextRef ctx, JSValueRef &val) { return RJSValidatedValueToNumber(ctx, val); } +template<> JSValueRef RJSAccessor::from_double(JSContextRef ctx, double d) { + return JSValueMakeNumber(ctx, d); +} template<> std::string RJSAccessor::to_string(JSContextRef ctx, JSValueRef &val) { return RJSValidatedStringForValue(ctx, val); } +template<> JSValueRef RJSAccessor::from_string(JSContextRef ctx, StringData s) { + return RJSValueForString(ctx, s); +} template<> DateTime RJSAccessor::to_datetime(JSContextRef ctx, JSValueRef &val) { JSObjectRef object = RJSValidatedValueToObject(ctx, val, "Property must be a Date"); @@ -176,6 +160,10 @@ template<> DateTime RJSAccessor::to_datetime(JSContextRef ctx, JSValueRef &val) return DateTime(utc); } +template<> JSValueRef RJSAccessor::from_datetime(JSContextRef ctx, DateTime dt) { + JSValueRef time = JSValueMakeNumber(ctx, dt.get_datetime()); + return JSObjectMakeDate(ctx, 1, &time, NULL); +} extern JSObjectRef RJSDictForPropertyArray(JSContextRef ctx, ObjectSchema &object_schema, JSObjectRef array); @@ -193,11 +181,16 @@ template<> size_t RJSAccessor::to_object_index(JSContextRef ctx, SharedRealm &re Object child = Object::create(ctx, realm, *object_schema, (JSValueRef)object, try_update); return child.row.get_index(); } - -template<> size_t RJSAccessor::array_size(JSContextRef ctx, JSValueRef &val) { - return RJSValidatedArrayLength(ctx, RJSValidatedValueToObject(ctx, val)); +template<> JSValueRef RJSAccessor::from_object(JSContextRef ctx, Object object) { + return RJSObjectCreate(ctx, object); } -template<> JSValueRef RJSAccessor::array_value_at_index(JSContextRef ctx, JSValueRef &val, size_t index) { +template<> size_t RJSAccessor::list_size(JSContextRef ctx, JSValueRef &val) { + return RJSValidatedListLength(ctx, RJSValidatedValueToObject(ctx, val)); +} +template<> JSValueRef RJSAccessor::list_value_at_index(JSContextRef ctx, JSValueRef &val, size_t index) { return RJSValidatedObjectAtIndex(ctx, RJSValidatedValueToObject(ctx, val), (unsigned int)index); } +template<> JSValueRef RJSAccessor::from_list(JSContextRef ctx, List list) { + return RJSListCreate(ctx, list); +} diff --git a/src/RJSRealm.mm b/src/RJSRealm.mm index dff5b647..78d45c5c 100644 --- a/src/RJSRealm.mm +++ b/src/RJSRealm.mm @@ -19,7 +19,7 @@ #import "RJSRealm.hpp" #import "RJSObject.hpp" #import "RJSResults.hpp" -#import "RJSArray.hpp" +#import "RJSList.hpp" #import "RJSSchema.hpp" #import "shared_realm.hpp" @@ -221,7 +221,7 @@ JSValueRef RealmObjects(JSContextRef ctx, JSObjectRef function, JSObjectRef this JSObjectRef RJSDictForPropertyArray(JSContextRef ctx, ObjectSchema &object_schema, JSObjectRef array) { // copy to dictionary - if (object_schema.properties.size() != RJSValidatedArrayLength(ctx, array)) { + if (object_schema.properties.size() != RJSValidatedListLength(ctx, array)) { throw std::runtime_error("Array must contain values for all object properties"); } @@ -280,10 +280,10 @@ JSValueRef RealmDelete(JSContextRef ctx, JSObjectRef function, JSObjectRef thisO if (RJSIsValueArray(ctx, arguments[0]) || JSValueIsObjectOfClass(ctx, arguments[0], RJSResultsClass()) || - JSValueIsObjectOfClass(ctx, arguments[0], RJSArrayClass())) + JSValueIsObjectOfClass(ctx, arguments[0], RJSListClass())) { JSObjectRef array = RJSValidatedValueToObject(ctx, arguments[0]); - size_t length = RJSValidatedArrayLength(ctx, array); + size_t length = RJSValidatedListLength(ctx, array); for (long i = length-1; i >= 0; i--) { JSValueRef object = RJSValidatedObjectAtIndex(ctx, array, (unsigned int)i); RealmDelete(ctx, function, thisObject, 1, &object, jsException); diff --git a/src/RJSSchema.mm b/src/RJSSchema.mm index 534b44b5..ef9fdb12 100644 --- a/src/RJSSchema.mm +++ b/src/RJSSchema.mm @@ -127,7 +127,7 @@ static inline ObjectSchema RJSParseObjectSchema(JSContextRef ctx, JSObjectRef ob static JSStringRef nameString = JSStringCreateWithUTF8CString("name"); objectSchema.name = RJSValidatedStringProperty(ctx, objectSchemaObject, nameString); - size_t numProperties = RJSValidatedArrayLength(ctx, propertiesObject); + size_t numProperties = RJSValidatedListLength(ctx, propertiesObject); for (unsigned int p = 0; p < numProperties; p++) { JSObjectRef property = RJSValidatedObjectAtIndex(ctx, propertiesObject, p); objectSchema.properties.emplace_back(RJSParseProperty(ctx, property)); @@ -163,7 +163,7 @@ static inline ObjectSchema RJSParseObjectSchema(JSContextRef ctx, JSObjectRef ob realm::Schema RJSParseSchema(JSContextRef ctx, JSObjectRef jsonObject) { std::vector schema; - size_t length = RJSValidatedArrayLength(ctx, jsonObject); + 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); diff --git a/src/RJSUtil.hpp b/src/RJSUtil.hpp index fc90edb7..b53f2034 100644 --- a/src/RJSUtil.hpp +++ b/src/RJSUtil.hpp @@ -161,7 +161,7 @@ static inline std::string RJSValidatedStringProperty(JSContextRef ctx, JSObjectR return RJSValidatedStringForValue(ctx, propertyValue); } -static inline size_t RJSValidatedArrayLength(JSContextRef ctx, JSObjectRef object) { +static inline size_t RJSValidatedListLength(JSContextRef ctx, JSObjectRef object) { JSValueRef exception = NULL; static JSStringRef lengthString = JSStringCreateWithUTF8CString("length"); JSValueRef lengthValue = JSObjectGetProperty(ctx, object, lengthString, &exception); diff --git a/src/RealmRPC.mm b/src/RealmRPC.mm index d38d664e..c8a2a5a6 100644 --- a/src/RealmRPC.mm +++ b/src/RealmRPC.mm @@ -24,7 +24,7 @@ #include "RealmJS.h" #include "RJSObject.hpp" #include "RJSResults.hpp" -#include "RJSArray.hpp" +#include "RJSList.hpp" #include "RJSRealm.hpp" #include "RJSUtil.hpp" @@ -140,7 +140,7 @@ using RPCRequest = std::function; JSValueRef exception = NULL; static JSStringRef lengthPropertyName = JSStringCreateWithUTF8CString("length"); - JSValueRef lengthValue = ArrayGetProperty(_context, _objects[listId], lengthPropertyName, &exception); + JSValueRef lengthValue = ListGetProperty(_context, _objects[listId], lengthPropertyName, &exception); size_t length = JSValueToNumber(_context, lengthValue, &exception); if (exception) { @@ -154,7 +154,7 @@ using RPCRequest = std::function; JSValueRef exception = NULL; JSStringRef indexPropertyName = JSStringCreateWithUTF8CString(std::to_string(index).c_str()); - JSValueRef objectValue = ArrayGetProperty(_context, _objects[listId], indexPropertyName, &exception); + JSValueRef objectValue = ListGetProperty(_context, _objects[listId], indexPropertyName, &exception); JSStringRelease(indexPropertyName); if (exception) { @@ -166,7 +166,7 @@ using RPCRequest = std::function; _requests["/call_list_method"] = [=](NSDictionary *dict) { NSString *name = dict[@"name"]; return [self performObjectMethod:name.UTF8String - classMethods:RJSArrayFuncs + classMethods:RJSListFuncs args:dict[@"arguments"] objectId:[dict[@"listId"] unsignedLongValue]]; }; @@ -249,14 +249,14 @@ using RPCRequest = std::function; @"schema": [self objectSchemaToJSONObject:object->object_schema] }; } - else if (JSValueIsObjectOfClass(_context, value, RJSArrayClass())) { - realm::ObjectArray *array = RJSGetInternal(jsObject); + else if (JSValueIsObjectOfClass(_context, value, RJSListClass())) { + realm::List *list = RJSGetInternal(jsObject); RPCObjectID oid = [self storeObject:jsObject]; return @{ @"type": @(RJSTypeGet(realm::PropertyTypeArray).c_str()), @"id": @(oid), - @"size": @(array->link_view->size()), - @"schema": [self objectSchemaToJSONObject:array->object_schema] + @"size": @(list->link_view->size()), + @"schema": [self objectSchemaToJSONObject:list->object_schema] }; } else if (JSValueIsObjectOfClass(_context, value, RJSResultsClass())) { @@ -270,7 +270,7 @@ using RPCRequest = std::function; }; } else if (RJSIsValueArray(_context, value)) { - size_t length = RJSValidatedArrayLength(_context, jsObject); + size_t length = RJSValidatedListLength(_context, jsObject); NSMutableArray *array = [NSMutableArray new]; for (unsigned int i = 0; i < length; i++) { [array addObject:[self resultForJSValue:JSObjectGetPropertyAtIndex(_context, jsObject, i, NULL)]]; diff --git a/src/object-store/list.cpp b/src/object-store/list.cpp new file mode 100644 index 00000000..d4b2bb57 --- /dev/null +++ b/src/object-store/list.cpp @@ -0,0 +1,50 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#include "list.hpp" +#import + +using namespace realm; + +size_t List::size() { + return link_view->size(); +} + +Row List::get(std::size_t row_ndx) { + verify_valid_row(row_ndx); + return link_view->get(row_ndx); +} + +void List::set(std::size_t row_ndx, std::size_t target_row_ndx) { + verify_valid_row(row_ndx); + link_view->set(row_ndx, target_row_ndx); +} + +void List::verify_valid_row(std::size_t row_ndx) { + size_t size = link_view->size(); + if (row_ndx >= size) { + throw std::out_of_range(std::string("Index ") + std::to_string(row_ndx) + " is outside of range 0..." + std::to_string(size) + "."); + } +} + +void List::verify_attached() { + if (!link_view->is_attached()) { + throw std::runtime_error("Tableview is not attached"); + } + link_view->sync_if_needed(); +} diff --git a/src/RJSArray.hpp b/src/object-store/list.hpp similarity index 73% rename from src/RJSArray.hpp rename to src/object-store/list.hpp index 08934e9d..a1fa1dde 100644 --- a/src/RJSArray.hpp +++ b/src/object-store/list.hpp @@ -16,13 +16,15 @@ // //////////////////////////////////////////////////////////////////////////// -#import "RJSUtil.hpp" +#ifndef REALM_LIST_HPP +#define REALM_LIST_HPP + #import "shared_realm.hpp" #import namespace realm { - struct ObjectArray { - ObjectArray(SharedRealm &r, ObjectSchema &s, LinkViewRef l) : realm(r), object_schema(s), link_view(l) {} + struct List { + List(SharedRealm &r, ObjectSchema &s, LinkViewRef l) : realm(r), object_schema(s), link_view(l) {} // FIXME - all should be const SharedRealm realm; ObjectSchema &object_schema; @@ -36,8 +38,5 @@ namespace realm { }; } -extern const JSStaticFunction RJSArrayFuncs[]; -JSClassRef RJSArrayClass(); -JSObjectRef RJSArrayCreate(JSContextRef ctx, realm::ObjectArray *array); -JSValueRef ArrayGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* jsException); +#endif /* REALM_LIST_HPP */ diff --git a/src/object-store/object_accessor.hpp b/src/object-store/object_accessor.hpp index fa6d6366..69bffa70 100644 --- a/src/object-store/object_accessor.hpp +++ b/src/object-store/object_accessor.hpp @@ -21,43 +21,9 @@ #include #include "shared_realm.hpp" +#include "list.hpp" namespace realm { - template - class NativeAccessor { - public: - // - // Value converters - template specializations must be implemented for each platform - // - 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 to_bool(ContextType ctx, ValueType &val); - static long long to_long(ContextType ctx, ValueType &val); - static float to_float(ContextType ctx, ValueType &val); - static double to_double(ContextType ctx, ValueType &val); - static std::string to_string(ContextType ctx, ValueType &val); - static DateTime to_datetime(ContextType ctx, ValueType &val); - - static bool is_null(ContextType ctx, ValueType &val); - - // convert value to persisted object - // for existing objects return the existing row index - // for new/updated objects return the row index - static size_t to_object_index(ContextType ctx, SharedRealm &realm, ValueType &val, std::string &type, bool try_update); - - // array value acessors - static size_t array_size(ContextType ctx, ValueType &val); - static ValueType array_value_at_index(ContextType ctx, ValueType &val, size_t index); - - // - // Deprecated - // - static Mixed to_mixed(ContextType ctx, ValueType &val) { throw std::runtime_error("'Any' type is unsupported"); } - }; class Object { public: @@ -67,10 +33,13 @@ namespace realm { ObjectSchema &object_schema; Row row; - // property setter + // property getter/setter template inline void set_property_value(ContextType ctx, std::string prop_name, ValueType value, bool try_update); + template + inline ValueType get_property_value(ContextType ctx, std::string prop_name); + // create an Object from a native representation template static inline Object create(ContextType ctx, SharedRealm realm, ObjectSchema &object_schema, ValueType value, bool try_update); @@ -78,6 +47,53 @@ namespace realm { private: template inline void set_property_value_impl(ContextType ctx, Property &property, ValueType value, bool try_update); + template + inline ValueType get_property_value_impl(ContextType ctx, Property &property); + }; + + // + // Value converters - template specializations must be implemented for each platform in order to call templated methods on Object + // + template + class NativeAccessor { + public: + 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 to_bool(ContextType, ValueType &); + static ValueType from_bool(ContextType, bool); + static long long to_long(ContextType, ValueType &); + static ValueType from_long(ContextType, long long); + static float to_float(ContextType, ValueType &); + static ValueType from_float(ContextType, float); + static double to_double(ContextType, ValueType &); + static ValueType from_double(ContextType, double); + static std::string to_string(ContextType, ValueType &); + static ValueType from_string(ContextType, StringData); + static DateTime to_datetime(ContextType, ValueType &); + static ValueType from_datetime(ContextType, DateTime); + + static bool is_null(ContextType, ValueType &); + static ValueType null_value(ContextType); + + // convert value to persisted object + // for existing objects return the existing row index + // for new/updated objects return the row index + static size_t to_object_index(ContextType ctx, SharedRealm &realm, ValueType &val, std::string &type, bool try_update); + static ValueType from_object(ContextType ctx, Object); + + // list value acessors + static size_t list_size(ContextType ctx, ValueType &val); + static ValueType list_value_at_index(ContextType ctx, ValueType &val, size_t index); + static ValueType from_list(ContextType ctx, List); + + // + // Deprecated + // + static Mixed to_mixed(ContextType ctx, ValueType &val) { throw std::runtime_error("'Any' type is unsupported"); } }; // @@ -93,6 +109,16 @@ namespace realm { set_property_value_impl(ctx, *prop, value, try_update); }; + template + inline ValueType Object::get_property_value(ContextType ctx, std::string prop_name) + { + Property *prop = object_schema.property_for_name(prop_name); + if (!prop) { + throw std::runtime_error("Setting invalid property '" + prop_name + "' on object '" + object_schema.name + "'."); + } + return get_property_value_impl(ctx, *prop); + }; + template inline void Object::set_property_value_impl(ContextType ctx, Property &property, ValueType value, bool try_update) { @@ -140,9 +166,9 @@ namespace realm { case PropertyTypeArray: { realm::LinkViewRef link_view = row.get_linklist(column); link_view->clear(); - size_t count = Accessor::array_size(ctx, value); + size_t count = Accessor::list_size(ctx, value); for (size_t i = 0; i < count; i++) { - ValueType element = Accessor::array_value_at_index(ctx, value, i); + ValueType element = Accessor::list_value_at_index(ctx, value, i); link_view->add(Accessor::to_object_index(ctx, realm, element, property.object_type, try_update)); } break; @@ -150,6 +176,44 @@ namespace realm { } } + template + inline ValueType Object::get_property_value_impl(ContextType ctx, Property &property) + { + using Accessor = NativeAccessor; + + size_t column = property.table_column; + switch (property.type) { + case PropertyTypeBool: + return Accessor::from_bool(ctx, row.get_bool(column)); + case PropertyTypeInt: + return Accessor::from_long(ctx, row.get_int(column)); + case PropertyTypeFloat: + return Accessor::from_float(ctx, row.get_float(column)); + case PropertyTypeDouble: + return Accessor::from_double(ctx, row.get_double(column)); + case PropertyTypeString: + return Accessor::from_string(ctx, row.get_string(column)); + case PropertyTypeData: + return Accessor::from_string(ctx, (std::string)row.get_binary(column)); + case PropertyTypeAny: + throw "Any not supported"; + case PropertyTypeDate: + return Accessor::from_datetime(ctx, row.get_datetime(column)); + case PropertyTypeObject: { + auto linkObjectSchema = realm->config().schema->find(property.object_type); + TableRef table = ObjectStore::table_for_object_type(realm->read_group(), linkObjectSchema->name); + if (row.is_null_link(property.table_column)) { + return Accessor::null_value(ctx); + } + return Accessor::from_object(ctx, std::move(Object(realm, *linkObjectSchema, table->get(row.get_link(column))))); + } + case PropertyTypeArray: { + auto arrayObjectSchema = realm->config().schema->find(property.object_type); + return Accessor::from_list(ctx, std::move(List(realm, *arrayObjectSchema, static_cast(row.get_linklist(column))))); + } + } + } + template inline Object Object::create(ContextType ctx, SharedRealm realm, ObjectSchema &object_schema, ValueType value, bool try_update) { diff --git a/tests/RealmJSTests.mm b/tests/RealmJSTests.mm index 5f556422..0f89a761 100644 --- a/tests/RealmJSTests.mm +++ b/tests/RealmJSTests.mm @@ -243,9 +243,9 @@ static JSClassRef s_globalClass; } @end -@interface RJSArrayTests : RealmJSTests +@interface RJSListTests : RealmJSTests @end -@implementation RJSArrayTests +@implementation RJSListTests + (NSString *)jsSuiteName { return @"ArrayTests"; }