Merge branch 'master' into kneth/xcode9

# Conflicts:
#	tests/js/list-tests.js
#	tests/js/results-tests.js
This commit is contained in:
blagoev 2017-12-13 18:56:17 +02:00
commit aa9ae00c35
25 changed files with 402 additions and 58 deletions

View File

@ -1,9 +1,69 @@
X.Y.Z Release notes
=============================================================
### Breaking changes
* None.
### Enhancements
* Added property `Realm.isClosed` which indicates if a Realm instance is closed or not.
### Bug fixes
* None.
### Internal
* None.
2.0.13 Release notes (2017-12-8)
=============================================================
### Breaking changes
* None.
### Enhancements
* None.
### Bug fixes
* [Object Server] When authentication fails due to a misbehaving server, a proper error is thrown.
### Internal
* [Object Server] Strings can now be assigned to Date columns. When that happens the JavaScript Date constructor will be invoked to parse the string.
* [Object Server] Base64 strings can now be assigned to Data columns.
2.0.12 Release notes (2017-12-1)
=============================================================
### Breaking changes
* None.
### Enhancements
* None.
### Bug fixes
* Fixed a bug in 3rd party JSON parser: `localeconv()` does not exist on Android API < 21 and should not be called.
### Internal
* Fixed issues in unit tests (`addListener` hangs on Android).
* Upgraded to Realm Sync 2.1.8 (no external effects).
2.0.11 Release notes (2017-11-23)
=============================================================
### Breaking changes
* None.
### Enhancements
* None
### Bug fixes
* [Object Server] Fixed a bug where deleted-then-recreated objects with identical primary keys to become empty.
* [Object Server] Fixed a bug in outward partial sync is changed to ensure convergence of partial sync in the case where the client creates a primary key object, that is already present on the server, and subscribes to it in the same transaction.
### Internal
* Updated to Realm Sync 2.1.7 (see under "Bug fixes").
2.0.10 Release notes (2017-11-21) 2.0.10 Release notes (2017-11-21)
============================================================= =============================================================
### Breaking changes ### Breaking changes
* None. * None.
### Enchancements ### Enhancements
* None * None
### Bug fixes ### Bug fixes
@ -17,7 +77,7 @@
### Breaking changes ### Breaking changes
* None. * None.
### Enchancements ### Enhancements
* None * None
### Bug fixes ### Bug fixes
@ -31,7 +91,7 @@
### Breaking changes ### Breaking changes
* None. * None.
### Enchancements ### Enhancements
* [Object Server] Improving performance of processing large changesets. * [Object Server] Improving performance of processing large changesets.
### Bug fixes ### Bug fixes
@ -46,7 +106,7 @@
### Breaking changes ### Breaking changes
* None * None
### Enchancements ### Enhancements
* None * None
### Bug fixes ### Bug fixes
@ -61,7 +121,7 @@
### Breaking changes ### Breaking changes
* None. * None.
### Enchancements ### Enhancements
* Improved notification performance for objects with no object or list properties. * Improved notification performance for objects with no object or list properties.
### Bug fixes ### Bug fixes
@ -77,7 +137,7 @@
### Breaking changes ### Breaking changes
* None. * None.
### Enchancements ### Enhancements
* None. * None.
### Bug fixes ### Bug fixes

View File

@ -10,9 +10,37 @@
"object-store" "object-store"
], ],
"sources": [ "sources": [
"src/node/platform.cpp",
"src/js_realm.cpp", "src/js_realm.cpp",
"src/node/node_init.cpp" "src/node/node_init.cpp",
"src/node/platform.cpp",
"src/concurrent_deque.hpp",
"src/event_loop_dispatcher.hpp",
"src/js_class.hpp",
"src/js_collection.hpp",
"src/js_list.hpp",
"src/js_object_accessor.hpp",
"src/js_observable.hpp",
"src/js_realm.hpp",
"src/js_realm_object.hpp",
"src/js_results.hpp",
"src/js_schema.hpp",
"src/js_sync.hpp",
"src/js_types.hpp",
"src/js_util.hpp",
"src/node/node_class.hpp",
"src/node/node_context.hpp",
"src/node/node_exception.hpp",
"src/node/node_function.hpp",
"src/node/node_init.hpp",
"src/node/node_object.hpp",
"src/node/node_protected.hpp",
"src/node/node_return_value.hpp",
"src/node/node_string.hpp",
"src/node/node_types.hpp",
"src/node/node_value.hpp",
"src/platform.hpp",
"src/rpc.hpp",
], ],
"include_dirs": [ "include_dirs": [
"src" "src"
@ -28,6 +56,100 @@
"destination": "<(module_path)" "destination": "<(module_path)"
} }
] ]
},
{
"target_name": "scripts",
"type": "none",
"sources": [
"CHANGELOG.md",
"README.md",
"binding.gyp",
"dependencies.list",
"package.json",
"realm.gypi",
"target_defaults.gypi",
"lib/collection-methods.js",
"lib/errors.js",
"lib/extensions.js",
"lib/index.d.ts",
"lib/index.js",
"lib/management-schema.js",
"lib/permission-api.js",
"lib/submit-analytics.js",
"lib/user-methods.js",
"lib/browser/base64.js",
"lib/browser/collections.js",
"lib/browser/constants.js",
"lib/browser/index.js",
"lib/browser/lists.js",
"lib/browser/objects.js",
"lib/browser/results.js",
"lib/browser/rpc.js",
"lib/browser/session.js",
"lib/browser/user.js",
"lib/browser/util.js"
"scripts/build-node-pre-gyp.ps1",
"scripts/build-node-pre-gyp.sh",
"scripts/ccache-clang++.sh",
"scripts/ccache-clang.sh",
"scripts/changelog-header.sh",
"scripts/check-environment.js",
"scripts/docker-android-wrapper.sh",
"scripts/docker-wrapper.sh",
"scripts/docker_build_wrapper.sh",
"scripts/download-object-server.sh",
"scripts/download-realm.js",
"scripts/download_and_start_server.sh",
"scripts/find-ios-device.rb",
"scripts/git-win-symlink-aliases",
"scripts/handle-license-check.js",
"scripts/prepublish.js",
"scripts/publish.sh",
"scripts/react-tests-android.js",
"scripts/set-version.sh",
"scripts/test.sh",
"tests/.eslintrc.json",
"tests/index.js",
"tests/js/admin-user-helper.js",
"tests/js/asserts.js",
"tests/js/async-tests.js",
"tests/js/download-api-helper.js",
"tests/js/encryption-tests.js",
"tests/js/garbage-collection.js",
"tests/js/index.js",
"tests/js/linkingobjects-tests.js",
"tests/js/list-tests.js",
"tests/js/migration-tests.js",
"tests/js/object-id-tests.js",
"tests/js/object-tests.js",
"tests/js/package.json",
"tests/js/permission-tests.js",
"tests/js/query-tests.js",
"tests/js/query-tests.json",
"tests/js/realm-tests.js",
"tests/js/results-tests.js",
"tests/js/schemas.js",
"tests/js/session-tests.js",
"tests/js/user-tests.js",
"tests/js/worker-tests-script.js",
"tests/js/worker.js",
"tests/package.json",
"tests/spec/helpers/mock_realm.js",
"tests/spec/helpers/reporters.js",
"tests/spec/helpers/setup-module-path.js",
"tests/spec/support/jasmine.json",
"tests/spec/unit_tests.js",
"tests/test-runners/ava/package.json",
"tests/test-runners/ava/test.js",
"tests/test-runners/jest/package.json",
"tests/test-runners/jest/test.js",
"tests/test-runners/mocha/package.json",
"tests/test-runners/mocha/test.js",
]
} }
] ]
} }

View File

@ -1,5 +1,5 @@
PACKAGE_NAME=realm-js PACKAGE_NAME=realm-js
VERSION=2.0.10 VERSION=2.0.13
REALM_CORE_VERSION=4.0.2 REALM_CORE_VERSION=4.0.2
REALM_SYNC_VERSION=2.1.6 REALM_SYNC_VERSION=2.1.8
REALM_OBJECT_SERVER_VERSION=2.0.21 REALM_OBJECT_SERVER_VERSION=2.0.21

View File

@ -72,6 +72,14 @@ class Realm {
*/ */
get isInTransaction() {} get isInTransaction() {}
/**
* Indicates if this Realm has been closed.
* @type {boolean}
* @readonly
* @since 2.1.0
*/
get isClosed() {}
/** /**
* Gets the sync session if this is a synced Realm * Gets the sync session if this is a synced Realm
* @type {Session} * @type {Session}

View File

@ -408,7 +408,7 @@ class Adapter {
* @param {string} local_path - the local path where realm files are stored * @param {string} local_path - the local path where realm files are stored
* @param {string} server_url - the sync server to listen to * @param {string} server_url - the sync server to listen to
* @param {SyncUser} admin_user - an admin user obtained by calling `new Realm.Sync.User.adminUser` * @param {SyncUser} admin_user - an admin user obtained by calling `new Realm.Sync.User.adminUser`
* @param {string} regex - a regular expression used to determine which cahnged Realms should be monitored - * @param {string} regex - a regular expression used to determine which changed Realms should be monitored -
* use `.*` to match all all Realms * use `.*` to match all all Realms
* @param {function(realm_path)} change_callback - called when a new transaction is available * @param {function(realm_path)} change_callback - called when a new transaction is available
* to process for the given realm_path * to process for the given realm_path

View File

@ -60,6 +60,7 @@ function setupRealm(realm, realmId) {
'schemaVersion', 'schemaVersion',
'syncSession', 'syncSession',
'isInTransaction', 'isInTransaction',
'isClosed',
'subscribeToObjects', 'subscribeToObjects',
].forEach((name) => { ].forEach((name) => {
Object.defineProperty(realm, name, {get: util.getterForProperty(name)}); Object.defineProperty(realm, name, {get: util.getterForProperty(name)});

1
lib/index.d.ts vendored
View File

@ -458,6 +458,7 @@ declare class Realm {
readonly schema: Realm.ObjectSchema[]; readonly schema: Realm.ObjectSchema[];
readonly schemaVersion: number; readonly schemaVersion: number;
readonly isInTransaction: boolean; readonly isInTransaction: boolean;
readonly isClosed: boolean;
readonly syncSession: Realm.Sync.Session | null; readonly syncSession: Realm.Sync.Session | null;

View File

@ -154,7 +154,15 @@ function _authenticate(userConstructor, server, json, callback) {
const promise = performFetch(url, options) const promise = performFetch(url, options)
.then((response) => { .then((response) => {
if (response.status !== 200) { const contentType = response.headers.get('Content-Type');
if (contentType.indexOf('application/json') === -1) {
return response.text().then((body) => {
throw new AuthError({
title: `Could not authenticate: Realm Object Server didn't respond with valid JSON`,
body,
});
});
} else if (!response.ok) {
return response.json().then((body) => Promise.reject(new AuthError(body))); return response.json().then((body) => Promise.reject(new AuthError(body)));
} else { } else {
return response.json().then(function (body) { return response.json().then(function (body) {

24
package-lock.json generated
View File

@ -1,6 +1,6 @@
{ {
"name": "realm", "name": "realm",
"version": "2.0.0-rc11", "version": "2.0.12",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@ -270,9 +270,9 @@
} }
}, },
"bluebird": { "bluebird": {
"version": "3.5.0", "version": "3.5.1",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
"integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw=", "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==",
"dev": true "dev": true
}, },
"boom": { "boom": {
@ -1537,18 +1537,18 @@
"optional": true "optional": true
}, },
"jsdoc": { "jsdoc": {
"version": "3.5.4", "version": "3.5.5",
"resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.5.4.tgz", "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.5.5.tgz",
"integrity": "sha1-zu73xLrEM1yxD/QeOg9Yk5pTRCg=", "integrity": "sha512-6PxB65TAU4WO0Wzyr/4/YhlGovXl0EVYfpKbpSroSj0qBxT4/xod/l40Opkm38dRHRdQgdeY836M0uVnJQG7kg==",
"dev": true, "dev": true,
"requires": { "requires": {
"babylon": "7.0.0-beta.19", "babylon": "7.0.0-beta.19",
"bluebird": "3.5.0", "bluebird": "3.5.1",
"catharsis": "0.8.9", "catharsis": "0.8.9",
"escape-string-regexp": "1.0.5", "escape-string-regexp": "1.0.5",
"js2xmlparser": "3.0.0", "js2xmlparser": "3.0.0",
"klaw": "2.0.0", "klaw": "2.0.0",
"marked": "0.3.6", "marked": "0.3.7",
"mkdirp": "0.5.1", "mkdirp": "0.5.1",
"requizzle": "0.2.1", "requizzle": "0.2.1",
"strip-json-comments": "2.0.1", "strip-json-comments": "2.0.1",
@ -2497,9 +2497,9 @@
} }
}, },
"marked": { "marked": {
"version": "0.3.6", "version": "0.3.7",
"resolved": "https://registry.npmjs.org/marked/-/marked-0.3.6.tgz", "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.7.tgz",
"integrity": "sha1-ssbGGPzOzk74bE/Gy4p8v1rtqNc=", "integrity": "sha512-zBEP4qO1YQp5aXHt8S5wTiOv9i2X74V/LQL0zhUNvVaklt6Ywa6lChxIvS+ibYlCGgADwKwZFhjC3+XfpsvQvQ==",
"dev": true "dev": true
}, },
"mime-db": { "mime-db": {

View File

@ -1,7 +1,7 @@
{ {
"name": "realm", "name": "realm",
"description": "Realm is a mobile database: an alternative to SQLite and key-value stores", "description": "Realm is a mobile database: an alternative to SQLite and key-value stores",
"version": "2.0.10", "version": "2.0.13",
"license": "Apache-2.0", "license": "Apache-2.0",
"homepage": "https://realm.io", "homepage": "https://realm.io",
"keywords": [ "keywords": [
@ -99,7 +99,7 @@
"eslint": "^3.2.2", "eslint": "^3.2.2",
"eslint-plugin-jasmine": "^2.1.0", "eslint-plugin-jasmine": "^2.1.0",
"eslint-plugin-react": "^6.7.0", "eslint-plugin-react": "^6.7.0",
"jsdoc": "^3.4.0", "jsdoc": "^3.5.5",
"license-checker": "^8.0.3", "license-checker": "^8.0.3",
"mockery": "^2.0.0", "mockery": "^2.0.0",
"rimraf": "^2.6.1", "rimraf": "^2.6.1",

View File

@ -63,6 +63,68 @@
"src/object-store/src/parser/query_builder.cpp", "src/object-store/src/parser/query_builder.cpp",
"src/object-store/src/util/format.cpp", "src/object-store/src/util/format.cpp",
"src/object-store/src/util/uuid.cpp", "src/object-store/src/util/uuid.cpp",
"src/object-store/src/binding_callback_thread_observer.hpp",
"src/object-store/src/binding_context.hpp",
"src/object-store/src/collection_notifications.hpp",
"src/object-store/src/descriptor_ordering.hpp",
"src/object-store/src/execution_context_id.hpp",
"src/object-store/src/feature_checks.hpp",
"src/object-store/src/impl/apple/external_commit_helper.hpp",
"src/object-store/src/impl/apple/keychain_helper.hpp",
"src/object-store/src/impl/collection_change_builder.hpp",
"src/object-store/src/impl/collection_notifier.hpp",
"src/object-store/src/impl/epoll/external_commit_helper.hpp",
"src/object-store/src/impl/external_commit_helper.hpp",
"src/object-store/src/impl/generic/external_commit_helper.hpp",
"src/object-store/src/impl/list_notifier.hpp",
"src/object-store/src/impl/notification_wrapper.hpp",
"src/object-store/src/impl/object_accessor_impl.hpp",
"src/object-store/src/impl/object_notifier.hpp",
"src/object-store/src/impl/primitive_list_notifier.hpp",
"src/object-store/src/impl/realm_coordinator.hpp",
"src/object-store/src/impl/results_notifier.hpp",
"src/object-store/src/impl/transact_log_handler.hpp",
"src/object-store/src/impl/weak_realm_notifier.hpp",
"src/object-store/src/impl/windows/external_commit_helper.hpp",
"src/object-store/src/index_set.hpp",
"src/object-store/src/list.hpp",
"src/object-store/src/object.hpp",
"src/object-store/src/object_accessor.hpp",
"src/object-store/src/object_schema.hpp",
"src/object-store/src/object_store.hpp",
"src/object-store/src/parser/parser.hpp",
"src/object-store/src/parser/query_builder.hpp",
"src/object-store/src/property.hpp",
"src/object-store/src/results.hpp",
"src/object-store/src/schema.hpp",
"src/object-store/src/shared_realm.hpp",
"src/object-store/src/sync/impl/apple/network_reachability_observer.hpp",
"src/object-store/src/sync/impl/apple/system_configuration.hpp",
"src/object-store/src/sync/impl/network_reachability.hpp",
"src/object-store/src/sync/impl/sync_client.hpp",
"src/object-store/src/sync/impl/sync_file.hpp",
"src/object-store/src/sync/impl/sync_metadata.hpp",
"src/object-store/src/sync/partial_sync.hpp",
"src/object-store/src/sync/sync_config.hpp",
"src/object-store/src/sync/sync_manager.hpp",
"src/object-store/src/sync/sync_permission.hpp",
"src/object-store/src/sync/sync_session.hpp",
"src/object-store/src/sync/sync_user.hpp",
"src/object-store/src/thread_safe_reference.hpp",
"src/object-store/src/util/aligned_union.hpp",
"src/object-store/src/util/android/event_loop_signal.hpp",
"src/object-store/src/util/any.hpp",
"src/object-store/src/util/apple/event_loop_signal.hpp",
"src/object-store/src/util/atomic_shared_ptr.hpp",
"src/object-store/src/util/compiler.hpp",
"src/object-store/src/util/event_loop_signal.hpp",
"src/object-store/src/util/format.hpp",
"src/object-store/src/util/generic/event_loop_signal.hpp",
"src/object-store/src/util/tagged_bool.hpp",
"src/object-store/src/util/time.hpp",
"src/object-store/src/util/uuid.hpp",
"src/object-store/src/util/uv/event_loop_signal.hpp",
], ],
"conditions": [ "conditions": [
["OS=='win'", { ["OS=='win'", {
@ -115,13 +177,15 @@
"target_name": "realm-core", "target_name": "realm-core",
"type": "none", "type": "none",
"direct_dependent_settings": { "direct_dependent_settings": {
"libraries": [ "-lrealm<(debug_library_suffix)" ],
"conditions": [ "conditions": [
["use_realm_debug", { ["use_realm_debug", {
"defines": [ "REALM_DEBUG=1" ] "defines": [ "REALM_DEBUG=1" ]
}] }]
] ]
}, },
"link_settings": {
"libraries": [ "-lrealm<(debug_library_suffix)" ],
},
"variables": { "variables": {
"prefix": "<!(node -p \"process.env.REALM_CORE_PREFIX || String()\")" "prefix": "<!(node -p \"process.env.REALM_CORE_PREFIX || String()\")"
}, },
@ -130,7 +194,7 @@
"all_dependent_settings": { "all_dependent_settings": {
"include_dirs": [ "<(prefix)/src", "<(prefix)/<(build_directory)/src" ], "include_dirs": [ "<(prefix)/src", "<(prefix)/<(build_directory)/src" ],
}, },
"direct_dependent_settings": { "link_settings": {
"library_dirs": [ "<(prefix)/<(build_directory)/src/realm" ] "library_dirs": [ "<(prefix)/<(build_directory)/src/realm" ]
} }
}, { }, {
@ -145,7 +209,7 @@
"target_name": "realm-sync", "target_name": "realm-sync",
"type": "none", "type": "none",
"dependencies": [ "realm-core" ], "dependencies": [ "realm-core" ],
"direct_dependent_settings": { "link_settings": {
"conditions": [ "conditions": [
["OS=='win'", { ["OS=='win'", {
"libraries": [ "-lrealm-sync<(debug_library_suffix)" ] "libraries": [ "-lrealm-sync<(debug_library_suffix)" ]
@ -180,7 +244,7 @@
{ {
"target_name": "OpenSSL", "target_name": "OpenSSL",
"type": "none", "type": "none",
"direct_dependent_settings": { "link_settings": {
"conditions": [ "conditions": [
["OS=='win'", { ["OS=='win'", {
"libraries": [ "libeay32.lib", "ssleay32.lib" ], "libraries": [ "libeay32.lib", "ssleay32.lib" ],

View File

@ -998,7 +998,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 2.0.10; CURRENT_PROJECT_VERSION = 2.0.13;
CXX = "$(SRCROOT)/../scripts/ccache-clang++.sh"; CXX = "$(SRCROOT)/../scripts/ccache-clang++.sh";
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
@ -1062,7 +1062,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 2.0.10; CURRENT_PROJECT_VERSION = 2.0.13;
CXX = "$(SRCROOT)/../scripts/ccache-clang++.sh"; CXX = "$(SRCROOT)/../scripts/ccache-clang++.sh";
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO; ENABLE_NS_ASSERTIONS = NO;

View File

@ -22,6 +22,10 @@
#include "js_realm_object.hpp" #include "js_realm_object.hpp"
#include "js_schema.hpp" #include "js_schema.hpp"
#if REALM_ENABLE_SYNC
#include <realm/util/base64.hpp>
#endif
namespace realm { namespace realm {
class List; class List;
class Object; class Object;
@ -239,7 +243,23 @@ struct Unbox<JSEngine, BinaryData> {
if (ctx->is_null(value)) { if (ctx->is_null(value)) {
return BinaryData(); return BinaryData();
} }
ctx->m_owned_binary_data = js::Value<JSEngine>::validated_to_binary(ctx->m_ctx, value, "Property"); #if REALM_ENABLE_SYNC
// realm-sync holds the base64-decoding routine
if (js::Value<JSEngine>::is_string(ctx->m_ctx, value)) {
// the incoming value might be a base64 string, so let's try to parse it
std::string str = js::Value<JSEngine>::to_string(ctx->m_ctx, value);
size_t max_size = util::base64_decoded_size(str.size());
std::unique_ptr<char[]> data(new char[max_size]);
if (auto size = util::base64_decode(str, data.get(), max_size)) {
ctx->m_owned_binary_data = OwnedBinaryData(std::move(data), *size);
return ctx->m_owned_binary_data.get();
} else {
throw std::runtime_error("Attempting to populate BinaryData from string that is not valid base64");
}
}
#endif
ctx->m_owned_binary_data = js::Value<JSEngine>::validated_to_binary(ctx->m_ctx, value);
return ctx->m_owned_binary_data.get(); return ctx->m_owned_binary_data.get();
} }
}; };
@ -257,7 +277,14 @@ struct Unbox<JSEngine, Timestamp> {
if (ctx->is_null(value)) { if (ctx->is_null(value)) {
return Timestamp(); return Timestamp();
} }
auto date = js::Value<JSEngine>::validated_to_date(ctx->m_ctx, value, "Property"); typename JSEngine::Value date;
if (js::Value<JSEngine>::is_string(ctx->m_ctx, value)) {
// the incoming value might be a date string, so let the Date constructor have at it
date = js::Value<JSEngine>::to_date(ctx->m_ctx, value);
} else {
date = js::Value<JSEngine>::validated_to_date(ctx->m_ctx, value);
}
double milliseconds = js::Value<JSEngine>::to_number(ctx->m_ctx, date); double milliseconds = js::Value<JSEngine>::to_number(ctx->m_ctx, date);
int64_t seconds = milliseconds / 1000; int64_t seconds = milliseconds / 1000;
int32_t nanoseconds = ((int64_t)milliseconds % 1000) * 1000000; int32_t nanoseconds = ((int64_t)milliseconds % 1000) * 1000000;

View File

@ -198,6 +198,7 @@ public:
static void get_in_memory(ContextType, ObjectType, ReturnValue &); static void get_in_memory(ContextType, ObjectType, ReturnValue &);
static void get_read_only(ContextType, ObjectType, ReturnValue &); static void get_read_only(ContextType, ObjectType, ReturnValue &);
static void get_is_in_transaction(ContextType, ObjectType, ReturnValue &); static void get_is_in_transaction(ContextType, ObjectType, ReturnValue &);
static void get_is_closed(ContextType, ObjectType, ReturnValue &);
#if REALM_ENABLE_SYNC #if REALM_ENABLE_SYNC
static void get_sync_session(ContextType, ObjectType, ReturnValue &); static void get_sync_session(ContextType, ObjectType, ReturnValue &);
#endif #endif
@ -259,6 +260,7 @@ public:
{"inMemory", {wrap<get_in_memory>, nullptr}}, {"inMemory", {wrap<get_in_memory>, nullptr}},
{"readOnly", {wrap<get_read_only>, nullptr}}, {"readOnly", {wrap<get_read_only>, nullptr}},
{"isInTransaction", {wrap<get_is_in_transaction>, nullptr}}, {"isInTransaction", {wrap<get_is_in_transaction>, nullptr}},
{"isClosed", {wrap<get_is_closed>, nullptr}},
#if REALM_ENABLE_SYNC #if REALM_ENABLE_SYNC
{"syncSession", {wrap<get_sync_session>, nullptr}}, {"syncSession", {wrap<get_sync_session>, nullptr}},
#endif #endif
@ -694,6 +696,11 @@ void RealmClass<T>::get_is_in_transaction(ContextType ctx, ObjectType object, Re
return_value.set(get_internal<T, RealmClass<T>>(object)->get()->is_in_transaction()); return_value.set(get_internal<T, RealmClass<T>>(object)->get()->is_in_transaction());
} }
template<typename T>
void RealmClass<T>::get_is_closed(ContextType ctx, ObjectType object, ReturnValue &return_value) {
return_value.set(get_internal<T, RealmClass<T>>(object)->get()->is_closed());
}
#if REALM_ENABLE_SYNC #if REALM_ENABLE_SYNC
template<typename T> template<typename T>
void RealmClass<T>::get_sync_session(ContextType ctx, ObjectType object, ReturnValue &return_value) { void RealmClass<T>::get_sync_session(ContextType ctx, ObjectType object, ReturnValue &return_value) {
@ -738,7 +745,7 @@ void RealmClass<T>::wait_for_download_completion(ContextType ctx, ObjectType thi
ValueType callback_arguments[1]; ValueType callback_arguments[1];
callback_arguments[0] = object; callback_arguments[0] = object;
Function<T>::callback(protected_ctx, protected_callback, typename T::Object(), 1, callback_arguments); Function<T>::callback(protected_ctx, protected_callback, typename T::Object(), 1, callback_arguments);
} }

View File

@ -389,9 +389,9 @@ inline bool Value<T>::is_valid_for_property_type(ContextType context, const Valu
case PropertyType::String: case PropertyType::String:
return is_string(context, value); return is_string(context, value);
case PropertyType::Data: case PropertyType::Data:
return is_binary(context, value); return is_binary(context, value) || is_string(context, value);
case PropertyType::Date: case PropertyType::Date:
return is_date(context, value); return is_date(context, value) || is_string(context, value);
case PropertyType::Object: case PropertyType::Object:
return true; return true;
case PropertyType::Any: case PropertyType::Any:

View File

@ -203,6 +203,15 @@ inline JSObjectRef jsc::Value::to_constructor(JSContextRef ctx, const JSValueRef
template<> template<>
inline JSObjectRef jsc::Value::to_date(JSContextRef ctx, const JSValueRef &value) { inline JSObjectRef jsc::Value::to_date(JSContextRef ctx, const JSValueRef &value) {
if (JSValueIsString(ctx, value)) {
JSValueRef error;
std::array<JSValueRef, 1> args { value };
if (JSObjectRef result = JSObjectMakeDate(ctx, args.size(), args.data(), &error)) {
return result;
} else {
throw jsc::Exception(ctx, error);
}
}
return to_object(ctx, value); return to_object(ctx, value);
} }

View File

@ -21,9 +21,9 @@
#include "node_string.hpp" #include "node_string.hpp"
#include "node_protected.hpp" #include "node_protected.hpp"
#include "node_context.hpp" #include "node_context.hpp"
#include "node_value.hpp"
#include "node_object.hpp" #include "node_object.hpp"
#include "node_function.hpp" #include "node_function.hpp"
#include "node_value.hpp"
#include "node_exception.hpp" #include "node_exception.hpp"
#include "node_return_value.hpp" #include "node_return_value.hpp"
#include "node_class.hpp" #include "node_class.hpp"

View File

@ -204,11 +204,6 @@ inline v8::Local<v8::Object> node::Value::to_array(v8::Isolate* isolate, const v
return to_object(isolate, value); return to_object(isolate, value);
} }
template<>
inline v8::Local<v8::Object> node::Value::to_date(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {
return to_object(isolate, value);
}
template<> template<>
inline v8::Local<v8::Function> node::Value::to_function(v8::Isolate* isolate, const v8::Local<v8::Value> &value) { inline v8::Local<v8::Function> node::Value::to_function(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {
return value->IsFunction() ? v8::Local<v8::Function>::Cast(value) : v8::Local<v8::Function>(); return value->IsFunction() ? v8::Local<v8::Function>::Cast(value) : v8::Local<v8::Function>();
@ -218,6 +213,16 @@ template<>
inline v8::Local<v8::Function> node::Value::to_constructor(v8::Isolate* isolate, const v8::Local<v8::Value> &value) { inline v8::Local<v8::Function> node::Value::to_constructor(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {
return to_function(isolate, value); return to_function(isolate, value);
} }
template<>
inline v8::Local<v8::Object> node::Value::to_date(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {
if (value->IsString()) {
v8::Local<v8::Function> date_constructor = to_constructor(isolate, node::Object::get_property(isolate, isolate->GetCurrentContext()->Global(), "Date"));
std::array<v8::Local<v8::Value>, 1> args { {value} };
return node::Function::construct(isolate, date_constructor, args.size(), args.data());
}
return to_object(isolate, value);
}
} // js } // js
} // realm } // realm

View File

@ -39,7 +39,6 @@ module.exports = {
}); });
TestCase.assertThrowsContaining(() => new Realm.List(), 'constructor'); TestCase.assertThrowsContaining(() => new Realm.List(), 'constructor');
TestCase.assertType(Realm.List, 'function');
TestCase.assertInstanceOf(Realm.List, Function); TestCase.assertInstanceOf(Realm.List, Function);
}, },

View File

@ -297,6 +297,15 @@ module.exports = {
}); });
TestCase.assertArraysEqual(new Uint8Array(object.dataCol), RANDOM_DATA); TestCase.assertArraysEqual(new Uint8Array(object.dataCol), RANDOM_DATA);
if (Realm.Sync) {
// The base64 decoder comes from realm-sync
// Should be able to also set a data property to base64-encoded string.
realm.write(function() {
object.dataCol = require('buffer/').Buffer.from(RANDOM_DATA).toString('base64');
});
TestCase.assertArraysEqual(new Uint8Array(object.dataCol), RANDOM_DATA);
}
// Should be to set a data property to a DataView. // Should be to set a data property to a DataView.
realm.write(function() { realm.write(function() {
object.dataCol = new DataView(RANDOM_DATA.buffer); object.dataCol = new DataView(RANDOM_DATA.buffer);
@ -348,7 +357,7 @@ module.exports = {
object.dataCol = 1; object.dataCol = 1;
}); });
TestCase.assertThrows(function() { TestCase.assertThrows(function() {
object.dataCol = 'data'; object.dataCol = 'some binary data';
}); });
TestCase.assertThrows(function() { TestCase.assertThrows(function() {
object.dataCol = [1]; object.dataCol = [1];
@ -431,15 +440,18 @@ module.exports = {
// test different dates // test different dates
var realm = new Realm({schema: [schemas.DateObject]}); var realm = new Realm({schema: [schemas.DateObject]});
const stringifiedDate = new Date();
realm.write(function() { realm.write(function() {
realm.create('Date', { currentDate: new Date(10000) }); realm.create('Date', { currentDate: new Date(10000) });
realm.create('Date', { currentDate: new Date(-10000) }); realm.create('Date', { currentDate: new Date(-10000) });
realm.create('Date', { currentDate: new Date(1000000000000) }); realm.create('Date', { currentDate: new Date(1000000000000) });
realm.create('Date', { currentDate: new Date(-1000000000000) }); realm.create('Date', { currentDate: new Date(-1000000000000) });
realm.create('Date', { currentDate: stringifiedDate.toString() });
}); });
TestCase.assertEqual(realm.objects('Date')[0].currentDate.getTime(), 10000); TestCase.assertEqual(realm.objects('Date')[0].currentDate.getTime(), 10000);
TestCase.assertEqual(realm.objects('Date')[1].currentDate.getTime(), -10000); TestCase.assertEqual(realm.objects('Date')[1].currentDate.getTime(), -10000);
TestCase.assertEqual(realm.objects('Date')[2].currentDate.getTime(), 1000000000000); TestCase.assertEqual(realm.objects('Date')[2].currentDate.getTime(), 1000000000000);
TestCase.assertEqual(realm.objects('Date')[3].currentDate.getTime(), -1000000000000); TestCase.assertEqual(realm.objects('Date')[3].currentDate.getTime(), -1000000000000);
TestCase.assertEqual(realm.objects('Date')[4].currentDate.toString(), stringifiedDate.toString());
} }
}; };

View File

@ -3,6 +3,7 @@
"version": "0.0.1", "version": "0.0.1",
"private": true, "private": true,
"dependencies": { "dependencies": {
"buffer": "^5.0.8",
"es6-promise": "^3.2.1" "es6-promise": "^3.2.1"
} }
} }

View File

@ -57,6 +57,13 @@ module.exports = {
TestCase.assertEqual(realm2.path, defaultDir + testPath2); TestCase.assertEqual(realm2.path, defaultDir + testPath2);
}, },
testRealmIsClosed: function() {
const realm = new Realm({schema: []});
TestCase.assertFalse(realm.isClosed);
realm.close();
TestCase.assertTrue(realm.isClosed);
},
testRealmConstructorSchemaVersion: function() { testRealmConstructorSchemaVersion: function() {
const defaultRealm = new Realm({schema: []}); const defaultRealm = new Realm({schema: []});
TestCase.assertEqual(defaultRealm.schemaVersion, 0); TestCase.assertEqual(defaultRealm.schemaVersion, 0);

View File

@ -451,11 +451,11 @@ module.exports = {
}); });
return new Promise((r, _reject) => { return new Promise((r, _reject) => {
resolve = r; resolve = r;
realm.write(() => { realm.write(() => {
realm.create('TestObject', { doubleCol: 1 }); realm.create('TestObject', { doubleCol: 1 });
});
}); });
});
}, },
testResultsAggregateFunctions: function() { testResultsAggregateFunctions: function() {

View File

@ -160,6 +160,20 @@ module.exports = {
.catch((e) => assertIsError(e)); .catch((e) => assertIsError(e));
}, },
testLoginTowardsMisbehavingServer() {
const username = uuid();
// Try authenticating towards a server thats clearly not ROS
return Realm.Sync.User.register('https://github.com/realm/realm-js', username, 'user')
.catch((e) => {
assertIsError(e);
TestCase.assertEqual(
e.message,
"Could not authenticate: Realm Object Server didn't respond with valid JSON"
);
});
},
testAll() { testAll() {
const all = Realm.Sync.User.all; const all = Realm.Sync.User.all;
TestCase.assertArrayLength(Object.keys(all), 0); TestCase.assertArrayLength(Object.keys(all), 0);
@ -324,4 +338,3 @@ module.exports = {
}, */ }, */
}; };

14
vendor/json.hpp vendored
View File

@ -8333,15 +8333,15 @@ class basic_json
// check if buffer was large enough // check if buffer was large enough
assert(static_cast<size_t>(written_bytes) < m_buf.size()); assert(static_cast<size_t>(written_bytes) < m_buf.size());
#if defined(ANDROID)
// Android NDK doesn't have access to locale info yet; API < 21 doesn't have localeconv()
const char thousands_sep = ',';
const char decimal_point = '.';
#else
// read information from locale // read information from locale
const auto loc = localeconv(); const auto loc = localeconv();
assert(loc != nullptr); assert(loc != nullptr);
#if defined(ANDROID)
// Android NDK doesn't have access to locale info yet
const char thousands_sep = ',';
const char decimal_point = '.';
#else
const char thousands_sep = !loc->thousands_sep ? '\0' const char thousands_sep = !loc->thousands_sep ? '\0'
: loc->thousands_sep[0]; : loc->thousands_sep[0];
@ -11176,11 +11176,11 @@ basic_json_parser_74:
// since dealing with strtod family of functions, we're // since dealing with strtod family of functions, we're
// getting the decimal point char from the C locale facilities // getting the decimal point char from the C locale facilities
// instead of C++'s numpunct facet of the current std::locale // instead of C++'s numpunct facet of the current std::locale
const auto loc = localeconv();
assert(loc != nullptr);
#if defined(ANDROID) #if defined(ANDROID)
const char decimal_point_char = '.'; const char decimal_point_char = '.';
#else #else
const auto loc = localeconv();
assert(loc != nullptr);
const char decimal_point_char = (loc->decimal_point == nullptr) ? '.' : loc->decimal_point[0]; const char decimal_point_char = (loc->decimal_point == nullptr) ? '.' : loc->decimal_point[0];
#endif #endif