BUG FIX: A schema is required when Realm is opened in a query-based sync situation (#1985)

This commit is contained in:
Kenneth Geisshirt 2018-08-24 08:50:27 +02:00 committed by GitHub
parent 05aef95bbd
commit 1b1b51ded2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 34 additions and 8 deletions

View File

@ -14,6 +14,7 @@ X.Y.Z Release notes (YYYY-MM-DD)
* [Sync] Added support for `Session.addConnectionNotification()` and `Session.removeConnectionNotification`.
* [Sync] Added `Session.connectionState`.
* [Sync] Added `Session.isConnected()`.
* [Sync] Added a check to prevent the case where query-based sync is opened without a schema. It is not possible to deduce the schema, and subscribing to a query-based sync will lead to an error if no schema is defined (#1976).
### Bug fixes
* React Native for Android now supports the Android Gradle Plugin 3.0 (#1742).

View File

@ -96,6 +96,8 @@ class Realm {
* In this case, `config.schema` is _optional_ or not have changed, unless
* `config.schemaVersion` is incremented, in which case the Realm will be automatically
* migrated to use the new schema.
* In the case of query-based sync, `config.schema` is required. An exception will be
* thrown if `config.schema` is not defined.
* @param {Realm~Configuration} [config] - **Required** when first creating the Realm.
* @throws {Error} If anything in the provided `config` is invalid.
* @throws {IncompatibleSyncedRealmError} when an incompatible synced Realm is opened
@ -105,8 +107,11 @@ class Realm {
/**
* Open a Realm asynchronously with a promise. If the Realm is synced, it will be fully
* synchronized before it is available.
* In the case of query-based sync, `config.schema` is required. An exception will be
* thrown if `config.schema` is not defined.
* @param {Realm~Configuration} config - if no config is defined, it will open the default realm
* @returns {ProgressPromise} - a promise that will be resolved with the Realm instance when it's available.
* @throws {Error} If anything in the provided `config` is invalid.
*/
static open(config) {}

View File

@ -80,6 +80,9 @@ module.exports = function(realmConstructor) {
// result in sync rejecting the writes. `_waitForDownload` ensures that the session is kept
// alive until our callback has returned, which prevents it from being torn down and recreated
// when we close the schemaless Realm and open it with the correct schema.
if (!config.sync.fullSynchronization && config.schema === undefined) {
throw new Error('Query-based sync requires a schema.');
}
let syncSession;
let promise = new Promise((resolve, reject) => {
let realm = new realmConstructor(waitForDownloadConfig(config));

View File

@ -609,6 +609,13 @@ SharedRealm RealmClass<T>::create_shared_realm(ContextType ctx, realm::Realm::Co
handleRealmFileException(ctx, config, ex);
}
#if REALM_ENABLE_SYNC
auto schema = realm->schema();
if (realm->is_partial() && schema.empty() && config.cache) {
throw std::invalid_argument("Query-based sync requires a schema.");
}
#endif
GlobalContextType global_context = Context<T>::get_global_context(ctx);
if (!realm->m_binding_context) {
realm->m_binding_context.reset(new RealmDelegate<T>(realm, global_context));

View File

@ -49,7 +49,7 @@ module.exports = {
}
return Realm.Sync.User.register('http://localhost:9080', uuid(), 'password').then(user => {
const config = user.createConfiguration({ sync: { url: 'realm://localhost:9080/~/myrealm' },
const config = user.createConfiguration({ sync: { url: 'realm://localhost:9080/~/myrealm', fullSynchronization: true },
schema: [{ name: 'IntegerPrimaryKey', properties: { int: 'int?' }, primaryKey: 'int' },
{ name: 'StringPrimaryKey', properties: { string: 'string?' }, primaryKey: 'string' },
{ name: 'NoPrimaryKey', properties: { string: 'string' }},

View File

@ -174,16 +174,16 @@ module.exports = {
let config = (user, url) => {
return {
schema: [
Realm.Permissions.Permission,
Realm.Permissions.User,
Realm.Permissions.Role,
{
name: 'Object',
properties: {
value: 'int',
permissions: '__Permission[]'
}
}
},
Realm.Permissions.Permission,
Realm.Permissions.User,
Realm.Permissions.Role,
],
sync: {user: user, url: url, fullSynchronization: false }
};

View File

@ -478,7 +478,8 @@ module.exports = {
sync: {
user,
error : err => console.log(err),
url: 'realm://localhost:9080/~/sync-v1'
url: 'realm://localhost:9080/~/sync-v1',
fullSynchronization: true,
}
};
return Realm.open(config)
@ -520,7 +521,8 @@ module.exports = {
sync: {
user,
error : err => console.log(err),
url: 'realm://localhost:9080/~/sync-v1'
url: 'realm://localhost:9080/~/sync-v1',
fullSynchronization: true,
}
};
@ -776,7 +778,8 @@ module.exports = {
url: `realm://localhost:9080/default/__partial/`,
_disableQueryBasedSyncUrlChecks: true,
fullSynchronization: false,
}
},
schema: [ { name: 'Dog', properties: { name: 'string' } } ]
};
const realm = new Realm(config1);
TestCase.assertFalse(realm.isClosed);
@ -816,6 +819,12 @@ module.exports = {
TestCase.assertThrows(() => Realm.automaticSyncConfiguration('foo', 'bar')); // too many arguments
}
function schemalessNotAllowed() {
let config = Realm.Sync.User.current.createConfiguration();
config.schema = undefined; // no schema in the configuration
Realm.deleteFile(config);
TestCase.assertThrows(() => { let realm = new Realm(config); } );
}
return runOutOfProcess(__dirname + '/partial-sync-api-helper.js', username, REALM_MODULE_PATH)
.then(() => {
@ -826,6 +835,7 @@ module.exports = {
__partialIsNotAllowed();
shouldFail();
defaultRealmInvalidArguments();
schemalessNotAllowed();
return new Promise((resolve, reject) => {
let config = Realm.Sync.User.current.createConfiguration();