From 6d86f8e91fab01b0a50d9b8a3df151a9cce0668e Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Mon, 16 May 2016 16:26:37 -0700 Subject: [PATCH 01/14] Consolidate RealmNode.xcodeproj into RealmJS.xcodeproj Moved it up one level since it references the whole source tree inside the src/ directory. Added the functionality to run Node tests from Xcode on the existing RealmNode target. --- Realm.xcworkspace/contents.xcworkspacedata | 5 +- .../ios/RealmReact.xcodeproj/project.pbxproj | 2 +- scripts/set-version.sh | 2 +- scripts/test.sh | 2 +- .../RealmJS.xcodeproj/project.pbxproj | 87 +++++---- .../xcschemes/GCDWebServers.xcscheme | 0 .../xcshareddata/xcschemes/RealmJS.xcscheme | 0 .../xcshareddata/xcschemes/RealmNode.xcscheme | 26 +-- src/node/RealmNode.xcodeproj/project.pbxproj | 184 ------------------ 9 files changed, 61 insertions(+), 247 deletions(-) rename src/{ios => }/RealmJS.xcodeproj/project.pbxproj (97%) rename src/{ios => }/RealmJS.xcodeproj/xcshareddata/xcschemes/GCDWebServers.xcscheme (100%) rename src/{ios => }/RealmJS.xcodeproj/xcshareddata/xcschemes/RealmJS.xcscheme (100%) rename src/{node/RealmNode.xcodeproj => RealmJS.xcodeproj}/xcshareddata/xcschemes/RealmNode.xcscheme (78%) delete mode 100644 src/node/RealmNode.xcodeproj/project.pbxproj diff --git a/Realm.xcworkspace/contents.xcworkspacedata b/Realm.xcworkspace/contents.xcworkspacedata index 9eb61350..65758602 100644 --- a/Realm.xcworkspace/contents.xcworkspacedata +++ b/Realm.xcworkspace/contents.xcworkspacedata @@ -2,7 +2,7 @@ + location = "group:src/RealmJS.xcodeproj"> @@ -13,7 +13,4 @@ - - diff --git a/react-native/ios/RealmReact.xcodeproj/project.pbxproj b/react-native/ios/RealmReact.xcodeproj/project.pbxproj index 96eb1e91..1df0816d 100644 --- a/react-native/ios/RealmReact.xcodeproj/project.pbxproj +++ b/react-native/ios/RealmReact.xcodeproj/project.pbxproj @@ -70,7 +70,7 @@ F60690181CA2766F0003FB26 /* RealmReact.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = RealmReact.mm; sourceTree = ""; }; F606901F1CA277410003FB26 /* RealmAnalytics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RealmAnalytics.h; sourceTree = ""; }; F60690201CA277410003FB26 /* RealmAnalytics.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RealmAnalytics.mm; sourceTree = ""; }; - F60690231CA277CC0003FB26 /* RealmJS.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RealmJS.xcodeproj; path = ../../src/ios/RealmJS.xcodeproj; sourceTree = ""; }; + F60690231CA277CC0003FB26 /* RealmJS.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RealmJS.xcodeproj; path = ../../src/RealmJS.xcodeproj; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXGroup section */ diff --git a/scripts/set-version.sh b/scripts/set-version.sh index 956b14f5..45ff6270 100755 --- a/scripts/set-version.sh +++ b/scripts/set-version.sh @@ -27,7 +27,7 @@ if ! $FORCE || [ "$VERSION" != "$(npm --silent run get-version)" ]; then fi # Update CURRENT_PROJECT_VERSION and DYLIB_CURRENT_VERSION in the Xcode project. -(cd src/ios && xcrun agvtool new-version "$RELEASE_VERSION") +(cd src && xcrun agvtool new-version "$RELEASE_VERSION") # Update CHANGELOG sed -i '' "1s/.*/$RELEASE_VERSION Release notes ($(date '+%Y-%-m-%-d'))/" CHANGELOG.md diff --git a/scripts/test.sh b/scripts/test.sh index daf019d5..a0bc2ecd 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -93,7 +93,7 @@ case "$TARGET" in npm run jsdoc ;; "realmjs") - pushd src/ios + pushd src xctest RealmJS ;; "react-tests") diff --git a/src/ios/RealmJS.xcodeproj/project.pbxproj b/src/RealmJS.xcodeproj/project.pbxproj similarity index 97% rename from src/ios/RealmJS.xcodeproj/project.pbxproj rename to src/RealmJS.xcodeproj/project.pbxproj index f6098eab..07b1df31 100644 --- a/src/ios/RealmJS.xcodeproj/project.pbxproj +++ b/src/RealmJS.xcodeproj/project.pbxproj @@ -45,7 +45,6 @@ F60102DE1CBB96CF00EC01BA /* weak_realm_notifier.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02F59ED11C88F1B6007F774C /* weak_realm_notifier.cpp */; }; F60102E01CBB96D900EC01BA /* realm_coordinator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02F59EDB1C88F2BA007F774C /* realm_coordinator.cpp */; }; F60102E11CBB96DD00EC01BA /* transact_log_handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02F59EDD1C88F2BB007F774C /* transact_log_handler.cpp */; }; - F60102E51CBBB19700EC01BA /* node_object_accessor.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F60102E31CBBB19700EC01BA /* node_object_accessor.hpp */; }; F60102EA1CBCAFC300EC01BA /* node_dummy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6267BCA1CADC49200AC36B1 /* node_dummy.cpp */; }; F61378791C18EAC5008BFC51 /* js in Resources */ = {isa = PBXBuildFile; fileRef = F61378781C18EAAC008BFC51 /* js */; }; F620F0581CB766DA0082977B /* node_init.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F620F0571CB766DA0082977B /* node_init.cpp */; }; @@ -225,7 +224,7 @@ F68A278B1BC2722A0063D40A /* RJSModuleLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RJSModuleLoader.m; path = ios/RJSModuleLoader.m; sourceTree = ""; }; F6BB7DEF1BF681BC00D0A69E /* base64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = base64.cpp; sourceTree = ""; }; F6BB7DF01BF681BC00D0A69E /* base64.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = base64.hpp; sourceTree = ""; }; - F6BCCFDF1C83809A00FE31AE /* lib */ = {isa = PBXFileReference; lastKnownFileType = folder; name = lib; path = ../../lib; sourceTree = SOURCE_ROOT; }; + F6BCCFDF1C83809A00FE31AE /* lib */ = {isa = PBXFileReference; lastKnownFileType = folder; name = lib; path = ../lib; sourceTree = SOURCE_ROOT; }; F6C3FBBC1BF680EC00E6FFD4 /* json.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = json.hpp; sourceTree = ""; }; /* End PBXFileReference section */ @@ -282,7 +281,6 @@ F6079B181CD3EB9000BD2401 /* concurrent_deque.hpp */, ); name = RealmJS; - path = ..; sourceTree = ""; }; 02B58CA71AE99CEB009B348C = { @@ -320,7 +318,7 @@ F68A278B1BC2722A0063D40A /* RJSModuleLoader.m */, ); name = RealmJSTests; - path = ../../tests; + path = ../tests; sourceTree = ""; }; 02B58CCF1AE99D8C009B348C /* Frameworks */ = { @@ -521,22 +519,11 @@ F6C3FBBC1BF680EC00E6FFD4 /* json.hpp */, ); name = Vendor; - path = ../../vendor; + path = ../vendor; sourceTree = ""; }; /* End PBXGroup section */ -/* Begin PBXHeadersBuildPhase section */ - F62BF8F91CAC71780022BCDC /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - F60102E51CBBB19700EC01BA /* node_object_accessor.hpp in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - /* Begin PBXNativeTarget section */ 02B58CBB1AE99CEC009B348C /* RealmJSTests */ = { isa = PBXNativeTarget; @@ -562,7 +549,7 @@ buildPhases = ( F62BF8F71CAC71780022BCDC /* Sources */, F62BF8F81CAC71780022BCDC /* Frameworks */, - F62BF8F91CAC71780022BCDC /* Headers */, + F63117A41CEA911000ECB2DE /* Build with node-gyp */, ); buildRules = ( ); @@ -676,7 +663,21 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "DEST=\"$TARGET_BUILD_DIR/$CONTENTS_FOLDER_PATH/js/query-tests.json\"\nrm -f \"$DEST\"\ncp ../object-store/tests/query.json \"$DEST\""; + shellScript = "DEST=\"$TARGET_BUILD_DIR/$CONTENTS_FOLDER_PATH/js/query-tests.json\"\nrm -f \"$DEST\"\ncp object-store/tests/query.json \"$DEST\""; + }; + F63117A41CEA911000ECB2DE /* Build with node-gyp */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Build with node-gyp"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "node/build-node.sh \"$CONFIGURATION\""; }; F63FF2C51C12462600B3B8E0 /* Download Core */ = { isa = PBXShellScriptBuildPhase; @@ -690,7 +691,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "../../scripts/download-core.sh"; + shellScript = "../scripts/download-core.sh"; }; /* End PBXShellScriptBuildPhase section */ @@ -822,18 +823,18 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = ( - "$(SRCROOT)/../object-store/external/pegtl", - "$(SRCROOT)/../object-store/src", - "$(SRCROOT)/../../vendor", + "$(SRCROOT)/object-store/external/pegtl", + "$(SRCROOT)/object-store/src", + "$(SRCROOT)/../vendor", ); IPHONEOS_DEPLOYMENT_TARGET = 8.0; - LIBRARY_SEARCH_PATHS = ../../core; + LIBRARY_SEARCH_PATHS = ../core; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; OTHER_CPLUSPLUSFLAGS = ( "$(OTHER_CFLAGS)", "-isystem", - ../../core/include, + ../core/include, "-ftemplate-backtrace-limit=0", ); SDKROOT = iphoneos; @@ -880,17 +881,17 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = ( - "$(SRCROOT)/../object-store/external/pegtl", - "$(SRCROOT)/../object-store/src", - "$(SRCROOT)/../../vendor", + "$(SRCROOT)/object-store/external/pegtl", + "$(SRCROOT)/object-store/src", + "$(SRCROOT)/../vendor", ); IPHONEOS_DEPLOYMENT_TARGET = 8.0; - LIBRARY_SEARCH_PATHS = ../../core; + LIBRARY_SEARCH_PATHS = ../core; MTL_ENABLE_DEBUG_INFO = NO; OTHER_CPLUSPLUSFLAGS = ( "$(OTHER_CFLAGS)", "-isystem", - ../../core/include, + ../core/include, "-ftemplate-backtrace-limit=0", ); SDKROOT = iphoneos; @@ -908,7 +909,7 @@ "DEBUG=1", "$(inherited)", ); - INFOPLIST_FILE = ../../tests/ios/Info.plist; + INFOPLIST_FILE = ../tests/ios/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; OTHER_CPLUSPLUSFLAGS = ( @@ -924,7 +925,7 @@ 02B58CCC1AE99CEC009B348C /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - INFOPLIST_FILE = ../../tests/ios/Info.plist; + INFOPLIST_FILE = ../tests/ios/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; OTHER_CPLUSPLUSFLAGS = ( @@ -977,18 +978,18 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = ( - "$(SRCROOT)/../object-store/external/pegtl", - "$(SRCROOT)/../object-store/src", - "$(SRCROOT)/../../vendor", + "$(SRCROOT)/object-store/external/pegtl", + "$(SRCROOT)/object-store/src", + "$(SRCROOT)/../vendor", ); IPHONEOS_DEPLOYMENT_TARGET = 8.0; - LIBRARY_SEARCH_PATHS = ../../core; + LIBRARY_SEARCH_PATHS = ../core; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; OTHER_CPLUSPLUSFLAGS = ( "$(OTHER_CFLAGS)", "-isystem", - ../../core/include, + ../core/include, "-ftemplate-backtrace-limit=0", ); SDKROOT = iphoneos; @@ -1005,7 +1006,7 @@ "DEBUG=1", "$(inherited)", ); - INFOPLIST_FILE = ../../tests/ios/Info.plist; + INFOPLIST_FILE = ../tests/ios/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; OTHER_CPLUSPLUSFLAGS = ( @@ -1032,7 +1033,7 @@ ); HEADER_SEARCH_PATHS = ( "$(inherited)", - "$(SRCROOT)/../../node_modules/nan", + "$(SRCROOT)/../node_modules/nan", /usr/local/include/node, ); LIBRARY_SEARCH_PATHS = ( @@ -1061,7 +1062,7 @@ ); HEADER_SEARCH_PATHS = ( "$(inherited)", - "$(SRCROOT)/../../node_modules/nan", + "$(SRCROOT)/../node_modules/nan", /usr/local/include/node, ); LIBRARY_SEARCH_PATHS = ( @@ -1090,7 +1091,7 @@ ); HEADER_SEARCH_PATHS = ( "$(inherited)", - "$(SRCROOT)/../../node_modules/nan", + "$(SRCROOT)/../node_modules/nan", /usr/local/include/node, ); LIBRARY_SEARCH_PATHS = ( @@ -1115,7 +1116,7 @@ "DEBUG=1", "$(inherited)", ); - OTHER_LIBTOOLFLAGS = "$(SRCROOT)/../../core/librealm-ios-bitcode.a"; + OTHER_LIBTOOLFLAGS = "$(SRCROOT)/../core/librealm-ios-bitcode.a"; PRODUCT_NAME = RealmJS; SKIP_INSTALL = YES; }; @@ -1124,7 +1125,7 @@ F63FF2B81C1241E500B3B8E0 /* GCov_Build */ = { isa = XCBuildConfiguration; buildSettings = { - OTHER_LIBTOOLFLAGS = "$(SRCROOT)/../../core/librealm-ios-bitcode.a"; + OTHER_LIBTOOLFLAGS = "$(SRCROOT)/../core/librealm-ios-bitcode.a"; PRODUCT_NAME = RealmJS; SKIP_INSTALL = YES; }; @@ -1133,7 +1134,7 @@ F63FF2B91C1241E500B3B8E0 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - OTHER_LIBTOOLFLAGS = "$(SRCROOT)/../../core/librealm-ios-bitcode.a"; + OTHER_LIBTOOLFLAGS = "$(SRCROOT)/../core/librealm-ios-bitcode.a"; PRODUCT_NAME = RealmJS; SKIP_INSTALL = YES; }; diff --git a/src/ios/RealmJS.xcodeproj/xcshareddata/xcschemes/GCDWebServers.xcscheme b/src/RealmJS.xcodeproj/xcshareddata/xcschemes/GCDWebServers.xcscheme similarity index 100% rename from src/ios/RealmJS.xcodeproj/xcshareddata/xcschemes/GCDWebServers.xcscheme rename to src/RealmJS.xcodeproj/xcshareddata/xcschemes/GCDWebServers.xcscheme diff --git a/src/ios/RealmJS.xcodeproj/xcshareddata/xcschemes/RealmJS.xcscheme b/src/RealmJS.xcodeproj/xcshareddata/xcschemes/RealmJS.xcscheme similarity index 100% rename from src/ios/RealmJS.xcodeproj/xcshareddata/xcschemes/RealmJS.xcscheme rename to src/RealmJS.xcodeproj/xcshareddata/xcschemes/RealmJS.xcscheme diff --git a/src/node/RealmNode.xcodeproj/xcshareddata/xcschemes/RealmNode.xcscheme b/src/RealmJS.xcodeproj/xcshareddata/xcschemes/RealmNode.xcscheme similarity index 78% rename from src/node/RealmNode.xcodeproj/xcshareddata/xcschemes/RealmNode.xcscheme rename to src/RealmJS.xcodeproj/xcshareddata/xcschemes/RealmNode.xcscheme index 28e7aa75..590746e9 100644 --- a/src/node/RealmNode.xcodeproj/xcshareddata/xcschemes/RealmNode.xcscheme +++ b/src/RealmJS.xcodeproj/xcshareddata/xcschemes/RealmNode.xcscheme @@ -1,6 +1,6 @@ + ReferencedContainer = "container:RealmJS.xcodeproj"> @@ -38,27 +38,27 @@ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" launchStyle = "0" useCustomWorkingDirectory = "YES" - customWorkingDirectory = "$(SRCROOT)" + customWorkingDirectory = "$(TEMP_DIR)" ignoresPersistentStateOnLaunch = "NO" debugDocumentVersioning = "YES" debugServiceExtension = "internal" allowLocationSimulation = "YES"> + FilePath = "/usr/local/bin/node"> + ReferencedContainer = "container:RealmJS.xcodeproj"> @@ -74,10 +74,10 @@ + ReferencedContainer = "container:RealmJS.xcodeproj"> diff --git a/src/node/RealmNode.xcodeproj/project.pbxproj b/src/node/RealmNode.xcodeproj/project.pbxproj deleted file mode 100644 index acb9ce3e..00000000 --- a/src/node/RealmNode.xcodeproj/project.pbxproj +++ /dev/null @@ -1,184 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXGroup section */ - 02D041F81CE13739000E4250 = { - isa = PBXGroup; - children = ( - ); - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXLegacyTarget section */ - 02D041FD1CE13739000E4250 /* RealmNode */ = { - isa = PBXLegacyTarget; - buildArgumentsString = "build-node.sh $(CONFIGURATION)"; - buildConfigurationList = 02D042001CE13739000E4250 /* Build configuration list for PBXLegacyTarget "RealmNode" */; - buildPhases = ( - ); - buildToolPath = /bin/bash; - buildWorkingDirectory = "$(SRCROOT)"; - dependencies = ( - ); - name = RealmNode; - passBuildSettingsInEnvironment = 0; - productName = RealmNode; - }; -/* End PBXLegacyTarget section */ - -/* Begin PBXProject section */ - 02D041F91CE13739000E4250 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0720; - ORGANIZATIONNAME = Realm; - TargetAttributes = { - 02D041FD1CE13739000E4250 = { - CreatedOnToolsVersion = 7.2; - }; - }; - }; - buildConfigurationList = 02D041FC1CE13739000E4250 /* Build configuration list for PBXProject "RealmNode" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - ); - mainGroup = 02D041F81CE13739000E4250; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 02D041FD1CE13739000E4250 /* RealmNode */, - ); - }; -/* End PBXProject section */ - -/* Begin XCBuildConfiguration section */ - 02D041FE1CE13739000E4250 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - }; - name = Debug; - }; - 02D041FF1CE13739000E4250 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MTL_ENABLE_DEBUG_INFO = NO; - }; - name = Release; - }; - 02D042011CE13739000E4250 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - DEBUGGING_SYMBOLS = YES; - DEBUG_INFORMATION_FORMAT = dwarf; - GCC_GENERATE_DEBUGGING_SYMBOLS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - OTHER_CFLAGS = ""; - OTHER_LDFLAGS = ""; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 02D042021CE13739000E4250 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - OTHER_CFLAGS = ""; - OTHER_LDFLAGS = ""; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 02D041FC1CE13739000E4250 /* Build configuration list for PBXProject "RealmNode" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 02D041FE1CE13739000E4250 /* Debug */, - 02D041FF1CE13739000E4250 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 02D042001CE13739000E4250 /* Build configuration list for PBXLegacyTarget "RealmNode" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 02D042011CE13739000E4250 /* Debug */, - 02D042021CE13739000E4250 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 02D041F91CE13739000E4250 /* Project object */; -} From 4d24b2955037928ddd3a701e55acb64f43690642 Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Fri, 20 May 2016 15:37:09 -0700 Subject: [PATCH 02/14] poc change notification --- examples/ReactExample/components/todo-app.js | 4 ++ src/RealmJS.xcodeproj/project.pbxproj | 2 + src/js_collection.hpp | 3 +- src/js_list.hpp | 46 ++++++++++++++++++- src/js_observable.hpp | 35 ++++++++++++++ src/js_realm.hpp | 3 +- src/js_results.hpp | 44 ++++++++++++++++++ .../src/impl/collection_notifier.cpp | 17 ++++--- .../src/impl/collection_notifier.hpp | 5 +- src/object-store/src/list.cpp | 19 +++++++- src/object-store/src/list.hpp | 5 +- src/object-store/src/results.cpp | 16 +++++++ src/object-store/src/results.hpp | 5 +- 13 files changed, 188 insertions(+), 16 deletions(-) create mode 100644 src/js_observable.hpp diff --git a/examples/ReactExample/components/todo-app.js b/examples/ReactExample/components/todo-app.js index 31e0d55a..0304e43a 100644 --- a/examples/ReactExample/components/todo-app.js +++ b/examples/ReactExample/components/todo-app.js @@ -48,6 +48,10 @@ export default class TodoApp extends Component { // This is a Results object, which will live-update. this.todoLists = todoLists; + todoLists.addListener(function() { + console.log("changed"); + }); + console.log("registered listener"); // Bind all the methods that we will be passing as props. this.renderScene = this.renderScene.bind(this); diff --git a/src/RealmJS.xcodeproj/project.pbxproj b/src/RealmJS.xcodeproj/project.pbxproj index 07b1df31..844b823d 100644 --- a/src/RealmJS.xcodeproj/project.pbxproj +++ b/src/RealmJS.xcodeproj/project.pbxproj @@ -114,6 +114,7 @@ 029048101C0428DF00ABDED4 /* rpc.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = rpc.hpp; sourceTree = ""; }; 029048351C042A3C00ABDED4 /* platform.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = platform.hpp; sourceTree = ""; }; 029048381C042A8F00ABDED4 /* platform.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = platform.mm; sourceTree = ""; }; + 0290934A1CEFA9170009769E /* js_observable.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = js_observable.hpp; sourceTree = ""; }; 02A3C7A41BC4341500B1A7BE /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; }; 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; }; @@ -264,6 +265,7 @@ F6874A441CAD2ACD00EEEE36 /* JSC */, F62BF9001CAC72C40022BCDC /* Node */, F62A35141C18E783004A917D /* Object Store */, + 0290934A1CEFA9170009769E /* js_observable.hpp */, F60102F71CBDA6D400EC01BA /* js_collection.hpp */, 029048041C0428DF00ABDED4 /* js_list.hpp */, 029048061C0428DF00ABDED4 /* js_realm_object.hpp */, diff --git a/src/js_collection.hpp b/src/js_collection.hpp index 510333a7..f8c2d29f 100644 --- a/src/js_collection.hpp +++ b/src/js_collection.hpp @@ -19,6 +19,7 @@ #pragma once #include "js_class.hpp" +#include "js_observable.hpp" namespace realm { namespace js { @@ -27,7 +28,7 @@ namespace js { class Collection {}; template -struct CollectionClass : ClassDefinition { +struct CollectionClass : ClassDefinition> { std::string const name = "Collection"; }; diff --git a/src/js_list.hpp b/src/js_list.hpp index d936159c..5235c7ca 100644 --- a/src/js_list.hpp +++ b/src/js_list.hpp @@ -37,6 +37,7 @@ struct ListClass : ClassDefinition> { using ContextType = typename T::Context; using ObjectType = typename T::Object; using ValueType = typename T::Value; + using FunctionType = typename T::Function; using Object = js::Object; using Value = js::Value; using ReturnValue = js::ReturnValue; @@ -58,7 +59,12 @@ struct ListClass : ClassDefinition> { static void filtered(ContextType, ObjectType, size_t, const ValueType[], ReturnValue &); static void sorted(ContextType, ObjectType, size_t, const ValueType[], ReturnValue &); static void is_valid(ContextType, ObjectType, size_t, const ValueType [], ReturnValue &); - + + // observable + static void add_listener(ContextType, ObjectType, size_t, const ValueType[], ReturnValue &); + static void remove_listener(ContextType, ObjectType, size_t, const ValueType[], ReturnValue &); + static void remove_all_listeners(ContextType, ObjectType, size_t, const ValueType[], ReturnValue &); + std::string const name = "List"; MethodMap const methods = { @@ -71,6 +77,9 @@ struct ListClass : ClassDefinition> { {"filtered", wrap}, {"sorted", wrap}, {"isValid", wrap}, + {"addListener", wrap}, + {"removeListener", wrap}, + {"removeAllListeners", wrap}, }; PropertyMap const properties = { @@ -230,6 +239,41 @@ template void ListClass::is_valid(ContextType ctx, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) { return_value.set(get_internal>(this_object)->is_valid()); } + +template +void ListClass::add_listener(ContextType ctx, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) { + validate_argument_count(argc, 1); + + auto list = get_internal>(this_object); + auto callback = Value::validated_to_function(ctx, arguments[0]); + Protected protected_callback(ctx, callback); + Protected protected_this(ctx, this_object); + Protected protected_ctx(Context::get_global_context(ctx)); + + list->add_notification_callback([=](CollectionChangeSet change_set, std::exception_ptr exception) { + ValueType arguments[2]; + arguments[0] = protected_this; + arguments[1] = Value::from_undefined(protected_ctx); + Function::call(protected_ctx, protected_callback, protected_this, 2, arguments); + }, (size_t)(ValueType)callback); +} + +template +void ListClass::remove_listener(ContextType ctx, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) { + validate_argument_count(argc, 1); + + auto list = get_internal>(this_object); + auto callback = Value::validated_to_function(ctx, arguments[0]); + list->remove_notification_callback((size_t)(ValueType)callback); +} + +template +void ListClass::remove_all_listeners(ContextType ctx, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) { + validate_argument_count(argc, 0); + + auto list = get_internal>(this_object); + list->remove_all_notification_callbacks(); +} } // js } // realm diff --git a/src/js_observable.hpp b/src/js_observable.hpp new file mode 100644 index 00000000..a49a1d0e --- /dev/null +++ b/src/js_observable.hpp @@ -0,0 +1,35 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 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. +// +//////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "js_class.hpp" + +namespace realm { +namespace js { + +// Empty class that merely serves as useful type for now. +class Observable {}; + +template +struct ObservableClass : ClassDefinition { + std::string const name = "Observable"; +}; + +} // js +} // realm diff --git a/src/js_realm.hpp b/src/js_realm.hpp index 2767df61..e455072b 100644 --- a/src/js_realm.hpp +++ b/src/js_realm.hpp @@ -28,6 +28,7 @@ #include "js_list.hpp" #include "js_results.hpp" #include "js_schema.hpp" +#include "js_observable.hpp" #include "shared_realm.hpp" #include "binding_context.hpp" @@ -124,7 +125,7 @@ void set_default_path(std::string path); void delete_all_realms(); template -class RealmClass : public ClassDefinition { +class RealmClass : public ClassDefinition> { using GlobalContextType = typename T::GlobalContext; using ContextType = typename T::Context; using FunctionType = typename T::Function; diff --git a/src/js_results.hpp b/src/js_results.hpp index 9f021fb7..4c313def 100644 --- a/src/js_results.hpp +++ b/src/js_results.hpp @@ -34,6 +34,7 @@ struct ResultsClass : ClassDefinition> { using ContextType = typename T::Context; using ObjectType = typename T::Object; using ValueType = typename T::Value; + using FunctionType = typename T::Function; using Object = js::Object; using Value = js::Value; using ReturnValue = js::ReturnValue; @@ -57,6 +58,11 @@ struct ResultsClass : ClassDefinition> { static void sorted(ContextType, ObjectType, size_t, const ValueType[], ReturnValue &); static void is_valid(ContextType, ObjectType, size_t, const ValueType [], ReturnValue &); + // observable + static void add_listener(ContextType, ObjectType, size_t, const ValueType[], ReturnValue &); + static void remove_listener(ContextType, ObjectType, size_t, const ValueType[], ReturnValue &); + static void remove_all_listeners(ContextType, ObjectType, size_t, const ValueType[], ReturnValue &); + std::string const name = "Results"; MethodMap const methods = { @@ -64,6 +70,9 @@ struct ResultsClass : ClassDefinition> { {"filtered", wrap}, {"sorted", wrap}, {"isValid", wrap}, + {"addListener", wrap}, + {"removeListener", wrap}, + {"removeAllListeners", wrap}, }; PropertyMap const properties = { @@ -239,6 +248,41 @@ template void ResultsClass::is_valid(ContextType ctx, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) { return_value.set(get_internal>(this_object)->is_valid()); } + +template +void ResultsClass::add_listener(ContextType ctx, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) { + validate_argument_count(argc, 1); + + auto list = get_internal>(this_object); + auto callback = Value::validated_to_function(ctx, arguments[0]); + Protected protected_callback(ctx, callback); + Protected protected_this(ctx, this_object); + Protected protected_ctx(Context::get_global_context(ctx)); + + list->add_notification_callback([=](CollectionChangeSet change_set, std::exception_ptr exception) { + ValueType arguments[2]; + arguments[0] = protected_this; + arguments[1] = Value::from_undefined(protected_ctx); + Function::call(protected_ctx, protected_callback, protected_this, 2, arguments); + }, (size_t)(ValueType)callback); +} +template +void ResultsClass::remove_listener(ContextType ctx, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) { + validate_argument_count(argc, 1); + + auto results = get_internal>(this_object); + auto callback = Value::validated_to_function(ctx, arguments[0]); + results->remove_notification_callback((size_t)(ValueType)callback); +} + +template +void ResultsClass::remove_all_listeners(ContextType ctx, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) { + validate_argument_count(argc, 0); + + auto results = get_internal>(this_object); + results->remove_all_notification_callbacks(); +} + } // js } // realm diff --git a/src/object-store/src/impl/collection_notifier.cpp b/src/object-store/src/impl/collection_notifier.cpp index 7751c3ac..956295f4 100644 --- a/src/object-store/src/impl/collection_notifier.cpp +++ b/src/object-store/src/impl/collection_notifier.cpp @@ -165,22 +165,19 @@ CollectionNotifier::~CollectionNotifier() unregister(); } -size_t CollectionNotifier::add_callback(CollectionChangeCallback callback) +size_t CollectionNotifier::add_callback(CollectionChangeCallback callback, size_t token) { m_realm->verify_thread(); - auto next_token = [=] { - size_t token = 0; + std::lock_guard lock(m_callback_mutex); + if (token == 0) { for (auto& callback : m_callbacks) { if (token <= callback.token) { token = callback.token + 1; } } - return token; - }; + } - std::lock_guard lock(m_callback_mutex); - auto token = next_token(); m_callbacks.push_back({std::move(callback), token, false}); if (m_callback_index == npos) { // Don't need to wake up if we're already sending notifications Realm::Internal::get_coordinator(*m_realm).send_commit_notifications(); @@ -216,6 +213,12 @@ void CollectionNotifier::remove_callback(size_t token) } } +void CollectionNotifier::remove_all_callbacks() +{ + m_callbacks.clear(); + m_have_callbacks = false; +} + void CollectionNotifier::unregister() noexcept { std::lock_guard lock(m_realm_mutex); diff --git a/src/object-store/src/impl/collection_notifier.hpp b/src/object-store/src/impl/collection_notifier.hpp index 211d5ced..3a78fc7a 100644 --- a/src/object-store/src/impl/collection_notifier.hpp +++ b/src/object-store/src/impl/collection_notifier.hpp @@ -109,12 +109,13 @@ public: // Add a callback to be called each time the collection changes // This can only be called from the target collection's thread // Returns a token which can be passed to remove_callback() - size_t add_callback(CollectionChangeCallback callback); + size_t add_callback(CollectionChangeCallback callback, size_t token = 0); // Remove a previously added token. The token is no longer valid after // calling this function and must not be used again. This function can be // called from any thread. void remove_callback(size_t token); - + void remove_all_callbacks(); + // ------------------------------------------------------------------------ // API for RealmCoordinator to manage running things and calling callbacks diff --git a/src/object-store/src/list.cpp b/src/object-store/src/list.cpp index fec20772..40f00d5b 100644 --- a/src/object-store/src/list.cpp +++ b/src/object-store/src/list.cpp @@ -184,12 +184,27 @@ size_t hash::operator()(realm::List const& list) const } } -NotificationToken List::add_notification_callback(CollectionChangeCallback cb) +size_t List::add_notification_callback(CollectionChangeCallback cb, size_t token) { verify_attached(); if (!m_notifier) { m_notifier = std::make_shared(m_link_view, m_realm); RealmCoordinator::register_notifier(m_notifier); } - return {m_notifier, m_notifier->add_callback(std::move(cb))}; + return m_notifier->add_callback(std::move(cb), token); +} + +NotificationToken List::add_notification_callback(CollectionChangeCallback cb) +{ + return {m_notifier, add_notification_callback(cb, 0)}; +} + +void List::remove_notification_callback(size_t token) +{ + m_notifier->remove_callback(token); +} + +void List::remove_all_notification_callbacks() +{ + m_notifier->remove_all_callbacks(); } diff --git a/src/object-store/src/list.hpp b/src/object-store/src/list.hpp index 8abd601d..1f381a66 100644 --- a/src/object-store/src/list.hpp +++ b/src/object-store/src/list.hpp @@ -74,7 +74,10 @@ public: bool operator==(List const& rgt) const noexcept; NotificationToken add_notification_callback(CollectionChangeCallback cb); - + size_t add_notification_callback(CollectionChangeCallback cb, size_t token); + void remove_notification_callback(size_t token); + void remove_all_notification_callbacks(); + // These are implemented in object_accessor.hpp template void add(ContextType ctx, ValueType value); diff --git a/src/object-store/src/results.cpp b/src/object-store/src/results.cpp index 362a2d95..bf9a874a 100644 --- a/src/object-store/src/results.cpp +++ b/src/object-store/src/results.cpp @@ -497,6 +497,22 @@ NotificationToken Results::add_notification_callback(CollectionChangeCallback cb return {m_notifier, m_notifier->add_callback(std::move(cb))}; } +void Results::add_notification_callback(CollectionChangeCallback cb, size_t token) +{ + prepare_async(); + m_notifier->add_callback(std::move(cb), token); +} + +void Results::remove_notification_callback(size_t token) +{ + m_notifier->remove_callback(token); +} + +void Results::remove_all_notification_callbacks() +{ + m_notifier->remove_all_callbacks(); +} + bool Results::is_in_table_order() const { switch (m_mode) { diff --git a/src/object-store/src/results.hpp b/src/object-store/src/results.hpp index c8a02f44..e9894cf9 100644 --- a/src/object-store/src/results.hpp +++ b/src/object-store/src/results.hpp @@ -180,7 +180,10 @@ public: // and then rerun after each commit (if needed) and redelivered if it changed NotificationToken async(std::function target); NotificationToken add_notification_callback(CollectionChangeCallback cb); - + void add_notification_callback(CollectionChangeCallback cb, size_t token); + void remove_notification_callback(size_t token); + void remove_all_notification_callbacks(); + bool wants_background_updates() const { return m_wants_background_updates; } // Returns whether the rows are guaranteed to be in table order. From ecf1924a51d08d65a1efc8147d3ac74cca7d7455 Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Mon, 23 May 2016 11:57:07 -0700 Subject: [PATCH 03/14] object store pr feedback --- src/js_realm.hpp | 4 ++-- .../src/impl/realm_coordinator.cpp | 2 +- src/object-store/src/object_store.hpp | 5 ----- src/object-store/src/shared_realm.cpp | 19 +++++++++++++++---- src/object-store/src/shared_realm.hpp | 12 ++++++++---- 5 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/js_realm.hpp b/src/js_realm.hpp index e455072b..b2e8cc94 100644 --- a/src/js_realm.hpp +++ b/src/js_realm.hpp @@ -249,8 +249,8 @@ inline typename T::Function RealmClass::create_constructor(ContextType ctx) { } static inline void convert_outdated_datetime_columns(const SharedRealm &realm) { - if (realm->config().upgrade_initial_version != realm->config().upgrade_final_version && - realm->config().upgrade_initial_version < 5) { + int old_file_format_version = realm->file_format_upgraded_from_version(); + if (old_file_format_version && old_file_format_version < 5) { // any versions earlier than file format 5 are stored as milliseconds and need to be converted to the new format for (auto& object_schema : *realm->config().schema) { auto table = ObjectStore::table_for_object_type(realm->read_group(), object_schema.name); diff --git a/src/object-store/src/impl/realm_coordinator.cpp b/src/object-store/src/impl/realm_coordinator.cpp index df53a2ce..47033a67 100644 --- a/src/object-store/src/impl/realm_coordinator.cpp +++ b/src/object-store/src/impl/realm_coordinator.cpp @@ -105,7 +105,7 @@ std::shared_ptr RealmCoordinator::get_realm(Realm::Config config) auto realm = std::make_shared(std::move(config)); realm->init(shared_from_this()); - + if (!config.read_only && !m_notifier && config.automatic_change_notifications) { try { m_notifier = std::make_unique(*this); diff --git a/src/object-store/src/object_store.hpp b/src/object-store/src/object_store.hpp index 508b43be..0b9f05f8 100644 --- a/src/object-store/src/object_store.hpp +++ b/src/object-store/src/object_store.hpp @@ -158,11 +158,6 @@ namespace realm { std::vector m_validation_errors; }; - class SchemaUpdateValidationException : public SchemaValidationException { - public: - SchemaUpdateValidationException(std::vector const& errors); - }; - class SchemaMismatchException : public ObjectStoreException { public: SchemaMismatchException(std::vector const& errors); diff --git a/src/object-store/src/shared_realm.cpp b/src/object-store/src/shared_realm.cpp index ff731ce3..b77ec99c 100644 --- a/src/object-store/src/shared_realm.cpp +++ b/src/object-store/src/shared_realm.cpp @@ -61,7 +61,7 @@ Realm::Config& Realm::Config::operator=(realm::Realm::Config const& c) Realm::Realm(Config config) : m_config(std::move(config)) { - open_with_config(m_config, m_history, m_shared_group, m_read_only_group); + open_with_config(m_config, m_history, m_shared_group, m_read_only_group, this); if (m_read_only_group) { m_group = m_read_only_group.get(); @@ -71,7 +71,8 @@ Realm::Realm(Config config) void Realm::open_with_config(Config& config, std::unique_ptr& history, std::unique_ptr& shared_group, - std::unique_ptr& read_only_group) + std::unique_ptr& read_only_group, + Realm *realm) { try { if (config.read_only) { @@ -85,8 +86,10 @@ void Realm::open_with_config(Config& config, SharedGroup::DurabilityLevel durability = config.in_memory ? SharedGroup::durability_MemOnly : SharedGroup::durability_Full; shared_group = std::make_unique(*history, durability, config.encryption_key.data(), !config.disable_format_upgrade, [&](int from_version, int to_version) { - config.upgrade_initial_version = from_version; - config.upgrade_final_version = to_version; + if (realm) { + realm->upgrade_initial_version = from_version; + realm->upgrade_final_version = to_version; + } }); } } @@ -459,3 +462,11 @@ void Realm::close() m_binding_context = nullptr; m_coordinator = nullptr; } + +int Realm::file_format_upgraded_from_version() const +{ + if (upgrade_initial_version != upgrade_final_version) { + return upgrade_initial_version; + } + return 0; +} diff --git a/src/object-store/src/shared_realm.hpp b/src/object-store/src/shared_realm.hpp index 2526d198..d22b2c2d 100644 --- a/src/object-store/src/shared_realm.hpp +++ b/src/object-store/src/shared_realm.hpp @@ -79,9 +79,6 @@ namespace realm { // everything can be done deterministically on one thread, and // speeds up tests that don't need notifications. bool automatic_change_notifications = true; - // File format versions populated when a file format upgrade takes place - // during realm opening - int upgrade_initial_version = 0, upgrade_final_version = 0; Config(); Config(Config&&); @@ -135,6 +132,9 @@ namespace realm { // Realm after closing it will produce undefined behavior. void close(); + // returns the file format version upgraded from, or 0 if not upgraded + int file_format_upgraded_from_version() const; + ~Realm(); void init(std::shared_ptr<_impl::RealmCoordinator> coordinator); @@ -161,7 +161,8 @@ namespace realm { static void open_with_config(Config& config, std::unique_ptr& history, std::unique_ptr& shared_group, - std::unique_ptr& read_only_group); + std::unique_ptr& read_only_group, + Realm *realm = nullptr); private: Config m_config; @@ -176,6 +177,9 @@ namespace realm { std::shared_ptr<_impl::RealmCoordinator> m_coordinator; + // File format versions populated when a file format upgrade takes place during realm opening + int upgrade_initial_version = 0, upgrade_final_version = 0; + public: std::unique_ptr m_binding_context; From 0d233215c37307577665e758b94fddb92e05ee07 Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Tue, 24 May 2016 15:11:57 -0700 Subject: [PATCH 04/14] add collection serialization --- examples/ReactExample/components/todo-app.js | 17 ++++---- src/js_collection.hpp | 42 ++++++++++++++++++++ src/js_results.hpp | 2 +- 3 files changed, 51 insertions(+), 10 deletions(-) diff --git a/examples/ReactExample/components/todo-app.js b/examples/ReactExample/components/todo-app.js index 0304e43a..5e497e4e 100644 --- a/examples/ReactExample/components/todo-app.js +++ b/examples/ReactExample/components/todo-app.js @@ -39,20 +39,19 @@ export default class TodoApp extends Component { constructor(props) { super(props); - let todoLists = realm.objects('TodoList'); - if (todoLists.length < 1) { + // This is a Results object, which will live-update. + this.todoLists = realm.objects('TodoList'); + this.todoLists.addListener(function(name, changes) { + console.log("changed: " + JSON.stringify(changes)); + }); + console.log("registered listener"); + + if (this.todoLists.length < 1) { realm.write(() => { realm.create('TodoList', {name: 'Todo List'}); }); } - // This is a Results object, which will live-update. - this.todoLists = todoLists; - todoLists.addListener(function() { - console.log("changed"); - }); - console.log("registered listener"); - // Bind all the methods that we will be passing as props. this.renderScene = this.renderScene.bind(this); this._addNewTodoList = this._addNewTodoList.bind(this); diff --git a/src/js_collection.hpp b/src/js_collection.hpp index f8c2d29f..790e3484 100644 --- a/src/js_collection.hpp +++ b/src/js_collection.hpp @@ -19,8 +19,11 @@ #pragma once #include "js_class.hpp" +#include "js_types.hpp" #include "js_observable.hpp" +#include "collection_notifications.hpp" + namespace realm { namespace js { @@ -29,8 +32,47 @@ class Collection {}; template struct CollectionClass : ClassDefinition> { + using ContextType = typename T::Context; + using ValueType = typename T::Value; + using ObjectType = typename T::Object; + using Object = js::Object; + using Value = js::Value; + std::string const name = "Collection"; + + static inline ValueType create_collection_change_set(ContextType ctx, const CollectionChangeSet &change_set); }; +template +typename T::Value CollectionClass::create_collection_change_set(ContextType ctx, const CollectionChangeSet &change_set) +{ + ObjectType object = Object::create_empty(ctx); + std::vector deletions, insertions, modifications, moves; + for (auto index : change_set.deletions.as_indexes()) { + deletions.push_back(Value::from_number(ctx, index)); + } + Object::set_property(ctx, object, "deletions", Object::create_array(ctx, deletions)); + + for (auto index : change_set.insertions.as_indexes()) { + insertions.push_back(Value::from_number(ctx, index)); + } + Object::set_property(ctx, object, "insertions", Object::create_array(ctx, insertions)); + + for (auto index : change_set.modifications.as_indexes()) { + modifications.push_back(Value::from_number(ctx, index)); + } + Object::set_property(ctx, object, "modifications", Object::create_array(ctx, modifications)); + + for (auto& move : change_set.moves) { + ObjectType move_object = Object::create_empty(ctx); + Object::set_property(ctx, move_object, "from", Value::from_number(ctx, move.from)); + Object::set_property(ctx, move_object, "to", Value::from_number(ctx, move.to)); + moves.push_back(move_object); + } + Object::set_property(ctx, object, "moves", Object::create_array(ctx, moves)); + + return object; +} + } // js } // realm diff --git a/src/js_results.hpp b/src/js_results.hpp index 4c313def..fbd507a7 100644 --- a/src/js_results.hpp +++ b/src/js_results.hpp @@ -262,7 +262,7 @@ void ResultsClass::add_listener(ContextType ctx, ObjectType this_object, size list->add_notification_callback([=](CollectionChangeSet change_set, std::exception_ptr exception) { ValueType arguments[2]; arguments[0] = protected_this; - arguments[1] = Value::from_undefined(protected_ctx); + arguments[1] = CollectionClass::create_collection_change_set(protected_ctx, change_set); Function::call(protected_ctx, protected_callback, protected_this, 2, arguments); }, (size_t)(ValueType)callback); } From eb1d87099393e9d0845890a4cf02706a1f1dc60c Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Fri, 27 May 2016 13:14:37 -0700 Subject: [PATCH 05/14] store notification tokens pt1 --- src/RealmJS.xcodeproj/project.pbxproj | 2 + src/js_list.hpp | 17 +++++--- src/js_results.hpp | 40 +++++++++++++------ src/js_types.hpp | 6 +++ src/jsc/jsc_init.hpp | 1 + src/jsc/jsc_notification_map.hpp | 34 ++++++++++++++++ .../src/impl/collection_notifier.cpp | 11 +++-- .../src/impl/collection_notifier.hpp | 2 +- src/object-store/src/list.cpp | 19 +-------- src/object-store/src/list.hpp | 5 +-- src/object-store/src/results.cpp | 16 -------- src/object-store/src/results.hpp | 5 +-- 12 files changed, 93 insertions(+), 65 deletions(-) create mode 100644 src/jsc/jsc_notification_map.hpp diff --git a/src/RealmJS.xcodeproj/project.pbxproj b/src/RealmJS.xcodeproj/project.pbxproj index 844b823d..ad0ca3b4 100644 --- a/src/RealmJS.xcodeproj/project.pbxproj +++ b/src/RealmJS.xcodeproj/project.pbxproj @@ -98,6 +98,7 @@ 02414B9F1CE6AAEF00A8669F /* results_notifier.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = results_notifier.cpp; path = src/impl/results_notifier.cpp; sourceTree = ""; }; 02414BA01CE6AAEF00A8669F /* results_notifier.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = results_notifier.hpp; path = src/impl/results_notifier.hpp; sourceTree = ""; }; 025678951CAB392000FB8501 /* jsc_types.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = jsc_types.hpp; sourceTree = ""; }; + 026D72111CF8B23C00EF1DCC /* jsc_notification_map.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = jsc_notification_map.hpp; sourceTree = ""; }; 0270BC5A1B7CFC1300010E03 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 0270BC781B7D020100010E03 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = ios/Info.plist; sourceTree = ""; }; 0270BC7A1B7D020100010E03 /* RealmJSTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RealmJSTests.h; path = ios/RealmJSTests.h; sourceTree = ""; }; @@ -507,6 +508,7 @@ F60103081CC4B4F900EC01BA /* jsc_protected.hpp */, F60103141CC4CC8C00EC01BA /* jsc_return_value.hpp */, F60102E71CBBB36500EC01BA /* jsc_object_accessor.hpp */, + 026D72111CF8B23C00EF1DCC /* jsc_notification_map.hpp */, ); name = JSC; path = jsc; diff --git a/src/js_list.hpp b/src/js_list.hpp index 5235c7ca..5b24648d 100644 --- a/src/js_list.hpp +++ b/src/js_list.hpp @@ -33,7 +33,16 @@ namespace realm { namespace js { template -struct ListClass : ClassDefinition> { +class List : public realm::List { + public: + List(std::shared_ptr r, const ObjectSchema& s, LinkViewRef l) noexcept : realm::List(r, s, l) {} + List(const realm::List &l) : realm::List(l) {} + + std::map::ComparableFunction, NotificationToken, FunctionComparator> m_notification_tokens; +}; + +template +struct ListClass : ClassDefinition, CollectionClass> { using ContextType = typename T::Context; using ObjectType = typename T::Object; using ValueType = typename T::Value; @@ -91,7 +100,7 @@ struct ListClass : ClassDefinition> { template typename T::Object ListClass::create_instance(ContextType ctx, realm::List &list) { - return create_object>(ctx, new realm::List(list)); + return create_object>(ctx, new realm::js::List(list)); } template @@ -255,7 +264,7 @@ void ListClass::add_listener(ContextType ctx, ObjectType this_object, size_t arguments[0] = protected_this; arguments[1] = Value::from_undefined(protected_ctx); Function::call(protected_ctx, protected_callback, protected_this, 2, arguments); - }, (size_t)(ValueType)callback); + }); } template @@ -264,7 +273,6 @@ void ListClass::remove_listener(ContextType ctx, ObjectType this_object, size auto list = get_internal>(this_object); auto callback = Value::validated_to_function(ctx, arguments[0]); - list->remove_notification_callback((size_t)(ValueType)callback); } template @@ -272,7 +280,6 @@ void ListClass::remove_all_listeners(ContextType ctx, ObjectType this_object, validate_argument_count(argc, 0); auto list = get_internal>(this_object); - list->remove_all_notification_callbacks(); } } // js diff --git a/src/js_results.hpp b/src/js_results.hpp index fbd507a7..9bf60351 100644 --- a/src/js_results.hpp +++ b/src/js_results.hpp @@ -30,7 +30,24 @@ namespace realm { namespace js { template -struct ResultsClass : ClassDefinition> { +class Results : public realm::Results { + public: + Results(Results const&) : realm::Results(*this) {}; + Results(Results&&) = default; + Results& operator=(Results&&) = default; + Results& operator=(Results const&) = default; + + Results() = default; + Results(SharedRealm r, const ObjectSchema& o, Table& table) : realm::Results(r, o, table) {} + Results(SharedRealm r, const ObjectSchema& o, Query q, SortOrder s = {}) : realm::Results(r, o, q, s) {} + Results(SharedRealm r, const ObjectSchema& o, TableView tv, SortOrder s) : realm::Results(r, o, tv, s) {} + Results(SharedRealm r, const ObjectSchema& o, LinkViewRef lv, util::Optional q = {}, SortOrder s = {}) : realm::Results(r, o, lv, q, s) {} + + std::map::ComparableFunction, NotificationToken, FunctionComparator> m_notification_tokens; +}; + +template +struct ResultsClass : ClassDefinition, CollectionClass> { using ContextType = typename T::Context; using ObjectType = typename T::Object; using ValueType = typename T::Value; @@ -39,7 +56,7 @@ struct ResultsClass : ClassDefinition> { using Value = js::Value; using ReturnValue = js::ReturnValue; - static ObjectType create_instance(ContextType, const realm::Results &, bool live = true); + static ObjectType create_instance(ContextType, const realm::js::Results &, bool live = true); static ObjectType create_instance(ContextType, const realm::List &, bool live = true); static ObjectType create_instance(ContextType, SharedRealm, const std::string &type, bool live = true); static ObjectType create_instance(ContextType, SharedRealm, const ObjectSchema &, Query, bool live = true); @@ -83,8 +100,8 @@ struct ResultsClass : ClassDefinition> { }; template -typename T::Object ResultsClass::create_instance(ContextType ctx, const realm::Results &results, bool live) { - auto new_results = new realm::Results(results); +typename T::Object ResultsClass::create_instance(ContextType ctx, const realm::js::Results &results, bool live) { + auto new_results = new realm::js::Results(results); new_results->set_live(live); return create_object>(ctx, new_results); @@ -105,7 +122,7 @@ typename T::Object ResultsClass::create_instance(ContextType ctx, SharedRealm throw std::runtime_error("Object type '" + type + "' not present in Realm."); } - auto results = new realm::Results(realm, *object_schema, *table); + auto results = new realm::js::Results(realm, *object_schema, *table); results->set_live(live); return create_object>(ctx, results); @@ -113,7 +130,7 @@ typename T::Object ResultsClass::create_instance(ContextType ctx, SharedRealm template typename T::Object ResultsClass::create_instance(ContextType ctx, SharedRealm realm, const ObjectSchema &object_schema, Query query, bool live) { - auto results = new realm::Results(realm, object_schema, std::move(query)); + auto results = new realm::js::Results(realm, object_schema, std::move(query)); results->set_live(live); return create_object>(ctx, results); @@ -195,7 +212,7 @@ typename T::Object ResultsClass::create_sorted(ContextType ctx, const U &coll columns.push_back(prop->table_column); } - auto results = new realm::Results(realm, object_schema, collection.get_query(), {std::move(columns), std::move(ascending)}); + auto results = new realm::js::Results(realm, object_schema, collection.get_query(), {std::move(columns), std::move(ascending)}); return create_object>(ctx, results); } @@ -253,18 +270,19 @@ template void ResultsClass::add_listener(ContextType ctx, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) { validate_argument_count(argc, 1); - auto list = get_internal>(this_object); + auto results = get_internal>(this_object); auto callback = Value::validated_to_function(ctx, arguments[0]); Protected protected_callback(ctx, callback); Protected protected_this(ctx, this_object); Protected protected_ctx(Context::get_global_context(ctx)); - list->add_notification_callback([=](CollectionChangeSet change_set, std::exception_ptr exception) { + auto token = results->add_notification_callback([=](CollectionChangeSet change_set, std::exception_ptr exception) { ValueType arguments[2]; arguments[0] = protected_this; arguments[1] = CollectionClass::create_collection_change_set(protected_ctx, change_set); Function::call(protected_ctx, protected_callback, protected_this, 2, arguments); - }, (size_t)(ValueType)callback); + }); + results->m_notification_tokens.emplace(std::make_pair(protected_ctx, protected_callback), std::move(token)); } template @@ -273,7 +291,6 @@ void ResultsClass::remove_listener(ContextType ctx, ObjectType this_object, s auto results = get_internal>(this_object); auto callback = Value::validated_to_function(ctx, arguments[0]); - results->remove_notification_callback((size_t)(ValueType)callback); } template @@ -281,7 +298,6 @@ void ResultsClass::remove_all_listeners(ContextType ctx, ObjectType this_obje validate_argument_count(argc, 0); auto results = get_internal>(this_object); - results->remove_all_notification_callbacks(); } } // js diff --git a/src/js_types.hpp b/src/js_types.hpp index 2b1f1fbc..2e797c80 100644 --- a/src/js_types.hpp +++ b/src/js_types.hpp @@ -289,6 +289,12 @@ struct ReturnValue { void set_undefined(); }; +template +struct FunctionComparator { + using ComparableFunction = std::pair, Protected>; + bool operator()(const ComparableFunction& a, const ComparableFunction& b) const; +}; + template REALM_JS_INLINE typename T::Object create_object(typename T::Context ctx, typename ClassType::Internal* internal = nullptr) { return Object::template create_instance(ctx, internal); diff --git a/src/jsc/jsc_init.hpp b/src/jsc/jsc_init.hpp index de19d7b9..e2629534 100644 --- a/src/jsc/jsc_init.hpp +++ b/src/jsc/jsc_init.hpp @@ -28,5 +28,6 @@ #include "jsc_exception.hpp" #include "jsc_return_value.hpp" #include "jsc_object_accessor.hpp" +#include "jsc_notification_map.hpp" #include "js_realm.hpp" diff --git a/src/jsc/jsc_notification_map.hpp b/src/jsc/jsc_notification_map.hpp new file mode 100644 index 00000000..fbd8c3b0 --- /dev/null +++ b/src/jsc/jsc_notification_map.hpp @@ -0,0 +1,34 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 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. +// +//////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "jsc_types.hpp" + +namespace realm { +namespace js { + +template<> +bool FunctionComparator::operator()(const ComparableFunction& a, const ComparableFunction& b) const { + if ((JSGlobalContextRef)a.first != (JSGlobalContextRef)b.first) { + return false; + } + return JSValueIsStrictEqual(a.first, a.second, b.second); +} + +}} diff --git a/src/object-store/src/impl/collection_notifier.cpp b/src/object-store/src/impl/collection_notifier.cpp index 956295f4..817f329e 100644 --- a/src/object-store/src/impl/collection_notifier.cpp +++ b/src/object-store/src/impl/collection_notifier.cpp @@ -165,16 +165,15 @@ CollectionNotifier::~CollectionNotifier() unregister(); } -size_t CollectionNotifier::add_callback(CollectionChangeCallback callback, size_t token) +size_t CollectionNotifier::add_callback(CollectionChangeCallback callback) { m_realm->verify_thread(); std::lock_guard lock(m_callback_mutex); - if (token == 0) { - for (auto& callback : m_callbacks) { - if (token <= callback.token) { - token = callback.token + 1; - } + size_t token = 0; + for (auto& callback : m_callbacks) { + if (token <= callback.token) { + token = callback.token + 1; } } diff --git a/src/object-store/src/impl/collection_notifier.hpp b/src/object-store/src/impl/collection_notifier.hpp index 3a78fc7a..97699cdb 100644 --- a/src/object-store/src/impl/collection_notifier.hpp +++ b/src/object-store/src/impl/collection_notifier.hpp @@ -109,7 +109,7 @@ public: // Add a callback to be called each time the collection changes // This can only be called from the target collection's thread // Returns a token which can be passed to remove_callback() - size_t add_callback(CollectionChangeCallback callback, size_t token = 0); + size_t add_callback(CollectionChangeCallback callback); // Remove a previously added token. The token is no longer valid after // calling this function and must not be used again. This function can be // called from any thread. diff --git a/src/object-store/src/list.cpp b/src/object-store/src/list.cpp index 40f00d5b..fec20772 100644 --- a/src/object-store/src/list.cpp +++ b/src/object-store/src/list.cpp @@ -184,27 +184,12 @@ size_t hash::operator()(realm::List const& list) const } } -size_t List::add_notification_callback(CollectionChangeCallback cb, size_t token) +NotificationToken List::add_notification_callback(CollectionChangeCallback cb) { verify_attached(); if (!m_notifier) { m_notifier = std::make_shared(m_link_view, m_realm); RealmCoordinator::register_notifier(m_notifier); } - return m_notifier->add_callback(std::move(cb), token); -} - -NotificationToken List::add_notification_callback(CollectionChangeCallback cb) -{ - return {m_notifier, add_notification_callback(cb, 0)}; -} - -void List::remove_notification_callback(size_t token) -{ - m_notifier->remove_callback(token); -} - -void List::remove_all_notification_callbacks() -{ - m_notifier->remove_all_callbacks(); + return {m_notifier, m_notifier->add_callback(std::move(cb))}; } diff --git a/src/object-store/src/list.hpp b/src/object-store/src/list.hpp index 1f381a66..8abd601d 100644 --- a/src/object-store/src/list.hpp +++ b/src/object-store/src/list.hpp @@ -74,10 +74,7 @@ public: bool operator==(List const& rgt) const noexcept; NotificationToken add_notification_callback(CollectionChangeCallback cb); - size_t add_notification_callback(CollectionChangeCallback cb, size_t token); - void remove_notification_callback(size_t token); - void remove_all_notification_callbacks(); - + // These are implemented in object_accessor.hpp template void add(ContextType ctx, ValueType value); diff --git a/src/object-store/src/results.cpp b/src/object-store/src/results.cpp index bf9a874a..362a2d95 100644 --- a/src/object-store/src/results.cpp +++ b/src/object-store/src/results.cpp @@ -497,22 +497,6 @@ NotificationToken Results::add_notification_callback(CollectionChangeCallback cb return {m_notifier, m_notifier->add_callback(std::move(cb))}; } -void Results::add_notification_callback(CollectionChangeCallback cb, size_t token) -{ - prepare_async(); - m_notifier->add_callback(std::move(cb), token); -} - -void Results::remove_notification_callback(size_t token) -{ - m_notifier->remove_callback(token); -} - -void Results::remove_all_notification_callbacks() -{ - m_notifier->remove_all_callbacks(); -} - bool Results::is_in_table_order() const { switch (m_mode) { diff --git a/src/object-store/src/results.hpp b/src/object-store/src/results.hpp index e9894cf9..c8a02f44 100644 --- a/src/object-store/src/results.hpp +++ b/src/object-store/src/results.hpp @@ -180,10 +180,7 @@ public: // and then rerun after each commit (if needed) and redelivered if it changed NotificationToken async(std::function target); NotificationToken add_notification_callback(CollectionChangeCallback cb); - void add_notification_callback(CollectionChangeCallback cb, size_t token); - void remove_notification_callback(size_t token); - void remove_all_notification_callbacks(); - + bool wants_background_updates() const { return m_wants_background_updates; } // Returns whether the rows are guaranteed to be in table order. From 583affbef7cb0cb8c41b1cb55c7a076af7feee67 Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Fri, 27 May 2016 13:38:20 -0700 Subject: [PATCH 06/14] remove FunctionComparator --- src/RealmJS.xcodeproj/project.pbxproj | 2 -- src/js_list.hpp | 2 +- src/js_results.hpp | 6 ++--- src/js_types.hpp | 7 +----- src/jsc/jsc_init.hpp | 1 - src/jsc/jsc_notification_map.hpp | 34 --------------------------- src/jsc/jsc_protected.hpp | 10 ++++++++ 7 files changed, 15 insertions(+), 47 deletions(-) delete mode 100644 src/jsc/jsc_notification_map.hpp diff --git a/src/RealmJS.xcodeproj/project.pbxproj b/src/RealmJS.xcodeproj/project.pbxproj index ad0ca3b4..844b823d 100644 --- a/src/RealmJS.xcodeproj/project.pbxproj +++ b/src/RealmJS.xcodeproj/project.pbxproj @@ -98,7 +98,6 @@ 02414B9F1CE6AAEF00A8669F /* results_notifier.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = results_notifier.cpp; path = src/impl/results_notifier.cpp; sourceTree = ""; }; 02414BA01CE6AAEF00A8669F /* results_notifier.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = results_notifier.hpp; path = src/impl/results_notifier.hpp; sourceTree = ""; }; 025678951CAB392000FB8501 /* jsc_types.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = jsc_types.hpp; sourceTree = ""; }; - 026D72111CF8B23C00EF1DCC /* jsc_notification_map.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = jsc_notification_map.hpp; sourceTree = ""; }; 0270BC5A1B7CFC1300010E03 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 0270BC781B7D020100010E03 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = ios/Info.plist; sourceTree = ""; }; 0270BC7A1B7D020100010E03 /* RealmJSTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RealmJSTests.h; path = ios/RealmJSTests.h; sourceTree = ""; }; @@ -508,7 +507,6 @@ F60103081CC4B4F900EC01BA /* jsc_protected.hpp */, F60103141CC4CC8C00EC01BA /* jsc_return_value.hpp */, F60102E71CBBB36500EC01BA /* jsc_object_accessor.hpp */, - 026D72111CF8B23C00EF1DCC /* jsc_notification_map.hpp */, ); name = JSC; path = jsc; diff --git a/src/js_list.hpp b/src/js_list.hpp index 5b24648d..752236a1 100644 --- a/src/js_list.hpp +++ b/src/js_list.hpp @@ -38,7 +38,7 @@ class List : public realm::List { List(std::shared_ptr r, const ObjectSchema& s, LinkViewRef l) noexcept : realm::List(r, s, l) {} List(const realm::List &l) : realm::List(l) {} - std::map::ComparableFunction, NotificationToken, FunctionComparator> m_notification_tokens; + std::map, NotificationToken, Protected> m_notification_tokens; }; template diff --git a/src/js_results.hpp b/src/js_results.hpp index 9bf60351..87876e78 100644 --- a/src/js_results.hpp +++ b/src/js_results.hpp @@ -32,7 +32,7 @@ namespace js { template class Results : public realm::Results { public: - Results(Results const&) : realm::Results(*this) {}; + Results(Results const& r) : realm::Results(r) {}; Results(Results&&) = default; Results& operator=(Results&&) = default; Results& operator=(Results const&) = default; @@ -43,7 +43,7 @@ class Results : public realm::Results { Results(SharedRealm r, const ObjectSchema& o, TableView tv, SortOrder s) : realm::Results(r, o, tv, s) {} Results(SharedRealm r, const ObjectSchema& o, LinkViewRef lv, util::Optional q = {}, SortOrder s = {}) : realm::Results(r, o, lv, q, s) {} - std::map::ComparableFunction, NotificationToken, FunctionComparator> m_notification_tokens; + std::map, NotificationToken, Protected> m_notification_tokens; }; template @@ -282,7 +282,7 @@ void ResultsClass::add_listener(ContextType ctx, ObjectType this_object, size arguments[1] = CollectionClass::create_collection_change_set(protected_ctx, change_set); Function::call(protected_ctx, protected_callback, protected_this, 2, arguments); }); - results->m_notification_tokens.emplace(std::make_pair(protected_ctx, protected_callback), std::move(token)); + results->m_notification_tokens.emplace(protected_callback, std::move(token)); } template diff --git a/src/js_types.hpp b/src/js_types.hpp index 2e797c80..b70b8f84 100644 --- a/src/js_types.hpp +++ b/src/js_types.hpp @@ -247,6 +247,7 @@ class Protected { bool operator!=(const ValueType &) const; bool operator==(const Protected &) const; bool operator!=(const Protected &) const; + bool operator()(const Protected& a, const Protected& b) const; }; template @@ -288,12 +289,6 @@ struct ReturnValue { void set_null(); void set_undefined(); }; - -template -struct FunctionComparator { - using ComparableFunction = std::pair, Protected>; - bool operator()(const ComparableFunction& a, const ComparableFunction& b) const; -}; template REALM_JS_INLINE typename T::Object create_object(typename T::Context ctx, typename ClassType::Internal* internal = nullptr) { diff --git a/src/jsc/jsc_init.hpp b/src/jsc/jsc_init.hpp index e2629534..de19d7b9 100644 --- a/src/jsc/jsc_init.hpp +++ b/src/jsc/jsc_init.hpp @@ -28,6 +28,5 @@ #include "jsc_exception.hpp" #include "jsc_return_value.hpp" #include "jsc_object_accessor.hpp" -#include "jsc_notification_map.hpp" #include "js_realm.hpp" diff --git a/src/jsc/jsc_notification_map.hpp b/src/jsc/jsc_notification_map.hpp deleted file mode 100644 index fbd8c3b0..00000000 --- a/src/jsc/jsc_notification_map.hpp +++ /dev/null @@ -1,34 +0,0 @@ -//////////////////////////////////////////////////////////////////////////// -// -// Copyright 2016 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. -// -//////////////////////////////////////////////////////////////////////////// - -#pragma once - -#include "jsc_types.hpp" - -namespace realm { -namespace js { - -template<> -bool FunctionComparator::operator()(const ComparableFunction& a, const ComparableFunction& b) const { - if ((JSGlobalContextRef)a.first != (JSGlobalContextRef)b.first) { - return false; - } - return JSValueIsStrictEqual(a.first, a.second, b.second); -} - -}} diff --git a/src/jsc/jsc_protected.hpp b/src/jsc/jsc_protected.hpp index 6c20d039..f3aa87ee 100644 --- a/src/jsc/jsc_protected.hpp +++ b/src/jsc/jsc_protected.hpp @@ -47,6 +47,10 @@ class Protected { operator bool() const { return m_context != nullptr; } + + bool operator() (const Protected& a, const Protected& b) const { + return a.m_context == b.m_context; + } }; template<> @@ -75,6 +79,12 @@ class Protected { operator bool() const { return m_value != nullptr; } + bool operator() (const Protected& a, const Protected& b) const { + if (a.m_context != b.m_context) { + return false; + } + return JSValueIsStrictEqual(a.m_context, a.m_value, b.m_value); + } }; template<> From 1e662f86e2936772585ba67475531a781a0b7006 Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Fri, 27 May 2016 13:54:39 -0700 Subject: [PATCH 07/14] move comparator to separate class --- src/js_list.hpp | 2 +- src/js_results.hpp | 2 +- src/js_types.hpp | 7 +++++-- src/jsc/jsc_protected.hpp | 21 +++++++++++++-------- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/js_list.hpp b/src/js_list.hpp index 752236a1..472caa9a 100644 --- a/src/js_list.hpp +++ b/src/js_list.hpp @@ -38,7 +38,7 @@ class List : public realm::List { List(std::shared_ptr r, const ObjectSchema& s, LinkViewRef l) noexcept : realm::List(r, s, l) {} List(const realm::List &l) : realm::List(l) {} - std::map, NotificationToken, Protected> m_notification_tokens; + std::map, NotificationToken, typename Protected::Comparator> m_notification_tokens; }; template diff --git a/src/js_results.hpp b/src/js_results.hpp index 87876e78..1addf422 100644 --- a/src/js_results.hpp +++ b/src/js_results.hpp @@ -43,7 +43,7 @@ class Results : public realm::Results { Results(SharedRealm r, const ObjectSchema& o, TableView tv, SortOrder s) : realm::Results(r, o, tv, s) {} Results(SharedRealm r, const ObjectSchema& o, LinkViewRef lv, util::Optional q = {}, SortOrder s = {}) : realm::Results(r, o, lv, q, s) {} - std::map, NotificationToken, Protected> m_notification_tokens; + std::map, NotificationToken, typename Protected::Comparator> m_notification_tokens; }; template diff --git a/src/js_types.hpp b/src/js_types.hpp index b70b8f84..ea531723 100644 --- a/src/js_types.hpp +++ b/src/js_types.hpp @@ -247,9 +247,12 @@ class Protected { bool operator!=(const ValueType &) const; bool operator==(const Protected &) const; bool operator!=(const Protected &) const; - bool operator()(const Protected& a, const Protected& b) const; + + struct Comparator { + bool operator()(const Protected& a, const Protected& b) const; + }; }; - + template struct Exception : public std::runtime_error { using ContextType = typename T::Context; diff --git a/src/jsc/jsc_protected.hpp b/src/jsc/jsc_protected.hpp index f3aa87ee..34ac870f 100644 --- a/src/jsc/jsc_protected.hpp +++ b/src/jsc/jsc_protected.hpp @@ -48,9 +48,11 @@ class Protected { return m_context != nullptr; } - bool operator() (const Protected& a, const Protected& b) const { - return a.m_context == b.m_context; - } + struct Comparator { + bool operator() (const Protected& a, const Protected& b) const { + return a.m_context == b.m_context; + } + }; }; template<> @@ -79,12 +81,15 @@ class Protected { operator bool() const { return m_value != nullptr; } - bool operator() (const Protected& a, const Protected& b) const { - if (a.m_context != b.m_context) { - return false; + + struct Comparator { + bool operator() (const Protected& a, const Protected& b) const { + if (a.m_context != b.m_context) { + return false; + } + return JSValueIsStrictEqual(a.m_context, a.m_value, b.m_value); } - return JSValueIsStrictEqual(a.m_context, a.m_value, b.m_value); - } + }; }; template<> From 03dad1ae90122fd7298980eaf5f2dfd638cc8cff Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Fri, 27 May 2016 14:03:12 -0700 Subject: [PATCH 08/14] hook up notification removal --- src/js_results.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/js_results.hpp b/src/js_results.hpp index 1addf422..ce4bbe3d 100644 --- a/src/js_results.hpp +++ b/src/js_results.hpp @@ -291,6 +291,7 @@ void ResultsClass::remove_listener(ContextType ctx, ObjectType this_object, s auto results = get_internal>(this_object); auto callback = Value::validated_to_function(ctx, arguments[0]); + results->m_notification_tokens.erase(Protected(ctx, callback)); } template @@ -298,6 +299,7 @@ void ResultsClass::remove_all_listeners(ContextType ctx, ObjectType this_obje validate_argument_count(argc, 0); auto results = get_internal>(this_object); + results->m_notification_tokens.clear(); } } // js From b60fbc2692e16c868616aa8a76c4524b945d6881 Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Fri, 27 May 2016 15:29:06 -0700 Subject: [PATCH 09/14] get basics workings --- examples/ReactExample/components/todo-app.js | 15 ++++---- .../src/impl/collection_notifier.cpp | 36 +++---------------- .../src/impl/collection_notifier.hpp | 14 +------- 3 files changed, 13 insertions(+), 52 deletions(-) diff --git a/examples/ReactExample/components/todo-app.js b/examples/ReactExample/components/todo-app.js index 5e497e4e..b75184b0 100644 --- a/examples/ReactExample/components/todo-app.js +++ b/examples/ReactExample/components/todo-app.js @@ -41,17 +41,19 @@ export default class TodoApp extends Component { // This is a Results object, which will live-update. this.todoLists = realm.objects('TodoList'); - this.todoLists.addListener(function(name, changes) { - console.log("changed: " + JSON.stringify(changes)); - }); - console.log("registered listener"); - if (this.todoLists.length < 1) { realm.write(() => { realm.create('TodoList', {name: 'Todo List'}); }); } + this.anotherList = realm.objects('TodoList'); + this.anotherList.addListener(function(name, changes) { + console.log("changed: " + JSON.stringify(changes)); + }); + console.log("registered listener"); + + // Bind all the methods that we will be passing as props. this.renderScene = this.renderScene.bind(this); this._addNewTodoList = this._addNewTodoList.bind(this); @@ -83,7 +85,6 @@ export default class TodoApp extends Component { component: TodoListView, passProps: { ref: 'listView', - items: this.todoLists, extraItems: extraItems, onPressItem: this._onPressTodoList, }, @@ -109,7 +110,7 @@ export default class TodoApp extends Component { } renderScene(route) { - return + return } _addNewTodoItem(list) { diff --git a/src/object-store/src/impl/collection_notifier.cpp b/src/object-store/src/impl/collection_notifier.cpp index 817f329e..ae2d074c 100644 --- a/src/object-store/src/impl/collection_notifier.cpp +++ b/src/object-store/src/impl/collection_notifier.cpp @@ -178,10 +178,8 @@ size_t CollectionNotifier::add_callback(CollectionChangeCallback callback) } m_callbacks.push_back({std::move(callback), token, false}); - if (m_callback_index == npos) { // Don't need to wake up if we're already sending notifications - Realm::Internal::get_coordinator(*m_realm).send_commit_notifications(); - m_have_callbacks = true; - } + Realm::Internal::get_coordinator(*m_realm).send_commit_notifications(); + return token; } @@ -200,22 +198,13 @@ void CollectionNotifier::remove_callback(size_t token) return; } - size_t idx = distance(begin(m_callbacks), it); - if (m_callback_index != npos && m_callback_index >= idx) { - --m_callback_index; - } - - old = std::move(*it); m_callbacks.erase(it); - - m_have_callbacks = !m_callbacks.empty(); } } void CollectionNotifier::remove_all_callbacks() { m_callbacks.clear(); - m_have_callbacks = false; } void CollectionNotifier::unregister() noexcept @@ -301,8 +290,8 @@ bool CollectionNotifier::deliver(Realm& realm, SharedGroup& sg, std::exception_p void CollectionNotifier::call_callbacks() { - while (auto fn = next_callback()) { - fn(m_changes_to_deliver, m_error); + for (auto &callback : m_callbacks) { + callback.fn(m_changes_to_deliver, m_error); } if (m_error) { @@ -313,23 +302,6 @@ void CollectionNotifier::call_callbacks() } } -CollectionChangeCallback CollectionNotifier::next_callback() -{ - std::lock_guard callback_lock(m_callback_mutex); - - for (++m_callback_index; m_callback_index < m_callbacks.size(); ++m_callback_index) { - auto& callback = m_callbacks[m_callback_index]; - if (!m_error && callback.initial_delivered && m_changes_to_deliver.empty()) { - continue; - } - callback.initial_delivered = true; - return callback.fn; - } - - m_callback_index = npos; - return nullptr; -} - void CollectionNotifier::attach_to(SharedGroup& sg) { REALM_ASSERT(!m_sg); diff --git a/src/object-store/src/impl/collection_notifier.hpp b/src/object-store/src/impl/collection_notifier.hpp index 97699cdb..29988eef 100644 --- a/src/object-store/src/impl/collection_notifier.hpp +++ b/src/object-store/src/impl/collection_notifier.hpp @@ -152,7 +152,7 @@ public: bool deliver(Realm&, SharedGroup&, std::exception_ptr); protected: - bool have_callbacks() const noexcept { return m_have_callbacks; } + bool have_callbacks() const noexcept { return m_callbacks.size() > 0; } void add_changes(CollectionChangeBuilder change) { m_accumulated_changes.merge(std::move(change)); } void set_table(Table const& table); std::unique_lock lock_target(); @@ -188,18 +188,6 @@ private: // while doing anything with them or m_callback_index std::mutex m_callback_mutex; std::vector m_callbacks; - - // Cached value for if m_callbacks is empty, needed to avoid deadlocks in - // run() due to lock-order inversion between m_callback_mutex and m_target_mutex - // It's okay if this value is stale as at worst it'll result in us doing - // some extra work. - std::atomic m_have_callbacks = {false}; - - // Iteration variable for looping over callbacks - // remove_callback() updates this when needed - size_t m_callback_index = npos; - - CollectionChangeCallback next_callback(); }; } // namespace _impl From e68324a63be008222d20fc7f6244e30168a9a986 Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Fri, 27 May 2016 17:13:55 -0700 Subject: [PATCH 10/14] start using updating list after first async response --- examples/ReactExample/components/realm.js | 1 + examples/ReactExample/components/todo-app.js | 8 +++++--- src/js_collection.hpp | 10 +--------- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/examples/ReactExample/components/realm.js b/examples/ReactExample/components/realm.js index 13d042ad..6e71639a 100644 --- a/examples/ReactExample/components/realm.js +++ b/examples/ReactExample/components/realm.js @@ -34,6 +34,7 @@ TodoList.schema = { name: 'TodoList', properties: { name: 'string', + creationDate: 'date', items: {type: 'list', objectType: 'Todo'}, }, }; diff --git a/examples/ReactExample/components/todo-app.js b/examples/ReactExample/components/todo-app.js index b75184b0..1bb92f89 100644 --- a/examples/ReactExample/components/todo-app.js +++ b/examples/ReactExample/components/todo-app.js @@ -43,13 +43,14 @@ export default class TodoApp extends Component { this.todoLists = realm.objects('TodoList'); if (this.todoLists.length < 1) { realm.write(() => { - realm.create('TodoList', {name: 'Todo List'}); + realm.create('TodoList', {name: 'Todo List', creationDate: new Date()}); }); } - this.anotherList = realm.objects('TodoList'); + this.anotherList = realm.objects('TodoList').sorted('creationDate'); this.anotherList.addListener(function(name, changes) { console.log("changed: " + JSON.stringify(changes)); + this.todoLists = this.anotherList; }); console.log("registered listener"); @@ -110,6 +111,7 @@ export default class TodoApp extends Component { } renderScene(route) { + console.log(this.todoLists); return } @@ -133,7 +135,7 @@ export default class TodoApp extends Component { } realm.write(() => { - realm.create('TodoList', {name: ''}); + realm.create('TodoList', {name: '', creationDate: new Date()}); }); this._setEditingRow(items.length - 1); diff --git a/src/js_collection.hpp b/src/js_collection.hpp index 790e3484..9a758d18 100644 --- a/src/js_collection.hpp +++ b/src/js_collection.hpp @@ -47,7 +47,7 @@ template typename T::Value CollectionClass::create_collection_change_set(ContextType ctx, const CollectionChangeSet &change_set) { ObjectType object = Object::create_empty(ctx); - std::vector deletions, insertions, modifications, moves; + std::vector deletions, insertions, modifications; for (auto index : change_set.deletions.as_indexes()) { deletions.push_back(Value::from_number(ctx, index)); } @@ -63,14 +63,6 @@ typename T::Value CollectionClass::create_collection_change_set(ContextType c } Object::set_property(ctx, object, "modifications", Object::create_array(ctx, modifications)); - for (auto& move : change_set.moves) { - ObjectType move_object = Object::create_empty(ctx); - Object::set_property(ctx, move_object, "from", Value::from_number(ctx, move.from)); - Object::set_property(ctx, move_object, "to", Value::from_number(ctx, move.to)); - moves.push_back(move_object); - } - Object::set_property(ctx, object, "moves", Object::create_array(ctx, moves)); - return object; } From b1db10e1775658ecf850e9e2c615a785da340e57 Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Thu, 30 Jun 2016 11:06:28 -0700 Subject: [PATCH 11/14] implement list notification removal --- src/js_list.hpp | 2 ++ src/js_types.hpp | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/js_list.hpp b/src/js_list.hpp index 3f1cbc3e..1339500c 100644 --- a/src/js_list.hpp +++ b/src/js_list.hpp @@ -273,6 +273,7 @@ void ListClass::remove_listener(ContextType ctx, ObjectType this_object, size auto list = get_internal>(this_object); auto callback = Value::validated_to_function(ctx, arguments[0]); + list->m_notification_tokens.erase(Protected(ctx, callback)); } template @@ -280,6 +281,7 @@ void ListClass::remove_all_listeners(ContextType ctx, ObjectType this_object, validate_argument_count(argc, 0); auto list = get_internal>(this_object); + list->m_notification_tokens.clear(); } } // js diff --git a/src/js_types.hpp b/src/js_types.hpp index ea531723..d0f3b6a4 100644 --- a/src/js_types.hpp +++ b/src/js_types.hpp @@ -247,12 +247,12 @@ class Protected { bool operator!=(const ValueType &) const; bool operator==(const Protected &) const; bool operator!=(const Protected &) const; - + struct Comparator { bool operator()(const Protected& a, const Protected& b) const; }; }; - + template struct Exception : public std::runtime_error { using ContextType = typename T::Context; @@ -292,7 +292,7 @@ struct ReturnValue { void set_null(); void set_undefined(); }; - + template REALM_JS_INLINE typename T::Object create_object(typename T::Context ctx, typename ClassType::Internal* internal = nullptr) { return Object::template create_instance(ctx, internal); From 56a0b903f950fc4c71218843be771c36ab70c893 Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Thu, 30 Jun 2016 15:28:45 -0700 Subject: [PATCH 12/14] Support Promise-based async tests from Xcode tests We already supported this for React Native and Node test runners. Now we support returning promises from tests everywhere. --- tests/ios/RJSModuleLoader.h | 1 + tests/ios/RJSModuleLoader.m | 12 +++++++ tests/ios/RealmJSCoreTests.m | 64 +++++++++++++++++++++++++++--------- tests/js/package.json | 5 ++- 4 files changed, 65 insertions(+), 17 deletions(-) diff --git a/tests/ios/RJSModuleLoader.h b/tests/ios/RJSModuleLoader.h index 91ab5bac..a9c8f77c 100644 --- a/tests/ios/RJSModuleLoader.h +++ b/tests/ios/RJSModuleLoader.h @@ -27,5 +27,6 @@ - (JSValue *)loadModuleFromURL:(NSURL *)url error:(NSError **)error; - (JSValue *)loadJSONFromURL:(NSURL *)url error:(NSError **)error; +- (JSValue *)loadGlobalModule:(NSString *)name relativeToURL:(NSURL *)url error:(NSError **)error; @end diff --git a/tests/ios/RJSModuleLoader.m b/tests/ios/RJSModuleLoader.m index 3c0613a9..39cbb066 100644 --- a/tests/ios/RJSModuleLoader.m +++ b/tests/ios/RJSModuleLoader.m @@ -195,6 +195,18 @@ static NSString * const RJSModuleLoaderErrorDomain = @"RJSModuleLoaderErrorDomai BOOL isDirectory; if ([fileManager fileExistsAtPath:moduleURL.path isDirectory:&isDirectory] && isDirectory) { + NSURL *packageURL = [moduleURL URLByAppendingPathComponent:@"package.json"]; + NSDictionary *package; + + if ([fileManager fileExistsAtPath:packageURL.path]) { + NSError *error; + NSData *data = [NSData dataWithContentsOfURL:packageURL options:0 error:&error]; + + package = data ? [NSJSONSerialization JSONObjectWithData:data options:0 error:&error] : nil; + NSAssert(package, @"%@", error); + } + + moduleURL = [moduleURL URLByAppendingPathComponent:package[@"main"] ?: @"index.js"]; return [self loadModuleFromURL:moduleURL error:error]; } diff --git a/tests/ios/RealmJSCoreTests.m b/tests/ios/RealmJSCoreTests.m index d3bf62c9..5fd0cf91 100644 --- a/tests/ios/RealmJSCoreTests.m +++ b/tests/ios/RealmJSCoreTests.m @@ -31,12 +31,23 @@ + (XCTestSuite *)defaultTestSuite { XCTestSuite *suite = [super defaultTestSuite]; - JSContext *context = [[JSContext alloc] init]; + + // We need a JS context from a UIWebView so it has setTimeout, Promise, etc. + UIWebView *webView = [[UIWebView alloc] init]; + JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; RJSModuleLoader *moduleLoader = [[RJSModuleLoader alloc] initWithContext:context]; NSURL *realmURL = [[NSBundle bundleForClass:self] URLForResource:@"index" withExtension:@"js" subdirectory:@"lib"]; NSURL *scriptURL = [[NSBundle bundleForClass:self] URLForResource:@"index" withExtension:@"js" subdirectory:@"js"]; NSError *error; + // The ES6 global Promise constructor was added in iOS 8. + if (![context[@"Promise"] isObject]) { + JSValue *promiseModule = [moduleLoader loadGlobalModule:@"es6-promise" relativeToURL:scriptURL error:&error]; + NSAssert(promiseModule, @"%@", error); + + context[@"Promise"] = promiseModule[@"Promise"]; + } + // Create Realm constructor in the JS context. RJSInitializeInContext(context.JSGlobalContextRef); @@ -73,25 +84,46 @@ JSContext *context = testObject.context; context.exception = nil; - [testObject invokeMethod:@"runTest" withArguments:@[NSStringFromClass(self.class), method]]; + JSValue *promise = [testObject invokeMethod:@"runTest" withArguments:@[NSStringFromClass(self.class), method]]; - JSValue *exception = context.exception; - if (exception) { - JSValue *message = [exception hasProperty:@"message"] ? exception[@"message"] : exception; - NSString *source = [exception hasProperty:@"sourceURL"] ? [exception[@"sourceURL"] toString] : nil; - NSUInteger line = [exception hasProperty:@"line"] ? [exception[@"line"] toUInt32] - 1 : 0; - NSURL *sourceURL = nil; + if (context.exception) { + [self recordException:context.exception]; + return; + } - if (source) { - NSString *path = [NSString pathWithComponents:@[[@(__FILE__) stringByDeletingLastPathComponent], @"..", @"js", source.lastPathComponent]]; - sourceURL = [NSURL URLWithString:path]; - } + if ([promise isObject]) { + XCTestExpectation *expectation = [self expectationWithDescription:@"Promise resolved or rejected"]; - [self recordFailureWithDescription:message.description - inFile:sourceURL ? sourceURL.absoluteString : @(__FILE__) - atLine:sourceURL ? line : __LINE__ - expected:YES]; + JSValue *onFulfilled = [JSValue valueWithObject:^() { + [expectation fulfill]; + } inContext:context]; + + JSValue *onRejected = [JSValue valueWithObject:^(JSValue *error) { + [self recordException:error]; + [expectation fulfill]; + } inContext:context]; + + [promise invokeMethod:@"then" withArguments:@[onFulfilled, onRejected]]; + + [self waitForExpectationsWithTimeout:5.0 handler:NULL]; } } +- (void)recordException:(JSValue *)exception { + JSValue *message = [exception hasProperty:@"message"] ? exception[@"message"] : exception; + NSString *source = [exception hasProperty:@"sourceURL"] ? [exception[@"sourceURL"] toString] : nil; + NSUInteger line = [exception hasProperty:@"line"] ? [exception[@"line"] toUInt32] - 1 : 0; + NSURL *sourceURL = nil; + + if (source) { + NSString *path = [NSString pathWithComponents:@[[@(__FILE__) stringByDeletingLastPathComponent], @"..", @"js", source.lastPathComponent]]; + sourceURL = [NSURL URLWithString:path]; + } + + [self recordFailureWithDescription:message.description + inFile:sourceURL ? sourceURL.absoluteString : @(__FILE__) + atLine:sourceURL ? line : __LINE__ + expected:YES]; +} + @end diff --git a/tests/js/package.json b/tests/js/package.json index 07bbe26a..c7afa5d5 100644 --- a/tests/js/package.json +++ b/tests/js/package.json @@ -1,5 +1,8 @@ { "name": "realm-tests", "version": "0.0.1", - "private": true + "private": true, + "dependencies": { + "es6-promise": "^3.2.1" + } } From 3095840d673ef8a6696e6ef1482b72c03e02a103 Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Fri, 8 Jul 2016 16:00:18 -0700 Subject: [PATCH 13/14] support latest react-native version --- examples/ReactExample/package.json | 4 ++-- tests/react-test-app/package.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/ReactExample/package.json b/examples/ReactExample/package.json index b1555215..5bc9e31a 100644 --- a/examples/ReactExample/package.json +++ b/examples/ReactExample/package.json @@ -6,8 +6,8 @@ "start": "react-native start" }, "dependencies": { - "react": "15.1.0", - "react-native": "^0.27.1", + "react": "~15.2.0", + "react-native": "^0.29.0", "realm": "file:../.." } } diff --git a/tests/react-test-app/package.json b/tests/react-test-app/package.json index 21802055..2ac3847f 100644 --- a/tests/react-test-app/package.json +++ b/tests/react-test-app/package.json @@ -6,8 +6,8 @@ "start": "react-native start" }, "dependencies": { - "react": "15.1.0", - "react-native": "^0.27.1", + "react": "~15.2.0", + "react-native": "^0.29.0", "react-native-fs": "^1.1.0", "xmlbuilder": "^4.2.1", "realm": "file:../..", From 65d052280dbd83aa95c2582786e804edaac21a22 Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Fri, 8 Jul 2016 16:48:48 -0700 Subject: [PATCH 14/14] compilation fixes for node --- src/js_list.hpp | 2 +- src/js_results.hpp | 2 +- src/node/node_protected.hpp | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/js_list.hpp b/src/js_list.hpp index 1339500c..6767f089 100644 --- a/src/js_list.hpp +++ b/src/js_list.hpp @@ -261,7 +261,7 @@ void ListClass::add_listener(ContextType ctx, ObjectType this_object, size_t list->add_notification_callback([=](CollectionChangeSet change_set, std::exception_ptr exception) { ValueType arguments[2]; - arguments[0] = protected_this; + arguments[0] = static_cast(protected_this); arguments[1] = Value::from_undefined(protected_ctx); Function::call(protected_ctx, protected_callback, protected_this, 2, arguments); }); diff --git a/src/js_results.hpp b/src/js_results.hpp index 6d354b88..9fdb5cb0 100644 --- a/src/js_results.hpp +++ b/src/js_results.hpp @@ -272,7 +272,7 @@ void ResultsClass::add_listener(ContextType ctx, ObjectType this_object, size auto token = results->add_notification_callback([=](CollectionChangeSet change_set, std::exception_ptr exception) { ValueType arguments[2]; - arguments[0] = protected_this; + arguments[0] = static_cast(protected_this); arguments[1] = CollectionClass::create_collection_change_set(protected_ctx, change_set); Function::call(protected_ctx, protected_callback, protected_this, 2, arguments); }); diff --git a/src/node/node_protected.hpp b/src/node/node_protected.hpp index 042a10a1..7253816c 100644 --- a/src/node/node_protected.hpp +++ b/src/node/node_protected.hpp @@ -50,6 +50,10 @@ class Protected { bool operator!=(const Protected &other) const { return m_value != other.m_value; } + + struct Comparator { + bool operator()(const Protected& a, const Protected& b) const { return a == b; } + }; }; } // node